├── .appveyor.yml ├── .github └── workflows │ ├── dist.yaml │ └── main.yml ├── .gitignore ├── .indent.pro ├── .makefile ├── .travis.yml ├── CMakeLists.txt ├── Changes ├── License ├── Makefile.am ├── ReadMe.md ├── announcement.msg ├── bootstrap ├── cmake └── config.h.in ├── configure.ac ├── doc └── doxygen.cfg ├── docker ├── README.mkd ├── alpine-3.7 ├── fedora-25 ├── ubuntu-14.04 └── ubuntu-16.04 ├── examples ├── anchors.yaml ├── array.yaml ├── global-tag.yaml ├── json.yaml ├── mapping.yaml ├── numbers.yaml ├── strings.yaml ├── tags.yaml └── yaml-version.yaml ├── include ├── Makefile.am └── yaml.h ├── pkg ├── ReadMe.md └── docker │ ├── .gitignore │ ├── Dockerfile │ ├── Makefile │ ├── output │ └── ReadMe │ └── scripts │ └── libyaml-dist.sh ├── regression-inputs └── clusterfuzz-testcase-minimized-5607885063061504.yml ├── src ├── Makefile.am ├── api.c ├── dumper.c ├── emitter.c ├── loader.c ├── parser.c ├── reader.c ├── scanner.c ├── writer.c └── yaml_private.h ├── tests ├── CMakeLists.txt ├── Makefile.am ├── ReadMe.md ├── example-deconstructor-alt.c ├── example-deconstructor.c ├── example-reformatter-alt.c ├── example-reformatter.c ├── run-all-tests.sh ├── run-dumper.c ├── run-emitter-test-suite.c ├── run-emitter.c ├── run-loader.c ├── run-parser-test-suite.c ├── run-parser.c ├── run-scanner.c ├── test-reader.c └── test-version.c ├── yaml-0.1.pc.in └── yamlConfig.cmake.in /.appveyor.yml: -------------------------------------------------------------------------------- 1 | version: 0.2.5.{build} 2 | 3 | image: 4 | - Visual Studio 2015 5 | - Visual Studio 2013 6 | 7 | build_script: 8 | 9 | # 10 | # CMake based in-source build and tests using Visual Studio 11 | # 12 | 13 | # Use 32-bit default generator ("Visual Studio 12 2013" or "Visual Studio 14 2015") 14 | - cmake . 15 | - cmake --build . --config Release --clean-first 16 | - ctest -C Release 17 | 18 | # 19 | # Autoconf based in-source build and tests under Cygwin using gcc 20 | # 21 | 22 | # 32-bit cygwin build 23 | - C:\cygwin\bin\sh -c "export PATH=/usr/bin:/usr/local/bin:$PATH && ./bootstrap && ./configure && make && make test && make distclean" 24 | # 64-bit cygwin build 25 | - C:\cygwin64\bin\sh -c "export PATH=/usr/bin:/usr/local/bin:$PATH && ./bootstrap && ./configure && make && make test && make distclean" 26 | # 32-bit mingw-w64 build 27 | - C:\cygwin\bin\sh -c "export PATH=/usr/bin:/usr/local/bin:$PATH && ./bootstrap && ./configure --host=i686-w64-mingw32 --target=i686-w64-mingw32 && make && make test && make distclean" 28 | # 64-bit mingw-w64 build 29 | - C:\cygwin64\bin\sh -c "export PATH=/usr/bin:/usr/local/bin:$PATH && ./bootstrap && ./configure --host=x86_64-w64-mingw32 --target=x86_64-w64-mingw32 && make && make test && make distclean" 30 | -------------------------------------------------------------------------------- /.github/workflows/dist.yaml: -------------------------------------------------------------------------------- 1 | name: dist 2 | 3 | on: 4 | push: 5 | branches: [ release/* ] 6 | 7 | jobs: 8 | dist: 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - uses: actions/checkout@v4 13 | - run: env | sort 14 | 15 | - name: Get image 16 | run: | 17 | time docker pull yamlio/libyaml-dev 18 | docker images | grep libyaml 19 | 20 | - run: | 21 | make -C pkg/docker libyaml-dist-ci 22 | ls -l pkg/docker/output 23 | 24 | - uses: actions/upload-artifact@v2 25 | with: 26 | name: release 27 | path: pkg/docker/output/yaml-0* 28 | 29 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: linux/mac 2 | 3 | on: 4 | push: 5 | branches: [ '*' ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | 11 | build: 12 | 13 | env: 14 | CC: ${{ matrix.compiler }} 15 | runs-on: ${{ matrix.os }} 16 | strategy: 17 | matrix: 18 | compiler: 19 | - gcc 20 | - clang 21 | os: 22 | - ubuntu-latest 23 | - macOS-latest 24 | 25 | steps: 26 | - uses: actions/checkout@v4 27 | 28 | - run: env | sort 29 | - name: Install software 30 | if: ${{ matrix.os == 'macOS-latest' }} 31 | run: | 32 | brew install automake bash coreutils make libtool 33 | echo "/usr/local/opt/coreutils/libexec/gnubin" >> $GITHUB_PATH 34 | echo "/usr/local/opt/make/libexec/gnubin" >> $GITHUB_PATH 35 | - name: Fetch branches 36 | run: | 37 | git config remote.origin.fetch +refs/heads/*:refs/remotes/origin/* 38 | git fetch --unshallow 39 | 40 | - run: ./bootstrap 41 | - run: ./configure 42 | - run: make 43 | - run: make test-all 44 | 45 | - run: | 46 | git clean -d -x -f 47 | rm -fr tests/run-test-suite 48 | git worktree prune 49 | 50 | - name: Compiler version 51 | run: ${{ matrix.compiler }} --version 52 | - run: cmake . 53 | - run: make 54 | - run: make test 55 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.BAK 2 | *.a 3 | *.cmake 4 | *.dll 5 | *.exe 6 | *.la 7 | *.lo 8 | *.log 9 | *.o 10 | *.pc 11 | *.so 12 | *.trs 13 | *~ 14 | .deps/ 15 | .libs/ 16 | /Testing/ 17 | /libtool 18 | CMakeCache.txt 19 | CMakeFiles/ 20 | GNUmakefile 21 | Makefile 22 | Makefile.in 23 | /aclocal.m4 24 | /autom4te.cache 25 | /config 26 | config.h* 27 | /config.status 28 | /configure 29 | stamp-h1 30 | !config/config.h.in 31 | /tests/run-dumper 32 | /tests/run-emitter 33 | /tests/run-emitter-test-suite 34 | /tests/run-loader 35 | /tests/run-parser 36 | /tests/run-parser-test-suite 37 | /tests/run-scanner 38 | /tests/example-deconstructor 39 | /tests/example-deconstructor-alt 40 | /tests/example-reformatter 41 | /tests/example-reformatter-alt 42 | /tests/run-test-suite 43 | /tests/test-reader 44 | /tests/test-version 45 | /dist/ 46 | -------------------------------------------------------------------------------- /.indent.pro: -------------------------------------------------------------------------------- 1 | -kr -nut -nce -l250 2 | -------------------------------------------------------------------------------- /.makefile: -------------------------------------------------------------------------------- 1 | # This file is used for common development targets that can be done with 2 | # needing the cumbersome bootstrapping process. 3 | # 4 | # You can use it like this: 5 | # 6 | # make -f .makefile indent 7 | # 8 | # If you copy or link this file to `GNUmakefile` then you can just do: 9 | # 10 | # make indent 11 | # 12 | # When copied to `GNUmakefile`, this file is can also be used for bootstrapping 13 | # Makefile targets. Since GNUmakefile is loaded before Makefile, we do the 14 | # bootstrapping tasks need to get a Makefile first, then we use the Makefile to 15 | # make our target. 16 | 17 | # Remind user when they are using GNUmakefile: 18 | ifeq ($(lastword $(MAKEFILE_LIST)),GNUmakefile) 19 | $(info *** NOTE: GNUmakefile in use. ***) 20 | endif 21 | 22 | MAKE_TARGETS := \ 23 | all \ 24 | all-am \ 25 | all-recursive \ 26 | docker-build \ 27 | docker-dist \ 28 | install \ 29 | test \ 30 | test-all \ 31 | test-suite \ 32 | 33 | # SOURCE_FILES := $(shell find . | grep '\.c$$') 34 | SOURCE_FILES := $(shell find tests/run-test-suite | grep '\.c$$') 35 | ifneq ($(shell which gindent),) 36 | INDENT := gindent 37 | else 38 | INDENT := indent 39 | endif 40 | 41 | # 42 | # Proxy make targets: 43 | # 44 | default: all 45 | 46 | # Proxy these targets to the real Makefile, after bootstrapping is necessary. 47 | $(MAKE_TARGETS): Makefile 48 | @make -f $< $@ 49 | 50 | Makefile: Makefile.in 51 | ./configure 52 | 53 | Makefile.in: 54 | ./bootstrap 55 | 56 | # 57 | # Development make targets: 58 | # 59 | indent: 60 | $(INDENT) $(SOURCE_FILES) 61 | 62 | distclean purge: 63 | git clean -dxf -e GNUmakefile 64 | rm -fr tests/run-test-suite 65 | git worktree prune 66 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | 3 | matrix: 4 | include: 5 | - os: linux 6 | compiler: gcc 7 | sudo: required 8 | - os: linux 9 | compiler: clang 10 | sudo: required 11 | - os: osx 12 | compiler: gcc 13 | - os: osx 14 | compiler: clang 15 | 16 | before_install: 17 | 18 | # Travis branch-specific clone problem workaround: 19 | - git config remote.origin.fetch +refs/heads/*:refs/remotes/origin/* 20 | - git fetch 21 | - env | sort 22 | 23 | - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then 24 | pip install --user scikit-ci-addons==0.15.0; 25 | ci_addons travis/install_cmake 3.2.0; 26 | fi 27 | 28 | script: tests/run-all-tests.sh 29 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | cmake_minimum_required(VERSION 3.0) 3 | project (yaml C) 4 | 5 | set (YAML_VERSION_MAJOR 0) 6 | set (YAML_VERSION_MINOR 2) 7 | set (YAML_VERSION_PATCH 5) 8 | set (YAML_VERSION_STRING "${YAML_VERSION_MAJOR}.${YAML_VERSION_MINOR}.${YAML_VERSION_PATCH}") 9 | 10 | option(BUILD_SHARED_LIBS "Build libyaml as a shared library" OFF) 11 | set(YAML_STATIC_LIB_NAME "yaml" CACHE STRING "Base name of static library output") 12 | 13 | # 14 | # Output directories for a build tree 15 | # 16 | if(NOT DEFINED CMAKE_RUNTIME_OUTPUT_DIRECTORY) 17 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) 18 | endif() 19 | 20 | # 21 | # Install relative directories 22 | # 23 | if(NOT DEFINED INSTALL_LIB_DIR) 24 | set(INSTALL_LIB_DIR lib) 25 | endif() 26 | if(NOT DEFINED INSTALL_BIN_DIR) 27 | set(INSTALL_BIN_DIR bin) 28 | endif() 29 | if(NOT DEFINED INSTALL_INCLUDE_DIR) 30 | set(INSTALL_INCLUDE_DIR include) 31 | endif() 32 | if(NOT DEFINED INSTALL_CMAKE_DIR) 33 | set(INSTALL_CMAKE_DIR cmake) 34 | endif() 35 | 36 | # 37 | # Build library 38 | # 39 | set(SRCS 40 | src/api.c 41 | src/dumper.c 42 | src/emitter.c 43 | src/loader.c 44 | src/parser.c 45 | src/reader.c 46 | src/scanner.c 47 | src/writer.c 48 | ) 49 | 50 | set(config_h ${CMAKE_CURRENT_BINARY_DIR}/include/config.h) 51 | configure_file( 52 | cmake/config.h.in 53 | ${config_h} 54 | ) 55 | 56 | add_library(yaml ${SRCS}) 57 | 58 | if(NOT BUILD_SHARED_LIBS) 59 | set_target_properties(yaml 60 | PROPERTIES OUTPUT_NAME ${YAML_STATIC_LIB_NAME} 61 | ) 62 | endif() 63 | 64 | set_target_properties(yaml 65 | PROPERTIES DEFINE_SYMBOL YAML_DECLARE_EXPORT 66 | ) 67 | 68 | target_compile_definitions(yaml 69 | PRIVATE HAVE_CONFIG_H 70 | PUBLIC 71 | $<$>:YAML_DECLARE_STATIC> 72 | $<$:_CRT_SECURE_NO_WARNINGS> 73 | ) 74 | 75 | target_include_directories(yaml PUBLIC 76 | $ 77 | $ 78 | $ 79 | ) 80 | 81 | # 82 | # Install rules 83 | # 84 | install( 85 | FILES 86 | include/yaml.h 87 | DESTINATION include COMPONENT Development 88 | ) 89 | 90 | install( 91 | TARGETS yaml 92 | EXPORT yamlTargets 93 | RUNTIME DESTINATION "${INSTALL_BIN_DIR}" COMPONENT Runtime 94 | LIBRARY DESTINATION "${INSTALL_LIB_DIR}" COMPONENT Development 95 | ARCHIVE DESTINATION "${INSTALL_LIB_DIR}" COMPONENT Development 96 | ) 97 | 98 | # 99 | # Add tests 100 | # 101 | include(CTest) # This module defines BUILD_TESTING option 102 | if(BUILD_TESTING) 103 | add_subdirectory(tests) 104 | endif() 105 | 106 | # 107 | # Generate 'yamlConfig.cmake', 'yamlConfigVersion.cmake' and 'yamlTargets.cmake' 108 | # 109 | include(CMakePackageConfigHelpers) 110 | 111 | # Configure 'yamlConfig.cmake' for a build tree 112 | set(CONFIG_DIR_CONFIG ${PROJECT_BINARY_DIR}) 113 | set(config_file ${PROJECT_BINARY_DIR}/yamlConfig.cmake) 114 | configure_package_config_file( 115 | yamlConfig.cmake.in 116 | ${config_file} 117 | INSTALL_DESTINATION ${PROJECT_BINARY_DIR} 118 | PATH_VARS CONFIG_DIR_CONFIG 119 | NO_CHECK_REQUIRED_COMPONENTS_MACRO 120 | ) 121 | 122 | # Configure 'yamlTargets.cmake' for a build tree 123 | export(TARGETS yaml 124 | FILE ${PROJECT_BINARY_DIR}/yamlTargets.cmake 125 | ) 126 | 127 | # Configure and install 'yamlConfig.cmake' for an install tree 128 | set(CONFIG_DIR_CONFIG ${INSTALL_CMAKE_DIR}) 129 | set(install_config_file ${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/yamlConfig.cmake ) 130 | configure_package_config_file( 131 | yamlConfig.cmake.in 132 | ${install_config_file} 133 | INSTALL_DESTINATION ${CMAKE_INSTALL_PREFIX}/${INSTALL_CMAKE_DIR} 134 | PATH_VARS CONFIG_DIR_CONFIG 135 | NO_CHECK_REQUIRED_COMPONENTS_MACRO 136 | ) 137 | install( 138 | FILES ${install_config_file} 139 | DESTINATION ${INSTALL_CMAKE_DIR} COMPONENT Development 140 | ) 141 | 142 | # Configure and install 'yamlTargets.cmake' for an install tree 143 | install(EXPORT yamlTargets 144 | FILE yamlTargets.cmake 145 | DESTINATION ${INSTALL_CMAKE_DIR} 146 | COMPONENT Development 147 | ) 148 | 149 | # Configure 'yamlConfigVersion.cmake' for a build tree 150 | set(config_version_file ${PROJECT_BINARY_DIR}/yamlConfigVersion.cmake) 151 | write_basic_package_version_file( 152 | ${config_version_file} 153 | VERSION ${YAML_VERSION_STRING} 154 | COMPATIBILITY AnyNewerVersion 155 | ) 156 | # ... and install for an install tree 157 | install( 158 | FILES ${config_version_file} 159 | DESTINATION ${INSTALL_CMAKE_DIR} COMPONENT Development 160 | ) 161 | -------------------------------------------------------------------------------- /Changes: -------------------------------------------------------------------------------- 1 | 0.2.5 2020-06-01 2 | 3 | https://github.com/yaml/libyaml/pull/105 4 | Allow question marks in plain scalars in flow collections 5 | 6 | https://github.com/yaml/libyaml/pull/186 7 | Emitter: Don't output trailing space for empty scalar nodes 8 | 9 | https://github.com/yaml/libyaml/pull/185 10 | Emitter: Output space after an alias mapping key 11 | 12 | https://github.com/yaml/libyaml/pull/187 13 | Add -h and --flow (on|off|keep) to run-*-test-suite 14 | 15 | https://github.com/yaml/libyaml/pull/182 16 | Remove unnecessary include and malloc 17 | 18 | https://github.com/yaml/libyaml/pull/177 19 | Add specific files back to .gitignore 20 | 21 | https://github.com/yaml/libyaml/pull/181 22 | Output error position in run-parser-test-suite.c 23 | 24 | https://github.com/yaml/libyaml/pull/191 25 | A couple patches to improve test suite support 26 | 27 | 0.2.4 2020-04-19 28 | 29 | - https://github.com/yaml/libyaml/pull/143 30 | Add packaging/docker-dist to Makefile.am 31 | 32 | - https://github.com/yaml/libyaml/pull/174 33 | Fix logic for document end before directive 34 | 35 | 36 | 0.2.3 2020-04-11 37 | 38 | - https://github.com/yaml/libyaml/pull/130 39 | Fixed typo. 40 | 41 | - https://github.com/yaml/libyaml/pull/144 42 | Fix typo in comment 43 | 44 | - https://github.com/yaml/libyaml/pull/140 45 | Use pointer to const for strings that aren't/shouldn't be modified 46 | 47 | - https://github.com/yaml/libyaml/pull/128 48 | Squash a couple of warnings in example-deconstructor-alt 49 | 50 | - https://github.com/yaml/libyaml/pull/151 51 | Fix spelling for error message 52 | 53 | - https://github.com/yaml/libyaml/pull/161 54 | Make appveyor config be a hidden file 55 | 56 | - https://github.com/yaml/libyaml/pull/159 57 | Add CHANGES file 58 | 59 | - https://github.com/yaml/libyaml/pull/160 60 | Always output document end before directive (YAML 1.2 compatibility) 61 | 62 | - https://github.com/yaml/libyaml/pull/162 63 | Output document end marker after open ended scalars 64 | 65 | - https://github.com/yaml/libyaml/pull/157 66 | change cmake target name from libOFF.a to libyaml.a 67 | 68 | - https://github.com/yaml/libyaml/pull/155 69 | include/yaml.h: fix comments 70 | 71 | - https://github.com/yaml/libyaml/pull/169 72 | Fixed missing token in example 73 | 74 | - https://github.com/yaml/libyaml/pull/127 75 | Avoid recursion in the document loader. 76 | 77 | - https://github.com/yaml/libyaml/pull/172 78 | Support %YAML 1.2 directives 79 | 80 | - https://github.com/yaml/libyaml/pull/66 81 | Change dllexport controlling macro to use _WIN32 82 | 83 | 0.2.2 2019-03-12 84 | 85 | - https://github.com/yaml/libyaml/pull/95 86 | build: do not install config.h 87 | 88 | - https://github.com/yaml/libyaml/pull/97 89 | appveyor.yml: fix Release build 90 | 91 | - https://github.com/yaml/libyaml/pull/103 92 | Remove unused code in yaml_document_delete 93 | 94 | - https://github.com/yaml/libyaml/pull/104 95 | Allow colons in plain scalars inside flow collections 96 | 97 | - https://github.com/yaml/libyaml/pull/109 98 | Fix comparison in tests/run-emitter.c 99 | 100 | - https://github.com/yaml/libyaml/pull/117 101 | Fix typo error 102 | 103 | - https://github.com/yaml/libyaml/pull/119 104 | The closing single quote needs to be indented... 105 | 106 | - https://github.com/yaml/libyaml/pull/121 107 | fix token name typos in comments 108 | 109 | - https://github.com/yaml/libyaml/pull/122 110 | Revert removing of open_ended after top level plain scalar 111 | 112 | - https://github.com/yaml/libyaml/pull/125 113 | Cherry-picks from PR 27 114 | 115 | - https://github.com/yaml/libyaml/pull/135 116 | Windows/C89 compatibility 117 | 118 | - https://github.com/yaml/libyaml/pull/136 119 | allow override of Windows static lib name 120 | 121 | 0.2.1 2018-06-24 122 | 123 | - https://github.com/yaml/libyaml/pull/10 124 | Support static and dynamic libraries 125 | 126 | - https://github.com/yaml/libyaml/pull/12 127 | Use .gitignore instead of .hgignore 128 | 129 | - https://github.com/yaml/libyaml/pull/13 130 | Add support for `make test` and travis 131 | 132 | - https://github.com/yaml/libyaml/pull/14 133 | Dockerfile for testing 134 | 135 | - https://github.com/yaml/libyaml/pull/15 136 | Apply old fix for `\/` that is not in master. 137 | 138 | - https://github.com/yaml/libyaml/pull/17 139 | Update license to include all years until now. 140 | 141 | - https://github.com/yaml/libyaml/pull/18 142 | Port bug fix from Perl binding 143 | 144 | - https://github.com/yaml/libyaml/pull/22 145 | Fix misspell: preceed 146 | 147 | - https://github.com/yaml/libyaml/pull/23 148 | Removed trailing-whitespaces 149 | 150 | - https://github.com/yaml/libyaml/pull/24 151 | Fix typo 152 | 153 | - https://github.com/yaml/libyaml/pull/25 154 | added an examples directory with a few yaml examples 155 | 156 | - https://github.com/yaml/libyaml/pull/26 157 | Added missing Cflags path in pkg-config file 158 | 159 | - https://github.com/yaml/libyaml/pull/31 160 | add unit tests to cmake configuration 161 | 162 | - https://github.com/yaml/libyaml/pull/32 163 | Include an example of a custom tag from Python 164 | 165 | - https://github.com/yaml/libyaml/pull/33 166 | Include an example of a %YAML tag 167 | 168 | - https://github.com/yaml/libyaml/pull/34 169 | Added an example of using a global tag 170 | 171 | - https://github.com/yaml/libyaml/pull/36 172 | Fix -Wformat compilation errors in tests 173 | 174 | - https://github.com/yaml/libyaml/pull/37 175 | Update bug report URL in LibYAML 176 | 177 | - https://github.com/yaml/libyaml/pull/38 178 | Use AM_CPPFLAGS since autotools deprecated INCLUDE 179 | 180 | - https://github.com/yaml/libyaml/pull/39 181 | Update bug report URL in README 182 | 183 | - https://github.com/yaml/libyaml/pull/41 184 | Add travis and Makefile support for libyaml-test 185 | 186 | - https://github.com/yaml/libyaml/pull/43 187 | Add Dockerfile for Fedora 25 188 | 189 | - https://github.com/yaml/libyaml/pull/44 190 | WIP: Enable all warnings (-Wall) in libyaml and tests 191 | 192 | - https://github.com/yaml/libyaml/pull/45 193 | Fix typo 194 | 195 | - https://github.com/yaml/libyaml/pull/47 196 | Move travis script guts to separate file 197 | 198 | - https://github.com/yaml/libyaml/pull/48 199 | `yaml/libyaml-test` should become part of `yaml/libyaml` 200 | 201 | - https://github.com/yaml/libyaml/pull/50 202 | Add a GNUMakefile for immediate make targets 203 | 204 | - https://github.com/yaml/libyaml/pull/53 205 | Switch from test blacklist to whitelist 206 | 207 | - https://github.com/yaml/libyaml/pull/55 208 | Update defs for MingGW support on Windows 209 | 210 | - https://github.com/yaml/libyaml/pull/58 211 | Improve CMakeLists 212 | 213 | - https://github.com/yaml/libyaml/pull/64 214 | README: Update libyaml link 215 | 216 | - https://github.com/yaml/libyaml/pull/69 217 | Skip 5 tests in libyaml-emitter.list 218 | 219 | - https://github.com/yaml/libyaml/pull/74 220 | Forbid escaped singlequote in doublequotes 221 | 222 | - https://github.com/yaml/libyaml/pull/76 223 | Rewrite make test-suite 224 | 225 | - https://github.com/yaml/libyaml/pull/77 226 | Undefined PTRDIFF_MAX on HP-UX 227 | 228 | - https://github.com/yaml/libyaml/pull/78 229 | Fixed most compiler warnings -Wall -Wextra 230 | 231 | - https://github.com/yaml/libyaml/pull/82 232 | Move yaml-test-suite integration onto a separate branch. 233 | 234 | - https://github.com/yaml/libyaml/pull/86 235 | Fix problems in CI failures (travis and semaphore) 236 | 237 | - https://github.com/yaml/libyaml/pull/87 238 | appveyor.yml: add mingw-w64 builds 239 | 240 | - https://github.com/yaml/libyaml/pull/88 241 | add -no-undefined to src/Makefile.am 242 | 243 | - https://github.com/yaml/libyaml/pull/89 244 | Added alpine linux testing to dockerfiles 245 | 246 | - https://github.com/yaml/libyaml/pull/93 247 | remove need for PTRDIFF_MAX 248 | 249 | - https://github.com/yaml/libyaml/pull/94 250 | .gitignore: major cleanup 251 | 252 | - https://github.com/yaml/libyaml/pull/120 253 | Fix doc. 254 | 255 | 0.1.7 2016-08-27 256 | 257 | - Fixed segfault in yaml_string_write_handler. 258 | 259 | - Fixed invalid simple key assertion. 260 | 261 | - Fixed error handling in some examples (thank to Mathias Svensson). 262 | 263 | - Removed obsolete VS project files. 264 | 265 | 0.1.6 2014-03-26 266 | 267 | - https://github.com/yaml/libyaml/commit/d1003a9 268 | Fixed heap overflow in yaml_parser_scan_uri_escapes (Thanks 269 | Ivan Fratric of the Google Security Team). 270 | 271 | - https://github.com/yaml/libyaml/commit/662f4be 272 | Added tag 0.1.5 for changeset a5142b24428b 273 | 274 | 0.1.5 2014-02-03 275 | 276 | - https://github.com/yaml/libyaml/commit/303b455 277 | Manually define PTRDIFF_MAX for VS C compiler. 278 | 279 | - https://github.com/yaml/libyaml/commit/1ef1171 280 | Forgot to set the error state. 281 | 282 | - https://github.com/yaml/libyaml/commit/c9479c7 283 | Limit input size to SIZE_MAX/2. 284 | 285 | - https://github.com/yaml/libyaml/commit/c201bf6 286 | Guard against overflows in indent and flow_level. 287 | 288 | - https://github.com/yaml/libyaml/commit/bb8ab82 289 | Added .hgignore. 290 | 291 | - https://github.com/yaml/libyaml/commit/2d94fc5 292 | Prevent node index overflow (Reported by Florian Weimer). 293 | 294 | - https://github.com/yaml/libyaml/commit/df33f25 295 | Bumped the version number. 296 | 297 | - https://github.com/yaml/libyaml/commit/f56726b 298 | Fixed invalid size_t->int cast (Thank to Florian Weimer). 299 | 300 | - https://github.com/yaml/libyaml/commit/01e8dad 301 | Added a basic CMake project. 302 | 303 | - https://github.com/yaml/libyaml/commit/f54fc40 304 | Added tag 0.1.4 for changeset 3e6507fa0c26 305 | 306 | 0.1.4 2012-12-24 307 | 308 | - Fixed a bug that prevented an empty mapping being used as a simple key 309 | (thank to spitzak(at)rhythm(dot)com). 310 | 311 | - Fixed pointer overflow when calculating the position of a potential 312 | simple key (thank to ppelletier(at)oblong(dot)com). 313 | 314 | - Fixed yaml.dll not exporting any symbols 315 | (thank to pxn11432(at)nifty(dot)com). 316 | 317 | - Added pkg-config support (thank to rainwoodman(at)gmail(dot)com). 318 | 319 | 0.1.3 2009-08-29 320 | 321 | - This release fixes non-standard structure initialization and 322 | a streaming-related issue. 323 | 324 | 0.1.2 2008-12-27 325 | 326 | - Minor bugfix release 327 | 328 | 0.1.1 2006-08-01 329 | 330 | - https://github.com/yaml/libyaml/commit/5e52c31 331 | Fixed a problem when the DOCUMENT-END event is not emitted until 332 | the beginning of the next document is available. Fixed #51. 333 | Thanks edward(at)sweetbytes.net for the bug report. 334 | 335 | - https://github.com/yaml/libyaml/commit/dd71484 336 | Add project files for Visual Studio 2003. 337 | 338 | - https://github.com/yaml/libyaml/commit/ce8a93e 339 | Fix the example_deconstructor project. 340 | 341 | - https://github.com/yaml/libyaml/commit/c9b74de 342 | Eliminate some warnings and add more doxygen definitions. 343 | 344 | - https://github.com/yaml/libyaml/commit/0122490 345 | Undefine the NDEBUG directive for the test programs. 346 | 347 | - https://github.com/yaml/libyaml/commit/071329a 348 | Fix a bug in the emitter introduced while fixing warnings for VC6. 349 | 350 | - https://github.com/yaml/libyaml/commit/6f6bbb8 351 | Add VC6 projects for the test executables. 352 | 353 | - https://github.com/yaml/libyaml/commit/0174ed6 354 | Add win32 fixes and project files for VC6. 355 | 356 | - https://github.com/yaml/libyaml/commit/e27a3c8 357 | Add functions for constructing, parsing and emitting YAML documents. 358 | 359 | - https://github.com/yaml/libyaml/commit/a907bf8 360 | Add `const` qualifier for `yaml_parser_set_input_string` parameter `input`. 361 | 362 | - https://github.com/yaml/libyaml/commit/c83b67a 363 | Force a new line at the end of the input stream even if there 364 | are no a new line character. This fixes a nasty bug when libyaml hangs on 365 | documents like `[[[[`. Thanks ciaranm for reporting the bug. 366 | 367 | - https://github.com/yaml/libyaml/commit/609cce0 368 | Older versions of gcc do not know about -Wno-pointer-sign. 369 | 370 | 0.0.1 2006-08-01 371 | 372 | - Initial release 373 | -------------------------------------------------------------------------------- /License: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017-2020 Ingy döt Net 2 | Copyright (c) 2006-2016 Kirill Simonov 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of 5 | this software and associated documentation files (the "Software"), to deal in 6 | the Software without restriction, including without limitation the rights to 7 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 8 | of the Software, and to permit persons to whom the Software is furnished to do 9 | so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | ## Run `./bootstrap` to generate the "Makefile.in" files in this directory and 2 | ## the "$SUBDIRS" subdirectories. 3 | 4 | SUBDIRS = include src . tests 5 | 6 | EXTRA_DIST = Changes ReadMe.md License CMakeLists.txt doc/doxygen.cfg 7 | 8 | LIBYAML_TEST_SUITE_RUN_REPO_DEFAULT := https://github.com/yaml/libyaml 9 | LIBYAML_TEST_SUITE_RUN_REPO ?= $(LIBYAML_TEST_SUITE_RUN_REPO_DEFAULT) 10 | LIBYAML_TEST_SUITE_RUN_BRANCH ?= run-test-suite 11 | 12 | pkgconfigdir = $(libdir)/pkgconfig 13 | pkgconfig_DATA = yaml-0.1.pc 14 | 15 | maintainer-clean-local: 16 | rm -f aclocal.m4 config.h.in configure config/* 17 | -find ${builddir} -name Makefile.in -exec rm -f '{}' ';' 18 | 19 | distclean-local: 20 | rm -fr tests/run-test-suite 21 | -git worktree prune 22 | 23 | .PHONY: bootstrap 24 | bootstrap: maintainer-clean 25 | ./bootstrap 26 | ./configure 27 | make 28 | 29 | test: all 30 | make -C tests check-TESTS 31 | 32 | test-suite: tests/run-test-suite all 33 | make -C $< test 34 | 35 | test-all: test test-suite 36 | 37 | tests/run-test-suite: 38 | ifeq ($(LIBYAML_TEST_SUITE_RUN_REPO),$(LIBYAML_TEST_SUITE_RUN_REPO_DEFAULT)) 39 | -git branch --track $(LIBYAML_TEST_SUITE_RUN_BRANCH) origin/$(LIBYAML_TEST_SUITE_RUN_BRANCH) 40 | -git worktree prune 41 | git worktree add $@ $(LIBYAML_TEST_SUITE_RUN_BRANCH) 42 | else 43 | git clone --branch $(LIBYAML_TEST_SUITE_RUN_BRANCH) $(LIBYAML_TEST_SUITE_RUN_REPO) $@ 44 | endif 45 | 46 | docker-build: 47 | make -C pkg/docker build 48 | 49 | docker-dist: 50 | make -C pkg/docker libyaml-dist 51 | 52 | -------------------------------------------------------------------------------- /ReadMe.md: -------------------------------------------------------------------------------- 1 | ## LibYAML - A C library for parsing and emitting YAML. 2 | 3 | To build and install the library, run: 4 | 5 | $ ./configure 6 | $ make 7 | # make install 8 | 9 | Required packages: 10 | 11 | - gcc 12 | - libtool 13 | - make 14 | 15 | If you checked the source code from the Git repository, run 16 | 17 | $ ./bootstrap 18 | $ ./configure 19 | $ make 20 | # make install 21 | 22 | Required packages: 23 | 24 | - autoconf 25 | - libtool 26 | - make 27 | 28 | For more information, check the [LibYAML 29 | homepage](https://github.com/yaml/libyaml). 30 | 31 | Discuss LibYAML with the maintainers in IRC #libyaml irc.freenode.net. 32 | 33 | You may also use the [YAML-Core mailing 34 | list](http://lists.sourceforge.net/lists/listinfo/yaml-core). 35 | 36 | Submit bug reports and feature requests to the [LibYAML bug 37 | tracker](https://github.com/yaml/libyaml/issues/new). 38 | 39 | This project was developed for Python Software Foundation as a part of Google 40 | Summer of Code under the mentorship of Clark Evans. 41 | 42 | The LibYAML module was written by Kirill Simonov . 43 | It is currently maintained by the YAML community. 44 | 45 | LibYAML is released under the MIT license. 46 | See the file LICENSE for more details. 47 | -------------------------------------------------------------------------------- /announcement.msg: -------------------------------------------------------------------------------- 1 | From: Tina Müller 2 | To: yaml-core@lists.sourceforge.net 3 | Subject: [ANN] LibYAML-0.2.5: A new release 4 | 5 | ========================= 6 | Announcing LibYAML-0.2.5 7 | ========================= 8 | 9 | A new release of LibYAML is now available: 10 | https://github.com/yaml/libyaml/tree/0.2.5 11 | 12 | The LibYAML project is now maintained by the YAML community. Planning happens 13 | on the #yaml-dev and #libyaml IRC channels on irc.freenode.net. 14 | 15 | 16 | Changes 17 | ======= 18 | 19 | 20 | https://github.com/yaml/libyaml/pull/187 21 | Add -h and --flow (on|off|keep) to run-*-test-suite 22 | 23 | https://github.com/yaml/libyaml/pull/182 24 | Remove unnecessary include and malloc 25 | 26 | https://github.com/yaml/libyaml/pull/177 27 | Add specific files back to .gitignore 28 | 29 | https://github.com/yaml/libyaml/pull/181 30 | Output error position in run-parser-test-suite.c 31 | 32 | https://github.com/yaml/libyaml/pull/105 33 | Allow question marks in plain scalars in flow collections 34 | 35 | https://github.com/yaml/libyaml/pull/186 36 | Emitter: Don't output trailing space for empty scalar nodes 37 | 38 | https://github.com/yaml/libyaml/pull/185 39 | Emitter: Output space after an alias mapping key 40 | 41 | https://github.com/yaml/libyaml/pull/191 42 | A couple patches to improve test suite support 43 | 44 | 45 | Resources 46 | ========= 47 | 48 | LibYAML IRC Channel: #libyaml on irc.freenode.net 49 | LibYAML homepage: https://github.com/yaml/libyaml 50 | Source download: https://github.com/yaml/libyaml/archive/dist-0.2.3.zip 51 | GitHub repository: https://github.com/yaml/libyaml 52 | Bug tracking: https://github.com/yaml/libyaml/issues 53 | 54 | YAML homepage: http://yaml.org/ 55 | YAML-core mailing list: http://lists.sourceforge.net/lists/listinfo/yaml-core 56 | 57 | 58 | About LibYAML 59 | ============= 60 | 61 | YAML is a data serialization format designed for human readability and 62 | interaction with scripting languages. 63 | 64 | LibYAML is a C library for parsing and emitting YAML. LibYAML is the underlying 65 | parser/emitter code for YAML frameworks in many programming languages. 66 | 67 | 68 | Maintainers 69 | =========== 70 | 71 | The following people are responsible for maintaining LibYAML: 72 | 73 | * Ingy döt Net 74 | 75 | and many thanks to all who have contribributed! 76 | See: https://github.com/yaml/libyaml/pulls 77 | 78 | 79 | Copyright 80 | ========= 81 | 82 | Copyright (c) 2017-2020 Ingy döt Net 83 | Copyright (c) 2006-2016 Kirill Simonov 84 | 85 | The LibYAML module was written by Kirill Simonov. 86 | It is currently maintained by the YAML community. 87 | 88 | LibYAML is released under the MIT license. 89 | See the file LICENSE for more details. 90 | -------------------------------------------------------------------------------- /bootstrap: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | exec autoreconf -fvi 4 | -------------------------------------------------------------------------------- /cmake/config.h.in: -------------------------------------------------------------------------------- 1 | #define YAML_VERSION_MAJOR @YAML_VERSION_MAJOR@ 2 | #define YAML_VERSION_MINOR @YAML_VERSION_MINOR@ 3 | #define YAML_VERSION_PATCH @YAML_VERSION_PATCH@ 4 | #define YAML_VERSION_STRING "@YAML_VERSION_STRING@" 5 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | # Run `./bootstrap` to generate the "configure" script. 2 | 3 | # Define the package version numbers and the bug reporting link. 4 | m4_define([YAML_MAJOR], 0) 5 | m4_define([YAML_MINOR], 2) 6 | m4_define([YAML_PATCH], 5) 7 | m4_define([YAML_BUGS], [https://github.com/yaml/libyaml/issues/new]) 8 | 9 | # Define the libtool version numbers; check the Autobook, Section 11.4. 10 | # Bump the libtool version numbers using the following algorithm: 11 | # if (the current interface has not been changed): 12 | # YAML_REVISION += 1 13 | # else: 14 | # YAML_REVISION = 0 15 | # YAML_CURRENT += 1 16 | # if (this release is backward compatible with the previous release): 17 | # YAML_AGE += 1 18 | # else: 19 | # YAML_AGE = 0 20 | m4_define([YAML_RELEASE], 0) 21 | m4_define([YAML_CURRENT], 2) 22 | m4_define([YAML_REVISION], 9) 23 | m4_define([YAML_AGE], 0) 24 | 25 | # Initialize autoconf & automake. 26 | AC_PREREQ(2.59) 27 | AC_INIT([yaml], [YAML_MAJOR.YAML_MINOR.YAML_PATCH], [YAML_BUGS]) 28 | AC_CONFIG_AUX_DIR([config]) 29 | AC_CONFIG_HEADERS([include/config.h]) 30 | AM_INIT_AUTOMAKE([1.9 foreign]) 31 | 32 | # Define macro variables for the package version numbers. 33 | AC_DEFINE(YAML_VERSION_MAJOR, YAML_MAJOR, [Define the major version number.]) 34 | AC_DEFINE(YAML_VERSION_MINOR, YAML_MINOR, [Define the minor version number.]) 35 | AC_DEFINE(YAML_VERSION_PATCH, YAML_PATCH, [Define the patch version number.]) 36 | AC_DEFINE(YAML_VERSION_STRING, "YAML_MAJOR.YAML_MINOR.YAML_PATCH", [Define the version string.]) 37 | 38 | # Define substitutions for the libtool version numbers. 39 | YAML_LT_RELEASE=YAML_RELEASE 40 | YAML_LT_CURRENT=YAML_CURRENT 41 | YAML_LT_REVISION=YAML_REVISION 42 | YAML_LT_AGE=YAML_AGE 43 | AC_SUBST(YAML_LT_RELEASE) 44 | AC_SUBST(YAML_LT_CURRENT) 45 | AC_SUBST(YAML_LT_REVISION) 46 | AC_SUBST(YAML_LT_AGE) 47 | 48 | # Note: in order to update checks, run `autoscan` and look through "configure.scan". 49 | 50 | # Checks for programs. 51 | AC_PROG_CC 52 | AC_PROG_CPP 53 | AC_PROG_INSTALL 54 | AC_PROG_LN_S 55 | AC_PROG_MAKE_SET 56 | AC_PROG_LIBTOOL 57 | 58 | AC_CHECK_PROG(DOXYGEN, [doxygen], [true], [false]) 59 | AM_CONDITIONAL(DOXYGEN, [test "$DOXYGEN" = true]) 60 | 61 | # Checks for header files. 62 | AC_HEADER_STDC 63 | AC_CHECK_HEADERS([stdlib.h]) 64 | 65 | # Checks for typedefs, structures, and compiler characteristics. 66 | AC_C_CONST 67 | AC_TYPE_SIZE_T 68 | 69 | # Define Makefiles. 70 | AC_CONFIG_FILES([yaml-0.1.pc include/Makefile src/Makefile Makefile tests/Makefile]) 71 | 72 | # Generate the "configure" script. 73 | AC_OUTPUT 74 | -------------------------------------------------------------------------------- /doc/doxygen.cfg: -------------------------------------------------------------------------------- 1 | # Doxyfile 1.4.4 2 | 3 | #--------------------------------------------------------------------------- 4 | # Project related configuration options 5 | #--------------------------------------------------------------------------- 6 | PROJECT_NAME = $(PACKAGE) 7 | PROJECT_NUMBER = $(VERSION) 8 | OUTPUT_DIRECTORY = $(top_builddir)/doc/ 9 | CREATE_SUBDIRS = NO 10 | OUTPUT_LANGUAGE = English 11 | USE_WINDOWS_ENCODING = NO 12 | BRIEF_MEMBER_DESC = YES 13 | REPEAT_BRIEF = YES 14 | ABBREVIATE_BRIEF = 15 | ALWAYS_DETAILED_SEC = NO 16 | INLINE_INHERITED_MEMB = NO 17 | FULL_PATH_NAMES = YES 18 | STRIP_FROM_PATH = 19 | STRIP_FROM_INC_PATH = 20 | SHORT_NAMES = NO 21 | JAVADOC_AUTOBRIEF = YES 22 | MULTILINE_CPP_IS_BRIEF = NO 23 | DETAILS_AT_TOP = NO 24 | INHERIT_DOCS = YES 25 | DISTRIBUTE_GROUP_DOC = NO 26 | SEPARATE_MEMBER_PAGES = NO 27 | TAB_SIZE = 8 28 | ALIASES = 29 | OPTIMIZE_OUTPUT_FOR_C = YES 30 | OPTIMIZE_OUTPUT_JAVA = NO 31 | SUBGROUPING = YES 32 | #--------------------------------------------------------------------------- 33 | # Build related configuration options 34 | #--------------------------------------------------------------------------- 35 | EXTRACT_ALL = NO 36 | EXTRACT_PRIVATE = NO 37 | EXTRACT_STATIC = NO 38 | EXTRACT_LOCAL_CLASSES = NO 39 | EXTRACT_LOCAL_METHODS = NO 40 | HIDE_UNDOC_MEMBERS = NO 41 | HIDE_UNDOC_CLASSES = NO 42 | HIDE_FRIEND_COMPOUNDS = NO 43 | HIDE_IN_BODY_DOCS = NO 44 | INTERNAL_DOCS = NO 45 | CASE_SENSE_NAMES = YES 46 | HIDE_SCOPE_NAMES = NO 47 | SHOW_INCLUDE_FILES = YES 48 | INLINE_INFO = YES 49 | SORT_MEMBER_DOCS = NO 50 | SORT_BRIEF_DOCS = NO 51 | SORT_BY_SCOPE_NAME = NO 52 | GENERATE_TODOLIST = YES 53 | GENERATE_TESTLIST = YES 54 | GENERATE_BUGLIST = YES 55 | GENERATE_DEPRECATEDLIST= YES 56 | ENABLED_SECTIONS = 57 | MAX_INITIALIZER_LINES = 30 58 | SHOW_USED_FILES = YES 59 | SHOW_DIRECTORIES = YES 60 | FILE_VERSION_FILTER = 61 | #--------------------------------------------------------------------------- 62 | # configuration options related to warning and progress messages 63 | #--------------------------------------------------------------------------- 64 | QUIET = NO 65 | WARNINGS = YES 66 | WARN_IF_UNDOCUMENTED = YES 67 | WARN_IF_DOC_ERROR = YES 68 | WARN_NO_PARAMDOC = NO 69 | WARN_FORMAT = "$file:$line: $text" 70 | WARN_LOGFILE = 71 | #--------------------------------------------------------------------------- 72 | # configuration options related to the input files 73 | #--------------------------------------------------------------------------- 74 | INPUT = $(top_srcdir)/include/ 75 | FILE_PATTERNS = *.h 76 | RECURSIVE = YES 77 | EXCLUDE = 78 | EXCLUDE_SYMLINKS = NO 79 | EXCLUDE_PATTERNS = 80 | EXAMPLE_PATH = 81 | EXAMPLE_PATTERNS = 82 | EXAMPLE_RECURSIVE = NO 83 | IMAGE_PATH = 84 | INPUT_FILTER = 85 | FILTER_PATTERNS = 86 | FILTER_SOURCE_FILES = NO 87 | #--------------------------------------------------------------------------- 88 | # configuration options related to source browsing 89 | #--------------------------------------------------------------------------- 90 | SOURCE_BROWSER = NO 91 | INLINE_SOURCES = NO 92 | STRIP_CODE_COMMENTS = YES 93 | REFERENCED_BY_RELATION = NO 94 | REFERENCES_RELATION = NO 95 | USE_HTAGS = NO 96 | VERBATIM_HEADERS = NO 97 | #--------------------------------------------------------------------------- 98 | # configuration options related to the alphabetical class index 99 | #--------------------------------------------------------------------------- 100 | ALPHABETICAL_INDEX = NO 101 | COLS_IN_ALPHA_INDEX = 5 102 | IGNORE_PREFIX = 103 | #--------------------------------------------------------------------------- 104 | # configuration options related to the HTML output 105 | #--------------------------------------------------------------------------- 106 | GENERATE_HTML = YES 107 | HTML_OUTPUT = html 108 | HTML_FILE_EXTENSION = .html 109 | HTML_HEADER = 110 | HTML_FOOTER = 111 | HTML_STYLESHEET = 112 | HTML_ALIGN_MEMBERS = YES 113 | GENERATE_HTMLHELP = NO 114 | CHM_FILE = 115 | HHC_LOCATION = 116 | GENERATE_CHI = NO 117 | BINARY_TOC = NO 118 | TOC_EXPAND = NO 119 | DISABLE_INDEX = NO 120 | ENUM_VALUES_PER_LINE = 1 121 | GENERATE_TREEVIEW = NO 122 | TREEVIEW_WIDTH = 250 123 | #--------------------------------------------------------------------------- 124 | # configuration options related to the LaTeX output 125 | #--------------------------------------------------------------------------- 126 | GENERATE_LATEX = NO 127 | LATEX_OUTPUT = latex 128 | LATEX_CMD_NAME = latex 129 | MAKEINDEX_CMD_NAME = makeindex 130 | COMPACT_LATEX = NO 131 | PAPER_TYPE = a4wide 132 | EXTRA_PACKAGES = 133 | LATEX_HEADER = 134 | PDF_HYPERLINKS = NO 135 | USE_PDFLATEX = NO 136 | LATEX_BATCHMODE = NO 137 | LATEX_HIDE_INDICES = NO 138 | #--------------------------------------------------------------------------- 139 | # configuration options related to the RTF output 140 | #--------------------------------------------------------------------------- 141 | GENERATE_RTF = NO 142 | RTF_OUTPUT = rtf 143 | COMPACT_RTF = NO 144 | RTF_HYPERLINKS = NO 145 | RTF_STYLESHEET_FILE = 146 | RTF_EXTENSIONS_FILE = 147 | #--------------------------------------------------------------------------- 148 | # configuration options related to the man page output 149 | #--------------------------------------------------------------------------- 150 | GENERATE_MAN = NO 151 | MAN_OUTPUT = man 152 | MAN_EXTENSION = .3 153 | MAN_LINKS = NO 154 | #--------------------------------------------------------------------------- 155 | # configuration options related to the XML output 156 | #--------------------------------------------------------------------------- 157 | GENERATE_XML = NO 158 | XML_OUTPUT = xml 159 | XML_SCHEMA = 160 | XML_DTD = 161 | XML_PROGRAMLISTING = YES 162 | #--------------------------------------------------------------------------- 163 | # configuration options for the AutoGen Definitions output 164 | #--------------------------------------------------------------------------- 165 | GENERATE_AUTOGEN_DEF = NO 166 | #--------------------------------------------------------------------------- 167 | # configuration options related to the Perl module output 168 | #--------------------------------------------------------------------------- 169 | GENERATE_PERLMOD = NO 170 | PERLMOD_LATEX = NO 171 | PERLMOD_PRETTY = YES 172 | PERLMOD_MAKEVAR_PREFIX = 173 | #--------------------------------------------------------------------------- 174 | # Configuration options related to the preprocessor 175 | #--------------------------------------------------------------------------- 176 | ENABLE_PREPROCESSING = YES 177 | MACRO_EXPANSION = YES 178 | EXPAND_ONLY_PREDEF = YES 179 | SEARCH_INCLUDES = YES 180 | INCLUDE_PATH = 181 | INCLUDE_FILE_PATTERNS = 182 | PREDEFINED = "YAML_DECLARE(type)=type" 183 | EXPAND_AS_DEFINED = 184 | SKIP_FUNCTION_MACROS = YES 185 | #--------------------------------------------------------------------------- 186 | # Configuration::additions related to external references 187 | #--------------------------------------------------------------------------- 188 | TAGFILES = 189 | GENERATE_TAGFILE = 190 | ALLEXTERNALS = NO 191 | EXTERNAL_GROUPS = YES 192 | PERL_PATH = /usr/bin/perl 193 | #--------------------------------------------------------------------------- 194 | # Configuration options related to the dot tool 195 | #--------------------------------------------------------------------------- 196 | CLASS_DIAGRAMS = NO 197 | HIDE_UNDOC_RELATIONS = YES 198 | HAVE_DOT = NO 199 | CLASS_GRAPH = YES 200 | COLLABORATION_GRAPH = YES 201 | GROUP_GRAPHS = YES 202 | UML_LOOK = NO 203 | TEMPLATE_RELATIONS = NO 204 | INCLUDE_GRAPH = YES 205 | INCLUDED_BY_GRAPH = YES 206 | CALL_GRAPH = NO 207 | GRAPHICAL_HIERARCHY = YES 208 | DIRECTORY_GRAPH = YES 209 | DOT_IMAGE_FORMAT = png 210 | DOT_PATH = 211 | DOTFILE_DIRS = 212 | MAX_DOT_GRAPH_WIDTH = 1024 213 | MAX_DOT_GRAPH_HEIGHT = 1024 214 | MAX_DOT_GRAPH_DEPTH = 0 215 | DOT_TRANSPARENT = NO 216 | DOT_MULTI_TARGETS = NO 217 | GENERATE_LEGEND = YES 218 | DOT_CLEANUP = YES 219 | #--------------------------------------------------------------------------- 220 | # Configuration::additions related to the search engine 221 | #--------------------------------------------------------------------------- 222 | SEARCHENGINE = NO 223 | -------------------------------------------------------------------------------- /docker/README.mkd: -------------------------------------------------------------------------------- 1 | # LibYAML Dockerfiles 2 | 3 | This directory is a collection of dockerfiles that can be used when developing 4 | and testing LibYAML. 5 | 6 | The current list is supports: 7 | 8 | - Ubuntu 16.04 9 | - Ubuntu 14.04 10 | 11 | ## Example Usage 12 | 13 | ```bash 14 | $ docker pull ubuntu 15 | $ docker build -t libyaml-ubuntu:16.04 -f dockerfiles/ubuntu-16.04 . 16 | $ docker run -it libyaml-ubuntu:16.04 make test 17 | ``` 18 | -------------------------------------------------------------------------------- /docker/alpine-3.7: -------------------------------------------------------------------------------- 1 | # vim: ft=dockerfile 2 | FROM alpine:3.7 3 | MAINTAINER Ingy döt Net 4 | 5 | RUN apk update && \ 6 | apk add --no-cache \ 7 | autoconf \ 8 | automake \ 9 | build-base \ 10 | cmake \ 11 | git \ 12 | libtool \ 13 | perl-dev && \ 14 | mkdir /libyaml 15 | 16 | COPY . /libyaml/ 17 | WORKDIR /libyaml 18 | 19 | ENV LD_LIBRARY_PATH=/libyaml/src/.libs 20 | 21 | RUN ./bootstrap && \ 22 | ./configure && \ 23 | make && \ 24 | make install 25 | 26 | CMD ["bash"] 27 | -------------------------------------------------------------------------------- /docker/fedora-25: -------------------------------------------------------------------------------- 1 | # vim: ft=dockerfile 2 | FROM fedora:25 3 | MAINTAINER Ian Cordasco 4 | 5 | # NOTE(sigmavirus24): We need "perl-core" here for the "prove" binary 6 | # required by the test-all Makefile target 7 | RUN dnf install -y \ 8 | automake \ 9 | gcc \ 10 | git \ 11 | make \ 12 | libtool \ 13 | perl-core && \ 14 | mkdir /libyaml 15 | 16 | COPY . /libyaml/ 17 | WORKDIR /libyaml 18 | 19 | ENV LD_LIBRARY_PATH=/libyaml/src/.libs 20 | 21 | RUN ./bootstrap && \ 22 | ./configure && \ 23 | make && \ 24 | make install 25 | 26 | CMD ["bash"] 27 | -------------------------------------------------------------------------------- /docker/ubuntu-14.04: -------------------------------------------------------------------------------- 1 | # vim: ft=dockerfile 2 | FROM ubuntu:14.04 3 | MAINTAINER Ian Cordasco 4 | 5 | RUN apt-get update && \ 6 | apt-get install -y \ 7 | software-properties-common \ 8 | python-software-properties && \ 9 | add-apt-repository ppa:git-core/ppa && \ 10 | apt-get update && \ 11 | apt-get install -y \ 12 | autoconf \ 13 | build-essential \ 14 | git \ 15 | libtool && \ 16 | rm -rf /var/lib/apt/lists/* && \ 17 | mkdir /libyaml 18 | 19 | COPY . /libyaml/ 20 | WORKDIR /libyaml 21 | 22 | ENV LD_LIBRARY_PATH=/libyaml/src/.libs 23 | 24 | RUN ./bootstrap && \ 25 | ./configure && \ 26 | make && \ 27 | make install 28 | 29 | CMD ["bash"] 30 | -------------------------------------------------------------------------------- /docker/ubuntu-16.04: -------------------------------------------------------------------------------- 1 | # vim: ft=dockerfile 2 | FROM ubuntu:16.04 3 | MAINTAINER Ian Cordasco 4 | 5 | RUN apt-get update && \ 6 | apt-get install -y \ 7 | autoconf \ 8 | build-essential \ 9 | git \ 10 | libtool && \ 11 | rm -rf /var/lib/apt/lists/* && \ 12 | mkdir /libyaml 13 | 14 | COPY . /libyaml/ 15 | WORKDIR /libyaml 16 | 17 | ENV LD_LIBRARY_PATH=/libyaml/src/.libs 18 | 19 | RUN ./bootstrap && \ 20 | ./configure && \ 21 | make && \ 22 | make install 23 | 24 | CMD ["bash"] 25 | -------------------------------------------------------------------------------- /examples/anchors.yaml: -------------------------------------------------------------------------------- 1 | base: &base 2 | name: Everyone has same name 3 | 4 | foo: &foo 5 | <<: *base 6 | age: 10 7 | 8 | bar: &bar 9 | <<: *base 10 | age: 20 11 | -------------------------------------------------------------------------------- /examples/array.yaml: -------------------------------------------------------------------------------- 1 | - member 2 | - member2 3 | -------------------------------------------------------------------------------- /examples/global-tag.yaml: -------------------------------------------------------------------------------- 1 | %TAG ! tag:clarkevans.com,2002: 2 | --- !shape 3 | # Use the ! handle for presenting 4 | # tag:clarkevans.com,2002:circle 5 | - !circle 6 | center: &ORIGIN {x: 73, y: 129} 7 | radius: 7 8 | - !line 9 | start: *ORIGIN 10 | finish: { x: 89, y: 102 } 11 | - !label 12 | start: *ORIGIN 13 | color: 0xFFEEBB 14 | text: Pretty vector drawing. 15 | -------------------------------------------------------------------------------- /examples/json.yaml: -------------------------------------------------------------------------------- 1 | {"key": ["value", 3]} 2 | -------------------------------------------------------------------------------- /examples/mapping.yaml: -------------------------------------------------------------------------------- 1 | key: value 2 | other-key: other-value 3 | -------------------------------------------------------------------------------- /examples/numbers.yaml: -------------------------------------------------------------------------------- 1 | [100, 12.5, -130, 1.3e+9] 2 | -------------------------------------------------------------------------------- /examples/strings.yaml: -------------------------------------------------------------------------------- 1 | unquoted: string 2 | literal-block: | 3 | This entire block of text will be the value of the 'literal-block' key, 4 | with line breaks being preserved. 5 | folded: > 6 | This entire block of text will be the value of 'folded', but this 7 | time, all newlines will be replaced with a single space. 8 | -------------------------------------------------------------------------------- /examples/tags.yaml: -------------------------------------------------------------------------------- 1 | gif_file: !!binary | 2 | R0lGODlhDAAMAIQAAP//9/X17unp5WZmZgAAAOfn515eXvPz7Y6OjuDg4J+fn5 3 | OTk6enp56enmlpaWNjY6Ojo4SEhP/++f/++f/++f/++f/++f/++f/++f/++f/+ 4 | +f/++f/++f/++f/++f/++SH+Dk1hZGUgd2l0aCBHSU1QACwAAAAADAAMAAAFLC 5 | AgjoEwnuNAFOhpEMTRiggcz4BNJHrv/zCFcLiwMWYNG84BwwEeECcgggoBADs= 6 | explicit_string: !!str 0.5 7 | python_tag: !!python/complex '1.0+2.0j' 8 | -------------------------------------------------------------------------------- /examples/yaml-version.yaml: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | --- 3 | [1, 2, 3] 4 | -------------------------------------------------------------------------------- /include/Makefile.am: -------------------------------------------------------------------------------- 1 | AM_CPPFLAGS = yaml.h 2 | DOXYGEN_CFG = $(top_srcdir)/doc/doxygen.cfg 3 | 4 | nobase_include_HEADERS = $(AM_CPPFLAGS) 5 | 6 | if DOXYGEN 7 | 8 | html: $(AM_CPPFLAGS) $(DOXYGEN_CFG) 9 | PACKAGE=$(PACKAGE) VERSION=$(VERSION) top_srcdir=$(top_srcdir) top_builddir=$(top_builddir) doxygen $(DOXYGEN_CFG) 10 | 11 | endif 12 | 13 | maintainer-clean-local: 14 | -rm -rf $(top_builddir)/doc/html 15 | 16 | dist-hook: html 17 | cp -a $(top_builddir)/doc/html $(top_distdir)/doc 18 | -------------------------------------------------------------------------------- /pkg/ReadMe.md: -------------------------------------------------------------------------------- 1 | # How to Make a `libyaml` Release 2 | 3 | ## Versioning 4 | 5 | Update libyaml version in: 6 | * announcement.msg 7 | * Changes 8 | * CMakeLists.txt 9 | * `YAML_VERSION_MAJOR`, `YAML_VERSION_MINOR`, `YAML_VERSION_PATCH` 10 | * .appveyor.yml 11 | * configure.ac 12 | * `YAML_MAJOR`, `YAML_MINOR`, `YAML_PATCH`, `YAML_RELEASE`, `YAML_CURRENT`, `YAML_REVISION` 13 | 14 | Commit and push everything to `release/0.x.y`. 15 | 16 | ## Test and Create Release Archives 17 | 18 | ### GitHub Actions Automation 19 | 20 | The github workflow: 21 | 22 | .github/workflows/dist.yaml 23 | 24 | will do this automatically for you. 25 | 26 | #### .github/workflows/dist.yaml 27 | 28 | This workflow will create release archives (`tar.gz` and `zip`). 29 | 30 | ### Manually 31 | 32 | Make sure you have a clean git repository (no changed files). 33 | The following process will clone your current git directory. 34 | 35 | This will need the docker image `yamlio/libyaml-dev`. 36 | You can either pull it, or create it yourself: 37 | 38 | make docker-build 39 | 40 | ### Create dist archives 41 | 42 | Run: 43 | 44 | make docker-dist 45 | 46 | It will run `make dist` in the container to create a tarball written to 47 | `pkg/docker/output`. 48 | It will also create a zipfile. 49 | 50 | ## Update master 51 | 52 | git merge release/0.x.y 53 | git tag -a 0.x.y 54 | # 55 | # Paste the corresponding entry from the Changes file 56 | # Look at an earlier release for how it should look like: 57 | # git show 0.2.3 58 | git push origin master 0.x.y 59 | 60 | ## Create a GitHub release 61 | 62 | Go to "Releases" and click on "Draft a new release". 63 | 64 | Fill in the tag you just created in the previous step. 65 | 66 | Fill in the release title: v0.x.y 67 | 68 | Paste the changelog into the description field. 69 | 70 | Upload the tar.gz and .zip file. 71 | 72 | You can "Save draft" and publish later, or directly click on "Publish release". 73 | 74 | ## Update pyyaml.org 75 | 76 | See . 77 | 78 | -------------------------------------------------------------------------------- /pkg/docker/.gitignore: -------------------------------------------------------------------------------- 1 | output/* 2 | !Makefile 3 | !output/ReadMe 4 | -------------------------------------------------------------------------------- /pkg/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:18.04 2 | 3 | RUN apt-get update \ 4 | && apt-get install -y \ 5 | automake \ 6 | bison \ 7 | build-essential \ 8 | cmake \ 9 | curl \ 10 | doxygen \ 11 | flex \ 12 | git \ 13 | less \ 14 | libtool \ 15 | python \ 16 | vim \ 17 | zip \ 18 | && true 19 | 20 | # http://www.doxygen.nl/manual/install.html 21 | 22 | RUN curl https://sourceforge.net/projects/doxygen/files/rel-1.8.14/doxygen-1.8.14.src.tar.gz/download \ 23 | -L -o /doxygen-1.8.14.src.tar.gz \ 24 | && cd / \ 25 | && tar -xvf doxygen-1.8.14.src.tar.gz \ 26 | && cd doxygen-1.8.14 \ 27 | && mkdir build \ 28 | && cd build \ 29 | && cmake -G "Unix Makefiles" .. \ 30 | && make \ 31 | && make install \ 32 | && true 33 | -------------------------------------------------------------------------------- /pkg/docker/Makefile: -------------------------------------------------------------------------------- 1 | DOCKER_IMAGE ?= yamlio/libyaml-dev 2 | 3 | build: 4 | docker build -t $(DOCKER_IMAGE) . 5 | 6 | run: build 7 | docker run -it --rm $(DOCKER_IMAGE) bash 8 | 9 | prepare-git: 10 | rm -rf output/libyaml.git 11 | git clone ../../.git output/libyaml.git 12 | 13 | libyaml-dist: libyaml-dist-ci 14 | 15 | libyaml-dist-ci: prepare-git 16 | docker run --rm -u $$(id -u) \ 17 | -v"$$PWD/output:/output" \ 18 | -v"$$PWD/scripts:/scripts" \ 19 | $(DOCKER_IMAGE) /scripts/libyaml-dist.sh 20 | 21 | clean: 22 | rm -rf output/libyaml.git 23 | rm -rf output/yaml-*.* 24 | -------------------------------------------------------------------------------- /pkg/docker/output/ReadMe: -------------------------------------------------------------------------------- 1 | Output directory for build files created by docker 2 | -------------------------------------------------------------------------------- /pkg/docker/scripts/libyaml-dist.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -ex 4 | 5 | cp -r /output/libyaml.git /tmp/ 6 | cd /tmp/libyaml.git 7 | ./bootstrap 8 | ./configure 9 | make dist 10 | 11 | # get the tarball filename 12 | tarballs=(yaml-*.tar.gz) 13 | tarball=${tarballs[0]:?} 14 | dirname=${tarball/.tar.gz/} 15 | 16 | # Copy to output dir 17 | cp "$tarball" /output 18 | 19 | # Create zip archive 20 | cd /tmp 21 | cp "/output/$tarball" . 22 | tar xvf "$tarball" 23 | zip -r "/output/$dirname.zip" "$dirname" 24 | -------------------------------------------------------------------------------- /regression-inputs/clusterfuzz-testcase-minimized-5607885063061504.yml: -------------------------------------------------------------------------------- 1 | "(\ 2 | -------------------------------------------------------------------------------- /src/Makefile.am: -------------------------------------------------------------------------------- 1 | AM_CPPFLAGS = -I$(top_srcdir)/include -Wall 2 | lib_LTLIBRARIES = libyaml.la 3 | libyaml_la_SOURCES = yaml_private.h api.c reader.c scanner.c parser.c loader.c writer.c emitter.c dumper.c 4 | libyaml_la_LDFLAGS = -no-undefined -release $(YAML_LT_RELEASE) -version-info $(YAML_LT_CURRENT):$(YAML_LT_REVISION):$(YAML_LT_AGE) 5 | -------------------------------------------------------------------------------- /src/dumper.c: -------------------------------------------------------------------------------- 1 | 2 | #include "yaml_private.h" 3 | 4 | /* 5 | * API functions. 6 | */ 7 | 8 | YAML_DECLARE(int) 9 | yaml_emitter_open(yaml_emitter_t *emitter); 10 | 11 | YAML_DECLARE(int) 12 | yaml_emitter_close(yaml_emitter_t *emitter); 13 | 14 | YAML_DECLARE(int) 15 | yaml_emitter_dump(yaml_emitter_t *emitter, yaml_document_t *document); 16 | 17 | /* 18 | * Clean up functions. 19 | */ 20 | 21 | static void 22 | yaml_emitter_delete_document_and_anchors(yaml_emitter_t *emitter); 23 | 24 | /* 25 | * Anchor functions. 26 | */ 27 | 28 | static void 29 | yaml_emitter_anchor_node(yaml_emitter_t *emitter, int index); 30 | 31 | static yaml_char_t * 32 | yaml_emitter_generate_anchor(yaml_emitter_t *emitter, int anchor_id); 33 | 34 | 35 | /* 36 | * Serialize functions. 37 | */ 38 | 39 | static int 40 | yaml_emitter_dump_node(yaml_emitter_t *emitter, int index); 41 | 42 | static int 43 | yaml_emitter_dump_alias(yaml_emitter_t *emitter, yaml_char_t *anchor); 44 | 45 | static int 46 | yaml_emitter_dump_scalar(yaml_emitter_t *emitter, yaml_node_t *node, 47 | yaml_char_t *anchor); 48 | 49 | static int 50 | yaml_emitter_dump_sequence(yaml_emitter_t *emitter, yaml_node_t *node, 51 | yaml_char_t *anchor); 52 | 53 | static int 54 | yaml_emitter_dump_mapping(yaml_emitter_t *emitter, yaml_node_t *node, 55 | yaml_char_t *anchor); 56 | 57 | /* 58 | * Issue a STREAM-START event. 59 | */ 60 | 61 | YAML_DECLARE(int) 62 | yaml_emitter_open(yaml_emitter_t *emitter) 63 | { 64 | yaml_event_t event; 65 | yaml_mark_t mark = { 0, 0, 0 }; 66 | 67 | assert(emitter); /* Non-NULL emitter object is required. */ 68 | assert(!emitter->opened); /* Emitter should not be opened yet. */ 69 | 70 | STREAM_START_EVENT_INIT(event, YAML_ANY_ENCODING, mark, mark); 71 | 72 | if (!yaml_emitter_emit(emitter, &event)) { 73 | return 0; 74 | } 75 | 76 | emitter->opened = 1; 77 | 78 | return 1; 79 | } 80 | 81 | /* 82 | * Issue a STREAM-END event. 83 | */ 84 | 85 | YAML_DECLARE(int) 86 | yaml_emitter_close(yaml_emitter_t *emitter) 87 | { 88 | yaml_event_t event; 89 | yaml_mark_t mark = { 0, 0, 0 }; 90 | 91 | assert(emitter); /* Non-NULL emitter object is required. */ 92 | assert(emitter->opened); /* Emitter should be opened. */ 93 | 94 | if (emitter->closed) return 1; 95 | 96 | STREAM_END_EVENT_INIT(event, mark, mark); 97 | 98 | if (!yaml_emitter_emit(emitter, &event)) { 99 | return 0; 100 | } 101 | 102 | emitter->closed = 1; 103 | 104 | return 1; 105 | } 106 | 107 | /* 108 | * Dump a YAML document. 109 | */ 110 | 111 | YAML_DECLARE(int) 112 | yaml_emitter_dump(yaml_emitter_t *emitter, yaml_document_t *document) 113 | { 114 | yaml_event_t event; 115 | yaml_mark_t mark = { 0, 0, 0 }; 116 | 117 | assert(emitter); /* Non-NULL emitter object is required. */ 118 | assert(document); /* Non-NULL emitter object is expected. */ 119 | 120 | emitter->document = document; 121 | 122 | if (!emitter->opened) { 123 | if (!yaml_emitter_open(emitter)) goto error; 124 | } 125 | 126 | if (STACK_EMPTY(emitter, document->nodes)) { 127 | if (!yaml_emitter_close(emitter)) goto error; 128 | yaml_emitter_delete_document_and_anchors(emitter); 129 | return 1; 130 | } 131 | 132 | assert(emitter->opened); /* Emitter should be opened. */ 133 | 134 | emitter->anchors = (yaml_anchors_t*)yaml_malloc(sizeof(*(emitter->anchors)) 135 | * (document->nodes.top - document->nodes.start)); 136 | if (!emitter->anchors) goto error; 137 | memset(emitter->anchors, 0, sizeof(*(emitter->anchors)) 138 | * (document->nodes.top - document->nodes.start)); 139 | 140 | DOCUMENT_START_EVENT_INIT(event, document->version_directive, 141 | document->tag_directives.start, document->tag_directives.end, 142 | document->start_implicit, mark, mark); 143 | if (!yaml_emitter_emit(emitter, &event)) goto error; 144 | 145 | yaml_emitter_anchor_node(emitter, 1); 146 | if (!yaml_emitter_dump_node(emitter, 1)) goto error; 147 | 148 | DOCUMENT_END_EVENT_INIT(event, document->end_implicit, mark, mark); 149 | if (!yaml_emitter_emit(emitter, &event)) goto error; 150 | 151 | yaml_emitter_delete_document_and_anchors(emitter); 152 | 153 | return 1; 154 | 155 | error: 156 | 157 | yaml_emitter_delete_document_and_anchors(emitter); 158 | 159 | return 0; 160 | } 161 | 162 | /* 163 | * Clean up the emitter object after a document is dumped. 164 | */ 165 | 166 | static void 167 | yaml_emitter_delete_document_and_anchors(yaml_emitter_t *emitter) 168 | { 169 | int index; 170 | 171 | if (!emitter->anchors) { 172 | yaml_document_delete(emitter->document); 173 | emitter->document = NULL; 174 | return; 175 | } 176 | 177 | for (index = 0; emitter->document->nodes.start + index 178 | < emitter->document->nodes.top; index ++) { 179 | yaml_node_t node = emitter->document->nodes.start[index]; 180 | if (!emitter->anchors[index].serialized) { 181 | yaml_free(node.tag); 182 | if (node.type == YAML_SCALAR_NODE) { 183 | yaml_free(node.data.scalar.value); 184 | } 185 | } 186 | if (node.type == YAML_SEQUENCE_NODE) { 187 | STACK_DEL(emitter, node.data.sequence.items); 188 | } 189 | if (node.type == YAML_MAPPING_NODE) { 190 | STACK_DEL(emitter, node.data.mapping.pairs); 191 | } 192 | } 193 | 194 | STACK_DEL(emitter, emitter->document->nodes); 195 | yaml_free(emitter->anchors); 196 | 197 | emitter->anchors = NULL; 198 | emitter->last_anchor_id = 0; 199 | emitter->document = NULL; 200 | } 201 | 202 | /* 203 | * Check the references of a node and assign the anchor id if needed. 204 | */ 205 | 206 | static void 207 | yaml_emitter_anchor_node(yaml_emitter_t *emitter, int index) 208 | { 209 | yaml_node_t *node = emitter->document->nodes.start + index - 1; 210 | yaml_node_item_t *item; 211 | yaml_node_pair_t *pair; 212 | 213 | emitter->anchors[index-1].references ++; 214 | 215 | if (emitter->anchors[index-1].references == 1) { 216 | switch (node->type) { 217 | case YAML_SEQUENCE_NODE: 218 | for (item = node->data.sequence.items.start; 219 | item < node->data.sequence.items.top; item ++) { 220 | yaml_emitter_anchor_node(emitter, *item); 221 | } 222 | break; 223 | case YAML_MAPPING_NODE: 224 | for (pair = node->data.mapping.pairs.start; 225 | pair < node->data.mapping.pairs.top; pair ++) { 226 | yaml_emitter_anchor_node(emitter, pair->key); 227 | yaml_emitter_anchor_node(emitter, pair->value); 228 | } 229 | break; 230 | default: 231 | break; 232 | } 233 | } 234 | 235 | else if (emitter->anchors[index-1].references == 2) { 236 | emitter->anchors[index-1].anchor = (++ emitter->last_anchor_id); 237 | } 238 | } 239 | 240 | /* 241 | * Generate a textual representation for an anchor. 242 | */ 243 | 244 | #define ANCHOR_TEMPLATE "id%03d" 245 | #define ANCHOR_TEMPLATE_LENGTH 16 246 | 247 | static yaml_char_t * 248 | yaml_emitter_generate_anchor(SHIM(yaml_emitter_t *emitter), int anchor_id) 249 | { 250 | yaml_char_t *anchor = YAML_MALLOC(ANCHOR_TEMPLATE_LENGTH); 251 | 252 | if (!anchor) return NULL; 253 | 254 | sprintf((char *)anchor, ANCHOR_TEMPLATE, anchor_id); 255 | 256 | return anchor; 257 | } 258 | 259 | /* 260 | * Serialize a node. 261 | */ 262 | 263 | static int 264 | yaml_emitter_dump_node(yaml_emitter_t *emitter, int index) 265 | { 266 | yaml_node_t *node = emitter->document->nodes.start + index - 1; 267 | int anchor_id = emitter->anchors[index-1].anchor; 268 | yaml_char_t *anchor = NULL; 269 | 270 | if (anchor_id) { 271 | anchor = yaml_emitter_generate_anchor(emitter, anchor_id); 272 | if (!anchor) return 0; 273 | } 274 | 275 | if (emitter->anchors[index-1].serialized) { 276 | return yaml_emitter_dump_alias(emitter, anchor); 277 | } 278 | 279 | emitter->anchors[index-1].serialized = 1; 280 | 281 | switch (node->type) { 282 | case YAML_SCALAR_NODE: 283 | return yaml_emitter_dump_scalar(emitter, node, anchor); 284 | case YAML_SEQUENCE_NODE: 285 | return yaml_emitter_dump_sequence(emitter, node, anchor); 286 | case YAML_MAPPING_NODE: 287 | return yaml_emitter_dump_mapping(emitter, node, anchor); 288 | default: 289 | assert(0); /* Could not happen. */ 290 | break; 291 | } 292 | 293 | return 0; /* Could not happen. */ 294 | } 295 | 296 | /* 297 | * Serialize an alias. 298 | */ 299 | 300 | static int 301 | yaml_emitter_dump_alias(yaml_emitter_t *emitter, yaml_char_t *anchor) 302 | { 303 | yaml_event_t event; 304 | yaml_mark_t mark = { 0, 0, 0 }; 305 | 306 | ALIAS_EVENT_INIT(event, anchor, mark, mark); 307 | 308 | return yaml_emitter_emit(emitter, &event); 309 | } 310 | 311 | /* 312 | * Serialize a scalar. 313 | */ 314 | 315 | static int 316 | yaml_emitter_dump_scalar(yaml_emitter_t *emitter, yaml_node_t *node, 317 | yaml_char_t *anchor) 318 | { 319 | yaml_event_t event; 320 | yaml_mark_t mark = { 0, 0, 0 }; 321 | 322 | int plain_implicit = (strcmp((char *)node->tag, 323 | YAML_DEFAULT_SCALAR_TAG) == 0); 324 | int quoted_implicit = (strcmp((char *)node->tag, 325 | YAML_DEFAULT_SCALAR_TAG) == 0); 326 | 327 | SCALAR_EVENT_INIT(event, anchor, node->tag, node->data.scalar.value, 328 | node->data.scalar.length, plain_implicit, quoted_implicit, 329 | node->data.scalar.style, mark, mark); 330 | 331 | return yaml_emitter_emit(emitter, &event); 332 | } 333 | 334 | /* 335 | * Serialize a sequence. 336 | */ 337 | 338 | static int 339 | yaml_emitter_dump_sequence(yaml_emitter_t *emitter, yaml_node_t *node, 340 | yaml_char_t *anchor) 341 | { 342 | yaml_event_t event; 343 | yaml_mark_t mark = { 0, 0, 0 }; 344 | 345 | int implicit = (strcmp((char *)node->tag, YAML_DEFAULT_SEQUENCE_TAG) == 0); 346 | 347 | yaml_node_item_t *item; 348 | 349 | SEQUENCE_START_EVENT_INIT(event, anchor, node->tag, implicit, 350 | node->data.sequence.style, mark, mark); 351 | if (!yaml_emitter_emit(emitter, &event)) return 0; 352 | 353 | for (item = node->data.sequence.items.start; 354 | item < node->data.sequence.items.top; item ++) { 355 | if (!yaml_emitter_dump_node(emitter, *item)) return 0; 356 | } 357 | 358 | SEQUENCE_END_EVENT_INIT(event, mark, mark); 359 | if (!yaml_emitter_emit(emitter, &event)) return 0; 360 | 361 | return 1; 362 | } 363 | 364 | /* 365 | * Serialize a mapping. 366 | */ 367 | 368 | static int 369 | yaml_emitter_dump_mapping(yaml_emitter_t *emitter, yaml_node_t *node, 370 | yaml_char_t *anchor) 371 | { 372 | yaml_event_t event; 373 | yaml_mark_t mark = { 0, 0, 0 }; 374 | 375 | int implicit = (strcmp((char *)node->tag, YAML_DEFAULT_MAPPING_TAG) == 0); 376 | 377 | yaml_node_pair_t *pair; 378 | 379 | MAPPING_START_EVENT_INIT(event, anchor, node->tag, implicit, 380 | node->data.mapping.style, mark, mark); 381 | if (!yaml_emitter_emit(emitter, &event)) return 0; 382 | 383 | for (pair = node->data.mapping.pairs.start; 384 | pair < node->data.mapping.pairs.top; pair ++) { 385 | if (!yaml_emitter_dump_node(emitter, pair->key)) return 0; 386 | if (!yaml_emitter_dump_node(emitter, pair->value)) return 0; 387 | } 388 | 389 | MAPPING_END_EVENT_INIT(event, mark, mark); 390 | if (!yaml_emitter_emit(emitter, &event)) return 0; 391 | 392 | return 1; 393 | } 394 | 395 | -------------------------------------------------------------------------------- /src/loader.c: -------------------------------------------------------------------------------- 1 | 2 | #include "yaml_private.h" 3 | 4 | /* 5 | * API functions. 6 | */ 7 | 8 | YAML_DECLARE(int) 9 | yaml_parser_load(yaml_parser_t *parser, yaml_document_t *document); 10 | 11 | /* 12 | * Error handling. 13 | */ 14 | 15 | static int 16 | yaml_parser_set_composer_error(yaml_parser_t *parser, 17 | const char *problem, yaml_mark_t problem_mark); 18 | 19 | static int 20 | yaml_parser_set_composer_error_context(yaml_parser_t *parser, 21 | const char *context, yaml_mark_t context_mark, 22 | const char *problem, yaml_mark_t problem_mark); 23 | 24 | 25 | /* 26 | * Alias handling. 27 | */ 28 | 29 | static int 30 | yaml_parser_register_anchor(yaml_parser_t *parser, 31 | int index, yaml_char_t *anchor); 32 | 33 | /* 34 | * Clean up functions. 35 | */ 36 | 37 | static void 38 | yaml_parser_delete_aliases(yaml_parser_t *parser); 39 | 40 | /* 41 | * Document loading context. 42 | */ 43 | struct loader_ctx { 44 | int *start; 45 | int *end; 46 | int *top; 47 | }; 48 | 49 | /* 50 | * Composer functions. 51 | */ 52 | static int 53 | yaml_parser_load_nodes(yaml_parser_t *parser, struct loader_ctx *ctx); 54 | 55 | static int 56 | yaml_parser_load_document(yaml_parser_t *parser, yaml_event_t *event); 57 | 58 | static int 59 | yaml_parser_load_alias(yaml_parser_t *parser, yaml_event_t *event, 60 | struct loader_ctx *ctx); 61 | 62 | static int 63 | yaml_parser_load_scalar(yaml_parser_t *parser, yaml_event_t *event, 64 | struct loader_ctx *ctx); 65 | 66 | static int 67 | yaml_parser_load_sequence(yaml_parser_t *parser, yaml_event_t *event, 68 | struct loader_ctx *ctx); 69 | 70 | static int 71 | yaml_parser_load_mapping(yaml_parser_t *parser, yaml_event_t *event, 72 | struct loader_ctx *ctx); 73 | 74 | static int 75 | yaml_parser_load_sequence_end(yaml_parser_t *parser, yaml_event_t *event, 76 | struct loader_ctx *ctx); 77 | 78 | static int 79 | yaml_parser_load_mapping_end(yaml_parser_t *parser, yaml_event_t *event, 80 | struct loader_ctx *ctx); 81 | 82 | /* 83 | * Load the next document of the stream. 84 | */ 85 | 86 | YAML_DECLARE(int) 87 | yaml_parser_load(yaml_parser_t *parser, yaml_document_t *document) 88 | { 89 | yaml_event_t event; 90 | 91 | assert(parser); /* Non-NULL parser object is expected. */ 92 | assert(document); /* Non-NULL document object is expected. */ 93 | 94 | memset(document, 0, sizeof(yaml_document_t)); 95 | if (!STACK_INIT(parser, document->nodes, yaml_node_t*)) 96 | goto error; 97 | 98 | if (!parser->stream_start_produced) { 99 | if (!yaml_parser_parse(parser, &event)) goto error; 100 | assert(event.type == YAML_STREAM_START_EVENT); 101 | /* STREAM-START is expected. */ 102 | } 103 | 104 | if (parser->stream_end_produced) { 105 | return 1; 106 | } 107 | 108 | if (!yaml_parser_parse(parser, &event)) goto error; 109 | if (event.type == YAML_STREAM_END_EVENT) { 110 | return 1; 111 | } 112 | 113 | if (!STACK_INIT(parser, parser->aliases, yaml_alias_data_t*)) 114 | goto error; 115 | 116 | parser->document = document; 117 | 118 | if (!yaml_parser_load_document(parser, &event)) goto error; 119 | 120 | yaml_parser_delete_aliases(parser); 121 | parser->document = NULL; 122 | 123 | return 1; 124 | 125 | error: 126 | 127 | yaml_parser_delete_aliases(parser); 128 | yaml_document_delete(document); 129 | parser->document = NULL; 130 | 131 | return 0; 132 | } 133 | 134 | /* 135 | * Set composer error. 136 | */ 137 | 138 | static int 139 | yaml_parser_set_composer_error(yaml_parser_t *parser, 140 | const char *problem, yaml_mark_t problem_mark) 141 | { 142 | parser->error = YAML_COMPOSER_ERROR; 143 | parser->problem = problem; 144 | parser->problem_mark = problem_mark; 145 | 146 | return 0; 147 | } 148 | 149 | /* 150 | * Set composer error with context. 151 | */ 152 | 153 | static int 154 | yaml_parser_set_composer_error_context(yaml_parser_t *parser, 155 | const char *context, yaml_mark_t context_mark, 156 | const char *problem, yaml_mark_t problem_mark) 157 | { 158 | parser->error = YAML_COMPOSER_ERROR; 159 | parser->context = context; 160 | parser->context_mark = context_mark; 161 | parser->problem = problem; 162 | parser->problem_mark = problem_mark; 163 | 164 | return 0; 165 | } 166 | 167 | /* 168 | * Delete the stack of aliases. 169 | */ 170 | 171 | static void 172 | yaml_parser_delete_aliases(yaml_parser_t *parser) 173 | { 174 | while (!STACK_EMPTY(parser, parser->aliases)) { 175 | yaml_free(POP(parser, parser->aliases).anchor); 176 | } 177 | STACK_DEL(parser, parser->aliases); 178 | } 179 | 180 | /* 181 | * Compose a document object. 182 | */ 183 | 184 | static int 185 | yaml_parser_load_document(yaml_parser_t *parser, yaml_event_t *event) 186 | { 187 | struct loader_ctx ctx = { NULL, NULL, NULL }; 188 | 189 | assert(event->type == YAML_DOCUMENT_START_EVENT); 190 | /* DOCUMENT-START is expected. */ 191 | 192 | parser->document->version_directive 193 | = event->data.document_start.version_directive; 194 | parser->document->tag_directives.start 195 | = event->data.document_start.tag_directives.start; 196 | parser->document->tag_directives.end 197 | = event->data.document_start.tag_directives.end; 198 | parser->document->start_implicit 199 | = event->data.document_start.implicit; 200 | parser->document->start_mark = event->start_mark; 201 | 202 | if (!STACK_INIT(parser, ctx, int*)) return 0; 203 | if (!yaml_parser_load_nodes(parser, &ctx)) { 204 | STACK_DEL(parser, ctx); 205 | return 0; 206 | } 207 | STACK_DEL(parser, ctx); 208 | 209 | return 1; 210 | } 211 | 212 | /* 213 | * Compose a node tree. 214 | */ 215 | 216 | static int 217 | yaml_parser_load_nodes(yaml_parser_t *parser, struct loader_ctx *ctx) 218 | { 219 | yaml_event_t event; 220 | 221 | do { 222 | if (!yaml_parser_parse(parser, &event)) return 0; 223 | 224 | switch (event.type) { 225 | case YAML_ALIAS_EVENT: 226 | if (!yaml_parser_load_alias(parser, &event, ctx)) return 0; 227 | break; 228 | case YAML_SCALAR_EVENT: 229 | if (!yaml_parser_load_scalar(parser, &event, ctx)) return 0; 230 | break; 231 | case YAML_SEQUENCE_START_EVENT: 232 | if (!yaml_parser_load_sequence(parser, &event, ctx)) return 0; 233 | break; 234 | case YAML_SEQUENCE_END_EVENT: 235 | if (!yaml_parser_load_sequence_end(parser, &event, ctx)) 236 | return 0; 237 | break; 238 | case YAML_MAPPING_START_EVENT: 239 | if (!yaml_parser_load_mapping(parser, &event, ctx)) return 0; 240 | break; 241 | case YAML_MAPPING_END_EVENT: 242 | if (!yaml_parser_load_mapping_end(parser, &event, ctx)) 243 | return 0; 244 | break; 245 | default: 246 | assert(0); /* Could not happen. */ 247 | return 0; 248 | case YAML_DOCUMENT_END_EVENT: 249 | break; 250 | } 251 | } while (event.type != YAML_DOCUMENT_END_EVENT); 252 | 253 | parser->document->end_implicit = event.data.document_end.implicit; 254 | parser->document->end_mark = event.end_mark; 255 | 256 | return 1; 257 | } 258 | 259 | /* 260 | * Add an anchor. 261 | */ 262 | 263 | static int 264 | yaml_parser_register_anchor(yaml_parser_t *parser, 265 | int index, yaml_char_t *anchor) 266 | { 267 | yaml_alias_data_t data; 268 | yaml_alias_data_t *alias_data; 269 | 270 | if (!anchor) return 1; 271 | 272 | data.anchor = anchor; 273 | data.index = index; 274 | data.mark = parser->document->nodes.start[index-1].start_mark; 275 | 276 | for (alias_data = parser->aliases.start; 277 | alias_data != parser->aliases.top; alias_data ++) { 278 | if (strcmp((char *)alias_data->anchor, (char *)anchor) == 0) { 279 | yaml_free(anchor); 280 | return yaml_parser_set_composer_error_context(parser, 281 | "found duplicate anchor; first occurrence", 282 | alias_data->mark, "second occurrence", data.mark); 283 | } 284 | } 285 | 286 | if (!PUSH(parser, parser->aliases, data)) { 287 | yaml_free(anchor); 288 | return 0; 289 | } 290 | 291 | return 1; 292 | } 293 | 294 | /* 295 | * Compose node into its parent in the stree. 296 | */ 297 | 298 | static int 299 | yaml_parser_load_node_add(yaml_parser_t *parser, struct loader_ctx *ctx, 300 | int index) 301 | { 302 | struct yaml_node_s *parent; 303 | int parent_index; 304 | 305 | if (STACK_EMPTY(parser, *ctx)) { 306 | /* This is the root node, there's no tree to add it to. */ 307 | return 1; 308 | } 309 | 310 | parent_index = *((*ctx).top - 1); 311 | parent = &parser->document->nodes.start[parent_index-1]; 312 | 313 | switch (parent->type) { 314 | case YAML_SEQUENCE_NODE: 315 | if (!STACK_LIMIT(parser, parent->data.sequence.items, INT_MAX-1)) 316 | return 0; 317 | if (!PUSH(parser, parent->data.sequence.items, index)) 318 | return 0; 319 | break; 320 | case YAML_MAPPING_NODE: { 321 | yaml_node_pair_t pair; 322 | if (!STACK_EMPTY(parser, parent->data.mapping.pairs)) { 323 | yaml_node_pair_t *p = parent->data.mapping.pairs.top - 1; 324 | if (p->key != 0 && p->value == 0) { 325 | p->value = index; 326 | break; 327 | } 328 | } 329 | 330 | pair.key = index; 331 | pair.value = 0; 332 | if (!STACK_LIMIT(parser, parent->data.mapping.pairs, INT_MAX-1)) 333 | return 0; 334 | if (!PUSH(parser, parent->data.mapping.pairs, pair)) 335 | return 0; 336 | 337 | break; 338 | } 339 | default: 340 | assert(0); /* Could not happen. */ 341 | return 0; 342 | } 343 | return 1; 344 | } 345 | 346 | /* 347 | * Compose a node corresponding to an alias. 348 | */ 349 | 350 | static int 351 | yaml_parser_load_alias(yaml_parser_t *parser, yaml_event_t *event, 352 | struct loader_ctx *ctx) 353 | { 354 | yaml_char_t *anchor = event->data.alias.anchor; 355 | yaml_alias_data_t *alias_data; 356 | 357 | for (alias_data = parser->aliases.start; 358 | alias_data != parser->aliases.top; alias_data ++) { 359 | if (strcmp((char *)alias_data->anchor, (char *)anchor) == 0) { 360 | yaml_free(anchor); 361 | return yaml_parser_load_node_add(parser, ctx, alias_data->index); 362 | } 363 | } 364 | 365 | yaml_free(anchor); 366 | return yaml_parser_set_composer_error(parser, "found undefined alias", 367 | event->start_mark); 368 | } 369 | 370 | /* 371 | * Compose a scalar node. 372 | */ 373 | 374 | static int 375 | yaml_parser_load_scalar(yaml_parser_t *parser, yaml_event_t *event, 376 | struct loader_ctx *ctx) 377 | { 378 | yaml_node_t node; 379 | int index; 380 | yaml_char_t *tag = event->data.scalar.tag; 381 | 382 | if (!STACK_LIMIT(parser, parser->document->nodes, INT_MAX-1)) goto error; 383 | 384 | if (!tag || strcmp((char *)tag, "!") == 0) { 385 | yaml_free(tag); 386 | tag = yaml_strdup((yaml_char_t *)YAML_DEFAULT_SCALAR_TAG); 387 | if (!tag) goto error; 388 | } 389 | 390 | SCALAR_NODE_INIT(node, tag, event->data.scalar.value, 391 | event->data.scalar.length, event->data.scalar.style, 392 | event->start_mark, event->end_mark); 393 | 394 | if (!PUSH(parser, parser->document->nodes, node)) goto error; 395 | 396 | index = parser->document->nodes.top - parser->document->nodes.start; 397 | 398 | if (!yaml_parser_register_anchor(parser, index, 399 | event->data.scalar.anchor)) return 0; 400 | 401 | return yaml_parser_load_node_add(parser, ctx, index); 402 | 403 | error: 404 | yaml_free(tag); 405 | yaml_free(event->data.scalar.anchor); 406 | yaml_free(event->data.scalar.value); 407 | return 0; 408 | } 409 | 410 | /* 411 | * Compose a sequence node. 412 | */ 413 | 414 | static int 415 | yaml_parser_load_sequence(yaml_parser_t *parser, yaml_event_t *event, 416 | struct loader_ctx *ctx) 417 | { 418 | yaml_node_t node; 419 | struct { 420 | yaml_node_item_t *start; 421 | yaml_node_item_t *end; 422 | yaml_node_item_t *top; 423 | } items = { NULL, NULL, NULL }; 424 | int index; 425 | yaml_char_t *tag = event->data.sequence_start.tag; 426 | 427 | if (!STACK_LIMIT(parser, parser->document->nodes, INT_MAX-1)) goto error; 428 | 429 | if (!tag || strcmp((char *)tag, "!") == 0) { 430 | yaml_free(tag); 431 | tag = yaml_strdup((yaml_char_t *)YAML_DEFAULT_SEQUENCE_TAG); 432 | if (!tag) goto error; 433 | } 434 | 435 | if (!STACK_INIT(parser, items, yaml_node_item_t*)) goto error; 436 | 437 | SEQUENCE_NODE_INIT(node, tag, items.start, items.end, 438 | event->data.sequence_start.style, 439 | event->start_mark, event->end_mark); 440 | 441 | if (!PUSH(parser, parser->document->nodes, node)) goto error; 442 | 443 | index = parser->document->nodes.top - parser->document->nodes.start; 444 | 445 | if (!yaml_parser_register_anchor(parser, index, 446 | event->data.sequence_start.anchor)) return 0; 447 | 448 | if (!yaml_parser_load_node_add(parser, ctx, index)) return 0; 449 | 450 | if (!STACK_LIMIT(parser, *ctx, INT_MAX-1)) return 0; 451 | if (!PUSH(parser, *ctx, index)) return 0; 452 | 453 | return 1; 454 | 455 | error: 456 | yaml_free(tag); 457 | yaml_free(event->data.sequence_start.anchor); 458 | return 0; 459 | } 460 | 461 | static int 462 | yaml_parser_load_sequence_end(yaml_parser_t *parser, yaml_event_t *event, 463 | struct loader_ctx *ctx) 464 | { 465 | int index; 466 | 467 | assert(((*ctx).top - (*ctx).start) > 0); 468 | 469 | index = *((*ctx).top - 1); 470 | assert(parser->document->nodes.start[index-1].type == YAML_SEQUENCE_NODE); 471 | parser->document->nodes.start[index-1].end_mark = event->end_mark; 472 | 473 | (void)POP(parser, *ctx); 474 | 475 | return 1; 476 | } 477 | 478 | /* 479 | * Compose a mapping node. 480 | */ 481 | 482 | static int 483 | yaml_parser_load_mapping(yaml_parser_t *parser, yaml_event_t *event, 484 | struct loader_ctx *ctx) 485 | { 486 | yaml_node_t node; 487 | struct { 488 | yaml_node_pair_t *start; 489 | yaml_node_pair_t *end; 490 | yaml_node_pair_t *top; 491 | } pairs = { NULL, NULL, NULL }; 492 | int index; 493 | yaml_char_t *tag = event->data.mapping_start.tag; 494 | 495 | if (!STACK_LIMIT(parser, parser->document->nodes, INT_MAX-1)) goto error; 496 | 497 | if (!tag || strcmp((char *)tag, "!") == 0) { 498 | yaml_free(tag); 499 | tag = yaml_strdup((yaml_char_t *)YAML_DEFAULT_MAPPING_TAG); 500 | if (!tag) goto error; 501 | } 502 | 503 | if (!STACK_INIT(parser, pairs, yaml_node_pair_t*)) goto error; 504 | 505 | MAPPING_NODE_INIT(node, tag, pairs.start, pairs.end, 506 | event->data.mapping_start.style, 507 | event->start_mark, event->end_mark); 508 | 509 | if (!PUSH(parser, parser->document->nodes, node)) goto error; 510 | 511 | index = parser->document->nodes.top - parser->document->nodes.start; 512 | 513 | if (!yaml_parser_register_anchor(parser, index, 514 | event->data.mapping_start.anchor)) return 0; 515 | 516 | if (!yaml_parser_load_node_add(parser, ctx, index)) return 0; 517 | 518 | if (!STACK_LIMIT(parser, *ctx, INT_MAX-1)) return 0; 519 | if (!PUSH(parser, *ctx, index)) return 0; 520 | 521 | return 1; 522 | 523 | error: 524 | yaml_free(tag); 525 | yaml_free(event->data.mapping_start.anchor); 526 | return 0; 527 | } 528 | 529 | static int 530 | yaml_parser_load_mapping_end(yaml_parser_t *parser, yaml_event_t *event, 531 | struct loader_ctx *ctx) 532 | { 533 | int index; 534 | 535 | assert(((*ctx).top - (*ctx).start) > 0); 536 | 537 | index = *((*ctx).top - 1); 538 | assert(parser->document->nodes.start[index-1].type == YAML_MAPPING_NODE); 539 | parser->document->nodes.start[index-1].end_mark = event->end_mark; 540 | 541 | (void)POP(parser, *ctx); 542 | 543 | return 1; 544 | } -------------------------------------------------------------------------------- /src/reader.c: -------------------------------------------------------------------------------- 1 | 2 | #include "yaml_private.h" 3 | 4 | /* 5 | * Declarations. 6 | */ 7 | 8 | static int 9 | yaml_parser_set_reader_error(yaml_parser_t *parser, const char *problem, 10 | size_t offset, int value); 11 | 12 | static int 13 | yaml_parser_update_raw_buffer(yaml_parser_t *parser); 14 | 15 | static int 16 | yaml_parser_determine_encoding(yaml_parser_t *parser); 17 | 18 | YAML_DECLARE(int) 19 | yaml_parser_update_buffer(yaml_parser_t *parser, size_t length); 20 | 21 | /* 22 | * Set the reader error and return 0. 23 | */ 24 | 25 | static int 26 | yaml_parser_set_reader_error(yaml_parser_t *parser, const char *problem, 27 | size_t offset, int value) 28 | { 29 | parser->error = YAML_READER_ERROR; 30 | parser->problem = problem; 31 | parser->problem_offset = offset; 32 | parser->problem_value = value; 33 | 34 | return 0; 35 | } 36 | 37 | /* 38 | * Byte order marks. 39 | */ 40 | 41 | #define BOM_UTF8 "\xef\xbb\xbf" 42 | #define BOM_UTF16LE "\xff\xfe" 43 | #define BOM_UTF16BE "\xfe\xff" 44 | 45 | /* 46 | * Determine the input stream encoding by checking the BOM symbol. If no BOM is 47 | * found, the UTF-8 encoding is assumed. Return 1 on success, 0 on failure. 48 | */ 49 | 50 | static int 51 | yaml_parser_determine_encoding(yaml_parser_t *parser) 52 | { 53 | /* Ensure that we had enough bytes in the raw buffer. */ 54 | 55 | while (!parser->eof 56 | && parser->raw_buffer.last - parser->raw_buffer.pointer < 3) { 57 | if (!yaml_parser_update_raw_buffer(parser)) { 58 | return 0; 59 | } 60 | } 61 | 62 | /* Determine the encoding. */ 63 | 64 | if (parser->raw_buffer.last - parser->raw_buffer.pointer >= 2 65 | && !memcmp(parser->raw_buffer.pointer, BOM_UTF16LE, 2)) { 66 | parser->encoding = YAML_UTF16LE_ENCODING; 67 | parser->raw_buffer.pointer += 2; 68 | parser->offset += 2; 69 | } 70 | else if (parser->raw_buffer.last - parser->raw_buffer.pointer >= 2 71 | && !memcmp(parser->raw_buffer.pointer, BOM_UTF16BE, 2)) { 72 | parser->encoding = YAML_UTF16BE_ENCODING; 73 | parser->raw_buffer.pointer += 2; 74 | parser->offset += 2; 75 | } 76 | else if (parser->raw_buffer.last - parser->raw_buffer.pointer >= 3 77 | && !memcmp(parser->raw_buffer.pointer, BOM_UTF8, 3)) { 78 | parser->encoding = YAML_UTF8_ENCODING; 79 | parser->raw_buffer.pointer += 3; 80 | parser->offset += 3; 81 | } 82 | else { 83 | parser->encoding = YAML_UTF8_ENCODING; 84 | } 85 | 86 | return 1; 87 | } 88 | 89 | /* 90 | * Update the raw buffer. 91 | */ 92 | 93 | static int 94 | yaml_parser_update_raw_buffer(yaml_parser_t *parser) 95 | { 96 | size_t size_read = 0; 97 | 98 | /* Return if the raw buffer is full. */ 99 | 100 | if (parser->raw_buffer.start == parser->raw_buffer.pointer 101 | && parser->raw_buffer.last == parser->raw_buffer.end) 102 | return 1; 103 | 104 | /* Return on EOF. */ 105 | 106 | if (parser->eof) return 1; 107 | 108 | /* Move the remaining bytes in the raw buffer to the beginning. */ 109 | 110 | if (parser->raw_buffer.start < parser->raw_buffer.pointer 111 | && parser->raw_buffer.pointer < parser->raw_buffer.last) { 112 | memmove(parser->raw_buffer.start, parser->raw_buffer.pointer, 113 | parser->raw_buffer.last - parser->raw_buffer.pointer); 114 | } 115 | parser->raw_buffer.last -= 116 | parser->raw_buffer.pointer - parser->raw_buffer.start; 117 | parser->raw_buffer.pointer = parser->raw_buffer.start; 118 | 119 | /* Call the read handler to fill the buffer. */ 120 | 121 | if (!parser->read_handler(parser->read_handler_data, parser->raw_buffer.last, 122 | parser->raw_buffer.end - parser->raw_buffer.last, &size_read)) { 123 | return yaml_parser_set_reader_error(parser, "input error", 124 | parser->offset, -1); 125 | } 126 | parser->raw_buffer.last += size_read; 127 | if (!size_read) { 128 | parser->eof = 1; 129 | } 130 | 131 | return 1; 132 | } 133 | 134 | /* 135 | * Ensure that the buffer contains at least `length` characters. 136 | * Return 1 on success, 0 on failure. 137 | * 138 | * The length is supposed to be significantly less that the buffer size. 139 | */ 140 | 141 | YAML_DECLARE(int) 142 | yaml_parser_update_buffer(yaml_parser_t *parser, size_t length) 143 | { 144 | int first = 1; 145 | 146 | assert(parser->read_handler); /* Read handler must be set. */ 147 | 148 | /* If the EOF flag is set and the raw buffer is empty, do nothing. */ 149 | 150 | if (parser->eof && parser->raw_buffer.pointer == parser->raw_buffer.last) 151 | return 1; 152 | 153 | /* Return if the buffer contains enough characters. */ 154 | 155 | if (parser->unread >= length) 156 | return 1; 157 | 158 | /* Determine the input encoding if it is not known yet. */ 159 | 160 | if (!parser->encoding) { 161 | if (!yaml_parser_determine_encoding(parser)) 162 | return 0; 163 | } 164 | 165 | /* Move the unread characters to the beginning of the buffer. */ 166 | 167 | if (parser->buffer.start < parser->buffer.pointer 168 | && parser->buffer.pointer < parser->buffer.last) { 169 | size_t size = parser->buffer.last - parser->buffer.pointer; 170 | memmove(parser->buffer.start, parser->buffer.pointer, size); 171 | parser->buffer.pointer = parser->buffer.start; 172 | parser->buffer.last = parser->buffer.start + size; 173 | } 174 | else if (parser->buffer.pointer == parser->buffer.last) { 175 | parser->buffer.pointer = parser->buffer.start; 176 | parser->buffer.last = parser->buffer.start; 177 | } 178 | 179 | /* Fill the buffer until it has enough characters. */ 180 | 181 | while (parser->unread < length) 182 | { 183 | /* Fill the raw buffer if necessary. */ 184 | 185 | if (!first || parser->raw_buffer.pointer == parser->raw_buffer.last) { 186 | if (!yaml_parser_update_raw_buffer(parser)) return 0; 187 | } 188 | first = 0; 189 | 190 | /* Decode the raw buffer. */ 191 | 192 | while (parser->raw_buffer.pointer != parser->raw_buffer.last) 193 | { 194 | unsigned int value = 0, value2 = 0; 195 | int incomplete = 0; 196 | unsigned char octet; 197 | unsigned int width = 0; 198 | int low, high; 199 | size_t k; 200 | size_t raw_unread = parser->raw_buffer.last - parser->raw_buffer.pointer; 201 | 202 | /* Decode the next character. */ 203 | 204 | switch (parser->encoding) 205 | { 206 | case YAML_UTF8_ENCODING: 207 | 208 | /* 209 | * Decode a UTF-8 character. Check RFC 3629 210 | * (http://www.ietf.org/rfc/rfc3629.txt) for more details. 211 | * 212 | * The following table (taken from the RFC) is used for 213 | * decoding. 214 | * 215 | * Char. number range | UTF-8 octet sequence 216 | * (hexadecimal) | (binary) 217 | * --------------------+------------------------------------ 218 | * 0000 0000-0000 007F | 0xxxxxxx 219 | * 0000 0080-0000 07FF | 110xxxxx 10xxxxxx 220 | * 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx 221 | * 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 222 | * 223 | * Additionally, the characters in the range 0xD800-0xDFFF 224 | * are prohibited as they are reserved for use with UTF-16 225 | * surrogate pairs. 226 | */ 227 | 228 | /* Determine the length of the UTF-8 sequence. */ 229 | 230 | octet = parser->raw_buffer.pointer[0]; 231 | width = (octet & 0x80) == 0x00 ? 1 : 232 | (octet & 0xE0) == 0xC0 ? 2 : 233 | (octet & 0xF0) == 0xE0 ? 3 : 234 | (octet & 0xF8) == 0xF0 ? 4 : 0; 235 | 236 | /* Check if the leading octet is valid. */ 237 | 238 | if (!width) 239 | return yaml_parser_set_reader_error(parser, 240 | "invalid leading UTF-8 octet", 241 | parser->offset, octet); 242 | 243 | /* Check if the raw buffer contains an incomplete character. */ 244 | 245 | if (width > raw_unread) { 246 | if (parser->eof) { 247 | return yaml_parser_set_reader_error(parser, 248 | "incomplete UTF-8 octet sequence", 249 | parser->offset, -1); 250 | } 251 | incomplete = 1; 252 | break; 253 | } 254 | 255 | /* Decode the leading octet. */ 256 | 257 | value = (octet & 0x80) == 0x00 ? octet & 0x7F : 258 | (octet & 0xE0) == 0xC0 ? octet & 0x1F : 259 | (octet & 0xF0) == 0xE0 ? octet & 0x0F : 260 | (octet & 0xF8) == 0xF0 ? octet & 0x07 : 0; 261 | 262 | /* Check and decode the trailing octets. */ 263 | 264 | for (k = 1; k < width; k ++) 265 | { 266 | octet = parser->raw_buffer.pointer[k]; 267 | 268 | /* Check if the octet is valid. */ 269 | 270 | if ((octet & 0xC0) != 0x80) 271 | return yaml_parser_set_reader_error(parser, 272 | "invalid trailing UTF-8 octet", 273 | parser->offset+k, octet); 274 | 275 | /* Decode the octet. */ 276 | 277 | value = (value << 6) + (octet & 0x3F); 278 | } 279 | 280 | /* Check the length of the sequence against the value. */ 281 | 282 | if (!((width == 1) || 283 | (width == 2 && value >= 0x80) || 284 | (width == 3 && value >= 0x800) || 285 | (width == 4 && value >= 0x10000))) 286 | return yaml_parser_set_reader_error(parser, 287 | "invalid length of a UTF-8 sequence", 288 | parser->offset, -1); 289 | 290 | /* Check the range of the value. */ 291 | 292 | if ((value >= 0xD800 && value <= 0xDFFF) || value > 0x10FFFF) 293 | return yaml_parser_set_reader_error(parser, 294 | "invalid Unicode character", 295 | parser->offset, value); 296 | 297 | break; 298 | 299 | case YAML_UTF16LE_ENCODING: 300 | case YAML_UTF16BE_ENCODING: 301 | 302 | low = (parser->encoding == YAML_UTF16LE_ENCODING ? 0 : 1); 303 | high = (parser->encoding == YAML_UTF16LE_ENCODING ? 1 : 0); 304 | 305 | /* 306 | * The UTF-16 encoding is not as simple as one might 307 | * naively think. Check RFC 2781 308 | * (http://www.ietf.org/rfc/rfc2781.txt). 309 | * 310 | * Normally, two subsequent bytes describe a Unicode 311 | * character. However a special technique (called a 312 | * surrogate pair) is used for specifying character 313 | * values larger than 0xFFFF. 314 | * 315 | * A surrogate pair consists of two pseudo-characters: 316 | * high surrogate area (0xD800-0xDBFF) 317 | * low surrogate area (0xDC00-0xDFFF) 318 | * 319 | * The following formulas are used for decoding 320 | * and encoding characters using surrogate pairs: 321 | * 322 | * U = U' + 0x10000 (0x01 00 00 <= U <= 0x10 FF FF) 323 | * U' = yyyyyyyyyyxxxxxxxxxx (0 <= U' <= 0x0F FF FF) 324 | * W1 = 110110yyyyyyyyyy 325 | * W2 = 110111xxxxxxxxxx 326 | * 327 | * where U is the character value, W1 is the high surrogate 328 | * area, W2 is the low surrogate area. 329 | */ 330 | 331 | /* Check for incomplete UTF-16 character. */ 332 | 333 | if (raw_unread < 2) { 334 | if (parser->eof) { 335 | return yaml_parser_set_reader_error(parser, 336 | "incomplete UTF-16 character", 337 | parser->offset, -1); 338 | } 339 | incomplete = 1; 340 | break; 341 | } 342 | 343 | /* Get the character. */ 344 | 345 | value = parser->raw_buffer.pointer[low] 346 | + (parser->raw_buffer.pointer[high] << 8); 347 | 348 | /* Check for unexpected low surrogate area. */ 349 | 350 | if ((value & 0xFC00) == 0xDC00) 351 | return yaml_parser_set_reader_error(parser, 352 | "unexpected low surrogate area", 353 | parser->offset, value); 354 | 355 | /* Check for a high surrogate area. */ 356 | 357 | if ((value & 0xFC00) == 0xD800) { 358 | 359 | width = 4; 360 | 361 | /* Check for incomplete surrogate pair. */ 362 | 363 | if (raw_unread < 4) { 364 | if (parser->eof) { 365 | return yaml_parser_set_reader_error(parser, 366 | "incomplete UTF-16 surrogate pair", 367 | parser->offset, -1); 368 | } 369 | incomplete = 1; 370 | break; 371 | } 372 | 373 | /* Get the next character. */ 374 | 375 | value2 = parser->raw_buffer.pointer[low+2] 376 | + (parser->raw_buffer.pointer[high+2] << 8); 377 | 378 | /* Check for a low surrogate area. */ 379 | 380 | if ((value2 & 0xFC00) != 0xDC00) 381 | return yaml_parser_set_reader_error(parser, 382 | "expected low surrogate area", 383 | parser->offset+2, value2); 384 | 385 | /* Generate the value of the surrogate pair. */ 386 | 387 | value = 0x10000 + ((value & 0x3FF) << 10) + (value2 & 0x3FF); 388 | } 389 | 390 | else { 391 | width = 2; 392 | } 393 | 394 | break; 395 | 396 | default: 397 | assert(1); /* Impossible. */ 398 | } 399 | 400 | /* Check if the raw buffer contains enough bytes to form a character. */ 401 | 402 | if (incomplete) break; 403 | 404 | /* 405 | * Check if the character is in the allowed range: 406 | * #x9 | #xA | #xD | [#x20-#x7E] (8 bit) 407 | * | #x85 | [#xA0-#xD7FF] | [#xE000-#xFFFD] (16 bit) 408 | * | [#x10000-#x10FFFF] (32 bit) 409 | */ 410 | 411 | if (! (value == 0x09 || value == 0x0A || value == 0x0D 412 | || (value >= 0x20 && value <= 0x7E) 413 | || (value == 0x85) || (value >= 0xA0 && value <= 0xD7FF) 414 | || (value >= 0xE000 && value <= 0xFFFD) 415 | || (value >= 0x10000 && value <= 0x10FFFF))) 416 | return yaml_parser_set_reader_error(parser, 417 | "control characters are not allowed", 418 | parser->offset, value); 419 | 420 | /* Move the raw pointers. */ 421 | 422 | parser->raw_buffer.pointer += width; 423 | parser->offset += width; 424 | 425 | /* Finally put the character into the buffer. */ 426 | 427 | /* 0000 0000-0000 007F -> 0xxxxxxx */ 428 | if (value <= 0x7F) { 429 | *(parser->buffer.last++) = value; 430 | } 431 | /* 0000 0080-0000 07FF -> 110xxxxx 10xxxxxx */ 432 | else if (value <= 0x7FF) { 433 | *(parser->buffer.last++) = 0xC0 + (value >> 6); 434 | *(parser->buffer.last++) = 0x80 + (value & 0x3F); 435 | } 436 | /* 0000 0800-0000 FFFF -> 1110xxxx 10xxxxxx 10xxxxxx */ 437 | else if (value <= 0xFFFF) { 438 | *(parser->buffer.last++) = 0xE0 + (value >> 12); 439 | *(parser->buffer.last++) = 0x80 + ((value >> 6) & 0x3F); 440 | *(parser->buffer.last++) = 0x80 + (value & 0x3F); 441 | } 442 | /* 0001 0000-0010 FFFF -> 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ 443 | else { 444 | *(parser->buffer.last++) = 0xF0 + (value >> 18); 445 | *(parser->buffer.last++) = 0x80 + ((value >> 12) & 0x3F); 446 | *(parser->buffer.last++) = 0x80 + ((value >> 6) & 0x3F); 447 | *(parser->buffer.last++) = 0x80 + (value & 0x3F); 448 | } 449 | 450 | parser->unread ++; 451 | } 452 | 453 | /* On EOF, put NUL into the buffer and return. */ 454 | 455 | if (parser->eof) { 456 | *(parser->buffer.last++) = '\0'; 457 | parser->unread ++; 458 | return 1; 459 | } 460 | 461 | } 462 | 463 | if (parser->offset >= MAX_FILE_SIZE) { 464 | return yaml_parser_set_reader_error(parser, "input is too long", 465 | parser->offset, -1); 466 | } 467 | 468 | return 1; 469 | } 470 | -------------------------------------------------------------------------------- /src/writer.c: -------------------------------------------------------------------------------- 1 | 2 | #include "yaml_private.h" 3 | 4 | /* 5 | * Declarations. 6 | */ 7 | 8 | static int 9 | yaml_emitter_set_writer_error(yaml_emitter_t *emitter, const char *problem); 10 | 11 | YAML_DECLARE(int) 12 | yaml_emitter_flush(yaml_emitter_t *emitter); 13 | 14 | /* 15 | * Set the writer error and return 0. 16 | */ 17 | 18 | static int 19 | yaml_emitter_set_writer_error(yaml_emitter_t *emitter, const char *problem) 20 | { 21 | emitter->error = YAML_WRITER_ERROR; 22 | emitter->problem = problem; 23 | 24 | return 0; 25 | } 26 | 27 | /* 28 | * Flush the output buffer. 29 | */ 30 | 31 | YAML_DECLARE(int) 32 | yaml_emitter_flush(yaml_emitter_t *emitter) 33 | { 34 | int low, high; 35 | 36 | assert(emitter); /* Non-NULL emitter object is expected. */ 37 | assert(emitter->write_handler); /* Write handler must be set. */ 38 | assert(emitter->encoding); /* Output encoding must be set. */ 39 | 40 | emitter->buffer.last = emitter->buffer.pointer; 41 | emitter->buffer.pointer = emitter->buffer.start; 42 | 43 | /* Check if the buffer is empty. */ 44 | 45 | if (emitter->buffer.start == emitter->buffer.last) { 46 | return 1; 47 | } 48 | 49 | /* If the output encoding is UTF-8, we don't need to recode the buffer. */ 50 | 51 | if (emitter->encoding == YAML_UTF8_ENCODING) 52 | { 53 | if (emitter->write_handler(emitter->write_handler_data, 54 | emitter->buffer.start, 55 | emitter->buffer.last - emitter->buffer.start)) { 56 | emitter->buffer.last = emitter->buffer.start; 57 | emitter->buffer.pointer = emitter->buffer.start; 58 | return 1; 59 | } 60 | else { 61 | return yaml_emitter_set_writer_error(emitter, "write error"); 62 | } 63 | } 64 | 65 | /* Recode the buffer into the raw buffer. */ 66 | 67 | low = (emitter->encoding == YAML_UTF16LE_ENCODING ? 0 : 1); 68 | high = (emitter->encoding == YAML_UTF16LE_ENCODING ? 1 : 0); 69 | 70 | while (emitter->buffer.pointer != emitter->buffer.last) 71 | { 72 | unsigned char octet; 73 | unsigned int width; 74 | unsigned int value; 75 | size_t k; 76 | 77 | /* 78 | * See the "reader.c" code for more details on UTF-8 encoding. Note 79 | * that we assume that the buffer contains a valid UTF-8 sequence. 80 | */ 81 | 82 | /* Read the next UTF-8 character. */ 83 | 84 | octet = emitter->buffer.pointer[0]; 85 | 86 | width = (octet & 0x80) == 0x00 ? 1 : 87 | (octet & 0xE0) == 0xC0 ? 2 : 88 | (octet & 0xF0) == 0xE0 ? 3 : 89 | (octet & 0xF8) == 0xF0 ? 4 : 0; 90 | 91 | value = (octet & 0x80) == 0x00 ? octet & 0x7F : 92 | (octet & 0xE0) == 0xC0 ? octet & 0x1F : 93 | (octet & 0xF0) == 0xE0 ? octet & 0x0F : 94 | (octet & 0xF8) == 0xF0 ? octet & 0x07 : 0; 95 | 96 | for (k = 1; k < width; k ++) { 97 | octet = emitter->buffer.pointer[k]; 98 | value = (value << 6) + (octet & 0x3F); 99 | } 100 | 101 | emitter->buffer.pointer += width; 102 | 103 | /* Write the character. */ 104 | 105 | if (value < 0x10000) 106 | { 107 | emitter->raw_buffer.last[high] = value >> 8; 108 | emitter->raw_buffer.last[low] = value & 0xFF; 109 | 110 | emitter->raw_buffer.last += 2; 111 | } 112 | else 113 | { 114 | /* Write the character using a surrogate pair (check "reader.c"). */ 115 | 116 | value -= 0x10000; 117 | emitter->raw_buffer.last[high] = 0xD8 + (value >> 18); 118 | emitter->raw_buffer.last[low] = (value >> 10) & 0xFF; 119 | emitter->raw_buffer.last[high+2] = 0xDC + ((value >> 8) & 0xFF); 120 | emitter->raw_buffer.last[low+2] = value & 0xFF; 121 | 122 | emitter->raw_buffer.last += 4; 123 | } 124 | } 125 | 126 | /* Write the raw buffer. */ 127 | 128 | if (emitter->write_handler(emitter->write_handler_data, 129 | emitter->raw_buffer.start, 130 | emitter->raw_buffer.last - emitter->raw_buffer.start)) { 131 | emitter->buffer.last = emitter->buffer.start; 132 | emitter->buffer.pointer = emitter->buffer.start; 133 | emitter->raw_buffer.last = emitter->raw_buffer.start; 134 | emitter->raw_buffer.pointer = emitter->raw_buffer.start; 135 | return 1; 136 | } 137 | else { 138 | return yaml_emitter_set_writer_error(emitter, "write error"); 139 | } 140 | } 141 | 142 | -------------------------------------------------------------------------------- /src/yaml_private.h: -------------------------------------------------------------------------------- 1 | #if HAVE_CONFIG_H 2 | #include "config.h" 3 | #endif 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | /* 12 | * Memory management. 13 | */ 14 | 15 | YAML_DECLARE(void *) 16 | yaml_malloc(size_t size); 17 | 18 | YAML_DECLARE(void *) 19 | yaml_realloc(void *ptr, size_t size); 20 | 21 | YAML_DECLARE(void) 22 | yaml_free(void *ptr); 23 | 24 | YAML_DECLARE(yaml_char_t *) 25 | yaml_strdup(const yaml_char_t *); 26 | 27 | /* 28 | * Reader: Ensure that the buffer contains at least `length` characters. 29 | */ 30 | 31 | YAML_DECLARE(int) 32 | yaml_parser_update_buffer(yaml_parser_t *parser, size_t length); 33 | 34 | /* 35 | * Scanner: Ensure that the token stack contains at least one token ready. 36 | */ 37 | 38 | YAML_DECLARE(int) 39 | yaml_parser_fetch_more_tokens(yaml_parser_t *parser); 40 | 41 | /* 42 | * The size of the input raw buffer. 43 | */ 44 | 45 | #define INPUT_RAW_BUFFER_SIZE 16384 46 | 47 | /* 48 | * The size of the input buffer. 49 | * 50 | * It should be possible to decode the whole raw buffer. 51 | */ 52 | 53 | #define INPUT_BUFFER_SIZE (INPUT_RAW_BUFFER_SIZE*3) 54 | 55 | /* 56 | * The size of the output buffer. 57 | */ 58 | 59 | #define OUTPUT_BUFFER_SIZE 16384 60 | 61 | /* 62 | * The size of the output raw buffer. 63 | * 64 | * It should be possible to encode the whole output buffer. 65 | */ 66 | 67 | #define OUTPUT_RAW_BUFFER_SIZE (OUTPUT_BUFFER_SIZE*2+2) 68 | 69 | /* 70 | * The maximum size of a YAML input file. 71 | * This used to be PTRDIFF_MAX, but that's not entirely portable 72 | * because stdint.h isn't available on all platforms. 73 | * It is not entirely clear why this isn't the maximum value 74 | * that can fit into the parser->offset field. 75 | */ 76 | 77 | #define MAX_FILE_SIZE (~(size_t)0 / 2) 78 | 79 | 80 | /* 81 | * The size of other stacks and queues. 82 | */ 83 | 84 | #define INITIAL_STACK_SIZE 16 85 | #define INITIAL_QUEUE_SIZE 16 86 | #define INITIAL_STRING_SIZE 16 87 | 88 | /* 89 | * Buffer management. 90 | */ 91 | 92 | #define BUFFER_INIT(context,buffer,size) \ 93 | (((buffer).start = (yaml_char_t *)yaml_malloc(size)) ? \ 94 | ((buffer).last = (buffer).pointer = (buffer).start, \ 95 | (buffer).end = (buffer).start+(size), \ 96 | 1) : \ 97 | ((context)->error = YAML_MEMORY_ERROR, \ 98 | 0)) 99 | 100 | #define BUFFER_DEL(context,buffer) \ 101 | (yaml_free((buffer).start), \ 102 | (buffer).start = (buffer).pointer = (buffer).end = 0) 103 | 104 | /* 105 | * String management. 106 | */ 107 | 108 | typedef struct { 109 | yaml_char_t *start; 110 | yaml_char_t *end; 111 | yaml_char_t *pointer; 112 | } yaml_string_t; 113 | 114 | YAML_DECLARE(int) 115 | yaml_string_extend(yaml_char_t **start, 116 | yaml_char_t **pointer, yaml_char_t **end); 117 | 118 | YAML_DECLARE(int) 119 | yaml_string_join( 120 | yaml_char_t **a_start, yaml_char_t **a_pointer, yaml_char_t **a_end, 121 | yaml_char_t **b_start, yaml_char_t **b_pointer, yaml_char_t **b_end); 122 | 123 | #define NULL_STRING { NULL, NULL, NULL } 124 | 125 | #define STRING(string,length) { (string), (string)+(length), (string) } 126 | 127 | #define STRING_ASSIGN(value,string,length) \ 128 | ((value).start = (string), \ 129 | (value).end = (string)+(length), \ 130 | (value).pointer = (string)) 131 | 132 | #define STRING_INIT(context,string,size) \ 133 | (((string).start = YAML_MALLOC(size)) ? \ 134 | ((string).pointer = (string).start, \ 135 | (string).end = (string).start+(size), \ 136 | memset((string).start, 0, (size)), \ 137 | 1) : \ 138 | ((context)->error = YAML_MEMORY_ERROR, \ 139 | 0)) 140 | 141 | #define STRING_DEL(context,string) \ 142 | (yaml_free((string).start), \ 143 | (string).start = (string).pointer = (string).end = 0) 144 | 145 | #define STRING_EXTEND(context,string) \ 146 | ((((string).pointer+5 < (string).end) \ 147 | || yaml_string_extend(&(string).start, \ 148 | &(string).pointer, &(string).end)) ? \ 149 | 1 : \ 150 | ((context)->error = YAML_MEMORY_ERROR, \ 151 | 0)) 152 | 153 | #define CLEAR(context,string) \ 154 | ((string).pointer = (string).start, \ 155 | memset((string).start, 0, (string).end-(string).start)) 156 | 157 | #define JOIN(context,string_a,string_b) \ 158 | ((yaml_string_join(&(string_a).start, &(string_a).pointer, \ 159 | &(string_a).end, &(string_b).start, \ 160 | &(string_b).pointer, &(string_b).end)) ? \ 161 | ((string_b).pointer = (string_b).start, \ 162 | 1) : \ 163 | ((context)->error = YAML_MEMORY_ERROR, \ 164 | 0)) 165 | 166 | /* 167 | * String check operations. 168 | */ 169 | 170 | /* 171 | * Check the octet at the specified position. 172 | */ 173 | 174 | #define CHECK_AT(string,octet,offset) \ 175 | ((string).pointer[offset] == (yaml_char_t)(octet)) 176 | 177 | /* 178 | * Check the current octet in the buffer. 179 | */ 180 | 181 | #define CHECK(string,octet) (CHECK_AT((string),(octet),0)) 182 | 183 | /* 184 | * Check if the character at the specified position is an alphabetical 185 | * character, a digit, '_', or '-'. 186 | */ 187 | 188 | #define IS_ALPHA_AT(string,offset) \ 189 | (((string).pointer[offset] >= (yaml_char_t) '0' && \ 190 | (string).pointer[offset] <= (yaml_char_t) '9') || \ 191 | ((string).pointer[offset] >= (yaml_char_t) 'A' && \ 192 | (string).pointer[offset] <= (yaml_char_t) 'Z') || \ 193 | ((string).pointer[offset] >= (yaml_char_t) 'a' && \ 194 | (string).pointer[offset] <= (yaml_char_t) 'z') || \ 195 | (string).pointer[offset] == '_' || \ 196 | (string).pointer[offset] == '-') 197 | 198 | #define IS_ALPHA(string) IS_ALPHA_AT((string),0) 199 | 200 | /* 201 | * Check if the character at the specified position is a digit. 202 | */ 203 | 204 | #define IS_DIGIT_AT(string,offset) \ 205 | (((string).pointer[offset] >= (yaml_char_t) '0' && \ 206 | (string).pointer[offset] <= (yaml_char_t) '9')) 207 | 208 | #define IS_DIGIT(string) IS_DIGIT_AT((string),0) 209 | 210 | /* 211 | * Get the value of a digit. 212 | */ 213 | 214 | #define AS_DIGIT_AT(string,offset) \ 215 | ((string).pointer[offset] - (yaml_char_t) '0') 216 | 217 | #define AS_DIGIT(string) AS_DIGIT_AT((string),0) 218 | 219 | /* 220 | * Check if the character at the specified position is a hex-digit. 221 | */ 222 | 223 | #define IS_HEX_AT(string,offset) \ 224 | (((string).pointer[offset] >= (yaml_char_t) '0' && \ 225 | (string).pointer[offset] <= (yaml_char_t) '9') || \ 226 | ((string).pointer[offset] >= (yaml_char_t) 'A' && \ 227 | (string).pointer[offset] <= (yaml_char_t) 'F') || \ 228 | ((string).pointer[offset] >= (yaml_char_t) 'a' && \ 229 | (string).pointer[offset] <= (yaml_char_t) 'f')) 230 | 231 | #define IS_HEX(string) IS_HEX_AT((string),0) 232 | 233 | /* 234 | * Get the value of a hex-digit. 235 | */ 236 | 237 | #define AS_HEX_AT(string,offset) \ 238 | (((string).pointer[offset] >= (yaml_char_t) 'A' && \ 239 | (string).pointer[offset] <= (yaml_char_t) 'F') ? \ 240 | ((string).pointer[offset] - (yaml_char_t) 'A' + 10) : \ 241 | ((string).pointer[offset] >= (yaml_char_t) 'a' && \ 242 | (string).pointer[offset] <= (yaml_char_t) 'f') ? \ 243 | ((string).pointer[offset] - (yaml_char_t) 'a' + 10) : \ 244 | ((string).pointer[offset] - (yaml_char_t) '0')) 245 | 246 | #define AS_HEX(string) AS_HEX_AT((string),0) 247 | 248 | /* 249 | * Check if the character is ASCII. 250 | */ 251 | 252 | #define IS_ASCII_AT(string,offset) \ 253 | ((string).pointer[offset] <= (yaml_char_t) '\x7F') 254 | 255 | #define IS_ASCII(string) IS_ASCII_AT((string),0) 256 | 257 | /* 258 | * Check if the character can be printed unescaped. 259 | */ 260 | 261 | #define IS_PRINTABLE_AT(string,offset) \ 262 | (((string).pointer[offset] == 0x0A) /* . == #x0A */ \ 263 | || ((string).pointer[offset] >= 0x20 /* #x20 <= . <= #x7E */ \ 264 | && (string).pointer[offset] <= 0x7E) \ 265 | || ((string).pointer[offset] == 0xC2 /* #0xA0 <= . <= #xD7FF */ \ 266 | && (string).pointer[offset+1] >= 0xA0) \ 267 | || ((string).pointer[offset] > 0xC2 \ 268 | && (string).pointer[offset] < 0xED) \ 269 | || ((string).pointer[offset] == 0xED \ 270 | && (string).pointer[offset+1] < 0xA0) \ 271 | || ((string).pointer[offset] == 0xEE) \ 272 | || ((string).pointer[offset] == 0xEF /* #xE000 <= . <= #xFFFD */ \ 273 | && !((string).pointer[offset+1] == 0xBB /* && . != #xFEFF */ \ 274 | && (string).pointer[offset+2] == 0xBF) \ 275 | && !((string).pointer[offset+1] == 0xBF \ 276 | && ((string).pointer[offset+2] == 0xBE \ 277 | || (string).pointer[offset+2] == 0xBF)))) 278 | 279 | #define IS_PRINTABLE(string) IS_PRINTABLE_AT((string),0) 280 | 281 | /* 282 | * Check if the character at the specified position is NUL. 283 | */ 284 | 285 | #define IS_Z_AT(string,offset) CHECK_AT((string),'\0',(offset)) 286 | 287 | #define IS_Z(string) IS_Z_AT((string),0) 288 | 289 | /* 290 | * Check if the character at the specified position is BOM. 291 | */ 292 | 293 | #define IS_BOM_AT(string,offset) \ 294 | (CHECK_AT((string),'\xEF',(offset)) \ 295 | && CHECK_AT((string),'\xBB',(offset)+1) \ 296 | && CHECK_AT((string),'\xBF',(offset)+2)) /* BOM (#xFEFF) */ 297 | 298 | #define IS_BOM(string) IS_BOM_AT(string,0) 299 | 300 | /* 301 | * Check if the character at the specified position is space. 302 | */ 303 | 304 | #define IS_SPACE_AT(string,offset) CHECK_AT((string),' ',(offset)) 305 | 306 | #define IS_SPACE(string) IS_SPACE_AT((string),0) 307 | 308 | /* 309 | * Check if the character at the specified position is tab. 310 | */ 311 | 312 | #define IS_TAB_AT(string,offset) CHECK_AT((string),'\t',(offset)) 313 | 314 | #define IS_TAB(string) IS_TAB_AT((string),0) 315 | 316 | /* 317 | * Check if the character at the specified position is blank (space or tab). 318 | */ 319 | 320 | #define IS_BLANK_AT(string,offset) \ 321 | (IS_SPACE_AT((string),(offset)) || IS_TAB_AT((string),(offset))) 322 | 323 | #define IS_BLANK(string) IS_BLANK_AT((string),0) 324 | 325 | /* 326 | * Check if the character at the specified position is a line break. 327 | */ 328 | 329 | #define IS_BREAK_AT(string,offset) \ 330 | (CHECK_AT((string),'\r',(offset)) /* CR (#xD)*/ \ 331 | || CHECK_AT((string),'\n',(offset)) /* LF (#xA) */ \ 332 | || (CHECK_AT((string),'\xC2',(offset)) \ 333 | && CHECK_AT((string),'\x85',(offset)+1)) /* NEL (#x85) */ \ 334 | || (CHECK_AT((string),'\xE2',(offset)) \ 335 | && CHECK_AT((string),'\x80',(offset)+1) \ 336 | && CHECK_AT((string),'\xA8',(offset)+2)) /* LS (#x2028) */ \ 337 | || (CHECK_AT((string),'\xE2',(offset)) \ 338 | && CHECK_AT((string),'\x80',(offset)+1) \ 339 | && CHECK_AT((string),'\xA9',(offset)+2))) /* PS (#x2029) */ 340 | 341 | #define IS_BREAK(string) IS_BREAK_AT((string),0) 342 | 343 | #define IS_CRLF_AT(string,offset) \ 344 | (CHECK_AT((string),'\r',(offset)) && CHECK_AT((string),'\n',(offset)+1)) 345 | 346 | #define IS_CRLF(string) IS_CRLF_AT((string),0) 347 | 348 | /* 349 | * Check if the character is a line break or NUL. 350 | */ 351 | 352 | #define IS_BREAKZ_AT(string,offset) \ 353 | (IS_BREAK_AT((string),(offset)) || IS_Z_AT((string),(offset))) 354 | 355 | #define IS_BREAKZ(string) IS_BREAKZ_AT((string),0) 356 | 357 | /* 358 | * Check if the character is a line break, space, or NUL. 359 | */ 360 | 361 | #define IS_SPACEZ_AT(string,offset) \ 362 | (IS_SPACE_AT((string),(offset)) || IS_BREAKZ_AT((string),(offset))) 363 | 364 | #define IS_SPACEZ(string) IS_SPACEZ_AT((string),0) 365 | 366 | /* 367 | * Check if the character is a line break, space, tab, or NUL. 368 | */ 369 | 370 | #define IS_BLANKZ_AT(string,offset) \ 371 | (IS_BLANK_AT((string),(offset)) || IS_BREAKZ_AT((string),(offset))) 372 | 373 | #define IS_BLANKZ(string) IS_BLANKZ_AT((string),0) 374 | 375 | /* 376 | * Determine the width of the character. 377 | */ 378 | 379 | #define WIDTH_AT(string,offset) \ 380 | (((string).pointer[offset] & 0x80) == 0x00 ? 1 : \ 381 | ((string).pointer[offset] & 0xE0) == 0xC0 ? 2 : \ 382 | ((string).pointer[offset] & 0xF0) == 0xE0 ? 3 : \ 383 | ((string).pointer[offset] & 0xF8) == 0xF0 ? 4 : 0) 384 | 385 | #define WIDTH(string) WIDTH_AT((string),0) 386 | 387 | /* 388 | * Move the string pointer to the next character. 389 | */ 390 | 391 | #define MOVE(string) ((string).pointer += WIDTH((string))) 392 | 393 | /* 394 | * Copy a character and move the pointers of both strings. 395 | */ 396 | 397 | #define COPY(string_a,string_b) \ 398 | ((*(string_b).pointer & 0x80) == 0x00 ? \ 399 | (*((string_a).pointer++) = *((string_b).pointer++)) : \ 400 | (*(string_b).pointer & 0xE0) == 0xC0 ? \ 401 | (*((string_a).pointer++) = *((string_b).pointer++), \ 402 | *((string_a).pointer++) = *((string_b).pointer++)) : \ 403 | (*(string_b).pointer & 0xF0) == 0xE0 ? \ 404 | (*((string_a).pointer++) = *((string_b).pointer++), \ 405 | *((string_a).pointer++) = *((string_b).pointer++), \ 406 | *((string_a).pointer++) = *((string_b).pointer++)) : \ 407 | (*(string_b).pointer & 0xF8) == 0xF0 ? \ 408 | (*((string_a).pointer++) = *((string_b).pointer++), \ 409 | *((string_a).pointer++) = *((string_b).pointer++), \ 410 | *((string_a).pointer++) = *((string_b).pointer++), \ 411 | *((string_a).pointer++) = *((string_b).pointer++)) : 0) 412 | 413 | /* 414 | * Stack and queue management. 415 | */ 416 | 417 | YAML_DECLARE(int) 418 | yaml_stack_extend(void **start, void **top, void **end); 419 | 420 | YAML_DECLARE(int) 421 | yaml_queue_extend(void **start, void **head, void **tail, void **end); 422 | 423 | #define STACK_INIT(context,stack,type) \ 424 | (((stack).start = (type)yaml_malloc(INITIAL_STACK_SIZE*sizeof(*(stack).start))) ? \ 425 | ((stack).top = (stack).start, \ 426 | (stack).end = (stack).start+INITIAL_STACK_SIZE, \ 427 | 1) : \ 428 | ((context)->error = YAML_MEMORY_ERROR, \ 429 | 0)) 430 | 431 | #define STACK_DEL(context,stack) \ 432 | (yaml_free((stack).start), \ 433 | (stack).start = (stack).top = (stack).end = 0) 434 | 435 | #define STACK_EMPTY(context,stack) \ 436 | ((stack).start == (stack).top) 437 | 438 | #define STACK_LIMIT(context,stack,size) \ 439 | ((stack).top - (stack).start < (size) ? \ 440 | 1 : \ 441 | ((context)->error = YAML_MEMORY_ERROR, \ 442 | 0)) 443 | 444 | #define PUSH(context,stack,value) \ 445 | (((stack).top != (stack).end \ 446 | || yaml_stack_extend((void **)&(stack).start, \ 447 | (void **)&(stack).top, (void **)&(stack).end)) ? \ 448 | (*((stack).top++) = value, \ 449 | 1) : \ 450 | ((context)->error = YAML_MEMORY_ERROR, \ 451 | 0)) 452 | 453 | #define POP(context,stack) \ 454 | (*(--(stack).top)) 455 | 456 | #define QUEUE_INIT(context,queue,size,type) \ 457 | (((queue).start = (type)yaml_malloc((size)*sizeof(*(queue).start))) ? \ 458 | ((queue).head = (queue).tail = (queue).start, \ 459 | (queue).end = (queue).start+(size), \ 460 | 1) : \ 461 | ((context)->error = YAML_MEMORY_ERROR, \ 462 | 0)) 463 | 464 | #define QUEUE_DEL(context,queue) \ 465 | (yaml_free((queue).start), \ 466 | (queue).start = (queue).head = (queue).tail = (queue).end = 0) 467 | 468 | #define QUEUE_EMPTY(context,queue) \ 469 | ((queue).head == (queue).tail) 470 | 471 | #define ENQUEUE(context,queue,value) \ 472 | (((queue).tail != (queue).end \ 473 | || yaml_queue_extend((void **)&(queue).start, (void **)&(queue).head, \ 474 | (void **)&(queue).tail, (void **)&(queue).end)) ? \ 475 | (*((queue).tail++) = value, \ 476 | 1) : \ 477 | ((context)->error = YAML_MEMORY_ERROR, \ 478 | 0)) 479 | 480 | #define DEQUEUE(context,queue) \ 481 | (*((queue).head++)) 482 | 483 | #define QUEUE_INSERT(context,queue,index,value) \ 484 | (((queue).tail != (queue).end \ 485 | || yaml_queue_extend((void **)&(queue).start, (void **)&(queue).head, \ 486 | (void **)&(queue).tail, (void **)&(queue).end)) ? \ 487 | (memmove((queue).head+(index)+1,(queue).head+(index), \ 488 | ((queue).tail-(queue).head-(index))*sizeof(*(queue).start)), \ 489 | *((queue).head+(index)) = value, \ 490 | (queue).tail++, \ 491 | 1) : \ 492 | ((context)->error = YAML_MEMORY_ERROR, \ 493 | 0)) 494 | 495 | /* 496 | * Token initializers. 497 | */ 498 | 499 | #define TOKEN_INIT(token,token_type,token_start_mark,token_end_mark) \ 500 | (memset(&(token), 0, sizeof(yaml_token_t)), \ 501 | (token).type = (token_type), \ 502 | (token).start_mark = (token_start_mark), \ 503 | (token).end_mark = (token_end_mark)) 504 | 505 | #define STREAM_START_TOKEN_INIT(token,token_encoding,start_mark,end_mark) \ 506 | (TOKEN_INIT((token),YAML_STREAM_START_TOKEN,(start_mark),(end_mark)), \ 507 | (token).data.stream_start.encoding = (token_encoding)) 508 | 509 | #define STREAM_END_TOKEN_INIT(token,start_mark,end_mark) \ 510 | (TOKEN_INIT((token),YAML_STREAM_END_TOKEN,(start_mark),(end_mark))) 511 | 512 | #define ALIAS_TOKEN_INIT(token,token_value,start_mark,end_mark) \ 513 | (TOKEN_INIT((token),YAML_ALIAS_TOKEN,(start_mark),(end_mark)), \ 514 | (token).data.alias.value = (token_value)) 515 | 516 | #define ANCHOR_TOKEN_INIT(token,token_value,start_mark,end_mark) \ 517 | (TOKEN_INIT((token),YAML_ANCHOR_TOKEN,(start_mark),(end_mark)), \ 518 | (token).data.anchor.value = (token_value)) 519 | 520 | #define TAG_TOKEN_INIT(token,token_handle,token_suffix,start_mark,end_mark) \ 521 | (TOKEN_INIT((token),YAML_TAG_TOKEN,(start_mark),(end_mark)), \ 522 | (token).data.tag.handle = (token_handle), \ 523 | (token).data.tag.suffix = (token_suffix)) 524 | 525 | #define SCALAR_TOKEN_INIT(token,token_value,token_length,token_style,start_mark,end_mark) \ 526 | (TOKEN_INIT((token),YAML_SCALAR_TOKEN,(start_mark),(end_mark)), \ 527 | (token).data.scalar.value = (token_value), \ 528 | (token).data.scalar.length = (token_length), \ 529 | (token).data.scalar.style = (token_style)) 530 | 531 | #define VERSION_DIRECTIVE_TOKEN_INIT(token,token_major,token_minor,start_mark,end_mark) \ 532 | (TOKEN_INIT((token),YAML_VERSION_DIRECTIVE_TOKEN,(start_mark),(end_mark)), \ 533 | (token).data.version_directive.major = (token_major), \ 534 | (token).data.version_directive.minor = (token_minor)) 535 | 536 | #define TAG_DIRECTIVE_TOKEN_INIT(token,token_handle,token_prefix,start_mark,end_mark) \ 537 | (TOKEN_INIT((token),YAML_TAG_DIRECTIVE_TOKEN,(start_mark),(end_mark)), \ 538 | (token).data.tag_directive.handle = (token_handle), \ 539 | (token).data.tag_directive.prefix = (token_prefix)) 540 | 541 | /* 542 | * Event initializers. 543 | */ 544 | 545 | #define EVENT_INIT(event,event_type,event_start_mark,event_end_mark) \ 546 | (memset(&(event), 0, sizeof(yaml_event_t)), \ 547 | (event).type = (event_type), \ 548 | (event).start_mark = (event_start_mark), \ 549 | (event).end_mark = (event_end_mark)) 550 | 551 | #define STREAM_START_EVENT_INIT(event,event_encoding,start_mark,end_mark) \ 552 | (EVENT_INIT((event),YAML_STREAM_START_EVENT,(start_mark),(end_mark)), \ 553 | (event).data.stream_start.encoding = (event_encoding)) 554 | 555 | #define STREAM_END_EVENT_INIT(event,start_mark,end_mark) \ 556 | (EVENT_INIT((event),YAML_STREAM_END_EVENT,(start_mark),(end_mark))) 557 | 558 | #define DOCUMENT_START_EVENT_INIT(event,event_version_directive, \ 559 | event_tag_directives_start,event_tag_directives_end,event_implicit,start_mark,end_mark) \ 560 | (EVENT_INIT((event),YAML_DOCUMENT_START_EVENT,(start_mark),(end_mark)), \ 561 | (event).data.document_start.version_directive = (event_version_directive), \ 562 | (event).data.document_start.tag_directives.start = (event_tag_directives_start), \ 563 | (event).data.document_start.tag_directives.end = (event_tag_directives_end), \ 564 | (event).data.document_start.implicit = (event_implicit)) 565 | 566 | #define DOCUMENT_END_EVENT_INIT(event,event_implicit,start_mark,end_mark) \ 567 | (EVENT_INIT((event),YAML_DOCUMENT_END_EVENT,(start_mark),(end_mark)), \ 568 | (event).data.document_end.implicit = (event_implicit)) 569 | 570 | #define ALIAS_EVENT_INIT(event,event_anchor,start_mark,end_mark) \ 571 | (EVENT_INIT((event),YAML_ALIAS_EVENT,(start_mark),(end_mark)), \ 572 | (event).data.alias.anchor = (event_anchor)) 573 | 574 | #define SCALAR_EVENT_INIT(event,event_anchor,event_tag,event_value,event_length, \ 575 | event_plain_implicit, event_quoted_implicit,event_style,start_mark,end_mark) \ 576 | (EVENT_INIT((event),YAML_SCALAR_EVENT,(start_mark),(end_mark)), \ 577 | (event).data.scalar.anchor = (event_anchor), \ 578 | (event).data.scalar.tag = (event_tag), \ 579 | (event).data.scalar.value = (event_value), \ 580 | (event).data.scalar.length = (event_length), \ 581 | (event).data.scalar.plain_implicit = (event_plain_implicit), \ 582 | (event).data.scalar.quoted_implicit = (event_quoted_implicit), \ 583 | (event).data.scalar.style = (event_style)) 584 | 585 | #define SEQUENCE_START_EVENT_INIT(event,event_anchor,event_tag, \ 586 | event_implicit,event_style,start_mark,end_mark) \ 587 | (EVENT_INIT((event),YAML_SEQUENCE_START_EVENT,(start_mark),(end_mark)), \ 588 | (event).data.sequence_start.anchor = (event_anchor), \ 589 | (event).data.sequence_start.tag = (event_tag), \ 590 | (event).data.sequence_start.implicit = (event_implicit), \ 591 | (event).data.sequence_start.style = (event_style)) 592 | 593 | #define SEQUENCE_END_EVENT_INIT(event,start_mark,end_mark) \ 594 | (EVENT_INIT((event),YAML_SEQUENCE_END_EVENT,(start_mark),(end_mark))) 595 | 596 | #define MAPPING_START_EVENT_INIT(event,event_anchor,event_tag, \ 597 | event_implicit,event_style,start_mark,end_mark) \ 598 | (EVENT_INIT((event),YAML_MAPPING_START_EVENT,(start_mark),(end_mark)), \ 599 | (event).data.mapping_start.anchor = (event_anchor), \ 600 | (event).data.mapping_start.tag = (event_tag), \ 601 | (event).data.mapping_start.implicit = (event_implicit), \ 602 | (event).data.mapping_start.style = (event_style)) 603 | 604 | #define MAPPING_END_EVENT_INIT(event,start_mark,end_mark) \ 605 | (EVENT_INIT((event),YAML_MAPPING_END_EVENT,(start_mark),(end_mark))) 606 | 607 | /* 608 | * Document initializer. 609 | */ 610 | 611 | #define DOCUMENT_INIT(document,document_nodes_start,document_nodes_end, \ 612 | document_version_directive,document_tag_directives_start, \ 613 | document_tag_directives_end,document_start_implicit, \ 614 | document_end_implicit,document_start_mark,document_end_mark) \ 615 | (memset(&(document), 0, sizeof(yaml_document_t)), \ 616 | (document).nodes.start = (document_nodes_start), \ 617 | (document).nodes.end = (document_nodes_end), \ 618 | (document).nodes.top = (document_nodes_start), \ 619 | (document).version_directive = (document_version_directive), \ 620 | (document).tag_directives.start = (document_tag_directives_start), \ 621 | (document).tag_directives.end = (document_tag_directives_end), \ 622 | (document).start_implicit = (document_start_implicit), \ 623 | (document).end_implicit = (document_end_implicit), \ 624 | (document).start_mark = (document_start_mark), \ 625 | (document).end_mark = (document_end_mark)) 626 | 627 | /* 628 | * Node initializers. 629 | */ 630 | 631 | #define NODE_INIT(node,node_type,node_tag,node_start_mark,node_end_mark) \ 632 | (memset(&(node), 0, sizeof(yaml_node_t)), \ 633 | (node).type = (node_type), \ 634 | (node).tag = (node_tag), \ 635 | (node).start_mark = (node_start_mark), \ 636 | (node).end_mark = (node_end_mark)) 637 | 638 | #define SCALAR_NODE_INIT(node,node_tag,node_value,node_length, \ 639 | node_style,start_mark,end_mark) \ 640 | (NODE_INIT((node),YAML_SCALAR_NODE,(node_tag),(start_mark),(end_mark)), \ 641 | (node).data.scalar.value = (node_value), \ 642 | (node).data.scalar.length = (node_length), \ 643 | (node).data.scalar.style = (node_style)) 644 | 645 | #define SEQUENCE_NODE_INIT(node,node_tag,node_items_start,node_items_end, \ 646 | node_style,start_mark,end_mark) \ 647 | (NODE_INIT((node),YAML_SEQUENCE_NODE,(node_tag),(start_mark),(end_mark)), \ 648 | (node).data.sequence.items.start = (node_items_start), \ 649 | (node).data.sequence.items.end = (node_items_end), \ 650 | (node).data.sequence.items.top = (node_items_start), \ 651 | (node).data.sequence.style = (node_style)) 652 | 653 | #define MAPPING_NODE_INIT(node,node_tag,node_pairs_start,node_pairs_end, \ 654 | node_style,start_mark,end_mark) \ 655 | (NODE_INIT((node),YAML_MAPPING_NODE,(node_tag),(start_mark),(end_mark)), \ 656 | (node).data.mapping.pairs.start = (node_pairs_start), \ 657 | (node).data.mapping.pairs.end = (node_pairs_end), \ 658 | (node).data.mapping.pairs.top = (node_pairs_start), \ 659 | (node).data.mapping.style = (node_style)) 660 | 661 | /* Strict C compiler warning helpers */ 662 | 663 | #if defined(__clang__) || defined(__GNUC__) 664 | # define HASATTRIBUTE_UNUSED 665 | #endif 666 | #ifdef HASATTRIBUTE_UNUSED 667 | # define __attribute__unused__ __attribute__((__unused__)) 668 | #else 669 | # define __attribute__unused__ 670 | #endif 671 | 672 | /* Shim arguments are arguments that must be included in your function, 673 | * but serve no purpose inside. Silence compiler warnings. */ 674 | #define SHIM(a) /*@unused@*/ a __attribute__unused__ 675 | 676 | /* UNUSED_PARAM() marks a shim argument in the body to silence compiler warnings */ 677 | #ifdef __clang__ 678 | # define UNUSED_PARAM(a) (void)(a); 679 | #else 680 | # define UNUSED_PARAM(a) /*@-noeffect*/if (0) (void)(a)/*@=noeffect*/; 681 | #endif 682 | 683 | #define YAML_MALLOC_STATIC(type) (type*)yaml_malloc(sizeof(type)) 684 | #define YAML_MALLOC(size) (yaml_char_t *)yaml_malloc(size) 685 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | function(add_yaml_executable name) 3 | add_executable(${name} ${name}.c) 4 | target_link_libraries(${name} yaml) 5 | endfunction() 6 | 7 | foreach(name IN ITEMS 8 | example-deconstructor 9 | example-deconstructor-alt 10 | example-reformatter 11 | example-reformatter-alt 12 | run-dumper 13 | run-emitter 14 | run-emitter-test-suite 15 | run-loader 16 | run-parser 17 | run-parser-test-suite 18 | run-scanner 19 | test-reader 20 | test-version 21 | ) 22 | add_yaml_executable(${name}) 23 | endforeach() 24 | 25 | add_test(NAME version COMMAND test-version) 26 | add_test(NAME reader COMMAND test-reader) 27 | 28 | -------------------------------------------------------------------------------- /tests/Makefile.am: -------------------------------------------------------------------------------- 1 | AM_CPPFLAGS = -I$(top_srcdir)/include -Wall 2 | #AM_CFLAGS = -Wno-pointer-sign 3 | LDADD = $(top_builddir)/src/libyaml.la 4 | TESTS = test-version test-reader 5 | check_PROGRAMS = test-version test-reader 6 | noinst_PROGRAMS = run-scanner run-parser run-loader run-emitter run-dumper \ 7 | example-reformatter example-reformatter-alt \ 8 | example-deconstructor example-deconstructor-alt \ 9 | run-parser-test-suite run-emitter-test-suite 10 | -------------------------------------------------------------------------------- /tests/ReadMe.md: -------------------------------------------------------------------------------- 1 | # Testing the Parser and Emitter 2 | 3 | There are several programs to test the parser and emitter. 4 | 5 | ## Parser 6 | 7 | echo 'foo: bar' | ./tests/run-parser-test-suite 8 | 9 | This will output the parsing events in yaml-test-suite format: 10 | 11 | +STR 12 | +DOC 13 | +MAP 14 | =VAL :foo 15 | =VAL :bar 16 | -MAP 17 | -DOC 18 | -STR 19 | 20 | For flow style events, you have to enable it with the `--flow` option: 21 | 22 | echo '{ foo: bar }' | ./tests/run-parser-test-suite --flow keep 23 | 24 | ... 25 | +MAP {} 26 | ... 27 | 28 | In the future, this will be the default. 29 | 30 | You can also explicitly disable this style with `--flow off`, or output 31 | flow style always, with `--flow on`. 32 | 33 | ## Emitter 34 | 35 | run-emitter-test-suite takes yaml-test-suite event format and emits YAML. 36 | 37 | ./tests/run-parser-test-suite ... | ./tests/run-emitter-test-suite 38 | 39 | ## Options 40 | 41 | * `--directive (1.1|1.2)` 42 | 43 | Prints a version directive before every document. 44 | 45 | * `--flow on` 46 | 47 | Will emit the whole document in flow style. 48 | 49 | * `--flow off` 50 | 51 | Will emit the whole document in block style. 52 | 53 | * `--flow keep` 54 | 55 | Will emit block/flow style like in the original document. 56 | 57 | Example: 58 | ``` 59 | % echo 'foo: [bar, {x: y}]' | 60 | ./tests/run-parser-test-suite --flow keep | 61 | ./tests/run-emitter-test-suite --flow keep 62 | foo: [bar, {x: y}] 63 | ``` 64 | -------------------------------------------------------------------------------- /tests/example-reformatter-alt.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | #include 5 | #include 6 | 7 | int 8 | main(int argc, char *argv[]) 9 | { 10 | int help = 0; 11 | int canonical = 0; 12 | int unicode = 0; 13 | int k; 14 | int done = 0; 15 | 16 | yaml_parser_t parser; 17 | yaml_emitter_t emitter; 18 | yaml_document_t document; 19 | 20 | /* Clear the objects. */ 21 | 22 | memset(&parser, 0, sizeof(parser)); 23 | memset(&emitter, 0, sizeof(emitter)); 24 | memset(&document, 0, sizeof(document)); 25 | 26 | /* Analyze command line options. */ 27 | 28 | for (k = 1; k < argc; k ++) 29 | { 30 | if (strcmp(argv[k], "-h") == 0 31 | || strcmp(argv[k], "--help") == 0) { 32 | help = 1; 33 | } 34 | 35 | else if (strcmp(argv[k], "-c") == 0 36 | || strcmp(argv[k], "--canonical") == 0) { 37 | canonical = 1; 38 | } 39 | 40 | else if (strcmp(argv[k], "-u") == 0 41 | || strcmp(argv[k], "--unicode") == 0) { 42 | unicode = 1; 43 | } 44 | 45 | else { 46 | fprintf(stderr, "Unrecognized option: %s\n" 47 | "Try `%s --help` for more information.\n", 48 | argv[k], argv[0]); 49 | return 1; 50 | } 51 | } 52 | 53 | /* Display the help string. */ 54 | 55 | if (help) 56 | { 57 | printf("%s [--canonical] [--unicode] output\n" 58 | "or\n%s -h | --help\nReformat a YAML stream\n\nOptions:\n" 59 | "-h, --help\t\tdisplay this help and exit\n" 60 | "-c, --canonical\t\toutput in the canonical YAML format\n" 61 | "-u, --unicode\t\toutput unescaped non-ASCII characters\n", 62 | argv[0], argv[0]); 63 | return 0; 64 | } 65 | 66 | /* Initialize the parser and emitter objects. */ 67 | 68 | if (!yaml_parser_initialize(&parser)) 69 | goto parser_error; 70 | 71 | if (!yaml_emitter_initialize(&emitter)) 72 | goto emitter_error; 73 | 74 | /* Set the parser parameters. */ 75 | 76 | yaml_parser_set_input_file(&parser, stdin); 77 | 78 | /* Set the emitter parameters. */ 79 | 80 | yaml_emitter_set_output_file(&emitter, stdout); 81 | 82 | yaml_emitter_set_canonical(&emitter, canonical); 83 | yaml_emitter_set_unicode(&emitter, unicode); 84 | 85 | /* The main loop. */ 86 | 87 | while (!done) 88 | { 89 | /* Get the next event. */ 90 | 91 | if (!yaml_parser_load(&parser, &document)) 92 | goto parser_error; 93 | 94 | /* Check if this is the stream end. */ 95 | 96 | if (!yaml_document_get_root_node(&document)) { 97 | done = 1; 98 | } 99 | 100 | /* Emit the event. */ 101 | 102 | if (!yaml_emitter_dump(&emitter, &document)) 103 | goto emitter_error; 104 | } 105 | 106 | yaml_parser_delete(&parser); 107 | yaml_emitter_delete(&emitter); 108 | 109 | return 0; 110 | 111 | parser_error: 112 | 113 | /* Display a parser error message. */ 114 | 115 | switch (parser.error) 116 | { 117 | case YAML_MEMORY_ERROR: 118 | fprintf(stderr, "Memory error: Not enough memory for parsing\n"); 119 | break; 120 | 121 | case YAML_READER_ERROR: 122 | if (parser.problem_value != -1) { 123 | fprintf(stderr, "Reader error: %s: #%X at %zd\n", parser.problem, 124 | parser.problem_value, parser.problem_offset); 125 | } 126 | else { 127 | fprintf(stderr, "Reader error: %s at %lu\n", parser.problem, 128 | parser.problem_offset); 129 | } 130 | break; 131 | 132 | case YAML_SCANNER_ERROR: 133 | if (parser.context) { 134 | fprintf(stderr, "Scanner error: %s at line %lu, column %lu\n" 135 | "%s at line %lu, column %lu\n", parser.context, 136 | parser.context_mark.line+1, parser.context_mark.column+1, 137 | parser.problem, parser.problem_mark.line+1, 138 | parser.problem_mark.column+1); 139 | } 140 | else { 141 | fprintf(stderr, "Scanner error: %s at line %lu, column %lu\n", 142 | parser.problem, parser.problem_mark.line+1, 143 | parser.problem_mark.column+1); 144 | } 145 | break; 146 | 147 | case YAML_PARSER_ERROR: 148 | if (parser.context) { 149 | fprintf(stderr, "Parser error: %s at line %lu, column %lu\n" 150 | "%s at line %lu, column %lu\n", parser.context, 151 | parser.context_mark.line+1, parser.context_mark.column+1, 152 | parser.problem, parser.problem_mark.line+1, 153 | parser.problem_mark.column+1); 154 | } 155 | else { 156 | fprintf(stderr, "Parser error: %s at line %lu, column %lu\n", 157 | parser.problem, parser.problem_mark.line+1, 158 | parser.problem_mark.column+1); 159 | } 160 | break; 161 | 162 | case YAML_COMPOSER_ERROR: 163 | if (parser.context) { 164 | fprintf(stderr, "Composer error: %s at line %lu, column %lu\n" 165 | "%s at line %lu, column %lu\n", parser.context, 166 | parser.context_mark.line+1, parser.context_mark.column+1, 167 | parser.problem, parser.problem_mark.line+1, 168 | parser.problem_mark.column+1); 169 | } 170 | else { 171 | fprintf(stderr, "Composer error: %s at line %lu, column %lu\n", 172 | parser.problem, parser.problem_mark.line+1, 173 | parser.problem_mark.column+1); 174 | } 175 | break; 176 | 177 | default: 178 | /* Couldn't happen. */ 179 | fprintf(stderr, "Internal error\n"); 180 | break; 181 | } 182 | 183 | yaml_parser_delete(&parser); 184 | yaml_emitter_delete(&emitter); 185 | 186 | return 1; 187 | 188 | emitter_error: 189 | 190 | /* Display an emitter error message. */ 191 | 192 | switch (emitter.error) 193 | { 194 | case YAML_MEMORY_ERROR: 195 | fprintf(stderr, "Memory error: Not enough memory for emitting\n"); 196 | break; 197 | 198 | case YAML_WRITER_ERROR: 199 | fprintf(stderr, "Writer error: %s\n", emitter.problem); 200 | break; 201 | 202 | case YAML_EMITTER_ERROR: 203 | fprintf(stderr, "Emitter error: %s\n", emitter.problem); 204 | break; 205 | 206 | default: 207 | /* Couldn't happen. */ 208 | fprintf(stderr, "Internal error\n"); 209 | break; 210 | } 211 | 212 | yaml_parser_delete(&parser); 213 | yaml_emitter_delete(&emitter); 214 | 215 | return 1; 216 | } 217 | 218 | -------------------------------------------------------------------------------- /tests/example-reformatter.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | #include 5 | #include 6 | 7 | int 8 | main(int argc, char *argv[]) 9 | { 10 | int help = 0; 11 | int canonical = 0; 12 | int unicode = 0; 13 | int k; 14 | int done = 0; 15 | 16 | yaml_parser_t parser; 17 | yaml_emitter_t emitter; 18 | yaml_event_t event; 19 | 20 | /* Clear the objects. */ 21 | 22 | memset(&parser, 0, sizeof(parser)); 23 | memset(&emitter, 0, sizeof(emitter)); 24 | memset(&event, 0, sizeof(event)); 25 | 26 | /* Analyze command line options. */ 27 | 28 | for (k = 1; k < argc; k ++) 29 | { 30 | if (strcmp(argv[k], "-h") == 0 31 | || strcmp(argv[k], "--help") == 0) { 32 | help = 1; 33 | } 34 | 35 | else if (strcmp(argv[k], "-c") == 0 36 | || strcmp(argv[k], "--canonical") == 0) { 37 | canonical = 1; 38 | } 39 | 40 | else if (strcmp(argv[k], "-u") == 0 41 | || strcmp(argv[k], "--unicode") == 0) { 42 | unicode = 1; 43 | } 44 | 45 | else { 46 | fprintf(stderr, "Unrecognized option: %s\n" 47 | "Try `%s --help` for more information.\n", 48 | argv[k], argv[0]); 49 | return 1; 50 | } 51 | } 52 | 53 | /* Display the help string. */ 54 | 55 | if (help) 56 | { 57 | printf("%s [--canonical] [--unicode] output\n" 58 | "or\n%s -h | --help\nReformat a YAML stream\n\nOptions:\n" 59 | "-h, --help\t\tdisplay this help and exit\n" 60 | "-c, --canonical\t\toutput in the canonical YAML format\n" 61 | "-u, --unicode\t\toutput unescaped non-ASCII characters\n", 62 | argv[0], argv[0]); 63 | return 0; 64 | } 65 | 66 | /* Initialize the parser and emitter objects. */ 67 | 68 | if (!yaml_parser_initialize(&parser)) 69 | goto parser_error; 70 | 71 | if (!yaml_emitter_initialize(&emitter)) 72 | goto emitter_error; 73 | 74 | /* Set the parser parameters. */ 75 | 76 | yaml_parser_set_input_file(&parser, stdin); 77 | 78 | /* Set the emitter parameters. */ 79 | 80 | yaml_emitter_set_output_file(&emitter, stdout); 81 | 82 | yaml_emitter_set_canonical(&emitter, canonical); 83 | yaml_emitter_set_unicode(&emitter, unicode); 84 | 85 | /* The main loop. */ 86 | 87 | while (!done) 88 | { 89 | /* Get the next event. */ 90 | 91 | if (!yaml_parser_parse(&parser, &event)) 92 | goto parser_error; 93 | 94 | /* Check if this is the stream end. */ 95 | 96 | if (event.type == YAML_STREAM_END_EVENT) { 97 | done = 1; 98 | } 99 | 100 | /* Emit the event. */ 101 | 102 | if (!yaml_emitter_emit(&emitter, &event)) 103 | goto emitter_error; 104 | } 105 | 106 | yaml_parser_delete(&parser); 107 | yaml_emitter_delete(&emitter); 108 | 109 | return 0; 110 | 111 | parser_error: 112 | 113 | /* Display a parser error message. */ 114 | 115 | switch (parser.error) 116 | { 117 | case YAML_MEMORY_ERROR: 118 | fprintf(stderr, "Memory error: Not enough memory for parsing\n"); 119 | break; 120 | 121 | case YAML_READER_ERROR: 122 | if (parser.problem_value != -1) { 123 | fprintf(stderr, "Reader error: %s: #%X at %ld\n", parser.problem, 124 | parser.problem_value, (long)parser.problem_offset); 125 | } 126 | else { 127 | fprintf(stderr, "Reader error: %s at %ld\n", parser.problem, 128 | (long)parser.problem_offset); 129 | } 130 | break; 131 | 132 | case YAML_SCANNER_ERROR: 133 | if (parser.context) { 134 | fprintf(stderr, "Scanner error: %s at line %d, column %d\n" 135 | "%s at line %d, column %d\n", parser.context, 136 | (int)parser.context_mark.line+1, (int)parser.context_mark.column+1, 137 | parser.problem, (int)parser.problem_mark.line+1, 138 | (int)parser.problem_mark.column+1); 139 | } 140 | else { 141 | fprintf(stderr, "Scanner error: %s at line %d, column %d\n", 142 | parser.problem, (int)parser.problem_mark.line+1, 143 | (int)parser.problem_mark.column+1); 144 | } 145 | break; 146 | 147 | case YAML_PARSER_ERROR: 148 | if (parser.context) { 149 | fprintf(stderr, "Parser error: %s at line %d, column %d\n" 150 | "%s at line %d, column %d\n", parser.context, 151 | (int)parser.context_mark.line+1, (int)parser.context_mark.column+1, 152 | parser.problem, (int)parser.problem_mark.line+1, 153 | (int)parser.problem_mark.column+1); 154 | } 155 | else { 156 | fprintf(stderr, "Parser error: %s at line %d, column %d\n", 157 | parser.problem, (int)parser.problem_mark.line+1, 158 | (int)parser.problem_mark.column+1); 159 | } 160 | break; 161 | 162 | default: 163 | /* Couldn't happen. */ 164 | fprintf(stderr, "Internal error\n"); 165 | break; 166 | } 167 | 168 | yaml_parser_delete(&parser); 169 | yaml_emitter_delete(&emitter); 170 | 171 | return 1; 172 | 173 | emitter_error: 174 | 175 | /* Display an emitter error message. */ 176 | 177 | switch (emitter.error) 178 | { 179 | case YAML_MEMORY_ERROR: 180 | fprintf(stderr, "Memory error: Not enough memory for emitting\n"); 181 | break; 182 | 183 | case YAML_WRITER_ERROR: 184 | fprintf(stderr, "Writer error: %s\n", emitter.problem); 185 | break; 186 | 187 | case YAML_EMITTER_ERROR: 188 | fprintf(stderr, "Emitter error: %s\n", emitter.problem); 189 | break; 190 | 191 | default: 192 | /* Couldn't happen. */ 193 | fprintf(stderr, "Internal error\n"); 194 | break; 195 | } 196 | 197 | yaml_parser_delete(&parser); 198 | yaml_emitter_delete(&emitter); 199 | 200 | return 1; 201 | } 202 | 203 | -------------------------------------------------------------------------------- /tests/run-all-tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | main() { 6 | # Autoconf based in-source build and tests 7 | clean 8 | 9 | ./bootstrap 10 | ./configure 11 | make test-all 12 | 13 | # CMake based in-source build and tests 14 | clean 15 | 16 | cmake . 17 | make 18 | make test 19 | 20 | clean 21 | } 22 | 23 | clean() { 24 | git clean -d -x -f 25 | rm -fr tests/run-test-suite 26 | git worktree prune 27 | } 28 | 29 | main "$@" 30 | -------------------------------------------------------------------------------- /tests/run-dumper.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #ifdef NDEBUG 8 | #undef NDEBUG 9 | #endif 10 | #include 11 | 12 | #define BUFFER_SIZE 65536 13 | #define MAX_DOCUMENTS 16 14 | 15 | int copy_document(yaml_document_t *document_to, yaml_document_t *document_from) 16 | { 17 | yaml_node_t *node; 18 | yaml_node_item_t *item; 19 | yaml_node_pair_t *pair; 20 | 21 | if (!yaml_document_initialize(document_to, document_from->version_directive, 22 | document_from->tag_directives.start, 23 | document_from->tag_directives.end, 24 | document_from->start_implicit, document_from->end_implicit)) 25 | return 0; 26 | 27 | for (node = document_from->nodes.start; 28 | node < document_from->nodes.top; node ++) { 29 | switch (node->type) { 30 | case YAML_SCALAR_NODE: 31 | if (!yaml_document_add_scalar(document_to, node->tag, 32 | node->data.scalar.value, node->data.scalar.length, 33 | node->data.scalar.style)) goto error; 34 | break; 35 | case YAML_SEQUENCE_NODE: 36 | if (!yaml_document_add_sequence(document_to, node->tag, 37 | node->data.sequence.style)) goto error; 38 | break; 39 | case YAML_MAPPING_NODE: 40 | if (!yaml_document_add_mapping(document_to, node->tag, 41 | node->data.mapping.style)) goto error; 42 | break; 43 | default: 44 | assert(0); 45 | break; 46 | } 47 | } 48 | 49 | for (node = document_from->nodes.start; 50 | node < document_from->nodes.top; node ++) { 51 | switch (node->type) { 52 | case YAML_SEQUENCE_NODE: 53 | for (item = node->data.sequence.items.start; 54 | item < node->data.sequence.items.top; item ++) { 55 | if (!yaml_document_append_sequence_item(document_to, 56 | node - document_from->nodes.start + 1, 57 | *item)) goto error; 58 | } 59 | break; 60 | case YAML_MAPPING_NODE: 61 | for (pair = node->data.mapping.pairs.start; 62 | pair < node->data.mapping.pairs.top; pair ++) { 63 | if (!yaml_document_append_mapping_pair(document_to, 64 | node - document_from->nodes.start + 1, 65 | pair->key, pair->value)) goto error; 66 | } 67 | break; 68 | default: 69 | break; 70 | } 71 | } 72 | return 1; 73 | 74 | error: 75 | yaml_document_delete(document_to); 76 | return 0; 77 | } 78 | 79 | int compare_nodes(yaml_document_t *document1, int index1, 80 | yaml_document_t *document2, int index2, int level) 81 | { 82 | int k; 83 | yaml_node_t *node1; 84 | yaml_node_t *node2; 85 | if (level++ > 1000) return 0; 86 | node1 = yaml_document_get_node(document1, index1); 87 | node2 = yaml_document_get_node(document2, index2); 88 | 89 | assert(node1); 90 | assert(node2); 91 | 92 | if (node1->type != node2->type) 93 | return 0; 94 | 95 | if (strcmp((char *)node1->tag, (char *)node2->tag) != 0) return 0; 96 | 97 | switch (node1->type) { 98 | case YAML_SCALAR_NODE: 99 | if (node1->data.scalar.length != node2->data.scalar.length) 100 | return 0; 101 | if (strncmp((char *)node1->data.scalar.value, (char *)node2->data.scalar.value, 102 | node1->data.scalar.length) != 0) return 0; 103 | break; 104 | case YAML_SEQUENCE_NODE: 105 | if ((node1->data.sequence.items.top - node1->data.sequence.items.start) != 106 | (node2->data.sequence.items.top - node2->data.sequence.items.start)) 107 | return 0; 108 | for (k = 0; k < (node1->data.sequence.items.top - node1->data.sequence.items.start); k ++) { 109 | if (!compare_nodes(document1, node1->data.sequence.items.start[k], 110 | document2, node2->data.sequence.items.start[k], level)) return 0; 111 | } 112 | break; 113 | case YAML_MAPPING_NODE: 114 | if ((node1->data.mapping.pairs.top - node1->data.mapping.pairs.start) != 115 | (node2->data.mapping.pairs.top - node2->data.mapping.pairs.start)) 116 | return 0; 117 | for (k = 0; k < (node1->data.mapping.pairs.top - node1->data.mapping.pairs.start); k ++) { 118 | if (!compare_nodes(document1, node1->data.mapping.pairs.start[k].key, 119 | document2, node2->data.mapping.pairs.start[k].key, level)) return 0; 120 | if (!compare_nodes(document1, node1->data.mapping.pairs.start[k].value, 121 | document2, node2->data.mapping.pairs.start[k].value, level)) return 0; 122 | } 123 | break; 124 | default: 125 | assert(0); 126 | break; 127 | } 128 | return 1; 129 | } 130 | 131 | int compare_documents(yaml_document_t *document1, yaml_document_t *document2) 132 | { 133 | int k; 134 | 135 | if ((document1->version_directive && !document2->version_directive) 136 | || (!document1->version_directive && document2->version_directive) 137 | || (document1->version_directive && document2->version_directive 138 | && (document1->version_directive->major != document2->version_directive->major 139 | || document1->version_directive->minor != document2->version_directive->minor))) 140 | return 0; 141 | 142 | if ((document1->tag_directives.end - document1->tag_directives.start) != 143 | (document2->tag_directives.end - document2->tag_directives.start)) 144 | return 0; 145 | for (k = 0; k < (document1->tag_directives.end - document1->tag_directives.start); k ++) { 146 | if ((strcmp((char *)document1->tag_directives.start[k].handle, 147 | (char *)document2->tag_directives.start[k].handle) != 0) 148 | || (strcmp((char *)document1->tag_directives.start[k].prefix, 149 | (char *)document2->tag_directives.start[k].prefix) != 0)) 150 | return 0; 151 | } 152 | 153 | if ((document1->nodes.top - document1->nodes.start) != 154 | (document2->nodes.top - document2->nodes.start)) 155 | return 0; 156 | 157 | if (document1->nodes.top != document1->nodes.start) { 158 | if (!compare_nodes(document1, 1, document2, 1, 0)) 159 | return 0; 160 | } 161 | 162 | return 1; 163 | } 164 | 165 | int print_output(char *name, unsigned char *buffer, size_t size, int count) 166 | { 167 | FILE *file; 168 | char data[BUFFER_SIZE]; 169 | size_t data_size = 1; 170 | size_t total_size = 0; 171 | if (count >= 0) { 172 | printf("FAILED (at the document #%d)\nSOURCE:\n", count+1); 173 | } 174 | file = fopen(name, "rb"); 175 | assert(file); 176 | while (data_size > 0) { 177 | data_size = fread(data, 1, BUFFER_SIZE, file); 178 | assert(!ferror(file)); 179 | if (!data_size) break; 180 | assert(fwrite(data, 1, data_size, stdout) == data_size); 181 | total_size += data_size; 182 | if (feof(file)) break; 183 | } 184 | fclose(file); 185 | printf("#### (length: %ld)\n", (long)total_size); 186 | printf("OUTPUT:\n%s#### (length: %ld)\n", buffer, (long)size); 187 | return 0; 188 | } 189 | 190 | int 191 | main(int argc, char *argv[]) 192 | { 193 | int number; 194 | int canonical = 0; 195 | int unicode = 0; 196 | 197 | number = 1; 198 | while (number < argc) { 199 | if (strcmp(argv[number], "-c") == 0) { 200 | canonical = 1; 201 | } 202 | else if (strcmp(argv[number], "-u") == 0) { 203 | unicode = 1; 204 | } 205 | else if (argv[number][0] == '-') { 206 | printf("Unknown option: '%s'\n", argv[number]); 207 | return 0; 208 | } 209 | if (argv[number][0] == '-') { 210 | if (number < argc-1) { 211 | memmove(argv+number, argv+number+1, (argc-number-1)*sizeof(char *)); 212 | } 213 | argc --; 214 | } 215 | else { 216 | number ++; 217 | } 218 | } 219 | 220 | if (argc < 2) { 221 | printf("Usage: %s [-c] [-u] file1.yaml ...\n", argv[0]); 222 | return 0; 223 | } 224 | 225 | for (number = 1; number < argc; number ++) 226 | { 227 | FILE *file; 228 | yaml_parser_t parser; 229 | yaml_emitter_t emitter; 230 | 231 | yaml_document_t document; 232 | unsigned char buffer[BUFFER_SIZE+1]; 233 | size_t written = 0; 234 | yaml_document_t documents[MAX_DOCUMENTS]; 235 | size_t document_number = 0; 236 | int done = 0; 237 | int count = 0; 238 | int error = 0; 239 | int k; 240 | memset(buffer, 0, BUFFER_SIZE+1); 241 | memset(documents, 0, MAX_DOCUMENTS*sizeof(yaml_document_t)); 242 | 243 | printf("[%d] Loading, dumping, and loading again '%s': ", number, argv[number]); 244 | fflush(stdout); 245 | 246 | file = fopen(argv[number], "rb"); 247 | assert(file); 248 | 249 | assert(yaml_parser_initialize(&parser)); 250 | yaml_parser_set_input_file(&parser, file); 251 | assert(yaml_emitter_initialize(&emitter)); 252 | if (canonical) { 253 | yaml_emitter_set_canonical(&emitter, 1); 254 | } 255 | if (unicode) { 256 | yaml_emitter_set_unicode(&emitter, 1); 257 | } 258 | yaml_emitter_set_output_string(&emitter, buffer, BUFFER_SIZE, &written); 259 | yaml_emitter_open(&emitter); 260 | 261 | while (!done) 262 | { 263 | if (!yaml_parser_load(&parser, &document)) { 264 | error = 1; 265 | break; 266 | } 267 | 268 | done = (!yaml_document_get_root_node(&document)); 269 | if (!done) { 270 | assert(document_number < MAX_DOCUMENTS); 271 | assert(copy_document(&(documents[document_number++]), &document)); 272 | assert(yaml_emitter_dump(&emitter, &document) || 273 | (yaml_emitter_flush(&emitter) && print_output(argv[number], buffer, written, count))); 274 | count ++; 275 | } 276 | else { 277 | yaml_document_delete(&document); 278 | } 279 | } 280 | 281 | yaml_parser_delete(&parser); 282 | assert(!fclose(file)); 283 | yaml_emitter_close(&emitter); 284 | yaml_emitter_delete(&emitter); 285 | 286 | if (!error) 287 | { 288 | count = done = 0; 289 | assert(yaml_parser_initialize(&parser)); 290 | yaml_parser_set_input_string(&parser, buffer, written); 291 | 292 | while (!done) 293 | { 294 | assert(yaml_parser_load(&parser, &document) || print_output(argv[number], buffer, written, count)); 295 | done = (!yaml_document_get_root_node(&document)); 296 | if (!done) { 297 | assert(compare_documents(documents+count, &document) || print_output(argv[number], buffer, written, count)); 298 | count ++; 299 | } 300 | yaml_document_delete(&document); 301 | } 302 | yaml_parser_delete(&parser); 303 | } 304 | 305 | for (k = 0; k < document_number; k ++) { 306 | yaml_document_delete(documents+k); 307 | } 308 | 309 | printf("PASSED (length: %ld)\n", (long)written); 310 | print_output(argv[number], buffer, written, -1); 311 | } 312 | 313 | return 0; 314 | } 315 | -------------------------------------------------------------------------------- /tests/run-emitter-test-suite.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include "../src/yaml_private.h" 7 | 8 | int get_line(FILE * input, char *line); 9 | char *get_anchor(char sigil, char *line, char *anchor); 10 | char *get_tag(char *line, char *tag); 11 | void get_value(char *line, char *value, int *style); 12 | int usage(int ret); 13 | 14 | int main(int argc, char *argv[]) 15 | { 16 | FILE *input; 17 | yaml_emitter_t emitter; 18 | yaml_event_t event; 19 | yaml_version_directive_t *version_directive = NULL; 20 | 21 | int canonical = 0; 22 | int unicode = 0; 23 | char line[1024]; 24 | int foundfile = 0; 25 | int i = 0; 26 | int minor = 0; 27 | int flow = -1; /** default no flow style collections */ 28 | 29 | for (i = 1; i < argc; i++) { 30 | if (strncmp(argv[i], "--help", 6) == 0) 31 | return usage(0); 32 | if (strncmp(argv[i], "-h", 2) == 0) 33 | return usage(0); 34 | if (strncmp(argv[i], "--flow", 6) == 0) { 35 | if (i+1 == argc) 36 | return usage(1); 37 | i++; 38 | if (strncmp(argv[i], "keep", 4) == 0) 39 | flow = 0; 40 | else if (strncmp(argv[i], "on", 2) == 0) 41 | flow = 1; 42 | else if (strncmp(argv[i], "off", 3) == 0) 43 | flow = -1; 44 | else 45 | return usage(1); 46 | } 47 | else if (strncmp(argv[i], "--directive", 11) == 0) { 48 | if (i+1 == argc) 49 | return usage(1); 50 | i++; 51 | if (strncmp(argv[i], "1.1", 3) == 0) 52 | minor = 1; 53 | else if (strncmp(argv[i], "1.2", 3) == 0) 54 | minor = 2; 55 | else 56 | return usage(1); 57 | } 58 | else if (!foundfile) { 59 | input = fopen(argv[i], "rb"); 60 | foundfile = 1; 61 | } 62 | 63 | } 64 | if (minor) { 65 | version_directive = YAML_MALLOC_STATIC(yaml_version_directive_t); 66 | version_directive->major = 1; 67 | version_directive->minor = minor; 68 | } 69 | if (!foundfile) 70 | input = stdin; 71 | 72 | assert(input); 73 | 74 | if (!yaml_emitter_initialize(&emitter)) { 75 | fprintf(stderr, "Could not initialize the emitter object\n"); 76 | return 1; 77 | } 78 | yaml_emitter_set_output_file(&emitter, stdout); 79 | yaml_emitter_set_canonical(&emitter, canonical); 80 | yaml_emitter_set_unicode(&emitter, unicode); 81 | 82 | 83 | while (get_line(input, line)) { 84 | int ok; 85 | char anchor[256]; 86 | char tag[256]; 87 | int implicit; 88 | int style; 89 | 90 | if (strncmp(line, "+STR", 4) == 0) { 91 | ok = yaml_stream_start_event_initialize(&event, YAML_UTF8_ENCODING); 92 | } 93 | else if (strncmp(line, "-STR", 4) == 0) { 94 | ok = yaml_stream_end_event_initialize(&event); 95 | } 96 | else if (strncmp(line, "+DOC", 4) == 0) { 97 | implicit = strncmp(line+4, " ---", 4) != 0; 98 | ok = yaml_document_start_event_initialize(&event, version_directive, NULL, NULL, implicit); 99 | } 100 | else if (strncmp(line, "-DOC", 4) == 0) { 101 | implicit = strncmp(line+4, " ...", 4) != 0; 102 | ok = yaml_document_end_event_initialize(&event, implicit); 103 | } 104 | else if (strncmp(line, "+MAP", 4) == 0) { 105 | style = YAML_BLOCK_MAPPING_STYLE; 106 | if (flow == 1) 107 | style = YAML_FLOW_MAPPING_STYLE; 108 | else if (flow == 0 && strncmp(line+5, "{}", 2) == 0) 109 | style = YAML_FLOW_MAPPING_STYLE; 110 | ok = yaml_mapping_start_event_initialize(&event, (yaml_char_t *) 111 | get_anchor('&', line, anchor), (yaml_char_t *) 112 | get_tag(line, tag), 0, style); 113 | } 114 | else if (strncmp(line, "-MAP", 4) == 0) { 115 | ok = yaml_mapping_end_event_initialize(&event); 116 | } 117 | else if (strncmp(line, "+SEQ", 4) == 0) { 118 | style = YAML_BLOCK_SEQUENCE_STYLE; 119 | if (flow == 1) 120 | style = YAML_FLOW_MAPPING_STYLE; 121 | else if (flow == 0 && strncmp(line+5, "[]", 2) == 0) 122 | style = YAML_FLOW_SEQUENCE_STYLE; 123 | ok = yaml_sequence_start_event_initialize(&event, (yaml_char_t *) 124 | get_anchor('&', line, anchor), (yaml_char_t *) 125 | get_tag(line, tag), 0, style); 126 | } 127 | else if (strncmp(line, "-SEQ", 4) == 0) { 128 | ok = yaml_sequence_end_event_initialize(&event); 129 | } 130 | else if (strncmp(line, "=VAL", 4) == 0) { 131 | char value[1024]; 132 | int style; 133 | 134 | get_value(line, value, &style); 135 | implicit = (get_tag(line, tag) == NULL); 136 | 137 | ok = yaml_scalar_event_initialize(&event, (yaml_char_t *) 138 | get_anchor('&', line, anchor), (yaml_char_t *) get_tag(line, tag), (yaml_char_t *) value, -1, implicit, implicit, style); 139 | } 140 | else if (strncmp(line, "=ALI", 4) == 0) { 141 | ok = yaml_alias_event_initialize(&event, (yaml_char_t *) 142 | get_anchor('*', line, anchor) 143 | ); 144 | } 145 | else { 146 | fprintf(stderr, "Unknown event: '%s'\n", line); 147 | fflush(stdout); 148 | return 1; 149 | } 150 | 151 | if (!ok) 152 | goto event_error; 153 | if (!yaml_emitter_emit(&emitter, &event)) 154 | goto emitter_error; 155 | } 156 | 157 | assert(!fclose(input)); 158 | yaml_emitter_delete(&emitter); 159 | fflush(stdout); 160 | 161 | return 0; 162 | 163 | emitter_error: 164 | switch (emitter.error) { 165 | case YAML_MEMORY_ERROR: 166 | fprintf(stderr, "Memory error: Not enough memory for emitting\n"); 167 | break; 168 | case YAML_WRITER_ERROR: 169 | fprintf(stderr, "Writer error: %s\n", emitter.problem); 170 | break; 171 | case YAML_EMITTER_ERROR: 172 | fprintf(stderr, "Emitter error: %s\n", emitter.problem); 173 | break; 174 | default: 175 | /* 176 | * Couldn't happen. 177 | */ 178 | fprintf(stderr, "Internal error\n"); 179 | break; 180 | } 181 | yaml_emitter_delete(&emitter); 182 | return 1; 183 | 184 | event_error: 185 | fprintf(stderr, "Memory error: Not enough memory for creating an event\n"); 186 | yaml_emitter_delete(&emitter); 187 | return 1; 188 | } 189 | 190 | int get_line(FILE * input, char *line) 191 | { 192 | char *newline; 193 | 194 | if (!fgets(line, 1024 - 1, input)) 195 | return 0; 196 | 197 | if ((newline = strchr(line, '\n')) == NULL) { 198 | fprintf(stderr, "Line too long: '%s'", line); 199 | abort(); 200 | } 201 | *newline = '\0'; 202 | 203 | return 1; 204 | } 205 | 206 | char *get_anchor(char sigil, char *line, char *anchor) 207 | { 208 | char *start; 209 | char *end; 210 | if ((start = strchr(line, sigil)) == NULL) 211 | return NULL; 212 | start++; 213 | if ((end = strchr(start, ' ')) == NULL) 214 | end = line + strlen(line); 215 | memcpy(anchor, start, end - start); 216 | anchor[end - start] = '\0'; 217 | return anchor; 218 | } 219 | 220 | char *get_tag(char *line, char *tag) 221 | { 222 | char *start; 223 | char *end; 224 | if ((start = strchr(line, '<')) == NULL) 225 | return NULL; 226 | if ((end = strchr(line, '>')) == NULL) 227 | return NULL; 228 | memcpy(tag, start + 1, end - start - 1); 229 | tag[end - start - 1] = '\0'; 230 | return tag; 231 | } 232 | 233 | void get_value(char *line, char *value, int *style) 234 | { 235 | int i = 0; 236 | char *c; 237 | char *start = NULL; 238 | char *end = line + strlen(line); 239 | 240 | for (c = line + 4; c < end; c++) { 241 | if (*c == ' ') { 242 | start = c + 1; 243 | if (*start == ':') 244 | *style = YAML_PLAIN_SCALAR_STYLE; 245 | else if (*start == '\'') 246 | *style = YAML_SINGLE_QUOTED_SCALAR_STYLE; 247 | else if (*start == '"') 248 | *style = YAML_DOUBLE_QUOTED_SCALAR_STYLE; 249 | else if (*start == '|') 250 | *style = YAML_LITERAL_SCALAR_STYLE; 251 | else if (*start == '>') 252 | *style = YAML_FOLDED_SCALAR_STYLE; 253 | else { 254 | start = NULL; 255 | continue; 256 | } 257 | start++; 258 | break; 259 | } 260 | } 261 | if (!start) 262 | abort(); 263 | 264 | for (c = start; c < end; c++) { 265 | if (*c == '\\') { 266 | if (*++c == '\\') 267 | value[i++] = '\\'; 268 | else if (*c == '0') 269 | value[i++] = '\0'; 270 | else if (*c == 'b') 271 | value[i++] = '\b'; 272 | else if (*c == 'n') 273 | value[i++] = '\n'; 274 | else if (*c == 'r') 275 | value[i++] = '\r'; 276 | else if (*c == 't') 277 | value[i++] = '\t'; 278 | else 279 | abort(); 280 | } 281 | else 282 | value[i++] = *c; 283 | } 284 | value[i] = '\0'; 285 | } 286 | 287 | int usage(int ret) { 288 | fprintf(stderr, "Usage: run-emitter-test-suite [--directive (1.1|1.2)] [--flow (on|off|keep)] []\n"); 289 | return ret; 290 | } 291 | -------------------------------------------------------------------------------- /tests/run-emitter.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #ifdef NDEBUG 8 | #undef NDEBUG 9 | #endif 10 | #include 11 | 12 | #define BUFFER_SIZE 65536 13 | #define MAX_EVENTS 1024 14 | 15 | int copy_event(yaml_event_t *event_to, yaml_event_t *event_from) 16 | { 17 | switch (event_from->type) 18 | { 19 | case YAML_STREAM_START_EVENT: 20 | return yaml_stream_start_event_initialize(event_to, 21 | event_from->data.stream_start.encoding); 22 | 23 | case YAML_STREAM_END_EVENT: 24 | return yaml_stream_end_event_initialize(event_to); 25 | 26 | case YAML_DOCUMENT_START_EVENT: 27 | return yaml_document_start_event_initialize(event_to, 28 | event_from->data.document_start.version_directive, 29 | event_from->data.document_start.tag_directives.start, 30 | event_from->data.document_start.tag_directives.end, 31 | event_from->data.document_start.implicit); 32 | 33 | case YAML_DOCUMENT_END_EVENT: 34 | return yaml_document_end_event_initialize(event_to, 35 | event_from->data.document_end.implicit); 36 | 37 | case YAML_ALIAS_EVENT: 38 | return yaml_alias_event_initialize(event_to, 39 | event_from->data.alias.anchor); 40 | 41 | case YAML_SCALAR_EVENT: 42 | return yaml_scalar_event_initialize(event_to, 43 | event_from->data.scalar.anchor, 44 | event_from->data.scalar.tag, 45 | event_from->data.scalar.value, 46 | event_from->data.scalar.length, 47 | event_from->data.scalar.plain_implicit, 48 | event_from->data.scalar.quoted_implicit, 49 | event_from->data.scalar.style); 50 | 51 | case YAML_SEQUENCE_START_EVENT: 52 | return yaml_sequence_start_event_initialize(event_to, 53 | event_from->data.sequence_start.anchor, 54 | event_from->data.sequence_start.tag, 55 | event_from->data.sequence_start.implicit, 56 | event_from->data.sequence_start.style); 57 | 58 | case YAML_SEQUENCE_END_EVENT: 59 | return yaml_sequence_end_event_initialize(event_to); 60 | 61 | case YAML_MAPPING_START_EVENT: 62 | return yaml_mapping_start_event_initialize(event_to, 63 | event_from->data.mapping_start.anchor, 64 | event_from->data.mapping_start.tag, 65 | event_from->data.mapping_start.implicit, 66 | event_from->data.mapping_start.style); 67 | 68 | case YAML_MAPPING_END_EVENT: 69 | return yaml_mapping_end_event_initialize(event_to); 70 | 71 | default: 72 | assert(1); 73 | } 74 | 75 | return 0; 76 | } 77 | 78 | int compare_events(yaml_event_t *event1, yaml_event_t *event2) 79 | { 80 | int k; 81 | 82 | if (event1->type != event2->type) 83 | return 0; 84 | 85 | switch (event1->type) 86 | { 87 | case YAML_STREAM_START_EVENT: 88 | return 1; 89 | /* return (event1->data.stream_start.encoding == 90 | event2->data.stream_start.encoding); */ 91 | 92 | case YAML_DOCUMENT_START_EVENT: 93 | if ((event1->data.document_start.version_directive && !event2->data.document_start.version_directive) 94 | || (!event1->data.document_start.version_directive && event2->data.document_start.version_directive) 95 | || (event1->data.document_start.version_directive && event2->data.document_start.version_directive 96 | && (event1->data.document_start.version_directive->major != event2->data.document_start.version_directive->major 97 | || event1->data.document_start.version_directive->minor != event2->data.document_start.version_directive->minor))) 98 | return 0; 99 | if ((event1->data.document_start.tag_directives.end - event1->data.document_start.tag_directives.start) != 100 | (event2->data.document_start.tag_directives.end - event2->data.document_start.tag_directives.start)) 101 | return 0; 102 | for (k = 0; k < (event1->data.document_start.tag_directives.end - event1->data.document_start.tag_directives.start); k ++) { 103 | if ((strcmp((char *)event1->data.document_start.tag_directives.start[k].handle, 104 | (char *)event2->data.document_start.tag_directives.start[k].handle) != 0) 105 | || (strcmp((char *)event1->data.document_start.tag_directives.start[k].prefix, 106 | (char *)event2->data.document_start.tag_directives.start[k].prefix) != 0)) 107 | return 0; 108 | } 109 | /* if (event1->data.document_start.implicit != event2->data.document_start.implicit) 110 | return 0; */ 111 | return 1; 112 | 113 | case YAML_DOCUMENT_END_EVENT: 114 | return 1; 115 | /* return (event1->data.document_end.implicit == 116 | event2->data.document_end.implicit); */ 117 | 118 | case YAML_ALIAS_EVENT: 119 | return (strcmp((char *)event1->data.alias.anchor, 120 | (char *)event2->data.alias.anchor) == 0); 121 | 122 | case YAML_SCALAR_EVENT: 123 | if ((event1->data.scalar.anchor && !event2->data.scalar.anchor) 124 | || (!event1->data.scalar.anchor && event2->data.scalar.anchor) 125 | || (event1->data.scalar.anchor && event2->data.scalar.anchor 126 | && strcmp((char *)event1->data.scalar.anchor, 127 | (char *)event2->data.scalar.anchor) != 0)) 128 | return 0; 129 | if ((event1->data.scalar.tag && !event2->data.scalar.tag 130 | && strcmp((char *)event1->data.scalar.tag, "!") != 0) 131 | || (!event1->data.scalar.tag && event2->data.scalar.tag 132 | && strcmp((char *)event2->data.scalar.tag, "!") != 0) 133 | || (event1->data.scalar.tag && event2->data.scalar.tag 134 | && strcmp((char *)event1->data.scalar.tag, 135 | (char *)event2->data.scalar.tag) != 0)) 136 | return 0; 137 | if ((event1->data.scalar.length != event2->data.scalar.length) 138 | || memcmp(event1->data.scalar.value, event2->data.scalar.value, 139 | event1->data.scalar.length) != 0) 140 | return 0; 141 | if ((event1->data.scalar.plain_implicit != event2->data.scalar.plain_implicit) 142 | || (event1->data.scalar.quoted_implicit != event2->data.scalar.quoted_implicit) 143 | /* || (event2->data.scalar.style != event2->data.scalar.style) */) 144 | return 0; 145 | return 1; 146 | 147 | case YAML_SEQUENCE_START_EVENT: 148 | if ((event1->data.sequence_start.anchor && !event2->data.sequence_start.anchor) 149 | || (!event1->data.sequence_start.anchor && event2->data.sequence_start.anchor) 150 | || (event1->data.sequence_start.anchor && event2->data.sequence_start.anchor 151 | && strcmp((char *)event1->data.sequence_start.anchor, 152 | (char *)event2->data.sequence_start.anchor) != 0)) 153 | return 0; 154 | if ((event1->data.sequence_start.tag && !event2->data.sequence_start.tag) 155 | || (!event1->data.sequence_start.tag && event2->data.sequence_start.tag) 156 | || (event1->data.sequence_start.tag && event2->data.sequence_start.tag 157 | && strcmp((char *)event1->data.sequence_start.tag, 158 | (char *)event2->data.sequence_start.tag) != 0)) 159 | return 0; 160 | if ((event1->data.sequence_start.implicit != event2->data.sequence_start.implicit) 161 | /* || (event2->data.sequence_start.style != event2->data.sequence_start.style) */) 162 | return 0; 163 | return 1; 164 | 165 | case YAML_MAPPING_START_EVENT: 166 | if ((event1->data.mapping_start.anchor && !event2->data.mapping_start.anchor) 167 | || (!event1->data.mapping_start.anchor && event2->data.mapping_start.anchor) 168 | || (event1->data.mapping_start.anchor && event2->data.mapping_start.anchor 169 | && strcmp((char *)event1->data.mapping_start.anchor, 170 | (char *)event2->data.mapping_start.anchor) != 0)) 171 | return 0; 172 | if ((event1->data.mapping_start.tag && !event2->data.mapping_start.tag) 173 | || (!event1->data.mapping_start.tag && event2->data.mapping_start.tag) 174 | || (event1->data.mapping_start.tag && event2->data.mapping_start.tag 175 | && strcmp((char *)event1->data.mapping_start.tag, 176 | (char *)event2->data.mapping_start.tag) != 0)) 177 | return 0; 178 | if ((event1->data.mapping_start.implicit != event2->data.mapping_start.implicit) 179 | /* || (event2->data.mapping_start.style != event2->data.mapping_start.style) */) 180 | return 0; 181 | return 1; 182 | 183 | default: 184 | return 1; 185 | } 186 | } 187 | 188 | int print_output(char *name, unsigned char *buffer, size_t size, int count) 189 | { 190 | FILE *file; 191 | char data[BUFFER_SIZE]; 192 | size_t data_size = 1; 193 | size_t total_size = 0; 194 | if (count >= 0) { 195 | printf("FAILED (at the event #%d)\nSOURCE:\n", count+1); 196 | } 197 | file = fopen(name, "rb"); 198 | assert(file); 199 | while (data_size > 0) { 200 | data_size = fread(data, 1, BUFFER_SIZE, file); 201 | assert(!ferror(file)); 202 | if (!data_size) break; 203 | assert(fwrite(data, 1, data_size, stdout) == data_size); 204 | total_size += data_size; 205 | if (feof(file)) break; 206 | } 207 | fclose(file); 208 | printf("#### (length: %ld)\n", (long)total_size); 209 | printf("OUTPUT:\n%s#### (length: %ld)\n", buffer, (long)size); 210 | return 0; 211 | } 212 | 213 | int 214 | main(int argc, char *argv[]) 215 | { 216 | int number; 217 | int canonical = 0; 218 | int unicode = 0; 219 | 220 | number = 1; 221 | while (number < argc) { 222 | if (strcmp(argv[number], "-c") == 0) { 223 | canonical = 1; 224 | } 225 | else if (strcmp(argv[number], "-u") == 0) { 226 | unicode = 1; 227 | } 228 | else if (argv[number][0] == '-') { 229 | printf("Unknown option: '%s'\n", argv[number]); 230 | return 0; 231 | } 232 | if (argv[number][0] == '-') { 233 | if (number < argc-1) { 234 | memmove(argv+number, argv+number+1, (argc-number-1)*sizeof(char *)); 235 | } 236 | argc --; 237 | } 238 | else { 239 | number ++; 240 | } 241 | } 242 | 243 | if (argc < 2) { 244 | printf("Usage: %s [-c] [-u] file1.yaml ...\n", argv[0]); 245 | return 0; 246 | } 247 | 248 | for (number = 1; number < argc; number ++) 249 | { 250 | FILE *file; 251 | yaml_parser_t parser; 252 | yaml_emitter_t emitter; 253 | yaml_event_t event; 254 | unsigned char buffer[BUFFER_SIZE+1]; 255 | size_t written = 0; 256 | yaml_event_t events[MAX_EVENTS]; 257 | size_t event_number = 0; 258 | int done = 0; 259 | int count = 0; 260 | int error = 0; 261 | int k; 262 | memset(buffer, 0, BUFFER_SIZE+1); 263 | memset(events, 0, MAX_EVENTS*sizeof(yaml_event_t)); 264 | 265 | printf("[%d] Parsing, emitting, and parsing again '%s': ", number, argv[number]); 266 | fflush(stdout); 267 | 268 | file = fopen(argv[number], "rb"); 269 | assert(file); 270 | 271 | assert(yaml_parser_initialize(&parser)); 272 | yaml_parser_set_input_file(&parser, file); 273 | assert(yaml_emitter_initialize(&emitter)); 274 | if (canonical) { 275 | yaml_emitter_set_canonical(&emitter, 1); 276 | } 277 | if (unicode) { 278 | yaml_emitter_set_unicode(&emitter, 1); 279 | } 280 | yaml_emitter_set_output_string(&emitter, buffer, BUFFER_SIZE, &written); 281 | 282 | while (!done) 283 | { 284 | if (!yaml_parser_parse(&parser, &event)) { 285 | error = 1; 286 | break; 287 | } 288 | 289 | done = (event.type == YAML_STREAM_END_EVENT); 290 | assert(event_number < MAX_EVENTS); 291 | assert(copy_event(&(events[event_number++]), &event)); 292 | assert(yaml_emitter_emit(&emitter, &event) || 293 | print_output(argv[number], buffer, written, count)); 294 | count ++; 295 | } 296 | 297 | yaml_parser_delete(&parser); 298 | assert(!fclose(file)); 299 | yaml_emitter_delete(&emitter); 300 | 301 | if (!error) 302 | { 303 | count = done = 0; 304 | assert(yaml_parser_initialize(&parser)); 305 | yaml_parser_set_input_string(&parser, buffer, written); 306 | 307 | while (!done) 308 | { 309 | assert(yaml_parser_parse(&parser, &event) || print_output(argv[number], buffer, written, count)); 310 | done = (event.type == YAML_STREAM_END_EVENT); 311 | assert(compare_events(events+count, &event) || print_output(argv[number], buffer, written, count)); 312 | yaml_event_delete(&event); 313 | count ++; 314 | } 315 | yaml_parser_delete(&parser); 316 | } 317 | 318 | for (k = 0; k < event_number; k ++) { 319 | yaml_event_delete(events+k); 320 | } 321 | 322 | printf("PASSED (length: %ld)\n", (long)written); 323 | print_output(argv[number], buffer, written, -1); 324 | } 325 | 326 | return 0; 327 | } 328 | -------------------------------------------------------------------------------- /tests/run-loader.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | #ifdef NDEBUG 7 | #undef NDEBUG 8 | #endif 9 | #include 10 | 11 | int 12 | main(int argc, char *argv[]) 13 | { 14 | int number; 15 | 16 | if (argc < 2) { 17 | printf("Usage: %s file1.yaml ...\n", argv[0]); 18 | return 0; 19 | } 20 | 21 | for (number = 1; number < argc; number ++) 22 | { 23 | FILE *file; 24 | yaml_parser_t parser; 25 | yaml_document_t document; 26 | int done = 0; 27 | int count = 0; 28 | int error = 0; 29 | 30 | printf("[%d] Loading '%s': ", number, argv[number]); 31 | fflush(stdout); 32 | 33 | file = fopen(argv[number], "rb"); 34 | assert(file); 35 | 36 | assert(yaml_parser_initialize(&parser)); 37 | 38 | yaml_parser_set_input_file(&parser, file); 39 | 40 | while (!done) 41 | { 42 | if (!yaml_parser_load(&parser, &document)) { 43 | error = 1; 44 | break; 45 | } 46 | 47 | done = (!yaml_document_get_root_node(&document)); 48 | 49 | yaml_document_delete(&document); 50 | 51 | if (!done) count ++; 52 | } 53 | 54 | yaml_parser_delete(&parser); 55 | 56 | assert(!fclose(file)); 57 | 58 | printf("%s (%d documents)\n", (error ? "FAILURE" : "SUCCESS"), count); 59 | } 60 | 61 | return 0; 62 | } 63 | 64 | -------------------------------------------------------------------------------- /tests/run-parser-test-suite.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | void print_escaped(yaml_char_t * str, size_t length); 7 | int usage(int ret); 8 | 9 | int main(int argc, char *argv[]) 10 | { 11 | FILE *input; 12 | yaml_parser_t parser; 13 | yaml_event_t event; 14 | int flow = -1; /** default no flow style collections */ 15 | int i = 0; 16 | int foundfile = 0; 17 | int max_level; 18 | char *output; 19 | 20 | for (i = 1; i < argc; i++) { 21 | if (strncmp(argv[i], "--max-level", 11) == 0) { 22 | i++; 23 | max_level = strtol(argv[i], &output, 10); 24 | yaml_set_max_nest_level(max_level); 25 | } 26 | else if (strncmp(argv[i], "--flow", 6) == 0) { 27 | if (i+1 == argc) 28 | return usage(1); 29 | i++; 30 | if (strncmp(argv[i], "keep", 4) == 0) 31 | flow = 0; 32 | else if (strncmp(argv[i], "on", 2) == 0) 33 | flow = 1; 34 | else if (strncmp(argv[i], "off", 3) == 0) 35 | flow = -1; 36 | else 37 | return usage(1); 38 | } 39 | else if (strncmp(argv[i], "--help", 6) == 0) 40 | return usage(0); 41 | else if (strncmp(argv[i], "-h", 2) == 0) 42 | return usage(0); 43 | else if (!foundfile) { 44 | input = fopen(argv[i], "rb"); 45 | foundfile = 1; 46 | } 47 | else 48 | return usage(1); 49 | } 50 | if (!foundfile) { 51 | input = stdin; 52 | } 53 | assert(input); 54 | 55 | if (!yaml_parser_initialize(&parser)) { 56 | fprintf(stderr, "Could not initialize the parser object\n"); 57 | return 1; 58 | } 59 | yaml_parser_set_input_file(&parser, input); 60 | 61 | while (1) { 62 | yaml_event_type_t type; 63 | if (!yaml_parser_parse(&parser, &event)) { 64 | if ( parser.problem_mark.line || parser.problem_mark.column ) { 65 | fprintf(stderr, "Parse error: %s\nLine: %lu Column: %lu\n", 66 | parser.problem, 67 | (unsigned long)parser.problem_mark.line + 1, 68 | (unsigned long)parser.problem_mark.column + 1); 69 | } 70 | else { 71 | fprintf(stderr, "Parse error: %s\n", parser.problem); 72 | } 73 | return 1; 74 | } 75 | type = event.type; 76 | 77 | if (type == YAML_NO_EVENT) 78 | printf("???\n"); 79 | else if (type == YAML_STREAM_START_EVENT) 80 | printf("+STR\n"); 81 | else if (type == YAML_STREAM_END_EVENT) 82 | printf("-STR\n"); 83 | else if (type == YAML_DOCUMENT_START_EVENT) { 84 | printf("+DOC"); 85 | if (!event.data.document_start.implicit) 86 | printf(" ---"); 87 | printf("\n"); 88 | } 89 | else if (type == YAML_DOCUMENT_END_EVENT) { 90 | printf("-DOC"); 91 | if (!event.data.document_end.implicit) 92 | printf(" ..."); 93 | printf("\n"); 94 | } 95 | else if (type == YAML_MAPPING_START_EVENT) { 96 | printf("+MAP"); 97 | if (flow == 0 && event.data.mapping_start.style == YAML_FLOW_MAPPING_STYLE) 98 | printf(" {}"); 99 | else if (flow == 1) 100 | printf(" {}"); 101 | if (event.data.mapping_start.anchor) 102 | printf(" &%s", event.data.mapping_start.anchor); 103 | if (event.data.mapping_start.tag) 104 | printf(" <%s>", event.data.mapping_start.tag); 105 | printf("\n"); 106 | } 107 | else if (type == YAML_MAPPING_END_EVENT) 108 | printf("-MAP\n"); 109 | else if (type == YAML_SEQUENCE_START_EVENT) { 110 | printf("+SEQ"); 111 | if (flow == 0 && event.data.sequence_start.style == YAML_FLOW_SEQUENCE_STYLE) 112 | printf(" []"); 113 | else if (flow == 1) 114 | printf(" []"); 115 | if (event.data.sequence_start.anchor) 116 | printf(" &%s", event.data.sequence_start.anchor); 117 | if (event.data.sequence_start.tag) 118 | printf(" <%s>", event.data.sequence_start.tag); 119 | printf("\n"); 120 | } 121 | else if (type == YAML_SEQUENCE_END_EVENT) 122 | printf("-SEQ\n"); 123 | else if (type == YAML_SCALAR_EVENT) { 124 | printf("=VAL"); 125 | if (event.data.scalar.anchor) 126 | printf(" &%s", event.data.scalar.anchor); 127 | if (event.data.scalar.tag) 128 | printf(" <%s>", event.data.scalar.tag); 129 | switch (event.data.scalar.style) { 130 | case YAML_PLAIN_SCALAR_STYLE: 131 | printf(" :"); 132 | break; 133 | case YAML_SINGLE_QUOTED_SCALAR_STYLE: 134 | printf(" '"); 135 | break; 136 | case YAML_DOUBLE_QUOTED_SCALAR_STYLE: 137 | printf(" \""); 138 | break; 139 | case YAML_LITERAL_SCALAR_STYLE: 140 | printf(" |"); 141 | break; 142 | case YAML_FOLDED_SCALAR_STYLE: 143 | printf(" >"); 144 | break; 145 | case YAML_ANY_SCALAR_STYLE: 146 | abort(); 147 | } 148 | print_escaped(event.data.scalar.value, event.data.scalar.length); 149 | printf("\n"); 150 | } 151 | else if (type == YAML_ALIAS_EVENT) 152 | printf("=ALI *%s\n", event.data.alias.anchor); 153 | else 154 | abort(); 155 | 156 | yaml_event_delete(&event); 157 | 158 | if (type == YAML_STREAM_END_EVENT) 159 | break; 160 | } 161 | 162 | assert(!fclose(input)); 163 | yaml_parser_delete(&parser); 164 | fflush(stdout); 165 | 166 | return 0; 167 | } 168 | 169 | void print_escaped(yaml_char_t * str, size_t length) 170 | { 171 | int i; 172 | char c; 173 | 174 | for (i = 0; i < length; i++) { 175 | c = *(str + i); 176 | if (c == '\\') 177 | printf("\\\\"); 178 | else if (c == '\0') 179 | printf("\\0"); 180 | else if (c == '\b') 181 | printf("\\b"); 182 | else if (c == '\n') 183 | printf("\\n"); 184 | else if (c == '\r') 185 | printf("\\r"); 186 | else if (c == '\t') 187 | printf("\\t"); 188 | else 189 | printf("%c", c); 190 | } 191 | } 192 | 193 | int usage(int ret) { 194 | fprintf(stderr, "Usage: libyaml-parser [--flow (on|off|keep)] []\n"); 195 | return ret; 196 | } 197 | -------------------------------------------------------------------------------- /tests/run-parser.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | #ifdef NDEBUG 7 | #undef NDEBUG 8 | #endif 9 | #include 10 | 11 | int 12 | main(int argc, char *argv[]) 13 | { 14 | int number; 15 | int start = 0; 16 | int i = 0; 17 | char *filename; 18 | char *output; 19 | int max_level; 20 | int show_error = 0; 21 | 22 | if (argc < 2) { 23 | printf("Usage: %s file1.yaml ...\n", argv[0]); 24 | return 0; 25 | } 26 | for (i = 1; i < argc; i++) { 27 | if (strncmp(argv[i], "--max-level", 11) == 0) { 28 | i++; 29 | max_level = strtol(argv[i], &output, 10); 30 | yaml_set_max_nest_level(max_level); 31 | start = i+1; 32 | } 33 | else if (strncmp(argv[i], "--show-error", 12) == 0) { 34 | show_error = 1; 35 | start = i+1; 36 | } 37 | } 38 | 39 | for (number = start; number < argc; number ++) 40 | { 41 | FILE *file; 42 | yaml_parser_t parser; 43 | yaml_event_t event; 44 | int done = 0; 45 | int count = 0; 46 | int error = 0; 47 | 48 | filename = argv[number]; 49 | printf("[%d] Parsing '%s': ", number, filename); 50 | fflush(stdout); 51 | 52 | file = fopen(filename, "rb"); 53 | assert(file); 54 | 55 | assert(yaml_parser_initialize(&parser)); 56 | 57 | yaml_parser_set_input_file(&parser, file); 58 | 59 | while (!done) 60 | { 61 | if (!yaml_parser_parse(&parser, &event)) { 62 | error = 1; 63 | if (show_error) { 64 | fprintf(stderr, "Parse error: %s\nLine: %lu Column: %lu\n", 65 | parser.problem, 66 | (unsigned long)parser.problem_mark.line + 1, 67 | (unsigned long)parser.problem_mark.column + 1); 68 | } 69 | break; 70 | } 71 | 72 | done = (event.type == YAML_STREAM_END_EVENT); 73 | 74 | yaml_event_delete(&event); 75 | 76 | count ++; 77 | } 78 | 79 | yaml_parser_delete(&parser); 80 | 81 | assert(!fclose(file)); 82 | 83 | printf("%s (%d events)\n", (error ? "FAILURE" : "SUCCESS"), count); 84 | } 85 | 86 | return 0; 87 | } 88 | 89 | -------------------------------------------------------------------------------- /tests/run-scanner.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | #ifdef NDEBUG 7 | #undef NDEBUG 8 | #endif 9 | #include 10 | 11 | int 12 | main(int argc, char *argv[]) 13 | { 14 | int number; 15 | 16 | if (argc < 2) { 17 | printf("Usage: %s file1.yaml ...\n", argv[0]); 18 | return 0; 19 | } 20 | 21 | for (number = 1; number < argc; number ++) 22 | { 23 | FILE *file; 24 | yaml_parser_t parser; 25 | yaml_token_t token; 26 | int done = 0; 27 | int count = 0; 28 | int error = 0; 29 | 30 | printf("[%d] Scanning '%s': ", number, argv[number]); 31 | fflush(stdout); 32 | 33 | file = fopen(argv[number], "rb"); 34 | assert(file); 35 | 36 | assert(yaml_parser_initialize(&parser)); 37 | 38 | yaml_parser_set_input_file(&parser, file); 39 | 40 | while (!done) 41 | { 42 | if (!yaml_parser_scan(&parser, &token)) { 43 | error = 1; 44 | break; 45 | } 46 | 47 | done = (token.type == YAML_STREAM_END_TOKEN); 48 | 49 | yaml_token_delete(&token); 50 | 51 | count ++; 52 | } 53 | 54 | yaml_parser_delete(&parser); 55 | 56 | assert(!fclose(file)); 57 | 58 | printf("%s (%d tokens)\n", (error ? "FAILURE" : "SUCCESS"), count); 59 | } 60 | 61 | return 0; 62 | } 63 | 64 | -------------------------------------------------------------------------------- /tests/test-reader.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | YAML_DECLARE(int) 4 | yaml_parser_update_buffer(yaml_parser_t *parser, size_t length); 5 | 6 | #include 7 | #include 8 | 9 | #ifdef NDEBUG 10 | #undef NDEBUG 11 | #endif 12 | #include 13 | 14 | /* 15 | * Test cases are stolen from 16 | * http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt 17 | */ 18 | 19 | typedef struct { 20 | char *title; 21 | char *test; 22 | int result; 23 | } test_case; 24 | 25 | test_case utf8_sequences[] = { 26 | /* {"title", "test 1|test 2|...|test N!", (0 or 1)}, */ 27 | 28 | {"a simple test", "'test' is '\xd0\xbf\xd1\x80\xd0\xbe\xd0\xb2\xd0\xb5\xd1\x80\xd0\xba\xd0\xb0' in Russian!", 1}, 29 | {"an empty line", "!", 1}, 30 | 31 | {"u-0 is a control character", "\x00!", 0}, 32 | {"u-80 is a control character", "\xc2\x80!", 0}, 33 | {"u-800 is valid", "\xe0\xa0\x80!", 1}, 34 | {"u-10000 is valid", "\xf0\x90\x80\x80!", 1}, 35 | {"5 bytes sequences are not allowed", "\xf8\x88\x80\x80\x80!", 0}, 36 | {"6 bytes sequences are not allowed", "\xfc\x84\x80\x80\x80\x80!", 0}, 37 | 38 | {"u-7f is a control character", "\x7f!", 0}, 39 | {"u-7FF is valid", "\xdf\xbf!", 1}, 40 | {"u-FFFF is a control character", "\xef\xbf\xbf!", 0}, 41 | {"u-1FFFFF is too large", "\xf7\xbf\xbf\xbf!", 0}, 42 | {"u-3FFFFFF is 5 bytes", "\xfb\xbf\xbf\xbf\xbf!", 0}, 43 | {"u-7FFFFFFF is 6 bytes", "\xfd\xbf\xbf\xbf\xbf\xbf!", 0}, 44 | 45 | {"u-D7FF", "\xed\x9f\xbf!", 1}, 46 | {"u-E000", "\xee\x80\x80!", 1}, 47 | {"u-FFFD", "\xef\xbf\xbd!", 1}, 48 | {"u-10FFFF", "\xf4\x8f\xbf\xbf!", 1}, 49 | {"u-110000", "\xf4\x90\x80\x80!", 0}, 50 | 51 | {"first continuation byte", "\x80!", 0}, 52 | {"last continuation byte", "\xbf!", 0}, 53 | 54 | {"2 continuation bytes", "\x80\xbf!", 0}, 55 | {"3 continuation bytes", "\x80\xbf\x80!", 0}, 56 | {"4 continuation bytes", "\x80\xbf\x80\xbf!", 0}, 57 | {"5 continuation bytes", "\x80\xbf\x80\xbf\x80!", 0}, 58 | {"6 continuation bytes", "\x80\xbf\x80\xbf\x80\xbf!", 0}, 59 | {"7 continuation bytes", "\x80\xbf\x80\xbf\x80\xbf\x80!", 0}, 60 | 61 | {"sequence of all 64 possible continuation bytes", 62 | "\x80|\x81|\x82|\x83|\x84|\x85|\x86|\x87|\x88|\x89|\x8a|\x8b|\x8c|\x8d|\x8e|\x8f|" 63 | "\x90|\x91|\x92|\x93|\x94|\x95|\x96|\x97|\x98|\x99|\x9a|\x9b|\x9c|\x9d|\x9e|\x9f|" 64 | "\xa0|\xa1|\xa2|\xa3|\xa4|\xa5|\xa6|\xa7|\xa8|\xa9|\xaa|\xab|\xac|\xad|\xae|\xaf|" 65 | "\xb0|\xb1|\xb2|\xb3|\xb4|\xb5|\xb6|\xb7|\xb8|\xb9|\xba|\xbb|\xbc|\xbd|\xbe|\xbf!", 0}, 66 | {"32 first bytes of 2-byte sequences {0xc0-0xdf}", 67 | "\xc0 |\xc1 |\xc2 |\xc3 |\xc4 |\xc5 |\xc6 |\xc7 |\xc8 |\xc9 |\xca |\xcb |\xcc |\xcd |\xce |\xcf |" 68 | "\xd0 |\xd1 |\xd2 |\xd3 |\xd4 |\xd5 |\xd6 |\xd7 |\xd8 |\xd9 |\xda |\xdb |\xdc |\xdd |\xde |\xdf !", 0}, 69 | {"16 first bytes of 3-byte sequences {0xe0-0xef}", 70 | "\xe0 |\xe1 |\xe2 |\xe3 |\xe4 |\xe5 |\xe6 |\xe7 |\xe8 |\xe9 |\xea |\xeb |\xec |\xed |\xee |\xef !", 0}, 71 | {"8 first bytes of 4-byte sequences {0xf0-0xf7}", "\xf0 |\xf1 |\xf2 |\xf3 |\xf4 |\xf5 |\xf6 |\xf7 !", 0}, 72 | {"4 first bytes of 5-byte sequences {0xf8-0xfb}", "\xf8 |\xf9 |\xfa |\xfb !", 0}, 73 | {"2 first bytes of 6-byte sequences {0xfc-0xfd}", "\xfc |\xfd !", 0}, 74 | 75 | {"sequences with last byte missing {u-0}", 76 | "\xc0|\xe0\x80|\xf0\x80\x80|\xf8\x80\x80\x80|\xfc\x80\x80\x80\x80!", 0}, 77 | {"sequences with last byte missing {u-...FF}", 78 | "\xdf|\xef\xbf|\xf7\xbf\xbf|\xfb\xbf\xbf\xbf|\xfd\xbf\xbf\xbf\xbf!", 0}, 79 | 80 | {"impossible bytes", "\xfe|\xff|\xfe\xfe\xff\xff!", 0}, 81 | 82 | {"overlong sequences {u-2f}", 83 | "\xc0\xaf|\xe0\x80\xaf|\xf0\x80\x80\xaf|\xf8\x80\x80\x80\xaf|\xfc\x80\x80\x80\x80\xaf!", 0}, 84 | 85 | {"maximum overlong sequences", 86 | "\xc1\xbf|\xe0\x9f\xbf|\xf0\x8f\xbf\xbf|\xf8\x87\xbf\xbf\xbf|\xfc\x83\xbf\xbf\xbf\xbf!", 0}, 87 | 88 | {"overlong representation of the NUL character", 89 | "\xc0\x80|\xe0\x80\x80|\xf0\x80\x80\x80|\xf8\x80\x80\x80\x80|\xfc\x80\x80\x80\x80\x80!", 0}, 90 | 91 | {"single UTF-16 surrogates", 92 | "\xed\xa0\x80|\xed\xad\xbf|\xed\xae\x80|\xed\xaf\xbf|\xed\xb0\x80|\xed\xbe\x80|\xed\xbf\xbf!", 0}, 93 | 94 | {"paired UTF-16 surrogates", 95 | "\xed\xa0\x80\xed\xb0\x80|\xed\xa0\x80\xed\xbf\xbf|\xed\xad\xbf\xed\xb0\x80|" 96 | "\xed\xad\xbf\xed\xbf\xbf|\xed\xae\x80\xed\xb0\x80|\xed\xae\x80\xed\xbf\xbf|" 97 | "\xed\xaf\xbf\xed\xb0\x80|\xed\xaf\xbf\xed\xbf\xbf!", 0}, 98 | 99 | {"other illegal code positions", "\xef\xbf\xbe|\xef\xbf\xbf!", 0}, 100 | 101 | {NULL, NULL, 0} 102 | }; 103 | 104 | test_case boms[] = { 105 | 106 | /* {"title", "test!", length}, */ 107 | 108 | {"no bom (utf-8)", "Hi is \xd0\x9f\xd1\x80\xd0\xb8\xd0\xb2\xd0\xb5\xd1\x82!", 13}, 109 | {"bom (utf-8)", "\xef\xbb\xbfHi is \xd0\x9f\xd1\x80\xd0\xb8\xd0\xb2\xd0\xb5\xd1\x82!", 13}, 110 | {"bom (utf-16-le)", "\xff\xfeH\x00i\x00 \x00i\x00s\x00 \x00\x1f\x04@\x04""8\x04""2\x04""5\x04""B\x04!", 13}, 111 | {"bom (utf-16-be)", "\xfe\xff\x00H\x00i\x00 \x00i\x00s\x00 \x04\x1f\x04@\x04""8\x04""2\x04""5\x04""B!", 13}, 112 | {NULL, NULL, 0} 113 | }; 114 | 115 | char *bom_original = "Hi is \xd0\x9f\xd1\x80\xd0\xb8\xd0\xb2\xd0\xb5\xd1\x82"; 116 | 117 | int check_utf8_sequences(void) 118 | { 119 | yaml_parser_t parser; 120 | int failed = 0; 121 | int k; 122 | printf("checking utf-8 sequences...\n"); 123 | for (k = 0; utf8_sequences[k].test; k++) { 124 | char *title = utf8_sequences[k].title; 125 | int check = utf8_sequences[k].result; 126 | int result; 127 | char *start = utf8_sequences[k].test; 128 | char *end = start; 129 | printf("\t%s:\n", title); 130 | while(1) { 131 | while (*end != '|' && *end != '!') end++; 132 | yaml_parser_initialize(&parser); 133 | yaml_parser_set_input_string(&parser, (unsigned char *)start, end-start); 134 | result = yaml_parser_update_buffer(&parser, end-start); 135 | if (result != check) { 136 | printf("\t\t- "); 137 | failed ++; 138 | } 139 | else { 140 | printf("\t\t+ "); 141 | } 142 | if (!parser.error) { 143 | printf("(no error)\n"); 144 | } 145 | else if (parser.error == YAML_READER_ERROR) { 146 | if (parser.problem_value != -1) { 147 | printf("(reader error: %s: #%X at %ld)\n", 148 | parser.problem, parser.problem_value, (long)parser.problem_offset); 149 | } 150 | else { 151 | printf("(reader error: %s at %ld)\n", 152 | parser.problem, (long)parser.problem_offset); 153 | } 154 | } 155 | if (*end == '!') break; 156 | start = ++end; 157 | yaml_parser_delete(&parser); 158 | }; 159 | printf("\n"); 160 | } 161 | printf("checking utf-8 sequences: %d fail(s)\n", failed); 162 | return failed; 163 | } 164 | 165 | int check_boms(void) 166 | { 167 | yaml_parser_t parser; 168 | int failed = 0; 169 | int k; 170 | printf("checking boms...\n"); 171 | for (k = 0; boms[k].test; k++) { 172 | char *title = boms[k].title; 173 | int check = boms[k].result; 174 | int result; 175 | char *start = boms[k].test; 176 | char *end = start; 177 | while (*end != '!') end++; 178 | printf("\t%s: ", title); 179 | yaml_parser_initialize(&parser); 180 | yaml_parser_set_input_string(&parser, (unsigned char *)start, end-start); 181 | result = yaml_parser_update_buffer(&parser, end-start); 182 | if (!result) { 183 | printf("- (reader error: %s at %ld)\n", parser.problem, (long)parser.problem_offset); 184 | failed++; 185 | } 186 | else { 187 | if (parser.unread != check) { 188 | printf("- (length=%ld while expected length=%d)\n", (long)parser.unread, check); 189 | failed++; 190 | } 191 | else if (memcmp(parser.buffer.start, bom_original, check) != 0) { 192 | printf("- (value '%s' does not equal to the original value '%s')\n", parser.buffer.start, bom_original); 193 | failed++; 194 | } 195 | else { 196 | printf("+\n"); 197 | } 198 | } 199 | yaml_parser_delete(&parser); 200 | } 201 | printf("checking boms: %d fail(s)\n", failed); 202 | return failed; 203 | } 204 | 205 | #define LONG 100000 206 | 207 | int check_long_utf8(void) 208 | { 209 | yaml_parser_t parser; 210 | int k = 0; 211 | int j; 212 | int failed = 0; 213 | unsigned char ch0, ch1; 214 | unsigned char *buffer = (unsigned char *)malloc(3+LONG*2); 215 | assert(buffer); 216 | printf("checking a long utf8 sequence...\n"); 217 | buffer[k++] = '\xef'; 218 | buffer[k++] = '\xbb'; 219 | buffer[k++] = '\xbf'; 220 | for (j = 0; j < LONG; j ++) { 221 | if (j % 2) { 222 | buffer[k++] = '\xd0'; 223 | buffer[k++] = '\x90'; 224 | } 225 | else { 226 | buffer[k++] = '\xd0'; 227 | buffer[k++] = '\xaf'; 228 | } 229 | } 230 | yaml_parser_initialize(&parser); 231 | yaml_parser_set_input_string(&parser, buffer, 3+LONG*2); 232 | for (k = 0; k < LONG; k++) { 233 | if (!parser.unread) { 234 | if (!yaml_parser_update_buffer(&parser, 1)) { 235 | printf("\treader error: %s at %ld\n", parser.problem, (long)parser.problem_offset); 236 | failed = 1; 237 | break; 238 | } 239 | } 240 | if (!parser.unread) { 241 | printf("\tnot enough characters at %d\n", k); 242 | failed = 1; 243 | break; 244 | } 245 | if (k % 2) { 246 | ch0 = '\xd0'; 247 | ch1 = '\x90'; 248 | } 249 | else { 250 | ch0 = '\xd0'; 251 | ch1 = '\xaf'; 252 | } 253 | if (parser.buffer.pointer[0] != ch0 || parser.buffer.pointer[1] != ch1) { 254 | printf("\tincorrect UTF-8 sequence: %X %X instead of %X %X\n", 255 | (int)parser.buffer.pointer[0], (int)parser.buffer.pointer[1], 256 | (int)ch0, (int)ch1); 257 | failed = 1; 258 | break; 259 | } 260 | parser.buffer.pointer += 2; 261 | parser.unread -= 1; 262 | } 263 | if (!failed) { 264 | if (!yaml_parser_update_buffer(&parser, 1)) { 265 | printf("\treader error: %s at %ld\n", parser.problem, (long)parser.problem_offset); 266 | failed = 1; 267 | } 268 | else if (parser.buffer.pointer[0] != '\0') { 269 | printf("\texpected NUL, found %X (eof=%d, unread=%ld)\n", (int)parser.buffer.pointer[0], parser.eof, (long)parser.unread); 270 | failed = 1; 271 | } 272 | } 273 | yaml_parser_delete(&parser); 274 | free(buffer); 275 | printf("checking a long utf8 sequence: %d fail(s)\n", failed); 276 | return failed; 277 | } 278 | 279 | int check_long_utf16(void) 280 | { 281 | yaml_parser_t parser; 282 | int k = 0; 283 | int j; 284 | int failed = 0; 285 | unsigned char ch0, ch1; 286 | unsigned char *buffer = (unsigned char *)malloc(2+LONG*2); 287 | assert(buffer); 288 | printf("checking a long utf16 sequence...\n"); 289 | buffer[k++] = '\xff'; 290 | buffer[k++] = '\xfe'; 291 | for (j = 0; j < LONG; j ++) { 292 | if (j % 2) { 293 | buffer[k++] = '\x10'; 294 | buffer[k++] = '\x04'; 295 | } 296 | else { 297 | buffer[k++] = '/'; 298 | buffer[k++] = '\x04'; 299 | } 300 | } 301 | yaml_parser_initialize(&parser); 302 | yaml_parser_set_input_string(&parser, buffer, 2+LONG*2); 303 | for (k = 0; k < LONG; k++) { 304 | if (!parser.unread) { 305 | if (!yaml_parser_update_buffer(&parser, 1)) { 306 | printf("\treader error: %s at %ld\n", parser.problem, (long)parser.problem_offset); 307 | failed = 1; 308 | break; 309 | } 310 | } 311 | if (!parser.unread) { 312 | printf("\tnot enough characters at %d\n", k); 313 | failed = 1; 314 | break; 315 | } 316 | if (k % 2) { 317 | ch0 = '\xd0'; 318 | ch1 = '\x90'; 319 | } 320 | else { 321 | ch0 = '\xd0'; 322 | ch1 = '\xaf'; 323 | } 324 | if (parser.buffer.pointer[0] != ch0 || parser.buffer.pointer[1] != ch1) { 325 | printf("\tincorrect UTF-8 sequence: %X %X instead of %X %X\n", 326 | (int)parser.buffer.pointer[0], (int)parser.buffer.pointer[1], 327 | (int)ch0, (int)ch1); 328 | failed = 1; 329 | break; 330 | } 331 | parser.buffer.pointer += 2; 332 | parser.unread -= 1; 333 | } 334 | if (!failed) { 335 | if (!yaml_parser_update_buffer(&parser, 1)) { 336 | printf("\treader error: %s at %ld\n", parser.problem, (long)parser.problem_offset); 337 | failed = 1; 338 | } 339 | else if (parser.buffer.pointer[0] != '\0') { 340 | printf("\texpected NUL, found %X (eof=%d, unread=%ld)\n", (int)parser.buffer.pointer[0], parser.eof, (long)parser.unread); 341 | failed = 1; 342 | } 343 | } 344 | yaml_parser_delete(&parser); 345 | free(buffer); 346 | printf("checking a long utf16 sequence: %d fail(s)\n", failed); 347 | return failed; 348 | } 349 | 350 | int 351 | main(void) 352 | { 353 | return check_utf8_sequences() + check_boms() + check_long_utf8() + check_long_utf16(); 354 | } 355 | -------------------------------------------------------------------------------- /tests/test-version.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | #ifdef NDEBUG 7 | #undef NDEBUG 8 | #endif 9 | #include 10 | 11 | int 12 | main(void) 13 | { 14 | int major = -1; 15 | int minor = -1; 16 | int patch = -1; 17 | char buf[64]; 18 | 19 | yaml_get_version(&major, &minor, &patch); 20 | sprintf(buf, "%d.%d.%d", major, minor, patch); 21 | assert(strcmp(buf, yaml_get_version_string()) == 0); 22 | 23 | /* Print structure sizes. */ 24 | printf("sizeof(token) = %ld\n", (long)sizeof(yaml_token_t)); 25 | printf("sizeof(event) = %ld\n", (long)sizeof(yaml_event_t)); 26 | printf("sizeof(parser) = %ld\n", (long)sizeof(yaml_parser_t)); 27 | 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /yaml-0.1.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@prefix@ 2 | exec_prefix=@exec_prefix@ 3 | includedir=@includedir@ 4 | libdir=@libdir@ 5 | 6 | Name: LibYAML 7 | Description: Library to parse and emit YAML 8 | Version: @PACKAGE_VERSION@ 9 | Cflags: -I${includedir} 10 | Libs: -L${libdir} -lyaml 11 | -------------------------------------------------------------------------------- /yamlConfig.cmake.in: -------------------------------------------------------------------------------- 1 | # Config file for the yaml library. 2 | # 3 | # It defines the following variables: 4 | # yaml_LIBRARIES - libraries to link against 5 | 6 | @PACKAGE_INIT@ 7 | 8 | set_and_check(yaml_TARGETS "@PACKAGE_CONFIG_DIR_CONFIG@/yamlTargets.cmake") 9 | 10 | if(NOT yaml_TARGETS_IMPORTED) 11 | set(yaml_TARGETS_IMPORTED 1) 12 | include(${yaml_TARGETS}) 13 | endif() 14 | 15 | set(yaml_LIBRARIES yaml) 16 | 17 | --------------------------------------------------------------------------------