1
0
Fork 0

Adding upstream version 3.1.0+dfsg.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-02-05 08:00:08 +01:00
parent 64dbec996d
commit cfcebb1a7d
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
569 changed files with 205393 additions and 0 deletions

3
.gitattributes vendored Normal file
View file

@ -0,0 +1,3 @@
# the tests check that LF is kept as a LF in the checkout
tests/modules/yang/ietf-netconf@*.yang -text
tests/modules/yang/ietf-netconf-nmda@*.yang -text

238
.github/workflows/ci.yml vendored Normal file
View file

@ -0,0 +1,238 @@
name: libyang CI
on:
push:
branches:
- master
- devel
pull_request:
branches:
- master
- devel
jobs:
build-unix:
name: ${{ matrix.config.name }}
runs-on: ${{ matrix.config.os }}
strategy:
fail-fast: false
matrix:
config:
- {
name: "Release, gcc",
os: "ubuntu-22.04",
build-type: "Release",
cc: "gcc",
options: "-DENABLE_TESTS=ON",
packager: "sudo apt-get",
# no expect because stdout seems to be redirected
packages: "libcmocka-dev shunit2",
snaps: "",
build-cmd: "make"
}
- {
name: "Release, clang",
os: "ubuntu-22.04",
build-type: "Release",
cc: "clang",
options: "-DENABLE_TESTS=ON",
packager: "sudo apt-get",
packages: "libcmocka-dev shunit2",
snaps: "",
build-cmd: "make"
}
- {
name: "Debug, gcc",
os: "ubuntu-22.04",
build-type: "Debug",
cc: "gcc",
options: "",
packager: "sudo apt-get",
packages: "libcmocka-dev valgrind shunit2",
snaps: "",
build-cmd: "make"
}
- {
name: "Debug, clang",
os: "ubuntu-22.04",
build-type: "Debug",
cc: "clang",
options: "",
packager: "sudo apt-get",
# no valgrind because it does not support DWARF5 yet generated by clang 14
packages: "libcmocka-dev shunit2",
snaps: "",
build-cmd: "make"
}
- {
name: "Release, macOS 11, clang",
os: "macos-11",
build-type: "Release",
cc: "clang",
options: "-DENABLE_TESTS=ON -DPATH_EXPECT=",
packager: "brew",
packages: "cmocka shunit2",
snaps: "",
build-cmd: "make"
}
- {
name: "ASAN and UBSAN",
os: "ubuntu-22.04",
build-type: "Debug",
cc: "clang",
options: "-DCMAKE_C_FLAGS=-fsanitize=address,undefined -DENABLE_TESTS=ON -DENABLE_VALGRIND_TESTS=OFF",
packager: "sudo apt-get",
packages: "libcmocka-dev",
snaps: "",
build-cmd: "make"
}
- {
name: "ABI Check",
os: "ubuntu-22.04",
build-type: "ABICheck",
cc: "gcc",
options: "",
packager: "sudo apt-get",
packages: "libcmocka-dev abi-dumper abi-compliance-checker",
snaps: "core universal-ctags",
build-cmd: "make abi-check"
}
- {
name: "DEB Package",
os: "ubuntu-22.04",
build-type: "Release",
cc: "gcc",
options: "",
packager: "sudo apt-get",
packages: "cmake debhelper libcmocka-dev python3-pip",
snaps: "",
build-cmd: ""
}
steps:
- uses: actions/checkout@main
with:
fetch-depth: 100
- name: Deps-packages
shell: bash
run: |
${{ matrix.config.packager }} update
if ${{ matrix.config.packages != '' }}
then ${{ matrix.config.packager }} install ${{ matrix.config.packages }}
fi
if ${{ matrix.config.snaps != '' }}
then sudo snap install ${{ matrix.config.snaps }}
fi
- name: Deps-uncrustify
shell: bash
working-directory: ${{ github.workspace }}
run: |
git clone --branch uncrustify-0.77.1 https://github.com/uncrustify/uncrustify
cd uncrustify
mkdir build
cd build
CC=${{ matrix.config.cc }} cmake ..
make
sudo make install
if: ${{ matrix.config.name == 'Debug, gcc' }}
- name: Build-and-install-package
shell: bash
working-directory: ${{ github.workspace }}
run: |
pip install apkg
apkg system-setup
apkg build
apkg install
if: ${{ matrix.config.name == 'DEB Package' }}
- name: Configure
shell: bash
working-directory: ${{ github.workspace }}
run: |
mkdir build
cd build
CC=${{ matrix.config.cc }} cmake -DCMAKE_BUILD_TYPE=${{ matrix.config.build-type }} ${{ matrix.config.options }} ..
if: ${{ matrix.config.name != 'DEB Package' }}
- name: Build
shell: bash
working-directory: ${{ github.workspace }}/build
run: |
export LC_ALL=C.UTF-8
export PATH=/snap/bin:${{ github.workspace }}/coverity-tools/bin:$PATH
${{ matrix.config.build-cmd }}
if: ${{ matrix.config.name != 'DEB Package' }}
- name: Test
shell: bash
working-directory: ${{ github.workspace }}/build
run: ctest --output-on-failure
if: ${{ matrix.config.name != 'DEB Package' }}
build-windows:
name: ${{ matrix.name }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- name: "Windows 2022 MSVC 16 LF"
os: windows-2022
triplet: x64-windows
build_type: Release
generators: "Visual Studio 17 2022"
autocrlf: input
eol: lf
- name: "Windows 2022 MSVC 16 no autoCRLF"
os: windows-2022
triplet: x64-windows
build_type: Release
generators: "Visual Studio 17 2022"
steps:
- name: Unix line endings in git
if: matrix.autocrlf
run: |
git config --global core.autocrlf ${{ matrix.autocrlf }}
- name: Unix line endings in git
if: matrix.eol
run: |
git config --global core.eol ${{ matrix.eol }}
- uses: actions/checkout@main
- name: Get number of CPU cores
id: cpu-cores
uses: SimenB/github-actions-cpu-cores@v1
- name: Install Windows dependencies
run: vcpkg install --triplet=${{ matrix.triplet }} pcre2 pthreads dirent dlfcn-win32 cmocka getopt
- name: Configure
shell: bash
run: |
cmake \
-S '${{ github.workspace }}/' \
-B '${{ github.workspace }}/'../build \
-G '${{ matrix.generators }}' \
-DCMAKE_BUILD_TYPE=${{ matrix.build_type }} \
-DVCPKG_TARGET_TRIPLET=${{ matrix.triplet }} \
-DCMAKE_TOOLCHAIN_FILE=${VCPKG_INSTALLATION_ROOT//\\//}/scripts/buildsystems/vcpkg.cmake \
-DENABLE_TESTS=ON \
'-DCMAKE_INSTALL_PREFIX:PATH=${{ github.workspace }}'/../target
- name: Build
working-directory: '${{ github.workspace }}/../build'
run: cmake --build . -j${{ steps.cpu-cores.outputs.count }} --config ${{ matrix.build_type }}
- name: Test
working-directory: '${{ github.workspace }}/../build'
run: ctest --output-on-failure -j${{ steps.cpu-cores.outputs.count }} --build-config ${{ matrix.build_type }}
- name: Install
working-directory: '${{ github.workspace }}/../build'
run: cmake --install . --strip

24
.github/workflows/cifuzz.yml vendored Normal file
View file

@ -0,0 +1,24 @@
name: CIFuzz
on: [pull_request]
jobs:
Fuzzing:
runs-on: ubuntu-latest
steps:
- name: Build Fuzzers
id: build
uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
with:
oss-fuzz-project-name: 'libyang'
dry-run: false
- name: Run Fuzzers
uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
with:
oss-fuzz-project-name: 'libyang'
fuzz-seconds: 300
dry-run: false
- name: Upload Crash
uses: actions/upload-artifact@v3
if: failure() && steps.build.outcome == 'success'
with:
name: artifacts
path: ./out/artifacts

39
.github/workflows/codeql.yml vendored Normal file
View file

@ -0,0 +1,39 @@
name: "CodeQL"
on:
push:
branches: [ "master", "devel" ]
pull_request:
branches: [ "devel" ]
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ cpp ]
steps:
- name: Checkout
uses: actions/checkout@main
- name: Initialize CodeQL
uses: github/codeql-action/init@main
with:
languages: ${{ matrix.language }}
queries: +security-and-quality
- name: Autobuild
uses: github/codeql-action/autobuild@main
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@main
with:
category: "/language:${{ matrix.language }}"

109
.github/workflows/devel-push.yml vendored Normal file
View file

@ -0,0 +1,109 @@
name: libyang devel push
on:
push:
branches:
- devel
env:
COVERITY_PROJECT: CESNET%2Flibyang
jobs:
build:
name: ${{ matrix.config.name }}
runs-on: ${{ matrix.config.os }}
strategy:
fail-fast: false
matrix:
config:
- {
name: "Coverity",
os: "ubuntu-latest",
build-type: "Debug",
cc: "clang",
options: "",
packager: "sudo apt-get",
packages: "",
snaps: "",
make-prepend: "cov-build --dir cov-int",
make-target: ""
}
- {
name: "Codecov",
os: "ubuntu-latest",
build-type: "Debug",
cc: "gcc",
options: "-DENABLE_COVERAGE=ON",
packager: "sudo apt-get",
packages: "libcmocka-dev lcov",
snaps: "",
make-prepend: "",
make-target: ""
}
steps:
- uses: actions/checkout@main
- name: Deps-packages
shell: bash
run: |
${{ matrix.config.packager }} update
if ${{ matrix.config.packages != '' }}
then ${{ matrix.config.packager }} install ${{ matrix.config.packages }}
fi
if ${{ matrix.config.snaps != '' }}
then sudo snap install ${{ matrix.config.snaps }}
fi
- name: Deps-coverity
shell: bash
working-directory: ${{ github.workspace }}
run: |
wget -q https://scan.coverity.com/download/linux64 --post-data "token=$TOKEN&project=$COVERITY_PROJECT" -O coverity-tools.tar.gz
mkdir coverity-tools
tar xzf coverity-tools.tar.gz --strip 1 -C coverity-tools
env:
TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}
if: ${{ matrix.config.name == 'Coverity' }}
- name: Configure
shell: bash
working-directory: ${{ github.workspace }}
run: |
mkdir build
cd build
CC=${{ matrix.config.cc }} cmake -DCMAKE_BUILD_TYPE=${{ matrix.config.build-type }} ${{ matrix.config.options }} ..
- name: Build
shell: bash
working-directory: ${{ github.workspace }}/build
run: |
export LC_ALL=C.UTF-8
export PATH=/snap/bin:${{ github.workspace }}/coverity-tools/bin:$PATH
${{ matrix.config.make-prepend }} make ${{ matrix.config.make-target }}
- name: Test
shell: bash
working-directory: ${{ github.workspace }}/build
run: ctest --output-on-failure
- name: Upload to Coverity.com
shell: bash
working-directory: ${{ github.workspace }}/build
run: |
tar czvf libyang.tgz cov-int
curl \
--form token=$TOKEN \
--form email=mvasko@cesnet.cz \
--form file=@libyang.tgz \
--form version="`./yanglint -v | cut -d\" \" -f2`" \
--form description="libyang YANG library" \
https://scan.coverity.com/builds?project=$COVERITY_PROJECT
env:
TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}
if: ${{ matrix.config.name == 'Coverity' }}
- name: Upload to Codecov.io
shell: bash
working-directory: ${{ github.workspace }}/build
run: bash <(curl -s https://codecov.io/bash)
if: ${{ matrix.config.name == 'Codecov' }}

6
.mailmap Normal file
View file

@ -0,0 +1,6 @@
David Sedlák <xsedla1d@stud.fit.vutbr.cz>
FredGan <ganshaolong@vip.qq.com>
Juraj Vijtiuk <juraj.vijtiuk@sartura.hr> <vijtiuk.juraj@gmail.com> <30860583+jvijtiuk@users.noreply.github.com>
Juraj Vijtiuk <juraj.vijtiuk@sartura.hr> <30860583+jvijtiuk@users.noreply.github.com>
Michal Vasko <mvasko@cesnet.cz>
Radek Krejci <rkrejci@cesnet.cz>

491
CMakeLists.txt Normal file
View file

@ -0,0 +1,491 @@
if(WIN32)
cmake_minimum_required(VERSION 3.22.0)
else()
cmake_minimum_required(VERSION 2.8.12...3.28.1)
endif()
# force out-of-source build
if(${CMAKE_CURRENT_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_BINARY_DIR})
message(FATAL_ERROR "In-source build is not allowed. Please make a standalone build directory and run CMake from there. You may need to remove CMakeCache.txt.")
endif()
project(libyang C)
# include custom Modules
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules/")
include(GNUInstallDirs)
include(UseCompat)
include(ABICheck)
include(SourceFormat)
include(GenDoc)
include(GenCoverage)
# set default build type if not specified by user
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Debug)
endif()
# normalize build type string
# see https://github.com/CESNET/libyang/pull/1692 for why CMAKE_C_FLAGS_<type> are not used directly
string(TOUPPER "${CMAKE_BUILD_TYPE}" BUILD_TYPE_UPPER)
if ("${BUILD_TYPE_UPPER}" STREQUAL "RELEASE")
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Build Type" FORCE)
set(CMAKE_C_FLAGS "-DNDEBUG -O2 ${CMAKE_C_FLAGS}")
elseif("${BUILD_TYPE_UPPER}" STREQUAL "DEBUG")
set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Build Type" FORCE)
set(CMAKE_C_FLAGS "-g3 -O0 ${CMAKE_C_FLAGS}")
elseif("${BUILD_TYPE_UPPER}" STREQUAL "RELWITHDEBINFO")
set(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING "Build Type" FORCE)
elseif("${BUILD_TYPE_UPPER}" STREQUAL "RELWITHDEBUG")
set(CMAKE_BUILD_TYPE "RelWithDebug" CACHE STRING "Build Type" FORCE)
elseif("${BUILD_TYPE_UPPER}" STREQUAL "ABICHECK")
set(CMAKE_BUILD_TYPE "ABICheck" CACHE STRING "Build Type" FORCE)
set(CMAKE_C_FLAGS "-g -Og ${CMAKE_C_FLAGS}")
elseif("${BUILD_TYPE_UPPER}" STREQUAL "DOCONLY")
set(CMAKE_BUILD_TYPE "DocOnly" CACHE STRING "Build Type" FORCE)
endif()
#
# variables
#
set(LIBYANG_DESCRIPTION "libyang is YANG data modelling language parser and toolkit written (and providing API) in C.")
# Correct RPATH usage on OS X
set(CMAKE_MACOSX_RPATH TRUE)
# keep all binaries in the build directory
set (CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
# set version of the project
set(LIBYANG_MAJOR_VERSION 3)
set(LIBYANG_MINOR_VERSION 1)
set(LIBYANG_MICRO_VERSION 0)
set(LIBYANG_VERSION ${LIBYANG_MAJOR_VERSION}.${LIBYANG_MINOR_VERSION}.${LIBYANG_MICRO_VERSION})
# set version of the library
set(LIBYANG_MAJOR_SOVERSION 3)
set(LIBYANG_MINOR_SOVERSION 2)
set(LIBYANG_MICRO_SOVERSION 0)
set(LIBYANG_SOVERSION_FULL ${LIBYANG_MAJOR_SOVERSION}.${LIBYANG_MINOR_SOVERSION}.${LIBYANG_MICRO_SOVERSION})
set(LIBYANG_SOVERSION ${LIBYANG_MAJOR_SOVERSION})
if(WIN32)
set(C_STANDARD 11)
set(C_STANDARD_REQUIRED ON)
set(CMAKE_C_FLAGS "/Zc:preprocessor /W3 /wd4711 /w14013 /utf-8 ${CMAKE_C_FLAGS}")
else()
# global C flags
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wpedantic -std=c11")
endif()
include_directories(${PROJECT_BINARY_DIR}/libyang ${PROJECT_SOURCE_DIR}/src ${PROJECT_SOURCE_DIR}/src/plugins_exts)
# type plugins are separate because they have their documentation generated
set(type_plugins
src/plugins_types/binary.c
src/plugins_types/bits.c
src/plugins_types/boolean.c
src/plugins_types/decimal64.c
src/plugins_types/empty.c
src/plugins_types/enumeration.c
src/plugins_types/identityref.c
src/plugins_types/instanceid.c
src/plugins_types/instanceid_keys.c
src/plugins_types/integer.c
src/plugins_types/leafref.c
src/plugins_types/lyds_tree.c
src/plugins_types/string.c
src/plugins_types/union.c
src/plugins_types/ipv4_address.c
src/plugins_types/ipv4_address_no_zone.c
src/plugins_types/ipv6_address.c
src/plugins_types/ipv6_address_no_zone.c
src/plugins_types/ipv4_prefix.c
src/plugins_types/ipv6_prefix.c
src/plugins_types/date_and_time.c
src/plugins_types/hex_string.c
src/plugins_types/xpath1.0.c
src/plugins_types/node_instanceid.c)
set(libsrc
src/ly_common.c
src/log.c
src/hash_table.c
src/dict.c
src/set.c
src/path.c
src/diff.c
src/context.c
src/json.c
src/tree_data.c
src/tree_data_free.c
src/tree_data_common.c
src/tree_data_hash.c
src/tree_data_new.c
src/parser_xml.c
src/parser_json.c
src/parser_lyb.c
src/out.c
src/printer_data.c
src/printer_xml.c
src/printer_json.c
src/printer_lyb.c
src/schema_compile.c
src/schema_compile_node.c
src/schema_compile_amend.c
src/schema_features.c
src/tree_data_sorted.c
src/tree_schema.c
src/tree_schema_free.c
src/tree_schema_common.c
src/in.c
src/lyb.c
src/parser_common.c
src/parser_yang.c
src/parser_yin.c
src/printer_schema.c
src/printer_yang.c
src/printer_yin.c
src/printer_tree.c
src/plugins.c
src/plugins_types.c
src/plugins_exts.c
src/plugins_exts/metadata.c
src/plugins_exts/nacm.c
src/plugins_exts/yangdata.c
src/plugins_exts/schema_mount.c
src/plugins_exts/structure.c
src/xml.c
src/xpath.c
src/validation.c
${type_plugins})
set(headers
src/context.h
src/hash_table.h
src/dict.h
src/in.h
src/libyang.h
src/log.h
src/out.h
src/parser_data.h
src/parser_schema.h
src/plugins.h
src/plugins_exts.h
src/plugins_exts/metadata.h
src/plugins_types.h
src/printer_data.h
src/printer_schema.h
src/set.h
src/tree.h
src/tree_data.h
src/tree_edit.h
src/tree_schema.h)
set(internal_headers
src/ly_common.h
src/diff.h
src/hash_table_internal.h
src/in_internal.h
src/json.h
src/lyb.h
src/out_internal.h
src/parser_internal.h
src/path.h
src/plugins_internal.h
src/printer_internal.h
src/schema_compile.h
src/schema_compile_amend.h
src/schema_compile_node.h
src/schema_features.h
src/tree_data_internal.h
src/tree_schema_internal.h
src/validation.h
src/xml.h
src/xpath.h)
set(gen_headers
version.h
ly_config.h)
# files to generate doxygen from
set(doxy_files
doc/build.dox
doc/transition_1_2.dox
doc/transition_2_3.dox
${headers}
${PROJECT_BINARY_DIR}/libyang/version.h
${type_plugins})
# project (doxygen) logo
set(project_logo
doc/logo.png)
# source files to be covered by the 'format' target
set(format_sources
compat/*.c
compat/*.h*
src/*.c
src/*.h
src/plugins_exts/*
src/plugins_types/*)
#
# options
#
if(("${BUILD_TYPE_UPPER}" STREQUAL "DEBUG") OR ("${BUILD_TYPE_UPPER}" STREQUAL "RELWITHDEBINFO"))
option(ENABLE_TESTS "Build tests" ON)
option(ENABLE_VALGRIND_TESTS "Build tests with valgrind" ON)
else()
option(ENABLE_TESTS "Build tests" OFF)
option(ENABLE_VALGRIND_TESTS "Build tests with valgrind" OFF)
endif()
option(ENABLE_PERF_TESTS "Build performance tests" OFF)
option(ENABLE_COVERAGE "Build code coverage report from tests" OFF)
option(ENABLE_FUZZ_TARGETS "Build target programs suitable for fuzzing with AFL" OFF)
option(ENABLE_INTERNAL_DOCS "Generate doxygen documentation also from internal headers" OFF)
option(ENABLE_YANGLINT_INTERACTIVE "Enable interactive CLI yanglint" ON)
option(ENABLE_TOOLS "Build binary tools 'yanglint' and 'yangre'" ON)
option(ENABLE_COMMON_TARGETS "Define common custom target names such as 'doc' or 'uninstall', may cause conflicts when using add_subdirectory() to build this project" ON)
option(BUILD_SHARED_LIBS "By default, shared libs are enabled. Turn off for a static build." ON)
set(YANG_MODULE_DIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATADIR}/yang/modules/libyang" CACHE STRING "Directory where to copy the YANG modules to")
if(ENABLE_INTERNAL_DOCS)
set(doxy_files ${doxy_files} ${internal_headers})
set(INTERNAL_DOCS YES)
else()
set(INTERNAL_DOCS NO)
endif()
set(LYD_VALUE_SIZE "24" CACHE STRING "Maximum size in bytes of data node values that do not need to be allocated dynamically, minimum is 8")
if(LYD_VALUE_SIZE LESS 8)
message(FATAL_ERROR "Data node value size \"${LYD_VALUE_SIZE}\" is not valid.")
endif()
set(PLUGINS_DIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/libyang" CACHE STRING "Directory with libyang plugins (extensions and user types)")
set(PLUGINS_DIR_EXTENSIONS "${PLUGINS_DIR}/extensions" CACHE STRING "Directory with libyang user extensions plugins")
set(PLUGINS_DIR_TYPES "${PLUGINS_DIR}/types" CACHE STRING "Directory with libyang user types plugins")
#
# checks
#
if(NOT BUILD_SHARED_LIBS)
message(STATUS "Disabling tests for static build")
set(ENABLE_TESTS OFF)
set(ENABLE_VALGRIND_TESTS OFF)
endif()
if(ENABLE_VALGRIND_TESTS)
if(NOT ENABLE_TESTS)
message(WARNING "Tests are disabled! Disabling memory leak tests.")
set(ENABLE_VALGRIND_TESTS OFF)
else()
find_program(VALGRIND_FOUND valgrind)
if(NOT VALGRIND_FOUND)
message(WARNING "valgrind executable not found! Disabling memory leak tests.")
set(ENABLE_VALGRIND_TESTS OFF)
endif()
endif()
endif()
if(ENABLE_TESTS)
find_package(CMocka 1.0.1)
if(NOT CMOCKA_FOUND)
message(STATUS "Disabling tests because of missing CMocka")
set(ENABLE_TESTS OFF)
endif()
endif()
if(ENABLE_PERF_TESTS)
find_path(VALGRIND_INCLUDE_DIR
NAMES
valgrind/callgrind.h
PATHS
/usr/include
/usr/local/include
/opt/local/include
/sw/include
${CMAKE_INCLUDE_PATH}
${CMAKE_INSTALL_PREFIX}/include)
if(VALGRIND_INCLUDE_DIR)
set(HAVE_CALLGRIND 1)
else()
message(STATUS "Disabling callgrind macros in performance tests because of missing valgrind headers")
endif()
endif()
if(ENABLE_COVERAGE)
gen_coverage_enable(${ENABLE_TESTS})
endif()
if ("${BUILD_TYPE_UPPER}" STREQUAL "DEBUG")
# enable before adding tests to let them detect that format checking is available - one of the tests is format checking
source_format_enable(0.77)
endif()
# generate and copy all public header files
configure_file(${PROJECT_SOURCE_DIR}/src/ly_config.h.in ${PROJECT_BINARY_DIR}/libyang/ly_config.h @ONLY)
configure_file(${PROJECT_SOURCE_DIR}/src/version.h.in ${PROJECT_BINARY_DIR}/libyang/version.h @ONLY)
file(COPY ${headers} DESTINATION ${PROJECT_BINARY_DIR}/libyang)
# DOC-only target with no extra dependencies
if("${BUILD_TYPE_UPPER}" STREQUAL "DOCONLY")
gen_doc("${doxy_files}" ${LIBYANG_VERSION} ${LIBYANG_DESCRIPTION} ${project_logo})
return()
endif()
#
# targets
#
# link compat
use_compat()
# create static libyang library
if(NOT BUILD_SHARED_LIBS)
add_definitions(-DSTATIC)
# allow binaries compilation linking both static and dynamic libraries never linking static glibc
#set(CMAKE_EXE_LINKER_FLAGS -static)
# prefer static libraries
set(CMAKE_FIND_LIBRARY_SUFFIXES .a;.so)
set(CMAKE_LINK_SEARCH_START_STATIC TRUE)
set(CMAKE_EXE_LINK_DYNAMIC_C_FLAGS) # remove -Wl,-Bdynamic
set(CMAKE_EXE_LINK_DYNAMIC_CXX_FLAGS)
add_library(yang STATIC ${libsrc} ${compatsrc})
else()
set(CMAKE_POSITION_INDEPENDENT_CODE TRUE)
add_library(yangobj OBJECT ${libsrc} ${compatsrc})
if(NOT WIN32)
set_target_properties(yangobj PROPERTIES COMPILE_FLAGS "-fvisibility=hidden")
endif()
target_compile_definitions(yangobj PRIVATE LIBYANG_BUILD)
add_library(yang SHARED $<TARGET_OBJECTS:yangobj>)
if(WIN32)
find_package(dlfcn-win32 REQUIRED)
set(CMAKE_DL_LIBS dlfcn-win32::dl)
endif()
#link dl
target_link_libraries(yang ${CMAKE_DL_LIBS})
endif()
if(WIN32)
find_path(DIRENT_INCLUDE_DIR NAMES dirent.h REQUIRED)
message(STATUS "Found <dirent.h> at ${DIRENT_INCLUDE_DIR}")
set(COMPAT_POSIX_INCLUDES
${CMAKE_CURRENT_SOURCE_DIR}/compat/posix-shims
${DIRENT_INCLUDE_DIR})
if(TARGET yangobj)
target_include_directories(yangobj PRIVATE ${COMPAT_POSIX_INCLUDES})
endif()
target_include_directories(yang PRIVATE ${COMPAT_POSIX_INCLUDES})
include_directories(${COMPAT_POSIX_INCLUDES})
find_package(pthreads REQUIRED)
set(COMPAT_WIN_LIBRARIES PThreads4W::PThreads4W shlwapi.lib ws2_32)
target_link_libraries(yang ${COMPAT_WIN_LIBRARIES})
endif()
set_target_properties(yang PROPERTIES VERSION ${LIBYANG_SOVERSION_FULL} SOVERSION ${LIBYANG_SOVERSION})
# link math
if(NOT WIN32)
target_link_libraries(yang m)
endif()
# find pthreads
set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
find_package(Threads REQUIRED)
target_link_libraries(yang ${CMAKE_THREAD_LIBS_INIT})
# find PCRE2 library
unset(PCRE2_LIBRARY CACHE)
find_package(PCRE2 10.21 REQUIRED)
include_directories(${PCRE2_INCLUDE_DIRS})
target_link_libraries(yang ${PCRE2_LIBRARIES})
# generated header list
foreach(h IN LISTS gen_headers)
list(APPEND g_headers ${PROJECT_BINARY_DIR}/libyang/${h})
endforeach()
# install the modules
install(DIRECTORY "${PROJECT_SOURCE_DIR}/models/" DESTINATION ${YANG_MODULE_DIR} FILES_MATCHING PATTERN "*.yang")
# install all library files
install(TARGETS yang DESTINATION ${CMAKE_INSTALL_LIBDIR})
install(FILES ${headers} ${g_headers} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/libyang)
find_package(PkgConfig)
if(PKG_CONFIG_FOUND)
# generate and install pkg-config file
configure_file("libyang.pc.in" "libyang.pc" @ONLY)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libyang.pc" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
# check that pkg-config includes the used path
execute_process(COMMAND ${PKG_CONFIG_EXECUTABLE} --variable pc_path pkg-config RESULT_VARIABLE RETURN OUTPUT_VARIABLE PC_PATH ERROR_QUIET)
if(RETURN EQUAL 0)
string(STRIP "${PC_PATH}" PC_PATH)
set(PC_PATH "${PC_PATH}:$ENV{PKG_CONFIG_PATH}")
string(REGEX MATCH "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/pkgconfig" SUBSTR "${PC_PATH}")
string(LENGTH "${SUBSTR}" SUBSTR_LEN)
if(SUBSTR_LEN EQUAL 0)
message(WARNING "pkg-config will not detect the new package after installation, adjust PKG_CONFIG_PATH using \"export PKG_CONFIG_PATH=\${PKG_CONFIG_PATH}:${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/pkgconfig\".")
endif()
endif()
endif()
# tests
if(ENABLE_TESTS OR ENABLE_PERF_TESTS)
enable_testing()
add_subdirectory(tests)
endif()
if(ENABLE_FUZZ_TARGETS)
set(FUZZER "AFL" CACHE STRING "fuzzer type")
if(FUZZER STREQUAL "LibFuzzer")
if (NOT CMAKE_C_COMPILER_ID STREQUAL "Clang")
message(FATAL_ERROR "LibFuzzer works only with clang")
endif()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address,undefined -fno-omit-frame-pointer")
endif()
endif()
# create coverage target for generating coverage reports
gen_coverage("utest_.*" "utest_.*_valgrind")
# tools - yanglint, yangre
if(ENABLE_TOOLS)
add_subdirectory(tools)
endif()
# generate doxygen documentation for libyang API
if(ENABLE_COMMON_TARGETS)
gen_doc("${doxy_files}" ${LIBYANG_VERSION} ${LIBYANG_DESCRIPTION} ${project_logo})
endif()
# generate API/ABI report
if("${BUILD_TYPE_UPPER}" STREQUAL "ABICHECK")
lib_abi_check(yang "${headers}" ${LIBYANG_SOVERSION_FULL} 708a8bfad983a4095c8d4dc537a9d2a1d5ca65c5)
endif()
# source code format target for Makefile
# - add it after tests which may also update list of sources to format
source_format(${format_sources})
# uninstall
if(ENABLE_COMMON_TARGETS)
add_custom_target(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_MODULE_PATH}/uninstall.cmake")
endif()
# clean cmake cache
add_custom_target(cclean
COMMAND make clean
COMMAND find . -iname '*cmake*' -not -name CMakeLists.txt -not -path './CMakeModules*' -exec rm -rf {} +
COMMAND rm -rf Makefile Doxyfile
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})

View file

@ -0,0 +1,66 @@
# generate API/ABI report
macro(LIB_ABI_CHECK LIB_TARGET LIB_HEADERS LIB_SOVERSION_FULL ABI_BASE_HASH)
# get short hash
string(SUBSTRING "${ABI_BASE_HASH}" 0 8 ABI_BASE_HASH_SHORT)
# find abi-dumper
find_program(ABI_DUMPER abi-dumper)
find_package_handle_standard_args(abi-dumper DEFAULT_MSG ABI_DUMPER)
if(NOT ABI_DUMPER)
message(FATAL_ERROR "Program abi-dumper not found!")
endif()
# find abi-checker
find_program(ABI_CHECKER abi-compliance-checker)
find_package_handle_standard_args(abi-compliance-checker DEFAULT_MSG ABI_CHECKER)
if(NOT ABI_CHECKER)
message(FATAL_ERROR "Program abi-compliance-checker not found!")
endif()
# abi-dump target - generating an ABI dump
set(PUBLIC_HEADERS ${LIB_HEADERS})
string(PREPEND PUBLIC_HEADERS "${CMAKE_SOURCE_DIR}/")
string(REPLACE ";" "\n${CMAKE_SOURCE_DIR}/" PUBLIC_HEADERS "${PUBLIC_HEADERS}")
file(GENERATE OUTPUT ${CMAKE_BINARY_DIR}/public_headers CONTENT "${PUBLIC_HEADERS}")
add_custom_target(abi-dump
COMMAND ${ABI_DUMPER} ./lib${LIB_TARGET}${CMAKE_SHARED_LIBRARY_SUFFIX}
-o lib${LIB_TARGET}.${LIB_SOVERSION_FULL}.dump
-lver ${LIB_SOVERSION_FULL} -public-headers ${CMAKE_BINARY_DIR}/public_headers
DEPENDS ${LIB_TARGET}
BYPRODUCTS ${CMAKE_BINARY_DIR}/lib${LIB_TARGET}.${LIB_SOVERSION_FULL}.dump
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
COMMENT "Dumping ABI information of version ${LIB_SOVERSION_FULL} for abi-check")
# get URL for fetching origin
execute_process(COMMAND git remote get-url origin OUTPUT_VARIABLE ORIGIN_URL OUTPUT_STRIP_TRAILING_WHITESPACE)
# generate script for generating the base ABI dump
file(GENERATE OUTPUT ${CMAKE_BINARY_DIR}/abibase.sh CONTENT "#!/bin/sh
if [ ! -d abibase ]; then mkdir abibase; fi
cd abibase
if [ ! -f build/lib${LIB_TARGET}.*.dump ]; then
if [ -d .git ] && [ \"${ABI_BASE_HASH}\" != \"`git log --pretty=oneline | cut -d' ' -f1`\" ]; then rm -rf .* 2> /dev/null; fi
if [ ! -d .git ]; then
git init --initial-branch=master
git remote add origin ${ORIGIN_URL}
git fetch origin --depth 1 ${ABI_BASE_HASH}
git reset --hard FETCH_HEAD
fi
if [ ! -d build ]; then mkdir build; fi
cd build
cmake -DCMAKE_BUILD_TYPE=ABICheck ..
make abi-dump
fi
")
# abi-check target - check ABI compatibility of current version and the base hash version
add_custom_target(abi-check
COMMAND bash ./abibase.sh
COMMAND ${ABI_CHECKER} -l lib${LIB_TARGET}${CMAKE_SHARED_LIBRARY_SUFFIX}
-old abibase/build/lib${LIB_TARGET}.*.dump
-new ./lib${LIB_TARGET}.${LIB_SOVERSION_FULL}.dump
DEPENDS ${LIB_TARGET} abi-dump
BYPRODUCTS ${CMAKE_BINARY_DIR}/compat_reports/lib${LIB_TARGET}${CMAKE_SHARED_LIBRARY_SUFFIX}/*_to_${LIB_SOVERSION_FULL}/compat_report.html
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
COMMENT "Checking ABI compatibility of version ${LIB_SOVERSION_FULL} and revision ${ABI_BASE_HASH_SHORT}")
endmacro()

View file

@ -0,0 +1,49 @@
# - Try to find CMocka
# Once done this will define
#
# CMOCKA_ROOT_DIR - Set this variable to the root installation of CMocka
#
# Read-Only variables:
# CMOCKA_FOUND - system has CMocka
# CMOCKA_INCLUDE_DIR - the CMocka include directory
# CMOCKA_LIBRARIES - Link these to use CMocka
# CMOCKA_DEFINITIONS - Compiler switches required for using CMocka
#
#=============================================================================
# Copyright (c) 2011-2012 Andreas Schneider <asn@cryptomilk.org>
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
#
find_path(CMOCKA_INCLUDE_DIR
NAMES
cmocka.h
PATHS
${CMOCKA_ROOT_DIR}/include
)
find_library(CMOCKA_LIBRARY
NAMES
cmocka
PATHS
${CMOCKA_ROOT_DIR}/include
)
if (CMOCKA_LIBRARY)
set(CMOCKA_LIBRARIES
${CMOCKA_LIBRARIES}
${CMOCKA_LIBRARY}
)
endif (CMOCKA_LIBRARY)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(CMocka DEFAULT_MSG CMOCKA_LIBRARIES CMOCKA_INCLUDE_DIR)
# show the CMOCKA_INCLUDE_DIR and CMOCKA_LIBRARIES variables only in the advanced view
mark_as_advanced(CMOCKA_INCLUDE_DIR CMOCKA_LIBRARIES)

View file

@ -0,0 +1,66 @@
# - Find pcre
# Find the native PCRE2 headers and libraries.
#
# PCRE2_INCLUDE_DIRS - where to find pcre.h, etc.
# PCRE2_LIBRARIES - List of libraries when using pcre.
# PCRE2_FOUND - True if pcre found.
include(FindPackageHandleStandardArgs)
if(PCRE2_LIBRARIES AND PCRE2_INCLUDE_DIRS)
# in cache already
set(PCRE2_FOUND TRUE)
else()
find_path(PCRE2_INCLUDE_DIR
NAMES
pcre2.h
PATHS
/usr/include
/usr/local/include
/opt/local/include
/sw/include
${CMAKE_INCLUDE_PATH}
${CMAKE_INSTALL_PREFIX}/include)
# Look for the library.
if (WIN32 AND "${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
# For the Debug build, the pcre2 library is called pcre2-8d. The Release build should be pcre2-8.
find_library(PCRE2_LIBRARY pcre2-8d)
else()
find_library(PCRE2_LIBRARY
NAMES
pcre2-8
PATHS
/usr/lib
/usr/lib64
/usr/local/lib
/usr/local/lib64
/opt/local/lib
/sw/lib
${CMAKE_LIBRARY_PATH}
${CMAKE_INSTALL_PREFIX}/lib)
endif()
if(PCRE2_INCLUDE_DIR AND PCRE2_LIBRARY)
# learn pcre2 version
file(STRINGS ${PCRE2_INCLUDE_DIR}/pcre2.h PCRE2_VERSION_MAJOR
REGEX "#define[ ]+PCRE2_MAJOR[ ]+[0-9]+")
string(REGEX MATCH " [0-9]+" PCRE2_VERSION_MAJOR ${PCRE2_VERSION_MAJOR})
string(STRIP "${PCRE2_VERSION_MAJOR}" PCRE2_VERSION_MAJOR)
file(STRINGS ${PCRE2_INCLUDE_DIR}/pcre2.h PCRE2_VERSION_MINOR
REGEX "#define[ ]+PCRE2_MINOR[ ]+[0-9]+")
string(REGEX MATCH " [0-9]+" PCRE2_VERSION_MINOR ${PCRE2_VERSION_MINOR})
string(STRIP "${PCRE2_VERSION_MINOR}" PCRE2_VERSION_MINOR)
set(PCRE2_VERSION ${PCRE2_VERSION_MAJOR}.${PCRE2_VERSION_MINOR})
endif()
set(PCRE2_INCLUDE_DIRS ${PCRE2_INCLUDE_DIR})
set(PCRE2_LIBRARIES ${PCRE2_LIBRARY})
mark_as_advanced(PCRE2_INCLUDE_DIRS PCRE2_LIBRARIES)
# Handle the QUIETLY and REQUIRED arguments and set PCRE2_FOUND to TRUE if all listed variables are TRUE.
find_package_handle_standard_args(PCRE2 FOUND_VAR PCRE2_FOUND
REQUIRED_VARS PCRE2_LIBRARY PCRE2_INCLUDE_DIR
VERSION_VAR PCRE2_VERSION)
endif()

View file

@ -0,0 +1,21 @@
# - Find uncrustify
# Find the uncrustify binary.
#
# UNCRUSTIFY - path ot the binary
# UNCRUSTIFY_VERSION - found version
# UNCRUSTIFY_FOUND - True if uncrustify found.
include(FindPackageHandleStandardArgs)
find_program(UNCRUSTIFY uncrustify)
if(UNCRUSTIFY)
execute_process(COMMAND ${UNCRUSTIFY} --version OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE VERSION)
string(FIND ${VERSION} "-" START_IDX)
math(EXPR START_IDX "${START_IDX} + 1")
string(SUBSTRING "${VERSION}" ${START_IDX} -1 VERSION)
string(FIND ${VERSION} "-" LEN)
string(SUBSTRING "${VERSION}" 0 ${LEN} UNCRUSTIFY_VERSION)
endif()
# Handle the QUIETLY and REQUIRED arguments and set UNCRUSTIFY_FOUND to TRUE if all listed variables are TRUE.
find_package_handle_standard_args(Uncrustify REQUIRED_VARS UNCRUSTIFY VERSION_VAR UNCRUSTIFY_VERSION)

View file

@ -0,0 +1,118 @@
# generate test code coverage report
# check that coverage tools are available - always use before GEN_COVERAGE
macro(GEN_COVERAGE_ENABLE ENABLE_TESTS)
# make into normal variable
set(TESTS_ENABLED ${ENABLE_TESTS})
set(GEN_COVERAGE_ENABLED ON)
if(NOT TESTS_ENABLED)
message(WARNING "You cannot generate coverage when tests are disabled. Enable test by additing parameter -DENABLE_TESTS=ON or run cmake with Debug build target.")
set(GEN_COVERAGE_ENABLED OFF)
endif()
if(GEN_COVERAGE_ENABLED)
find_program(PATH_GCOV NAMES gcov)
if(NOT PATH_GCOV)
message(WARNING "gcov executable not found! Disabling building code coverage report.")
set(GEN_COVERAGE_ENABLED OFF)
endif()
endif()
if(GEN_COVERAGE_ENABLED)
find_program(PATH_LCOV NAMES lcov)
if(NOT PATH_LCOV)
message(WARNING "lcov executable not found! Disabling building code coverage report.")
set(GEN_COVERAGE_ENABLED OFF)
endif()
endif()
if(GEN_COVERAGE_ENABLED)
find_program(PATH_GENHTML NAMES genhtml)
if(NOT PATH_GENHTML)
message(WARNING "genhtml executable not found! Disabling building code coverage report.")
set(GEN_COVERAGE_ENABLED OFF)
endif()
endif()
if(GEN_COVERAGE_ENABLED)
if(NOT CMAKE_COMPILER_IS_GNUCC)
message(WARNING "Compiler is not gcc! Coverage may break the tests!")
endif()
execute_process(
COMMAND bash "-c" "${CMAKE_C_COMPILER} --version | head -n1 | sed \"s/.* (.*) \\([0-9]\\+.[0-9]\\+.[0-9]\\+ .*\\)/\\1/\""
OUTPUT_VARIABLE GCC_VERSION_FULL
OUTPUT_STRIP_TRAILING_WHITESPACE
)
execute_process(
COMMAND bash "-c" "${PATH_GCOV} --version | head -n1 | sed \"s/.* (.*) \\([0-9]\\+.[0-9]\\+.[0-9]\\+ .*\\)/\\1/\""
OUTPUT_VARIABLE GCOV_VERSION_FULL
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if(NOT GCC_VERSION_FULL STREQUAL GCOV_VERSION_FULL)
message(WARNING "gcc and gcov versions do not match! Generating coverage may fail with errors.")
endif()
# add specific required compile flags
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --coverage -fprofile-arcs -ftest-coverage")
endif()
endmacro()
# tests are always expected to be in ${CMAKE_SOURCE_DIR}/tests
function(GEN_COVERAGE MATCH_TEST_REGEX EXCLUDE_TEST_REGEX)
if(NOT GEN_COVERAGE_ENABLED)
return()
endif()
# destination
set(COVERAGE_DIR "${CMAKE_BINARY_DIR}/code_coverage/")
set(COVERAGE_FILE_RAW "${CMAKE_BINARY_DIR}/coverage_raw.info")
set(COVERAGE_FILE_CLEAN "${CMAKE_BINARY_DIR}/coverage_clean.info")
# test match/exclude
if(MATCH_TEST_REGEX)
set(MATCH_TEST_ARGS -R \"${MATCH_TEST_REGEX}\")
endif()
if(EXCLUDE_TEST_REGEX)
set(EXCLUDE_TEST_ARGS -E \"${EXCLUDE_TEST_REGEX}\")
endif()
# coverage target
add_custom_target(coverage
COMMENT "Generating code coverage..."
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
# Cleanup code counters
COMMAND "${PATH_LCOV}" --directory . --zerocounters --quiet
# Run tests
COMMAND "${CMAKE_CTEST_COMMAND}" --quiet ${MATCH_TEST_ARGS} ${EXCLUDE_TEST_ARGS}
# Capture the counters
COMMAND "${PATH_LCOV}"
--directory .
--rc lcov_branch_coverage=1
--rc 'lcov_excl_line=assert'
--capture --quiet
--output-file "${COVERAGE_FILE_RAW}"
# Remove coverage of tests, system headers, etc.
COMMAND "${PATH_LCOV}"
--remove "${COVERAGE_FILE_RAW}" '${CMAKE_SOURCE_DIR}/tests/*'
--rc lcov_branch_coverage=1
--quiet --output-file "${COVERAGE_FILE_CLEAN}"
# Generate HTML report
COMMAND "${PATH_GENHTML}"
--branch-coverage --function-coverage --quiet --title "${PROJECT_NAME}"
--legend --show-details --output-directory "${COVERAGE_DIR}"
"${COVERAGE_FILE_CLEAN}"
# Delete the counters
COMMAND "${CMAKE_COMMAND}" -E remove
${COVERAGE_FILE_RAW} ${COVERAGE_FILE_CLEAN}
)
add_custom_command(TARGET coverage POST_BUILD
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/tests"
COMMENT "To see the code coverage report, open ${COVERAGE_DIR}index.html"
COMMAND ;
)
endfunction()

28
CMakeModules/GenDoc.cmake Normal file
View file

@ -0,0 +1,28 @@
# Prepare building doxygen documentation
macro(GEN_DOC INPUT_FILES PROJECT_VERSION PROJECT_DESCRIPTION DOC_LOGO)
find_package(Doxygen)
if(DOXYGEN_FOUND)
find_program(DOT_PATH dot PATH_SUFFIXES graphviz2.38/bin graphviz/bin)
if(DOT_PATH)
set(HAVE_DOT "YES")
else()
set(HAVE_DOT "NO")
message(AUTHOR_WARNING "Doxygen: to generate UML diagrams please install graphviz")
endif()
# target doc
add_custom_target(doc
COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_BINARY_DIR}/Doxyfile
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
# generate list with spaces as separators
string(REPLACE ";" " " DOXY_INPUT "${INPUT_FILES}")
# make other arguments into variables
set(PROJECT_VERSION ${PROJECT_VERSION})
set(PROJECT_DESCRIPTION ${PROJECT_DESCRIPTION})
set(DOC_LOGO ${DOC_LOGO})
configure_file(Doxyfile.in Doxyfile)
endif()
endmacro()

View file

@ -0,0 +1,36 @@
# format source files with uncrustify
# check that format checking is available - always use before SOURCE_FORMAT
macro(SOURCE_FORMAT_ENABLE)
if(NOT ${ARGC} EQUAL 1)
message(FATAL_ERROR "source_format_enable() needs the required Uncrustify version!")
endif()
find_package(Uncrustify ${ARGV0})
if(UNCRUSTIFY_FOUND)
set(SOURCE_FORMAT_ENABLED TRUE)
else()
set(SOURCE_FORMAT_ENABLED FALSE)
endif()
endmacro()
# files are expected to be a list and relative paths are resolved wtih respect to CMAKE_SOURCE DIR
macro(SOURCE_FORMAT)
if(NOT ${ARGC})
message(FATAL_ERROR "source_format() needs a list of files to format!")
endif()
if(SOURCE_FORMAT_ENABLED)
add_custom_target(format
COMMAND ${UNCRUSTIFY} -c ${CMAKE_SOURCE_DIR}/uncrustify.cfg --no-backup --replace ${ARGN}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
COMMENT "Formating sources with ${UNCRUSTIFY} ...")
add_custom_target(format-check
COMMAND ${UNCRUSTIFY} -c ${CMAKE_SOURCE_DIR}/uncrustify.cfg --check ${ARGN}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
COMMENT "Checking format of the sources with ${UNCRUSTIFY} ...")
set(SOURCE_FORMAT_ENABLED TRUE)
endif()
endmacro()

View file

@ -0,0 +1,77 @@
# - Use compat library providing various functions and macros that may be missing on some systems
# Once done this will define
#
# compatsrc - sources to add to compilation
#
# Additionally, "compat.h" include directory is added and can be included.
#
# Author Michal Vasko <mvasko@cesnet.cz>
# Copyright (c) 2021 CESNET, z.s.p.o.
#
# This source code is licensed under BSD 3-Clause License (the "License").
# You may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://opensource.org/licenses/BSD-3-Clause
#
include(CheckSymbolExists)
include(CheckFunctionExists)
include(CheckIncludeFile)
include(TestBigEndian)
if(POLICY CMP0075)
cmake_policy(SET CMP0075 NEW)
endif()
macro(USE_COMPAT)
# compatibility checks
list(APPEND CMAKE_REQUIRED_DEFINITIONS -D_POSIX_C_SOURCE=200809L)
list(APPEND CMAKE_REQUIRED_DEFINITIONS -D_GNU_SOURCE)
list(APPEND CMAKE_REQUIRED_DEFINITIONS -D__BSD_VISIBLE=1)
list(APPEND CMAKE_REQUIRED_DEFINITIONS -D_DEFAULT_SOURCE)
check_symbol_exists(vdprintf "stdio.h;stdarg.h" HAVE_VDPRINTF)
check_symbol_exists(asprintf "stdio.h" HAVE_ASPRINTF)
check_symbol_exists(vasprintf "stdio.h" HAVE_VASPRINTF)
check_symbol_exists(getline "stdio.h" HAVE_GETLINE)
check_symbol_exists(strndup "string.h" HAVE_STRNDUP)
check_symbol_exists(strnstr "string.h" HAVE_STRNSTR)
check_symbol_exists(strdupa "string.h" HAVE_STRDUPA)
check_symbol_exists(strchrnul "string.h" HAVE_STRCHRNUL)
check_symbol_exists(get_current_dir_name "unistd.h" HAVE_GET_CURRENT_DIR_NAME)
set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
find_package(Threads)
list(APPEND CMAKE_REQUIRED_LIBRARIES ${CMAKE_THREAD_LIBS_INIT})
check_function_exists(pthread_mutex_timedlock HAVE_PTHREAD_MUTEX_TIMEDLOCK)
list(REMOVE_ITEM CMAKE_REQUIRED_LIBRARIES ${CMAKE_THREAD_LIBS_INIT})
test_big_endian(IS_BIG_ENDIAN)
check_include_file("stdatomic.h" HAVE_STDATOMIC)
check_symbol_exists(realpath "stdlib.h" HAVE_REALPATH)
check_symbol_exists(localtime_r "time.h" HAVE_LOCALTIME_R)
check_symbol_exists(gmtime_r "time.h" HAVE_GMTIME_R)
check_function_exists(timegm HAVE_TIMEGM)
check_symbol_exists(strptime "time.h" HAVE_STRPTIME)
check_symbol_exists(mmap "sys/mman.h" HAVE_MMAP)
check_symbol_exists(setenv "stdlib.h" HAVE_SETENV)
list(REMOVE_ITEM CMAKE_REQUIRED_DEFINITIONS -D_POSIX_C_SOURCE=200809L)
list(REMOVE_ITEM CMAKE_REQUIRED_DEFINITIONS -D_GNU_SOURCE)
list(REMOVE_ITEM CMAKE_REQUIRED_DEFINITIONS -D__BSD_VISIBLE=1)
list(REMOVE_ITEM CMAKE_REQUIRED_DEFINITIONS -D_DEFAULT_SOURCE)
# header and source file (adding the source directly allows for hiding its symbols)
configure_file(${PROJECT_SOURCE_DIR}/compat/compat.h.in ${PROJECT_BINARY_DIR}/compat/compat.h @ONLY)
include_directories(${PROJECT_BINARY_DIR}/compat)
set(compatsrc ${PROJECT_SOURCE_DIR}/compat/compat.c)
if(WIN32)
include_directories(${PROJECT_SOURCE_DIR}/compat/posix-shims)
endif()
if(NOT HAVE_STRPTIME)
set(compatsrc ${compatsrc} ${PROJECT_SOURCE_DIR}/compat/strptime.c)
endif()
endmacro()

View file

@ -0,0 +1,27 @@
cmake_minimum_required(VERSION 3.0.2)
set(MANIFEST "${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt")
if(NOT EXISTS ${MANIFEST})
message(FATAL_ERROR "Cannot find install manifest: ${MANIFEST}")
endif()
file(STRINGS ${MANIFEST} files)
foreach(file ${files})
if(EXISTS ${file} OR IS_SYMLINK ${file})
message(STATUS "Removing: ${file}")
execute_process(COMMAND rm -f ${file}
RESULT_VARIABLE result
OUTPUT_QUIET
ERROR_VARIABLE stderr
ERROR_STRIP_TRAILING_WHITESPACE
)
if(NOT ${result} EQUAL 0)
message(FATAL_ERROR "${stderr}")
endif()
else()
message(STATUS "Does-not-exist: ${file}")
endif()
endforeach(file)

228
CONTRIBUTING.md Normal file
View file

@ -0,0 +1,228 @@
# Contributing to libyang
First of all, thanks for thinking about contribution to libyang! Not all of us
are C guru, but believe that helping us with docs, tests, helping other users to
solve their issues / answer ther questions or even letting us to know via
[issue tracker](https://github.com/CESNET/libyang/issues) that something
can be done in a better or just different way is really appreciated.
If you are willing to contribute, you will definitely have to build and install
libyang first. To do it, please check dependencies and follow build and install
instructions provided in [README](README.md).
If you have something what you believe should be part of the libyang repository,
add it via [Github Pull Request mechanism](https://help.github.com/articles/about-pull-requests/).
Remember to explain what you wish to add and why. The best approach is to start
with creating an issue and discuss possible approaches there. Pull requests can be
then connected with such issues.
## Branches
There are 2 main branches in libyang project. The default branch is named `master`. It is the
most stable and tested code which you get by default when cloning the Git repository. The
`devel` branch introduces new features, API changes or even bugfixes in case `master` and
`devel` differs significantly at that moment and the fix affects the changed code. There are
some more branches for work-in-progress features and special `coverity` branch for submitting
code for the [analysis in the Coverity tool](https://scan.coverity.com/projects/5259) usign
[Travis CI build](https://travis-ci.org/CESNET/libyang/branches).
When you create pull request, think carefully about the branch where the patch belongs to.
In most cases (if not all), it is the `devel` branch.
## Issue Ticketing
All the communication with the developers is done via [issue tracker](https://github.com/CESNET/libyang/issues).
You can send us an email, but in case you will ask a question we would think that someone else
could ask in future, our answer will be just **use the issue tracker**. Private emails are not visible
for others and we don't want to answer the same questions.
So when you are goingto submit a new issue, **please:**
* check that the issue you are having is not already solved in the devel branch,
* go through the present issues (in case of question, it can be already a closed issue) in the tracker,
* give it as descriptive title as possible,
* separate topics - solving multiple issues in one ticket hides the issues from others,
* provide as much relevant information as possible (versions, logs, input data, etc.).
## libyang Coding Style
When you are going to contribute C code, please follow these coding style guidelines.
### Basics
- Use space instead of tabs for indentations.
- There is no strict limit for the line length, However, try to keep lines in a
reasonable length (120 characters).
- Avoid trailing spaces on lines.
- Put one blank line between function definitions.
- Don't mix declarations and code within a block. Similarly, don't use
declarations in iteration statements.
### Naming
Use underscores to separate words in an identifier: `multi_word_name`.
Use lowercase for most names. Use uppercase for macros, macro parameters and
members of enumerations.
Do not use names that begin with `_`. If you need a name for "internal use
only", use `__` as a suffix instead of a prefix.
### Comments
Avoid `//` comments. Use `/* ... */` comments, write block comments with the
leading asterisk on each line. You may put the `/*` and `*/` on the same line as
comment text if you prefer.
```c
/*
* comment text
*/
```
### Functions
Put the return type, function name, and the braces that surround the function's
code on separate lines, all starting in column 0.
```c
static int
foo(int arg)
{
...
}
```
When you need to put the function parameters on multiple lines, start new line
at column after the opening parenthesis from the initial line.
```c
static int
my_function(struct my_struct *p1, struct another_struct *p2,
int size)
{
...
}
```
In the absence of good reasons for another order, the following parameter order
is preferred. One notable exception is that data parameters and their
corresponding size parameters should be paired.
1. The primary object being manipulated, if any (equivalent to the "this"
pointer in C++).
2. Input-only parameters.
3. Input/output parameters.
4. Output-only parameters.
5. Status parameter.
Functions that destroy an instance of a dynamically-allocated type should accept
and ignore a null pointer argument. Code that calls such a function (including
the C standard library function `free()`) should omit a null-pointer check. We
find that this usually makes code easier to read.
#### Function Prototypes
Put the return type and function name on the same line in a function prototype:
```c
static const struct int foo(int arg);
```
### Statements
- Indent each level of code with 4 spaces.
- Put single space between `if`, `while`, `for`, etc. statements and the
expression that follow them. On the other hand, function calls has no space
between the function name and opening parenthesis.
- Opening code block brace is kept at the same line with the `if`, `while`,
`for` or `switch` statements.
```c
if (a) {
x = exp(a);
} else {
return 1;
}
```
- Start switch's cases at the same column as the switch.
```c
switch (conn->state) {
case 0:
return "data found";
case 1:
return "data not found";
default:
return "unknown error";
}
```
- Do not put gratuitous parentheses around the expression in a return statement,
that is, write `return 0;` and not `return(0);`
### Types
Use typedefs sparingly. Code is clearer if the actual type is visible at the
point of declaration. Do not, in general, declare a typedef for a struct, union,
or enum. Do not declare a typedef for a pointer type, because this can be very
confusing to the reader.
Use the `int<N>_t` and `uint<N>_t` types from `<stdint.h>` for exact-width
integer types. Use the `PRId<N>`, `PRIu<N>`, and `PRIx<N>` macros from
`<inttypes.h>` for formatting them with `printf()` and related functions.
Pointer declarators bind to the variable name, not the type name. Write
`int *x`, not `int* x` and definitely not `int * x`.
### Expresions
Put one space on each side of infix binary and ternary operators:
```c
* / % + - << >> < <= > >= == != & ^ | && || ?: = += -= *= /= %= &= ^= |= <<= >>=
```
Do not put any white space around postfix, prefix, or grouping operators with
one exception - `sizeof`, see the note below.
```c
() [] -> . ! ~ ++ -- + - * &
```
The "sizeof" operator is unique among C operators in that it accepts two very
different kinds of operands: an expression or a type. In general, prefer to
specify an expression
```c
int *x = calloc(1, sizeof *x);
```
When the operand of sizeof is an expression, there is no need to parenthesize
that operand, and please don't. There is an exception to this rule when you need
to work with partially compatible structures:
```c
struct a_s {
uint8_t type;
}
struct b_s {
uint8_t type;
char *str;
}
struct c_s {
uint8_t type;
uint8_t *u8;
}
...
struct a_s *a;
switch (type) {
case 1:
a = (struct a_s *)calloc(1, sizeof(struct b_s));
break;
case 2:
a = (struct a_s *)calloc(1, sizeof(struct c_s));
break;
...
```

2457
Doxyfile.in Normal file

File diff suppressed because it is too large Load diff

89
FindLibYANG.cmake Normal file
View file

@ -0,0 +1,89 @@
# - Try to find LibYANG
# Once done this will define
#
# LIBYANG_FOUND - system has LibYANG
# LIBYANG_INCLUDE_DIRS - the LibYANG include directory
# LIBYANG_LIBRARIES - Link these to use LibYANG
# LIBYANG_VERSION - SO version of the found libyang library
#
# Author Michal Vasko <mvasko@cesnet.cz>
# Copyright (c) 2021 CESNET, z.s.p.o.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. The name of the author may not be used to endorse or promote products
# derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
include(FindPackageHandleStandardArgs)
if(LIBYANG_LIBRARIES AND LIBYANG_INCLUDE_DIRS)
# in cache already
set(LIBYANG_FOUND TRUE)
else()
find_path(LIBYANG_INCLUDE_DIR
NAMES
libyang/libyang.h
PATHS
/usr/include
/usr/local/include
/opt/local/include
/sw/include
${CMAKE_INCLUDE_PATH}
${CMAKE_INSTALL_PREFIX}/include
)
find_library(LIBYANG_LIBRARY
NAMES
yang
libyang
PATHS
/usr/lib
/usr/lib64
/usr/local/lib
/usr/local/lib64
/opt/local/lib
/sw/lib
${CMAKE_LIBRARY_PATH}
${CMAKE_INSTALL_PREFIX}/lib
)
if(LIBYANG_INCLUDE_DIR)
find_path(LY_VERSION_PATH "libyang/version.h" HINTS ${LIBYANG_INCLUDE_DIR})
if(LY_VERSION_PATH)
file(READ "${LY_VERSION_PATH}/libyang/version.h" LY_VERSION_FILE)
else()
find_path(LY_HEADER_PATH "libyang/libyang.h" HINTS ${LIBYANG_INCLUDE_DIR})
file(READ "${LY_HEADER_PATH}/libyang/libyang.h" LY_VERSION_FILE)
endif()
string(REGEX MATCH "#define LY_VERSION \"[0-9]+\\.[0-9]+\\.[0-9]+\"" LY_VERSION_MACRO "${LY_VERSION_FILE}")
string(REGEX MATCH "[0-9]+\\.[0-9]+\\.[0-9]+" LIBYANG_VERSION "${LY_VERSION_MACRO}")
endif()
set(LIBYANG_INCLUDE_DIRS ${LIBYANG_INCLUDE_DIR})
set(LIBYANG_LIBRARIES ${LIBYANG_LIBRARY})
mark_as_advanced(LIBYANG_INCLUDE_DIRS LIBYANG_LIBRARIES)
# handle the QUIETLY and REQUIRED arguments and set LIBYANG_FOUND to TRUE
# if all listed variables are TRUE
find_package_handle_standard_args(LibYANG FOUND_VAR LIBYANG_FOUND
REQUIRED_VARS LIBYANG_LIBRARY LIBYANG_INCLUDE_DIR
VERSION_VAR LIBYANG_VERSION)
endif()

28
LICENSE Normal file
View file

@ -0,0 +1,28 @@
Copyright (c) 2015-2024, CESNET
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of CESNET nor the names of
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

274
README.md Normal file
View file

@ -0,0 +1,274 @@
# libyang
[![BSD license](https://img.shields.io/badge/License-BSD-blue.svg)](https://opensource.org/licenses/BSD-3-Clause)
[![Build](https://github.com/CESNET/libyang/workflows/libyang%20CI/badge.svg)](https://github.com/CESNET/libyang/actions?query=workflow%3A%22libyang+CI%22)
[![Docs](https://img.shields.io/badge/docs-link-blue)](https://netopeer.liberouter.org/doc/libyang/)
[![Coverity Scan Build Status](https://scan.coverity.com/projects/5259/badge.svg)](https://scan.coverity.com/projects/5259)
[![codecov.io](https://codecov.io/github/CESNET/libyang/coverage.svg?branch=master)](https://codecov.io/github/CESNET/libyang?branch=master)
[![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/libyang.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:libyang)
[![Ohloh Project Status](https://www.openhub.net/p/libyang/widgets/project_thin_badge.gif)](https://www.openhub.net/p/libyang)
libyang is a YANG data modelling language parser and toolkit written (and
providing API) in C. The library is used e.g. in [libnetconf2](https://github.com/CESNET/libnetconf2),
[Netopeer2](https://github.com/CESNET/Netopeer2) or [sysrepo](https://github.com/sysrepo/sysrepo) projects.
## Branches
The project uses 2 main branches `master` and `devel`. Other branches should not be cloned. In `master` there are files of the
last official *release*. Any latest improvements and changes, which were tested at least briefly are found in `devel`. On every
new *release*, `devel` is merged into `master`.
This means that when only stable official releases are to be used, either `master` can be used or specific *releases* downloaded.
If all the latest bugfixes should be applied, `devel` branch is the one to be used. Note that whenever **a new issue is created**
and it occurs on the `master` branch, the **first response will likely be** to use `devel` before any further provided support.
## Migration from libyang version 1 or older
Look into the documentation and the section `Transition Manual`. That should help with basic migration and the
ability to compile a project. But to actually make use of the new features, it is required to read through
the whole documentation and the API.
## Provided Features
* Parsing (and validating) schemas in YANG format.
* Parsing (and validating) schemas in YIN format.
* Parsing, validating and printing instance data in XML format.
* Parsing, validating and printing instance data in JSON format
([RFC 7951](https://tools.ietf.org/html/rfc7951)).
* Manipulation with the instance data.
* Support for default values in the instance data ([RFC 6243](https://tools.ietf.org/html/rfc6243)).
* Support for YANG extensions.
* Support for YANG Metadata ([RFC 7952](https://tools.ietf.org/html/rfc7952)).
* Support for YANG Schema Mount ([RFC 8528](https://tools.ietf.org/html/rfc8528)).
* Support for YANG Structure ([RFC 8791](https://tools.ietf.org/html/rfc8791)).
* [yanglint](#yanglint) - feature-rich YANG tool.
Current implementation covers YANG 1.0 ([RFC 6020](https://tools.ietf.org/html/rfc6020))
as well as YANG 1.1 ([RFC 7950](https://tools.ietf.org/html/rfc7950)).
## Packages
Binary RPM or DEB packages of the latest release can be built locally using `apkg`, look into `README` in
the `distro` directory.
## Requirements
### Unix Build Requirements
* C compiler
* cmake >= 2.8.12
* libpcre2 >= 10.21 (including devel package)
* note, that PCRE is supposed to be compiled with unicode support (configure's options
`--enable-utf` and `--enable-unicode-properties`)
#### Optional
* doxygen (for generating documentation)
* cmocka >= 1.0.1 (for [tests](#Tests))
* valgrind (for enhanced testing)
* gcov (for code coverage)
* lcov (for code coverage)
* genhtml (for code coverage)
### Unix Runtime Requirements
* libpcre2 >= 10.21
### Windows Build Requirements
* Visual Studio 17 (2022)
* cmake >= 3.22.0
* libpcre2 (same considerations as on POSIX)
* [`pthreads-win32`](https://sourceware.org/pthreads-win32/)
* [`dirent`](https://github.com/tronkko/dirent)
* [`dlfcn-win32`](https://github.com/dlfcn-win32/dlfcn-win32)
* [`getopt-win32`](https://github.com/libimobiledevice-win32/getopt)
The Windows version [does not support plugins](https://github.com/CESNET/libyang/commit/323c31221645052e13db83f7d0e6e51c3ce9d802), and the `yanglint` works in a [non-interactive mode](https://github.com/CESNET/libyang/commit/2e3f935ed6f4a47e65b31de5aeebcd8877d5a09b) only.
On Windows, all YANG date-and-time values are first converted to UTC (if TZ offset was specified), and then returned with "unspecified timezone".
## Building
```
$ mkdir build; cd build
$ cmake ..
$ make
# make install
```
### Useful CMake Options
#### Changing Compiler
Set `CC` variable:
```
$ CC=/usr/bin/clang cmake ..
```
#### Changing Install Path
To change the prefix where the library, headers and any other files are installed,
set `CMAKE_INSTALL_PREFIX` variable:
```
$ cmake -DCMAKE_INSTALL_PREFIX:PATH=/usr ..
```
Default prefix is `/usr/local`.
#### Build Modes
There are two build modes:
* Release.
This generates library for the production use without any debug information.
* Debug.
This generates library with the debug information and disables optimization
of the code.
The `Debug` mode is currently used as the default one. to switch to the
`Release` mode, enter at the command line:
```
$ cmake -D CMAKE_BUILD_TYPE:String="Release" ..
```
#### Changing Extensions Plugins Directory
As for YANG extensions, libyang allows loading extension plugins. By default, the
directory to store the plugins is LIBDIR/libyang. To change it, use the following
cmake option with the value specifying the desired directory:
```
$ cmake -DPLUGINS_DIR:PATH=`pwd`"/src/extensions/" ..
```
The directory path can be also changed runtime via environment variable, e.g.:
```
$ LIBYANG_EXTENSIONS_PLUGINS_DIR=`pwd`/my/relative/path yanglint
```
Note that plugins are [not available on Windows](https://github.com/CESNET/libyang/commit/323c31221645052e13db83f7d0e6e51c3ce9d802).
#### Optimizations
Whenever the latest revision of a schema is supposed to be loaded (import without specific revision),
it is performed in the standard way, the first time. By default, every other time when the latest
revision of the same schema is needed, the one initially loaded is reused. If you know this can cause
problems meaning the latest available revision of a schema can change during operation, you can force
libyang to always search for the schema anew by:
```
$ cmake -DENABLE_LATEST_REVISIONS=OFF ..
```
### CMake Notes
Note that, with CMake, if you want to change the compiler or its options after
you already ran CMake, you need to clear its cache first - the most simple way
to do it is to remove all content from the 'build' directory.
## Usage
All libyang functions are available via the main header:
```
#include <libyang/libyang.h>
```
To compile your program with libyang, it is necessary to link it with libyang using the
following linker parameters:
```
-lyang
```
Note, that it may be necessary to call `ldconfig(8)` after library installation and if the
library was installed into a non-standard path, the path to libyang must be specified to the
linker. To help with setting all the compiler's options, there is `libyang.pc` file for
`pkg-config(1)` available in the source tree. The file is installed with the library.
If you are using `cmake` in you project, it is also possible to use the provided
`FindLibYANG.cmake` file to detect presence of the libyang library in the system.
## Bindings
There are no bindings for other languages directly in this project but they are
available separately.
* [Python](https://github.com/CESNET/libyang-python/)
* [C++](https://github.com/CESNET/libyang-cpp/)
* [Rust](https://github.com/holo-routing/yang2-rs/)
## yanglint
libyang project includes a feature-rich tool called `yanglint(1)` for validation
and conversion of the schemas and YANG modeled data. The source codes are
located at [`/tools/lint`](./tools/lint) and can be used to explore how an
application is supposed to use the libyang library. `yanglint(1)` binary as
well as its man page are installed together with the library itself.
There is also [README](./tools/lint/examples/README.md) describing some examples of
using `yanglint`.
## Tests
libyang includes several tests built with [cmocka](https://cmocka.org/). The tests
can be found in `tests` subdirectory and they are designed for checking library
functionality after code changes. Additional regression tests done with
a corpus of fuzzing inputs that previously caused crashes are done.
Those are available in `tests/fuzz` and are built automatically with the
cmocka unit tests.
The tests are by default built in the `Debug` build mode by running
```
$ make
```
In case of the `Release` mode, the tests are not built by default (it requires
additional dependency), but they can be enabled via cmake option:
```
$ cmake -DENABLE_TESTS=ON ..
```
Note that if the necessary [cmocka](https://cmocka.org/) headers are not present
in the system include paths, tests are not available despite the build mode or
cmake's options.
Tests can be run by the make's `test` target:
```
$ make test
```
### Perf
There is a performance measurement tool included that prints information about
the time required to execute common use-cases of working with YANG instance data.
To enable this test, use an option and to get representative results, enable Release build type:
```
$ cmake -DCMAKE_BUILD_TYPE=Release -DENABLE_PERF_TESTS=ON ..
```
and to run the test with seeing its output run:
```
$ make
$ ctest -V -R ly_perf
```
### Code Coverage
Based on the tests run, it is possible to generate code coverage report. But
it must be enabled and these commands are needed to generate the report:
```
$ cmake -DENABLE_COVERAGE=ON ..
$ make
$ make coverage
```
## Fuzzing
Multiple YANG fuzzing targets and fuzzing instructions are available in the
`tests/fuzz` directory.
All of the targets can be fuzzed with LLVM's LibFuzzer and AFL, and new targets
can easily be added.
Asciinema examples which describe the fuzzing setup for both AFL (https://asciinema.org/a/311060)
and LibFuzzer (https://asciinema.org/a/311035) are available.

31
codecov.yml Normal file
View file

@ -0,0 +1,31 @@
comment:
layout: header, changes, diff
coverage:
precision: 2
round: nearest
ignore:
- compat/.*
- tests/.*
status:
project:
default:
target: auto
if_no_uploads: error
patch:
default:
if_no_uploads: error
changes: true
parsers:
gcov:
branch_detection:
macro: no
loop: no
conditional: no
method: no

44
compat/check_includes.sh Executable file
View file

@ -0,0 +1,44 @@
#!/usr/bin/env bash
RETVAL=0
# params - paths to the source files to search
SRC="$*"
# param FUNC - name of the function in compat to check
check_compat_func () {
FILES=`grep -rE "([^[:alnum:]]|^)$1\([^\)]+\)" --include=\*.{c,h} $SRC | cut -d: -f1 | uniq`
for f in $FILES; do
grep -q "#include \"compat.h\"" $f
if [ $? -ne 0 ]; then
echo "Missing #include \"compat.h\" in file $f for function $1()"
RETVAL=$((RETVAL+1))
fi
done
}
check_compat_macro () {
FILES=`grep -rE "([^[:alnum:]]|^)$1([^[:alnum:]]|$)" --include=\*.{c,h} $SRC | cut -d: -f1 | uniq`
for f in $FILES; do
grep -q "#include \"compat.h\"" $f
if [ $? -ne 0 ]; then
echo "Missing #include \"compat.h\" in file $f for macro $1"
RETVAL=$((RETVAL+1))
fi
done
}
check_compat_func vdprintf
check_compat_func asprintf
check_compat_func vasprintf
check_compat_func getline
check_compat_func strndup
check_compat_func strnstr
check_compat_func strdupa
check_compat_func strchrnul
check_compat_func get_current_dir_name
check_compat_func pthread_mutex_timedlock
check_compat_func UNUSED
check_compat_macro _PACKED
exit $RETVAL

383
compat/compat.c Normal file
View file

@ -0,0 +1,383 @@
/**
* @file compat.c
* @author Michal Vasko <mvasko@cesnet.cz>
* @brief compatibility functions
*
* Copyright (c) 2021 CESNET, z.s.p.o.
*
* This source code is licensed under BSD 3-Clause License (the "License").
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*/
#define _POSIX_C_SOURCE 200809L /* fdopen, _POSIX_PATH_MAX, strdup */
#define _ISOC99_SOURCE /* vsnprintf */
#include "compat.h"
#include <errno.h>
#include <inttypes.h>
#include <limits.h>
#include <pthread.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef _MSC_VER
#include <sys/time.h>
#endif
#include <time.h>
#include <unistd.h>
#ifndef HAVE_VDPRINTF
int
vdprintf(int fd, const char *format, va_list ap)
{
FILE *stream;
int count = 0;
stream = fdopen(dup(fd), "a+");
if (stream) {
count = vfprintf(stream, format, ap);
fclose(stream);
}
return count;
}
#endif
#ifndef HAVE_ASPRINTF
int
asprintf(char **strp, const char *fmt, ...)
{
int ret;
va_list ap;
va_start(ap, fmt);
ret = vasprintf(strp, fmt, ap);
va_end(ap);
return ret;
}
#endif
#ifndef HAVE_VASPRINTF
int
vasprintf(char **strp, const char *fmt, va_list ap)
{
va_list ap2;
va_copy(ap2, ap);
int l = vsnprintf(0, 0, fmt, ap2);
va_end(ap2);
if ((l < 0) || !(*strp = malloc(l + 1U))) {
return -1;
}
return vsnprintf(*strp, l + 1U, fmt, ap);
}
#endif
#ifndef HAVE_GETLINE
ssize_t
getline(char **lineptr, size_t *n, FILE *stream)
{
static char chunk[256];
char *ptr;
ssize_t len, written;
if (!lineptr || !n) {
errno = EINVAL;
return -1;
}
if (ferror(stream) || feof(stream)) {
return -1;
}
*n = *lineptr ? *n : 0;
written = 0;
while (fgets(chunk, sizeof(chunk), stream)) {
len = strlen(chunk);
if ((size_t)(written + len) > *n) {
ptr = realloc(*lineptr, *n + sizeof(chunk));
if (!ptr) {
return -1;
}
*lineptr = ptr;
*n = *n + sizeof(chunk);
}
memcpy(*lineptr + written, &chunk, len);
written += len;
if ((*lineptr)[written - 1] == '\n') {
break;
}
}
if (written) {
(*lineptr)[written] = '\0';
} else {
written = -1;
}
return written;
}
#endif
#ifndef HAVE_STRNDUP
char *
strndup(const char *s, size_t n)
{
char *buf;
size_t len = 0;
/* strnlen */
for ( ; (len < n) && (s[len] != '\0'); ++len) {}
if (!(buf = malloc(len + 1U))) {
return NULL;
}
memcpy(buf, s, len);
buf[len] = '\0';
return buf;
}
#endif
#ifndef HAVE_STRNSTR
char *
strnstr(const char *s, const char *find, size_t slen)
{
char c, sc;
size_t len;
if ((c = *find++) != '\0') {
len = strlen(find);
do {
do {
if ((slen-- < 1) || ((sc = *s++) == '\0')) {
return NULL;
}
} while (sc != c);
if (len > slen) {
return NULL;
}
} while (strncmp(s, find, len));
s--;
}
return (char *)s;
}
#endif
#ifndef HAVE_STRCHRNUL
char *
strchrnul(const char *s, int c)
{
char *p = strchr(s, c);
return p ? p : (char *)s + strlen(s);
}
#endif
#ifndef HAVE_GET_CURRENT_DIR_NAME
char *
get_current_dir_name(void)
{
char tmp[_POSIX_PATH_MAX];
char *retval = NULL;
if (getcwd(tmp, sizeof(tmp))) {
retval = strdup(tmp);
if (!retval) {
errno = ENOMEM;
}
}
return retval;
}
#endif
#ifndef _MSC_VER
#ifndef HAVE_PTHREAD_MUTEX_TIMEDLOCK
int
pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec *abstime)
{
int64_t nsec_diff;
int32_t diff;
struct timespec cur, dur;
int rc;
/* try to acquire the lock and, if we fail, sleep for 5ms. */
while ((rc = pthread_mutex_trylock(mutex)) == EBUSY) {
/* get real time */
#ifdef CLOCK_REALTIME
clock_gettime(CLOCK_REALTIME, &cur);
#else
struct timeval tv;
gettimeofday(&tv, NULL);
cur.tv_sec = (time_t)tv.tv_sec;
cur.tv_nsec = 1000L * (long)tv.tv_usec;
#endif
/* get time diff */
nsec_diff = 0;
nsec_diff += (((int64_t)abstime->tv_sec) - ((int64_t)cur.tv_sec)) * 1000000000L;
nsec_diff += ((int64_t)abstime->tv_nsec) - ((int64_t)cur.tv_nsec);
diff = (nsec_diff ? nsec_diff / 1000000L : 0);
if (diff < 1) {
/* timeout */
break;
} else if (diff < 5) {
/* sleep until timeout */
dur.tv_sec = 0;
dur.tv_nsec = (long)diff * 1000000;
} else {
/* sleep 5 ms */
dur.tv_sec = 0;
dur.tv_nsec = 5000000;
}
nanosleep(&dur, NULL);
}
return rc;
}
#endif
#endif
#ifndef HAVE_REALPATH
#ifdef _WIN32
char *
realpath(const char *path, char *resolved_path)
{
char *resolved = _fullpath(resolved_path, path, PATH_MAX);
if ((_access(resolved, 0) == -1) && (errno == ENOENT)) {
return NULL;
}
return resolved;
}
#elif defined (__NetBSD__)
char *
realpath(const char *path, char *resolved_path)
{
ssize_t nbytes;
nbytes = readlink(path, resolved_path, PATH_MAX);
if (nbytes == -1) {
return NULL;
}
return resolved_path;
}
#else
#error No realpath() implementation for this platform is available.
#endif
#endif
#ifndef HAVE_LOCALTIME_R
#ifdef _WIN32
struct tm *
localtime_r(const time_t *timep, struct tm *result)
{
errno_t res = localtime_s(result, timep);
if (res) {
return NULL;
} else {
return result;
}
}
#else
#error No localtime_r() implementation for this platform is available.
#endif
#endif
#ifndef HAVE_GMTIME_R
#ifdef _WIN32
struct tm *
gmtime_r(const time_t *timep, struct tm *result)
{
errno_t res = gmtime_s(result, timep);
if (res) {
return NULL;
} else {
return result;
}
}
#else
#error No gmtime_r() implementation for this platform is available.
#endif
#endif
#ifndef HAVE_TIMEGM
time_t
timegm(struct tm *tm)
{
pthread_mutex_t tz_lock = PTHREAD_MUTEX_INITIALIZER;
time_t ret;
char *tz;
pthread_mutex_lock(&tz_lock);
tz = getenv("TZ");
if (tz) {
tz = strdup(tz);
}
setenv("TZ", "", 1);
tzset();
ret = mktime(tm);
if (tz) {
setenv("TZ", tz, 1);
free(tz);
} else {
unsetenv("TZ");
}
tzset();
pthread_mutex_unlock(&tz_lock);
return ret;
}
#endif
#ifndef HAVE_SETENV
#ifdef _WIN32
int
setenv(const char *name, const char *value, int overwrite)
{
int errcode = 0;
if (!overwrite) {
size_t envsize = 0;
errcode = getenv_s(&envsize, NULL, 0, name);
if (errcode || envsize) {
return errcode;
}
}
return _putenv_s(name, value);
}
#else
#error No setenv() implementation for this platform is available.
#endif
#endif

215
compat/compat.h.in Normal file
View file

@ -0,0 +1,215 @@
/**
* @file compat.h
* @author Michal Vasko <mvasko@cesnet.cz>
* @brief compatibility functions header
*
* Copyright (c) 2021 - 2023 CESNET, z.s.p.o.
*
* This source code is licensed under BSD 3-Clause License (the "License").
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*/
#ifndef _COMPAT_H_
#define _COMPAT_H_
#ifdef _WIN32
/* headers are broken on Windows, which means that some of them simply *have* to come first */
# include <winsock2.h>
# include <ws2tcpip.h>
#endif
#include <limits.h>
#include <pthread.h>
#include <stdarg.h>
#include <stdio.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#ifndef __WORDSIZE
# if defined __x86_64__ && !defined __ILP32__
# define __WORDSIZE 64
# else
# define __WORDSIZE 32
# endif
#endif
#ifndef __INT64_C
# if __WORDSIZE == 64
# define __INT64_C(c) c ## L
# define __UINT64_C(c) c ## UL
# else
# define __INT64_C(c) c ## LL
# define __UINT64_C(c) c ## ULL
# endif
#endif
#if defined (__GNUC__) || defined (__llvm__)
# define UNUSED(x) UNUSED_ ## x __attribute__((__unused__))
# define _PACKED __attribute__((__packed__))
#else
# define UNUSED(x) UNUSED_ ## x
# define _PACKED
#endif
#cmakedefine HAVE_VDPRINTF
#cmakedefine HAVE_ASPRINTF
#cmakedefine HAVE_VASPRINTF
#cmakedefine HAVE_GETLINE
#cmakedefine HAVE_STRNDUP
#cmakedefine HAVE_STRNSTR
#cmakedefine HAVE_STRDUPA
#cmakedefine HAVE_STRCHRNUL
#cmakedefine HAVE_GET_CURRENT_DIR_NAME
#cmakedefine HAVE_PTHREAD_MUTEX_TIMEDLOCK
#cmakedefine HAVE_REALPATH
#cmakedefine HAVE_LOCALTIME_R
#cmakedefine HAVE_GMTIME_R
#cmakedefine HAVE_TIMEGM
#cmakedefine HAVE_STRPTIME
#cmakedefine HAVE_MMAP
#cmakedefine HAVE_STRCASECMP
#cmakedefine HAVE_SETENV
#ifndef bswap64
#define bswap64(val) \
( (((val) >> 56) & 0x00000000000000FF) | (((val) >> 40) & 0x000000000000FF00) | \
(((val) >> 24) & 0x0000000000FF0000) | (((val) >> 8) & 0x00000000FF000000) | \
(((val) << 8) & 0x000000FF00000000) | (((val) << 24) & 0x0000FF0000000000) | \
(((val) << 40) & 0x00FF000000000000) | (((val) << 56) & 0xFF00000000000000) )
#endif
#undef le64toh
#undef htole64
#cmakedefine IS_BIG_ENDIAN
#ifdef IS_BIG_ENDIAN
# define le64toh(x) bswap64(x)
# define htole64(x) bswap64(x)
#else
# define le64toh(x) (x)
# define htole64(x) (x)
#endif
#cmakedefine HAVE_STDATOMIC
#ifdef HAVE_STDATOMIC
# include <stdatomic.h>
# define ATOMIC_T atomic_uint_fast32_t
# define ATOMIC_T_MAX UINT_FAST32_MAX
# define ATOMIC_STORE_RELAXED(var, x) atomic_store_explicit(&(var), x, memory_order_relaxed)
# define ATOMIC_LOAD_RELAXED(var) atomic_load_explicit(&(var), memory_order_relaxed)
# define ATOMIC_INC_RELAXED(var) atomic_fetch_add_explicit(&(var), 1, memory_order_relaxed)
# define ATOMIC_ADD_RELAXED(var, x) atomic_fetch_add_explicit(&(var), x, memory_order_relaxed)
# define ATOMIC_DEC_RELAXED(var) atomic_fetch_sub_explicit(&(var), 1, memory_order_relaxed)
# define ATOMIC_SUB_RELAXED(var, x) atomic_fetch_sub_explicit(&(var), x, memory_order_relaxed)
#else
# include <stdint.h>
# define ATOMIC_T uint32_t
# define ATOMIC_T_MAX UINT32_MAX
# define ATOMIC_STORE_RELAXED(var, x) ((var) = (x))
# define ATOMIC_LOAD_RELAXED(var) (var)
# ifndef _WIN32
# define ATOMIC_INC_RELAXED(var) __sync_fetch_and_add(&(var), 1)
# define ATOMIC_ADD_RELAXED(var, x) __sync_fetch_and_add(&(var), x)
# define ATOMIC_DEC_RELAXED(var) __sync_fetch_and_sub(&(var), 1)
# define ATOMIC_SUB_RELAXED(var, x) __sync_fetch_and_sub(&(var), x)
# else
# include <windows.h>
# define ATOMIC_INC_RELAXED(var) InterlockedExchangeAdd(&(var), 1)
# define ATOMIC_ADD_RELAXED(var, x) InterlockedExchangeAdd(&(var), x)
# define ATOMIC_DEC_RELAXED(var) InterlockedExchangeAdd(&(var), -1)
# define ATOMIC_SUB_RELAXED(var, x) InterlockedExchangeAdd(&(var), -(x))
# endif
#endif
#ifndef HAVE_VDPRINTF
int vdprintf(int fd, const char *format, va_list ap);
#endif
#ifndef HAVE_ASPRINTF
int asprintf(char **strp, const char *fmt, ...);
#endif
#ifndef HAVE_VASPRINTF
int vasprintf(char **strp, const char *fmt, va_list ap);
#endif
#ifndef HAVE_GETLINE
ssize_t getline(char **lineptr, size_t *n, FILE *stream);
#endif
#ifndef HAVE_STRNDUP
char *strndup(const char *s, size_t n);
#endif
#ifndef HAVE_STRNSTR
char *strnstr(const char *s, const char *find, size_t slen);
#endif
#ifndef HAVE_STRDUPA
#define strdupa(s) ( \
{ \
char *buf; \
size_t len = strlen(s); \
buf = alloca(len + 1); \
buf[len] = '\0'; \
(char *)memcpy(buf, s, len); \
})
#endif
#ifndef HAVE_STRCHRNUL
char *strchrnul(const char *s, int c);
#endif
#ifndef HAVE_GET_CURRENT_DIR_NAME
char *get_current_dir_name(void);
#endif
#ifndef HAVE_PTHREAD_MUTEX_TIMEDLOCK
int pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec *abstime);
#endif
#ifndef HAVE_REALPATH
char *realpath(const char *path, char *resolved_path);
#endif
#ifndef HAVE_LOCALTIME_R
struct tm *localtime_r(const time_t *timep, struct tm *result);
#endif
#ifndef HAVE_GMTIME_R
struct tm *gmtime_r(const time_t *timep, struct tm *result);
#endif
#ifndef HAVE_TIMEGM
# ifdef _WIN32
# define timegm _mkgmtime
# define HAVE_TIMEGM
# else
time_t timegm(struct tm *tm);
# endif
#endif
#ifndef HAVE_STRPTIME
char *strptime(const char *s, const char *format, struct tm *tm);
#endif
#ifdef _WIN32
# define strtok_r strtok_s
#endif
#ifndef HAVE_SETENV
int setenv(const char *name, const char *value, int overwrite);
#endif
#endif /* _COMPAT_H_ */

View file

@ -0,0 +1 @@
char *dirname(char *path);

View file

@ -0,0 +1,17 @@
#include <compat.h>
#ifndef HAVE_STRCASECMP
#ifdef _MSC_VER
#define strcasecmp _stricmp
#else
#error No strcasecmp() implementation for this platform is available.
#endif
#endif
#ifndef HAVE_STRNCASECMP
#ifdef _MSC_VER
#define strncasecmp _strnicmp
#else
#error No strncasecmp() implementation for this platform is available.
#endif
#endif

View file

@ -0,0 +1,78 @@
#ifndef _UNISTD_H
#define _UNISTD_H 1
/* headers are broken on Windows, which means that some of them simply *have* to come first */
# include <winsock2.h>
# include <ws2tcpip.h>
/* This is intended as a drop-in replacement for unistd.h on Windows.
* Please add functionality as neeeded.
* https://stackoverflow.com/a/826027/1202830
*/
#include <stdlib.h>
#include <io.h>
#include <process.h> /* for getpid() and the exec..() family */
#include <direct.h> /* for _getcwd() and _chdir() */
#define srandom srand
#define random rand
/* Values for the second argument to access.
These may be OR'd together. */
#define R_OK 4 /* Test for read permission. */
#define W_OK 2 /* Test for write permission. */
#define X_OK 0 /* jkt: unsupported on Windows, so we don't really care */
#define F_OK 0 /* Test for existence. */
#define access _access
#define dup2 _dup2
#define execve _execve
#define ftruncate _chsize
#define unlink _unlink
#define fileno _fileno
#define getcwd _getcwd
#define chdir _chdir
#define isatty _isatty
#define lseek _lseek
#define fsync _commit
#define timegm _mkgmtime
/* read, write, and close are NOT being #defined here, because while there are file handle specific versions for Windows, they probably don't work for sockets. You need to look at your app and consider whether to call e.g. closesocket(). */
#define ssize_t SSIZE_T
#define STDIN_FILENO 0
#define STDOUT_FILENO 1
#define STDERR_FILENO 2
/* should be in some equivalent to <sys/types.h> */
typedef __int8 int8_t;
typedef __int16 int16_t;
typedef __int32 int32_t;
typedef __int64 int64_t;
typedef unsigned __int8 uint8_t;
typedef unsigned __int16 uint16_t;
typedef unsigned __int32 uint32_t;
typedef unsigned __int64 uint64_t;
#include <windows.h>
#ifndef PATH_MAX
#define PATH_MAX MAX_PATH
#endif
#ifndef _POSIX_PATH_MAX
#define _POSIX_PATH_MAX 256
#endif
#ifndef S_ISREG
# define S_ISREG(m) (((m) & _S_IFMT) == _S_IFREG)
#endif
#ifndef S_ISDIR
# define S_ISDIR(m) (((m) & _S_IFMT) == _S_IFDIR)
#endif
#ifndef S_IRUSR
# define S_IRUSR _S_IREAD
#endif
#ifndef S_IWUSR
# define S_IWUSR _S_IWRITE
#endif
#endif /* unistd.h */

214
compat/strptime.c Normal file
View file

@ -0,0 +1,214 @@
/*
* This comes from the musl C library which has been licensed under the permissive MIT license.
*
* Downloaded from https://git.musl-libc.org/cgit/musl/plain/src/time/strptime.c,
* commit 98e688a9da5e7b2925dda17a2d6820dddf1fb287.
*
* Lobotomized to remove references to nl_langinfo().
* Adjusted coding style to fit libyang's uncrustify rules.
* */
#include <ctype.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
char *
strptime(const char * restrict s, const char * restrict f, struct tm * restrict tm)
{
int i, w, neg, adj, min, range, *dest, dummy;
int want_century = 0, century = 0, relyear = 0;
while (*f) {
if (*f != '%') {
if (isspace(*f)) {
for ( ; *s && isspace(*s); s++) {}
} else if (*s != *f) {
return 0;
} else {
s++;
}
f++;
continue;
}
f++;
if (*f == '+') {
f++;
}
if (isdigit(*f)) {
char *new_f;
w = strtoul(f, &new_f, 10);
f = new_f;
} else {
w = -1;
}
adj = 0;
switch (*f++) {
case 'a':
case 'A':
case 'b':
case 'B':
case 'h':
case 'c':
goto fail_nl_langinfo;
case 'C':
dest = &century;
if (w < 0) {
w = 2;
}
want_century |= 2;
goto numeric_digits;
case 'd':
case 'e':
dest = &tm->tm_mday;
min = 1;
range = 31;
goto numeric_range;
case 'D':
s = strptime(s, "%m/%d/%y", tm);
if (!s) {
return 0;
}
break;
case 'H':
dest = &tm->tm_hour;
min = 0;
range = 24;
goto numeric_range;
case 'I':
dest = &tm->tm_hour;
min = 1;
range = 12;
goto numeric_range;
case 'j':
dest = &tm->tm_yday;
min = 1;
range = 366;
adj = 1;
goto numeric_range;
case 'm':
dest = &tm->tm_mon;
min = 1;
range = 12;
adj = 1;
goto numeric_range;
case 'M':
dest = &tm->tm_min;
min = 0;
range = 60;
goto numeric_range;
case 'n':
case 't':
for ( ; *s && isspace(*s); s++) {}
break;
case 'p':
case 'r':
goto fail_nl_langinfo;
case 'R':
s = strptime(s, "%H:%M", tm);
if (!s) {
return 0;
}
break;
case 'S':
dest = &tm->tm_sec;
min = 0;
range = 61;
goto numeric_range;
case 'T':
s = strptime(s, "%H:%M:%S", tm);
if (!s) {
return 0;
}
break;
case 'U':
case 'W':
/* Throw away result, for now. (FIXME?) */
dest = &dummy;
min = 0;
range = 54;
goto numeric_range;
case 'w':
dest = &tm->tm_wday;
min = 0;
range = 7;
goto numeric_range;
case 'x':
case 'X':
goto fail_nl_langinfo;
case 'y':
dest = &relyear;
w = 2;
want_century |= 1;
goto numeric_digits;
case 'Y':
dest = &tm->tm_year;
if (w < 0) {
w = 4;
}
adj = 1900;
want_century = 0;
goto numeric_digits;
case '%':
if (*s++ != '%') {
return 0;
}
break;
default:
return 0;
numeric_range:
if (!isdigit(*s)) {
return 0;
}
*dest = 0;
for (i = 1; i <= min + range && isdigit(*s); i *= 10) {
*dest = *dest * 10 + *s++ - '0';
}
if (*dest - min >= range) {
return 0;
}
*dest -= adj;
switch ((char *)dest - (char *)tm) {
case offsetof(struct tm, tm_yday):
;
}
goto update;
numeric_digits:
neg = 0;
if (*s == '+') {
s++;
} else if (*s == '-') {
neg = 1, s++;
}
if (!isdigit(*s)) {
return 0;
}
for (*dest = i = 0; i < w && isdigit(*s); i++) {
*dest = *dest * 10 + *s++ - '0';
}
if (neg) {
*dest = -*dest;
}
*dest -= adj;
goto update;
update:
// FIXME
;
}
}
if (want_century) {
tm->tm_year = relyear;
if (want_century & 2) {
tm->tm_year += century * 100 - 1900;
} else if (tm->tm_year <= 68) {
tm->tm_year += 100;
}
}
return (char *)s;
fail_nl_langinfo:
fprintf(stderr, "strptime: nl_langinfo not available");
return NULL;
}

9
distro/README.md Normal file
View file

@ -0,0 +1,9 @@
# upstream packaging
## RPM-based system (Fedora, CentOS, SUSE, ...) quickstart
```
sudo dnf install -y git rpm-build python3-pip
pip3 install apkg
apkg build -i
```
See apkg docs: https://pkg.labs.nic.cz/pages/apkg/

10
distro/config/apkg.toml Normal file
View file

@ -0,0 +1,10 @@
[project]
name = "libyang"
make_archive_script = "distro/scripts/make-archive.sh"
[upstream]
archive_url = "https://github.com/CESNET/libyang/archive/v{{ version }}/libyang-{{ version }}.tar.gz"
version_script = "distro/scripts/upstream-version.sh"
[apkg]
compat = 2

View file

@ -0,0 +1,38 @@
Debian packaging for libyang
============================
Where to file issues
--------------------
Please file issues on the Debian BTS as usual. You could also open issues
on github, but if it's something about the Debian packaging it's better to
stick with the proper Debian ways. The Debian BTS is where other people
involved with Debian go look for bugs regarding a package, so that's where
they should be.
Building straight off git
-------------------------
Just the normal:
```
git clone https://github.com/CESNET/libyang -b debian/master
cd libyang
dpkg-buildpackage
```
Building a Debian .dsc
----------------------
Again, pretty much the normal:
```
git clone https://github.com/CESNET/libyang -b debian/master
wget -Olibyang_0.16.105.orig.tar.gz https://github.com/CESNET/libyang/archive/v0.16-r3.tar.gz
cd libyang
dpkg-source -b .
```
(Note the diverging release numbering though.)
-- Ondřej Surý <Ondřej Surý <ondrej@debian.org>>, Fri, 22 May 2020 11:10:55 +0200

View file

@ -0,0 +1,66 @@
This module uses gbp and upstream git repository
To update this package, first import the changes from upstream:
- git fetch --all
Find the latest version:
VERSION=$(git describe --tags $(git rev-list '--tags=v2*' --max-count=1) | sed 's/^v//')
echo $VERSION
Update debian/sid branch
- git checkout debian/master
- git merge v$VERSION
Update the debian/copyright file:
- cme update dpkg-copyright
See also https://github.com/dod38fr/config-model/wiki/Updating-debian-copyright-file-with-cme
Check patches (and cleanup if necessary):
- gbp pq rebase --commit --drop
Download upstream tarball:
- uscan --download --verbose --download-version $VERSION
Add pristine-tar:
- pristine-tar commit ../libyang_$VERSION.orig.tar.gz v$VERSION
Generate a temporary changelog:
- gbp dch --new-version=$VERSION-1 --snapshot --auto --commit debian/
Test the first build::
- gbp buildpackage --git-ignore-new --git-pristine-tar --git-no-purge
Regenerate the symbol file (See https://qt-kde-team.pages.debian.net/symbolfiles.html)
- pkgkde-symbolshelper batchpatch -v $VERSION < <path_to>/buildlog
See https://www.debian.org/doc/manuals/maint-guide/advanced.en.html#librarysymbols
and dpkg-gensymbols man page
Update the changelog:
- gbp dch -Ra -c
Once everything is fine, build a source package and tag:
- gbp buildpackage -S --git-tag
Push on salsa:
- gbp push
For more details, see
https://honk.sigxcpu.org/projects/git-buildpackage/manual-html/gbp.import.upstream-git.html#gbp.import.upstream.git.notarball
Maintainer Notes (moved from README.md)
=======================================
* the project version number is actually the SO ABI version. The release
point numbers (0.16-r3) isn't used for Debian.
* it's intentional that the SONAME is libyang.so.0.16 and not libyang.so.0.
ABI compatibility is indicated by the first two numbers being equal;
the third number is incremented for compatible changes. cf.
CESNET/libyang#656
* the watch file doesn't work yet but the libyang people agreed to make
future release tags the same as the internal version number. At that point
the watch file will work.
-- Ondřej Surý <Ondřej Surý <ondrej@debian.org>>, Tue, 21 Jul 2020 16:31:52 +0200

5
distro/pkg/deb/changelog Normal file
View file

@ -0,0 +1,5 @@
libyang3 ({{ version }}-{{ release }}) unstable; urgency=medium
* upstream packaging
-- Ondřej Surý <ondrej@debian.org> Tue, 04 May 2021 22:20:03 +0200

1
distro/pkg/deb/compat Normal file
View file

@ -0,0 +1 @@
10

73
distro/pkg/deb/control Normal file
View file

@ -0,0 +1,73 @@
Source: libyang3
Section: libs
Homepage: https://github.com/CESNET/libyang/
Maintainer: Ondřej Surý <ondrej@debian.org>
Priority: optional
Standards-Version: 4.5.0
Build-Depends: cmake,
debhelper (>= 10),
libcmocka-dev <!nocheck>,
libpcre2-dev,
pkg-config
Vcs-Browser: https://github.com/CESNET/libyang/tree/master
Vcs-Git: https://github.com/CESNET/libyang.git
Package: libyang3
Depends: ${misc:Depends},
${shlibs:Depends}
Architecture: any
Multi-Arch: same
Description: parser toolkit for IETF YANG data modeling - runtime
Libyang implements functions to process schemas expressed in the
YANG data modeling language defined by the IETF in RFCs 6020/7950.
Schemas expressed in this language primarily describe configuration
used by larger network equipment like routers and switches.
.
In addition to handling the schemas itself, the library also provides
functions to process data described by the schemas.
.
The library is implemented in C and provides an API for other software
to use in processing configurations.
Package: libyang-dev
Depends: libpcre2-dev,
libyang3 (= ${binary:Version}),
${misc:Depends}
Conflicts: libyang2-dev
Section: libdevel
Architecture: any
Multi-Arch: same
Description: parser toolkit for IETF YANG data modeling - development files
Libyang implements functions to process schemas expressed in the
YANG data modeling language defined by the IETF in RFCs 6020/7950.
Schemas expressed in this language primarily describe configuration
used by larger network equipment like routers and switches.
.
In addition to handling the schemas itself, the library also provides
functions to process data described by the schemas.
.
This package contains the C headers, a pkgconfig file, and .so entry point
for libyang.
Package: libyang-tools
Depends: libyang3 (= ${binary:Version}),
${misc:Depends},
${shlibs:Depends}
Breaks: libyang2-tools (<< ${source:Version})
Replaces: libyang2-tools (<< ${source:Version})
Section: devel
Architecture: any
Multi-Arch: foreign
Description: parser toolkit for IETF YANG data modeling - executable tools
This package provides the "yanglint" and "yangre" tools which can be used
during the creation of IETF YANG schemas. The tools are not generally
useful for normal operation where libyang primarily processes configuration
data, not schemas.
Package: libyang-modules
Section: devel
Architecture: all
Description: parser toolkit for IETF YANG data modeling - YANG modules
This package provides the IETF YANG modules used by libyang. These modules
are embedded into libyang so this package is not necessary for libyang
operation.

79
distro/pkg/deb/copyright Normal file
View file

@ -0,0 +1,79 @@
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: libyang
License: BSD-3-clause
Files: *
Copyright: 2015-2021 by CESNET, z.s.p.o.
License: BSD-3-clause
Files: */iana-*.yin */iana-*.yang */ietf-*.yin */ietf-*.yang */ietf-*.h
Copyright: 2011-2018 by the IETF Trust and the persons identified as authors
License: IETF-BSD-3-clause
Redistribution and use in source and binary forms, with or
without modification, is permitted pursuant to, and subject
to the license terms contained in, the Simplified BSD
License set forth in Section 4.c of the IETF Trust's
Legal Provisions Relating to IETF Documents
(http://trustee.ietf.org/license-info).
.
This version of this YANG module is part of RFC 6536; see
the RFC itself for full legal notices.
Files: tools/lint/linenoise/*
Copyright:
Copyright (c) 2010-2014, Salvatore Sanfilippo <antirez at gmail dot com>
Copyright (c) 2010-2013, Pieter Noordhuis <pcnoordhuis at gmail dot com>
License: BSD-2-clause
All rights reserved.
.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
.
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Files: debian/*
Copyright: 2018 by David Lamparter
2020-2021 Ondřej Surý
License: BSD-3-clause
License: BSD-3-clause
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
.
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
.
* Neither the name of libyang nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

4
distro/pkg/deb/gbp.conf Normal file
View file

@ -0,0 +1,4 @@
[DEFAULT]
pristine-tar = False
debian-branch = master
upstream-tree = SLOPPY

View file

@ -0,0 +1,3 @@
usr/include/libyang/*.h
usr/lib/*/*.so
usr/lib/*/pkgconfig/*.pc

View file

@ -0,0 +1 @@
usr/share/yang/modules/libyang

View file

@ -0,0 +1 @@
tools/lint/examples/*

View file

@ -0,0 +1,3 @@
usr/bin/yanglint
usr/bin/yangre
usr/share/man/man1

View file

@ -0,0 +1 @@
usr/lib/*/*.so.*

12
distro/pkg/deb/rules Executable file
View file

@ -0,0 +1,12 @@
#!/usr/bin/make -f
#export DH_VERBOSE=1
export DEB_BUILD_MAINT_OPTIONS = hardening=+all
include /usr/share/dpkg/default.mk
%:
dh $@
override_dh_auto_configure:
dh_auto_configure -- \
-DCMAKE_BUILD_TYPE:String="Release"

View file

@ -0,0 +1 @@
3.0 (quilt)

View file

@ -0,0 +1,3 @@
Tests: yanglint
Depends: gzip,
libyang-tools

18
distro/pkg/deb/tests/yanglint Executable file
View file

@ -0,0 +1,18 @@
#!/bin/sh
set -e
# Setup the test file
trap 'rm -f "${TESTFILE}"; rmdir "${TESTDIR}"' EXIT
TESTDIR=$(mktemp -d /tmp/yanglint.XXXXXX)
TESTFILE="${TESTDIR}/ietf-interfaces.yang"
# Unpack or copy the test file
if test -f /usr/share/doc/libyang-tools/examples/ietf-interfaces.yang.gz; then
gunzip -c < /usr/share/doc/libyang-tools/examples/ietf-interfaces.yang.gz > "${TESTFILE}"
else
cp /usr/share/doc/libyang-tools/examples/ietf-interfaces.yang "${TESTFILE}"
fi
# Lint the test file
yanglint "${TESTFILE}"

4
distro/pkg/deb/watch Normal file
View file

@ -0,0 +1,4 @@
version=4
opts="filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%libyang-$1.tar.gz%" \
https://github.com/CESNET/libyang/releases \
(?:.*?/)?v?(\d[\d.]*)(?:-r\d+)?\.tar\.gz debian uupdate

125
distro/pkg/rpm/libyang.spec Normal file
View file

@ -0,0 +1,125 @@
%if 0%{?rhel} == 8
%undefine __cmake_in_source_build
%endif
Name: libyang
Version: {{ version }}
Release: {{ release }}%{?dist}
Summary: YANG data modeling language library
Url: https://github.com/CESNET/libyang
Source: %{url}/archive/v%{version}/%{name}-%{version}.tar.gz
License: BSD
BuildRequires: cmake
BuildRequires: doxygen
BuildRequires: gcc
BuildRequires: cmake(cmocka) >= 1.0.1
BuildRequires: make
BuildRequires: pkgconfig(libpcre2-8) >= 10.21
%package modules
Summary: YANG modules for libyang
%package devel
Summary: Development files for libyang
Requires: %{name}%{?_isa} = %{version}-%{release}
Requires: pcre2-devel
%package devel-doc
Summary: Documentation of libyang API
Requires: %{name}%{?_isa} = %{version}-%{release}
%package tools
Summary: YANG validator tools
Requires: %{name}%{?_isa} = %{version}-%{release}
# This was not properly split out before
Conflicts: %{name} < 1.0.225-3
%description modules
YANG modules for libyang.
%description devel
Headers of libyang library.
%description devel-doc
Documentation of libyang API.
%description tools
YANG validator tools.
%description
Libyang is YANG data modeling language parser and toolkit
written (and providing API) in C.
%prep
%autosetup -p1
%if 0%{?rhel} && 0%{?rhel} < 8
mkdir build
%endif
%build
%if 0%{?rhel} && 0%{?rhel} < 8
cd build
cmake \
-DCMAKE_INSTALL_PREFIX:PATH=%{_prefix} \
-DCMAKE_BUILD_TYPE:String="Release" \
-DCMAKE_C_FLAGS="${RPM_OPT_FLAGS}" \
-DCMAKE_CXX_FLAGS="${RPM_OPT_FLAGS}" \
..
make
%else
%cmake -DCMAKE_BUILD_TYPE=RELWITHDEBINFO
%cmake_build
%if "x%{?suse_version}" == "x"
cd %{__cmake_builddir}
%endif
%endif
make doc
%check
%if ( 0%{?rhel} == 0 ) || 0%{?rhel} > 7
%if "x%{?suse_version}" == "x"
cd %{__cmake_builddir}
%endif
%endif
ctest --output-on-failure -V %{?_smp_mflags}
%install
mkdir -m0755 -p %{buildroot}/%{_docdir}/libyang
%if 0%{?rhel} && 0%{?rhel} < 8
cd build
make DESTDIR=%{buildroot} install
%else
%cmake_install
cp -a doc/html %{buildroot}/%{_docdir}/libyang/html
%endif
%files
%license LICENSE
%{_libdir}/libyang.so.3
%{_libdir}/libyang.so.3.*
%files modules
%{_datadir}/yang/modules/libyang/*.yang
%dir %{_datadir}/yang/
%dir %{_datadir}/yang/modules/
%dir %{_datadir}/yang/modules/libyang/
%files tools
%{_bindir}/yanglint
%{_bindir}/yangre
%{_datadir}/man/man1/yanglint.1.gz
%{_datadir}/man/man1/yangre.1.gz
%files devel
%{_libdir}/libyang.so
%{_libdir}/pkgconfig/libyang.pc
%{_includedir}/libyang/*.h
%dir %{_includedir}/libyang/
%files devel-doc
%{_docdir}/libyang
%changelog
* {{ now }} Jakub Ružička <jakub.ruzicka@nic.cz> - {{ version }}-{{ release }}
- upstream package

14
distro/scripts/make-archive.sh Executable file
View file

@ -0,0 +1,14 @@
#!/bin/bash
# create archive from current source using git
VERSION=$(git log --oneline -n1 --grep="^VERSION" | rev | cut -d' ' -f1 | rev)
NAMEVER=libyang-$VERSION
ARCHIVE=$NAMEVER.tar.gz
git archive --format tgz --output $ARCHIVE --prefix $NAMEVER/ HEAD
mkdir -p pkg/archives/dev/
mv $ARCHIVE pkg/archives/dev/
# apkg expects stdout to list archive files
echo pkg/archives/dev/$ARCHIVE

View file

@ -0,0 +1,7 @@
#!/bin/bash
# get latest upstream libyang version from github
RLS_URL=https://api.github.com/repos/CESNET/libyang/releases
VERSION=$(curl -s $RLS_URL | grep tag_name | cut -d '"' -f 4 | sort --version-sort | tail -n 1)
VERSION=${VERSION#v}
echo $VERSION

1
distro/tests/control Normal file
View file

@ -0,0 +1 @@
Tests: test-pkg-config.sh test-yanglint.sh

View file

@ -0,0 +1,5 @@
#!/bin/bash
set -ex
version=`pkg-config --modversion libyang`
echo "$version" | grep '2\.[0-9.]\+'

5
distro/tests/test-yanglint.sh Executable file
View file

@ -0,0 +1,5 @@
#!/bin/bash
set -ex
version=`yanglint --version`
echo "$version" | grep '2\.[0-9.]\+'

139
doc/build.dox Normal file
View file

@ -0,0 +1,139 @@
/**
* @page build Building libyang
*
* [TOC]
*
* libyang utilizes CMake build system to detect necessary dependencies, checkout the build environment and prepare Makefiles
* for the compilation of the library and acompanied tools.
*
* @section buildRequirements Requirements
*
* @subsection buildRequirementsCompile Building Requirements
*
* - C compiler (gcc, clang, ...)
* - CMake >= 2.8.12
* - libpcre2 (including headers - devel package) >= 10.30
*
* @subsubsection buildRequirementsCompileOptional Optional Requirements
*
* - doxygen (for generating documentation)
* - cmocka >= 1.0.0 (for tests)
* - valgrind (for enhanced testing)
* - gcov (for code coverage)
* - lcov (for code coverage)
* - genhtml (for code coverage)
*
* @subsection buildRequirementsRun Runtime Requirements
*
* - libpcre2 (runtime package) >= 10.30
*
* @section buildCommands Building
*
* To simply build libyang library and the accompanied tools with the default settings, follow these steps (the `#` character
* indicates command(s) to run with `root` privileges):
*
* $ mkdir build; cd build
* $ cmake ..
* $ make
* # make install
*
* The default settings can be changed with various CMake variables set via command line or using e.g. `ccmake(1)` tool.
* The following sections introduces those variables and explain their meaning.
*
* @section buildTypes Build Types
*
* There are several build types according to the primary goal of using the built binaries.
*
* @subsection buildTypesRelese Release
*
* Build type to produce final binaries for production use without any debug option. The compiler flags are set as follows:
*
* -Wall -Wextra -Wno-missing-field-initializers -std=c99 -O3 -DNDEBUG
*
* Here is the list of the selected additional options available in the *Release* build type.
*
* Option | Description | Default
* ----------------------|------------------------------------------------------------------------------------|--------
* ENABLE_BUILD_TESTS | Build tests. | OFF
* ENABLE_VALGRIND_TESTS | Build tests with valgrind. | OFF
* ENABLE_COVERAGE | Build code coverage report from tests. | OFF
* ENABLE_FUZZ_TARGETS | Build target programs suitable for fuzzing with AFL. | OFF
* BUILD_SHARED_LIBS | Build shared (.so) instead of static (.a) library | ON
* INTERNAL_DOCS | Include developers notes and internal API description into generated Documentation | OFF
*
* Here is the list of available important targets for the `make(1)` tool:
*
* Target | Description
* -------|------------------------------------------------------------------------------------------------------------
* all | Default target, builds libyang library (.so), `yanglint(1)` and `yangre(1)`.
* clean | Removes files generated by the make process.
* cclean | Extends the `clean` target by removing all the cmake generated files.
* doc | Generate HTML documentation. Requires `doxygen(1)`.
*
* @subsection buildTypesDebug Debug
*
* `Debug` is the default build type, the produced binaries include additional debug information and the prepared tests are
* also built. The compiler flags are set as follows:
*
* -Wall -Wextra -Wno-missing-field-initializers -std=c99 -g3 -O0
*
* Here is the list of the selected additional options available in the *Debug* build type.
*
* Option | Description | Default
* ----------------------|------------------------------------------------------------------------------------|--------
* ENABLE_BUILD_TESTS | Build tests. | ON
* ENABLE_VALGRIND_TESTS | Build tests with valgrind. | ON
* ENABLE_COVERAGE | Build code coverage report from tests. | OFF
* ENABLE_FUZZ_TARGETS | Build target programs suitable for fuzzing with AFL. | OFF
* BUILD_SHARED_LIBS | Build shared (.so) instead of static (.a) library | ON
* INTERNAL_DOCS | Include developers notes and internal API description into generated Documentation | OFF
*
* Here is the list of available important targets for the `make(1)` tool:
*
* Target | Description
* -------------|------------------------------------------------------------------------------------------------------
* all | Default target, builds libyang library (.so), `yanglint(1)` and `yangre(1)`.
* clean | Removes files generated by the make process.
* cclean | Extends the `clean` target by removing all the cmake generated files.
* doc | Generate HTML documentation. Requires `doxygen(1)`.
* test | Run implementation tests. Requires `cmocka` (and `valgrind(1)` for part of the tests).
* format | Reformat source codes using `uncrustify(1)`.
* format-check | Dry-run of the `format` target.
*
* @subsection buildTypesABICheck ABICheck
*
* Special build type to perform check of the ABI/API compatibility and generate reports. In addition to the basic
* requirements, the build type requires some of the <a href="https://abi-laboratory.pro/">ABI Laboratory tools</a>:
* `abi-dumper(1)` and `abi-compliance-checker(1)`.
*
* The compiler flags are set as follows:
*
* -Wall -Wextra -Wno-missing-field-initializers -std=c99 -g -Og
*
* All the additional options are switched OFF and the settings should not be changed.
*
* Here is the list of available important targets for the `make(1)` tool:
*
* Target | Description
* -------------|------------------------------------------------------------------------------------------------------
* all | Default target, builds libyang library (.so), `yanglint(1)` and `yangre(1)`.
* clean | Removes files generated by the make process.
* cclean | Extends the `clean` target by removing all the cmake generated files.
* doc | Generate HTML documentation. Requires `doxygen(1)`.
* abi-check | Check the backward compatibility of the API/ABI changes. Requires `abi-compliance-checker(1)` and `abi-dump(1)`.
* abi-dump | Helper target for `abi-check` generating API/ABI reports. Requires `abi-dump(1)`.
* @subsection buildTypesDocOnly DocOnly
*
* Special build type to avoid any requirements except those for building documentation. There are no compiler flags set
* since the build type does not allow building any binary output. The settings of the additional options should not be
* changed.
*
* Here is the list of available important targets for the `make(1)` tool:
*
* Target | Description
* -------------|------------------------------------------------------------------------------------------------------
* all | Default target, does nothing.
* doc | Generate HTML documentation. Requires `doxygen(1)`.
*
*/

106
doc/cesnet-style.css Normal file
View file

@ -0,0 +1,106 @@
/* CESNET blue: #0068a2 */
body {
background-color: #fff;
}
div.header {
background-image: none;
background-color: #fff;
}
div.contents {
background-color: #fff;
padding: 1.618em 3.236em;
max-width: 60em;
margin: auto;
margin-left: 0;
text-align: justify;
}
.sm-dox {
background-image: none;
background-color: #0068a2;
border-bottom: 1px solid white;
}
.sm-dox a {
background-image: none;
border-right: 1px solid white;
color: white;
text-shadow: none;
}
.sm-dox a:hover {
background-image: none;
background-color: rgba(0,0,0,0.3);
}
.sm-dox ul a:hover {
background-image: none;
background-color: #ddd;
text-shadow: none;
color: #555;
}
.navpath ul {
background-image: none;
background-color: #0068a2;
}
.navpath li.footer {
color: white;
}
img.footer {
height: 20px;
}
.navpath li.navelem a {
color: white;
text-shadow: none;
}
#side-nav {
background-color: #343131;
}
#nav-tree::-webkit-scrollbar {
width: 5px;
}
#nav-tree::-webkit-scrollbar-track {
background: #333;
border-radius: 50px;
}
#nav-tree::-webkit-scrollbar-thumb {
background: #ccc;
border-radius: 50px;
}
#nav-tree {
background: none;
}
#nav-tree .item {
padding-top: 10px;
padding-bottom: 10px;
}
#nav-tree .item:hover {
background-color: rgba(255,255,255,0.2);
}
#nav-tree a {
color: #fff;
font-size: 1.2em;
}
#nav-tree .selected {
background-image: none;
background-color: #0068a2;
}
#nav-tree-contents {
margin: 0;
}

406
doc/transition_1_2.dox Normal file
View file

@ -0,0 +1,406 @@
/**
* @page transition1_2 Transition Manual (1.x -> 2.0)
*
* [TOC]
*
* Rewriting libyang codebase and creating libyang version 2.0 was motivated mainly by improving long term maintainability.
* Especially some of the features and design decisions become killers for further development and maintaining the libyang
* codebase. On the other hand, most of the principles introduced in libyang 1.x to handle YANG schemas and manipulate
* instantiated data have proved successful. Therefore, we have decided to keep the basic mechanisms from version 1.x and
* remove the problematic features and modify the improper design decisions. Despite the vision to keep with the mechanisms
* also the API, the new version became a great opportunity to clean up the API and improve its usability mainly by unifying
* how the libyang functions are used. So, in the end, this manual is not just a description of the removed features listing
* removed, modified or added functions. The API should be even better prepared for adding new features and functions.
* Shortly, almost everything has changed at least a little, so you cannot move from version 1.x to 2.0 just by replacing
* code snippets. However, we believe that the change is good and libyang 2.0 is simply better.
*
* In this Manual, we want to introduce the differences between libyang 1.x and 2.0. It is intended for the transition
* from 1.x to 2.0, so if you are new to libyang, simply go to the @ref howto section, this Manual is not for you.
*
* The complete generated list of changes (without any additional notes) can be found in
* <a href="../compat_report_1_2.html">the compatibility report</a>.
*
* @section transition1_2General General Changes
*
*
* @subsection transition1_2GeneralErros Errors Handling
*
* The most visible change is probably the changed approach to handling errors. While libyang 1.x was using variable
* *ly_errno* to provide error information in case the called function failed, there is no such variable in libyang 2.0.
* On the other hand, most API functions now return ::LY_ERR values directly stating the result. In addition, in case
* the error is somehow connected with the [context](@ref howtoContext), more detailed error information can be obtained
* from the context handler itself. Mainly this change is responsible for the backward incompatibility of almost all
* functions between versions 1.x and 2.0.
*
* Here is the overview of the changed / removed / added functions connected with errors and logging.
*
* libyang 1.x | libyang 2.0 | Notes
* :-------------------------|:-------------------------------------|:-------------------------------------------------------
* - | ::ly_err_last() | New API for handling errors.
* ly_verb_dbg() | ::ly_log_dbg_groups() | Rename to align with the names of the accepted values.
* ly_verb() | ::ly_log_level() | ^
*
* More information about error handling in libyang 2.0 can be found at @ref howtoErrors page.
*
* @subsection transition1_2GeneralInOut Input / Output Processing
*
* libyang 2.0 introduces input (::ly_in) and output (::ly_out) handlers covering the specific input sources for parsers and
* output targets for printers. They are supposed mainly to simplify parser's and printer's API to avoid the need for
* separate functions for each source/target. The handlers can be used repeatedly to split the inputs or join the outputs.
*
* More information can be found at @ref howtoInput and @ref howtoOutput pages.
*
*
* @subsection transition1_2GeneralOutputFormatting Output Formatting
*
* In libyang 1.x, there was an inconsistency in printing schemas and data. While the schemas were always printed formatted,
* the data were printed by default without additional indentation. It is clearly visible in the YIN format of the schema,
* which is XML, and the XML encoding of the data. While there was a possibility to format data output with the LYP_FORMAT
* flag, it wasn't possible to change schema output formatting.
*
* libyang 2.0 unifies the behavior of all printers. By default, all the output formats are formatted now. Both, the data as
* well as the schema printers, accept the option to remove additional formatting (different for the specific format, usually
* indentations and blank lines): ::LYD_PRINT_SHRINK for the data printer and ::LYS_PRINT_SHRINK for the schema printer.
*
*
* @subsection transition1_2GeneralXPath Addressing
*
* If you compare the @ref howtoXPath page from libyang 1.x and 2.0 documentation, you will be probably confused since they
* seem very different. In fact, we have tried to simplify the API by removing the original Schema path format from the
* public API. Since this format is used in YANG format, libyang still supports it internally, but it is not possible to use
* it anywhere in the API. The new formats XPath and Path, mentioned at the @ref howtoXPath page, are both the Data paths
* used in libyang 1.x. The Path format is a subset of XPath format limited to refer to a single node.
*
* This change was reflected in functions serving to get a node based on the specified path. Unfortunately, when comparing
* old and new API, the transition can be confusing since the names are sometimes overloaded (be careful mainly of
* ::lys_find_path()). The following table depicts the changes, but probably a better approach is to handle the functions as
* a completely new API.
*
* libyang 1.x | libyang 2.0 | Notes
* :-------------------------|:-------------------------------------|:-------------------------------------------------------
* ly_ctx_find_path() | - | To simplify the different [types of paths](@ref howtoXPath), the Schema path format is not supported for now. If there will be use cases for it, it can be re-added later, but for now try using ::lys_find_xpath().
* %lys_find_path() | - | To simplify the different [types of paths](@ref howtoXPath), the Schema path format is not supported for now. If there will be use cases for it, it can be re-added later, but for now try using ::lys_find_xpath().
* ly_ctx_get_node() | ::lys_find_path() | Renamed to unify API functions, note that there was lys_find_path in libyang 1.x with different functionality in comparison to the function of the same name from libyang 2.0.
* - | ::lys_find_path_atoms() | Extension of ::lys_find_path().
* - | ::lys_find_lypath_atoms() | ^
* - | ::lys_find_xpath() | New function reflecting updated @ref howtoXPath\.
* lys_xpath_atomize() | ::lys_find_xpath_atoms() | Rename to unify with the new API, extends ::lys_find_xpath().
* - | ::lys_find_expr_atoms() | Extension of ::lys_find_xpath().
* %lyd_path() | ::lyd_path() | Same purpose, just extended functionality.
* lyd_find_path() | ::lyd_find_xpath() | Rename to unify with the new API.
* - | ::lyd_find_path() | Simplified version of ::lyd_find_path().
* - | ::lyxp_get_expr() | Added functionality due to the changed representation of XPath expressions.
* ly_path_data2schema() | - | Removed since the schema path is not available in API.
* ly_path_xml2json() | - | Removed since done internally, note that even the generic XML parser is not available now.
* lys_node_xpath_atomize() | - | Removed as useless/redundant, use ::lys_find_xpath_atoms().
*
* @section transition1_2Context Context
*
* Context, as a concept of a storage interconnecting YANG modules into a YANG schema and YANG schema with the instantiated
* data, was preserved. However, it is now more supposed to be prepared just once before connecting it with any instantiated
* data. The possibility of removing YANG modules from the context was completely dropped. Furthermore, we would like to
* introduce some kind of context lock to completely abandon any change of the YANG modules after starting work with the
* instantiated data.
*
* Another change to note is the removed destructor of private data (::lysc_node.priv) in ::ly_ctx_destroy(). The mechanism
* was not reliable with the context recompilation and the splitted parsed and compiled schema trees or the complexity of
* YANG extensions. It is better to let the caller maintain the allocated data directly via some memory pool or using
* ::lysc_tree_dfs_full() since he is the best to know where the additional data were added.
*
* The meaining of the ::lysc_node.priv pointer can be now also changed by ::LY_CTX_SET_PRIV_PARSED context option, which
* makes libyang to connect the original parsed schema node structure (::lysp_node) into the compiled nodes via their 'priv'
* pointer.
*
* Other significant changes connected with the context are depicted in the following table.
*
* libyang 1.x | libyang 2.0 | Notes
* :-------------------------|:-------------------------------------|:-------------------------------------------------------
* ly_ctx_clean() | - | Removed functionality of manipulating with the context and the modules already placed in the context.
* ly_ctx_remove_module() | - | ^
* ly_ctx_set_module_data_clb() and the associated ly_module_data_clb type. | - | ^
* ly_ctx_get_disabled_module() and the associated ly_ctx_get_disabled_module_iter() | - | ^
* ly_ctx_info() | ::ly_ctx_get_yanglib_data() | Clarification of what to expect as the output of the function and possibility to specify custom content ID.
* ly_ctx_get_module_set_id() | ::ly_ctx_get_change_count() | The functionality is the same but the exact meaning of the value was clarified.
* - | ::ly_ctx_unset_searchdir_last() | Extend the functionality of the ::ly_ctx_unset_searchdir() to make its use easier.
* ly_ctx_get_module_older() | - | Removed functionality.
* - | ::ly_ctx_get_module_implemented() | Supplement for ::ly_ctx_get_module()
* - | ::ly_ctx_get_module_latest() | ^
* - | ::ly_ctx_get_module_implemented_ns() | Supplement for ::ly_ctx_get_module_ns()
* - | ::ly_ctx_get_module_latest_ns() | ^
* - | ::ly_ctx_get_submodule_latest() | Supplement for ::ly_ctx_get_submodule()
* - | ::ly_ctx_get_submodule2_latest() | Supplement for ::ly_ctx_get_submodule2()
* ly_ctx_get_module_by_ns() | ::ly_ctx_get_module_ns () | Redesign the API - replace some of the parameters with standalone supplement functions.
* ly_ctx_unset_searchdirs() | ::ly_ctx_unset_searchdir() | Simplify API and instead of index numbers, work with the values themselves.
* ly_ctx_set*() | ::ly_ctx_set_options() | API simplification.
* ly_ctx_unset*() | ::ly_ctx_unset_options() | ^
* ly_ctx_destroy() | ::ly_ctx_destroy() | The destructor callback parameter was removed, see the notes above.
*
*
* @section transition1_2Schemas YANG Modules (Schema)
*
* The most significant change between libyang 1.x and 2.0 can be found in schema structures. The schema tree now has two
* different forms - parsed and compiled trees. While the parsed tree reflects the source of the YANG module, the compiled
* tree represents the final tree used to validate the instantiated data. Both formats can be found inside the covering
* ::lys_module structure. More about the new structures can be found at @ref howtoSchema page.
*
* This is an essential change allowing speed up and simplification of data validation, but requiring carefully determine
* which format is more suitable for the specific use case. As mentioned, the compiled trees are better for data validation
* and getting information about the intentioned structure of the schema with all the applied groupings, type modifications,
* augments, deviations, and any defined if-features. On the other hand, the parsed trees are useful for the schema format conversions since they
* provide the original structure of the modules. There is a number of new functions intended to work only with the
* parsed or the compiled tree. These functions are prefixed with `lysp_` and `lysp_` prefixes.
*
* Schema parser, as well as printer functions, are now extended to accept new
* [input / output handlers](@ref transition1_2GeneralInOut). The previous API working directly with inputs and outputs is
* preserved (or slightly changed), but the functions can be limited in the functionality of the new API. More information
* can be found at @ref howtoSchemaParsers and @ref howtoSchemaPrinters pages.
*
* libyang 1.x | libyang 2.0 | Notes
* :----------------------------|:--------------------------------|:---------------------------------------------------------
* - | ::lys_parse() | New generic schema parser API using [generic input handler](@ref howtoInput).
* - | ::lys_print_module() | New generic schema printer API using [generic output handler](@ref howtoOutput).
* - | ::lys_print_node() | ^
* - | ::lys_print_submodule() | ^
*
*
* The following table introduces other significant changes in the API functions connected with the schema.
*
* libyang 1.x | libyang 2.0 | Notes
* :----------------------------|:--------------------------------|:---------------------------------------------------------
* lys_set_private() | - | Not needed, all ::lysc_node compatible structures have this pointer so it can be accessed directly.
* lys_is_disabled() | - | Make no sense since the nodes disabled by if-feature are not present in the compiled tree.
* lys_features_list() | - | Not needed, the list of features is available in the parsed tree of the module and submodule.
* lys_features_enable(), lys_features_enable_force() | ::lys_set_implemented() | Set of enabled features can be changed but it causes the whole context (all the modules) to recompile.
* lys_features_disable(), lys_features_disable_force() | - | ^
* lys_features_state() | - | Redesign of the features handling in the schema tree, the feature's status is newly directly visible as ::LYS_FENABLED flag (in parsed feature structure).
* - | ::lys_feature_value() | Simplified API to get feature's state only based on a feature name string.
* - | ::lysp_feature_next() | After redesigning features handling, this function helps to iterate over all features connected with the module.
* lys_iffeature_value() | ::lysc_iffeature_value() | Renamed, but note that after features handling redesign, the compiled if-feature structure to evaluate is only in ::lysp_feature.iffeatures_c.
* lys_iffeature_value() | - | Not needed since the if-feature statements are directly applied onto the compiled tree.
* lys_is_disabled() | - | ^
* lys_parent() | - | The compiled tree is more straightforward without the need to take care of nodes added via augments.
* lys_main_module() | - | The compiled tree does not include submodules, so there is always only the main module.
* lys_node_module() | - | ^
* lys_set_enabled() | - | It is not possible to change context this way (remove or disable modules).
* lys_set_disabled() | - | ^
* - | ::lys_find_child() | Helpers wrapper around ::lys_getnext().
* - | ::lys_getnext_ext() | Alternative to ::lys_getnext() allowing processing schema trees inside extension instances.
* - | ::lys_nodetype2str() | New functionality.
* lys_is_key() | ::lysc_is_key() | Renamed to connect with the compiled schema tree.
* - | ::lysc_is_userordered() | Added functionality to simplify the examination of generic compiled schema nodes.
* - | ::lysc_is_np_cont() | ^
* - | ::lysc_node_child() | ^
* - | ::lysc_node_actions() | ^
* - | ::lysc_node_notifs() | ^
* - | ::lysp_node_child() | Added functionality to simplify the examination of generic parsed schema nodes.
* - | ::lysp_node_actions() | ^
* - | ::lysp_node_notifs() | ^
* - | ::lysp_node_groupings() | ^
* - | ::lysp_node_typedefs() | ^
* - | ::lysc_tree_dfs_full() | Alternative DFS passing implementation to ::LYSC_TREE_DFS_BEGIN macro.
* - | ::lysc_module_dfs_full() | Supplement functionality to ::lysc_tree_dfs_full().
* lys_path(), lys_data_path() | ::lysc_path() | Redesigned functionality.
* lys_data_path_pattern() | - | Removed as useless
* lys_implemented_module() | ::ly_ctx_get_module_implemented() | Removed, the same result can be simply achieved using ::ly_ctx_get_module_implemented().
*
* There is a set of functions available to implement data type plugins for storing and manipulating data values in a more
* natural way to the specific data type. For example, IPv4 address type is defined as a string with a pattern, but it is
* more effective and usual to store and handle IPv4 as a 32-bit number.
*
* libyang 1.x | libyang 2.0 | Notes
* :----------------------------|:---------------------------------|:--------------------------------------------------------
* lys_getnext_union_type() | - | Removed after the type representation redesign.
* - | ::lyplg_type_identity_isderived()| Helper functions for base types.
* - | ::lyplg_type_parse_dec64() | ^
* - | ::lyplg_type_parse_int() | ^
* - | ::lyplg_type_parse_uint() | ^
* - | ::lyplg_type_validate_patterns() | ^
* - | ::lyplg_type_validate_range() | ^
* - | ::lyplg_type_get_prefix() | Helper functions for processing prefixes in data values.
* - | ::lyplg_type_prefix_data_new() | ^
* - | ::lyplg_type_prefix_data_dup() | ^
* - | ::lyplg_type_prefix_data_free() | ^
*
*
* YANG extensions are supported via [extension plugins API](@ref pluginsExtensions) allowing to implement specific extension
* and load its support into libyang as a shared module. libyang implements several extensions on its own (see
* @ref howtoPluginsExtensions), but even these internal implementations use the same API. The API and [mechanism of loading
* external plugins](@ref howtoPlugins) changed a lot in contrast to libyang 1.x. The plugins are now loaded automatically
* with creating the first libyang context. The only public function to handle external plugins is ::lyplg_add().
*
*
* libyang 1.x | libyang 2.0 | Notes
* :----------------------------|:--------------------------------|:---------------------------------------------------------
* lys_ext_complex_get_substmt()| lysc_ext_substmt() | Changed design of the extensions and the way how it's substatements are accessed.
* lys_ext_instance_presence() | lysc_ext_substmt() | ^
* lys_ext_instance_substmt() | lysc_ext_substmt() | ^
* ly_clean_plugins() | - | Manipulating external plugins (from plugins directories) is now automatically connected with creating (first) and destroying (last) libyang contexts.
* ly_get_loaded_plugins() | - | ^
* ly_load_plugins() | - | ^
* ly_register_exts() | ::lyplg_add() | Redesigned to a common function for any plugin type.
* ly_register_types() | ::lyplg_add() | ^
*
*
* @section transition1_2Data Data Instances
*
* Conceptually, the data tree did not change as much as the schema tree. There is still a generic ::lyd_node structure that
* maps according to the schema node's nodetype to some of the other lyd_node_* structures. All the data nodes were extended
* by hashes to improve performance when searching and processing data trees. The hashes are used for example in the
* lyd_find_* functions.
*
* All the data nodes are also implicitly ordered following the order of the schema nodes. This is the
* reason to change the insertion function. Only the user-ordered lists and leaf-lists can be now placed relative to other
* instances of the same list/leaf-list. Otherwise, the data instance is always inserted/created at the correct place beside
* the right sibling nodes.
*
* For any functions that are available on inputs of different scale (node, subtree, all siblings, whole data tree),
* there are several variants of the specific function with suffix specifying what exactly the processed input will be
* (_single, _tree, _siblings, _all). This way the behavior is always clear in the code.
*
* libyang 1.x | libyang 2.0 | Notes
* :----------------------------|:--------------------------------|:---------------------------------------------------------
* %lyd_insert_after() | ::lyd_insert_after() | Changed meaning by limiting applicability only to user-ordered list and leaf-list instances.
* %lyd_insert_before() | ::lyd_insert_before() | ^
* lyd_schema_sort() | - | Not necessary since the nodes are sorted implicitly.
*
*
* Parsing data instances in XML format is newly done directly, without any interstep. Therefore, complete XML API
* (lyxml_*() functions) from libyang 1.x was removed.
*
* Parser's API was simplified to avoid variadic parameters. The functions are newly split to parsed data, notifications,
* RPCs and replies to the RPCs. Similarly to the schema parsers, also the new data parser API works with
* [input handlers](@ref transition1_2GeneralInOut). The data printer's API was also extended to use new
* [output handlers](@ref transition1_2GeneralInOut). However, part of the previous API working directly with inputs
* and outputs was preserved. More information about the data parser and printer can be found at
* @ref howtoDataParsers and @ref howtoDataPrinters pages.
*
* libyang 1.x | libyang 2.0 | Notes
* :----------------------------|:--------------------------------|:---------------------------------------------------------
* - | ::lyd_parse_data() | Redesigned data tree parser.
* lyd_parse_xml() | - | XML tree format was removed.
* lyd_parse_fd() | ::lyd_parse_data_fd() | Renamed and limited to data trees only.
* lyd_parse_mem() | ::lyd_parse_data_mem() | ^
* lyd_parse_path() | ::lyd_parse_data_path() | ^
* - | ::lyd_parse_ext_data() | Separated function for parsing data trees matching a schema tree of the given extension instance.
* - | ::lyd_parse_op() | Separated function for parsing RPCs, actions, replies, and notifications.
* - | ::lyd_parse_ext_op() | Separated function for parsing RPCs, actions, replies, and notifications of the given extension instance.
* - | ::lyd_print_all() | New API accepting ::ly_out.
* - | ::lyd_print_tree() | ^
*
*
* Data validation is still done as part of the parser's process. The standalone functionality is available to check the
* result of data manipulation with the values of the terminal nodes or with the structure of the data tree. In contrast to
* libyang 1.x, adding the default nodes was made available as a standalone function to simplify the data manipulation
* process before the final validation.
*
* Many validation flags were removed because they became obsolete (LYD_OPT_DESTRUCT, LYD_OPT_WHENAUTODEL,
* LYD_OPT_NOEXTDEPS, LYD_OPT_DATA_NO_YANGLIB, LYD_OPT_VAL_DIFF) or we consider them redundant (LYD_OPT_OBSOLETE,
* LYD_OPT_NOSIBLINGS, LYD_OPT_DATA_ADD_YANGLIB). As for LYD_OPT_TRUSTED, this option was mostly replaced with
* ::LYD_PARSE_ONLY because both skip validation but with the significant difference that LYD_OPT_TRUSTED also sets
* the data node flags to be considered validated. The current option ::LYD_PARSE_ONLY does not do this because
* there is now much better support for working with non-validated data trees. Also, in case an invalid tree was marked
* as validated, it could lead to some undesired behavior, which is now avoided.
*
* Worth mentioning is a difference in the LYB format, which now also stores its validation flags. So, in case
* a validated data tree is stored, it is also loaded as validated.
*
* libyang 1.x | libyang 2.0 | Notes
* :----------------------------|:--------------------------------|:---------------------------------------------------------
* lyd_validate() | ::lyd_validate_all(), ::lyd_validate_op() | Redesigned functionality.
* lyd_validate_modules() | ::lyd_validate_module() | ^
* lyd_validate_value(), lyd_value_type() | ::lyd_value_validate() | Redesigned functionality.
* - | ::lyd_new_implicit_all() | New in API to explicitly add default nodes, previously done only as part of the validation process.
* - | ::lyd_new_implicit_module() | Supplement functionality to ::lyd_new_implicit_all().
* - | ::lyd_new_implicit_tree() | ^
*
*
* The `diff` functionality was completely redesigned. Instead of the array of operations to transform one tree into another,
* the difference between two data trees has newly a form of the annotated data tree describing the differences. A number of
* functions to use the diff tree was added into API. To simply compare just nodes, there are the `compare` functions.
*
* libyang 1.x | libyang 2.0 | Notes
* :----------------------------|:--------------------------------|:---------------------------------------------------------
* lyd_diff() | ::lyd_diff_tree() | Redesigned functionality.
* - | ::lyd_diff_siblings() | Supplement functionality to ::lyd_diff_tree().
* - | ::lyd_diff_apply_all() | ^
* - | ::lyd_diff_apply_module() | ^
* - | ::lyd_diff_merge_all() | ^
* - | ::lyd_diff_merge_module() | ^
* - | ::lyd_diff_merge_tree() | ^
* - | ::lyd_diff_reverse_all() | ^
* lyd_free_diff() | - | Removed.
* lyd_free_val_diff() | - | Removed.
* - | ::lyd_compare_single() | Added functionality.
* - | ::lyd_compare_meta() | Supplement functionality to ::lyd_compare_single()
* - | ::lyd_compare_siblings() | ^
*
*
* For now, the functionality of moving data between two different contexts is not implemented. If you have a real use case
* for this functionality, let us know.
*
* libyang 1.x | libyang 2.0 | Notes
* :----------------------------|:--------------------------------|:---------------------------------------------------------
* lyd_dup() | ::lyd_dup_single() | Redesigned functionality.
* lyd_dup_withsiblings() | ::lyd_dup_siblings() | ^
* - | ::lyd_dup_meta_single() | Supplement functionality to ::lyd_dup_single().
* lyd_dup_to_ctx() | - | Transferring data from one context to another is not supported.
* lyd_merge() | ::lyd_merge_tree() | Renamed.
* - | ::lyd_merge_siblings() | Supplement functionality to ::lyd_merge_tree()
* lyd_merge_to_ctx() | - | Transferring data from one context to another is not supported.
*
*
* There is a significant change in the value structure in terminal nodes. Thanks to the changes in the schema tree,
* it is now much more straightforward to get the type of the value and work with the alternative representation of the value
* fitting better to its type. There is also a new API for the type plugins (see @ref howtoPluginsTypes). Even the base YANG
* data types are now implemented using this API and can be taken as examples for implementing derived data types.
*
* libyang 1.x | libyang 2.0 | Notes
* :----------------------------|:--------------------------------|:---------------------------------------------------------
* lyd_new(), lyd_new_output() | ::lyd_new_inner(), ::lyd_new_list(), ::lyd_new_list2() | Redesigned functionality to better fit new lyd_node structures, creating RPC's output data is now done via a flag parameter of the functions.
* lyd_new_leaf(), lyd_new_output_leaf() | ::lyd_new_term() | ^
* lyd_new_anydata(), lyd_new_output_anydata() | ::lyd_new_any() | ^
* lyd_new_yangdata() | ::lyd_new_ext_inner(), ::lyd_new_ext_list(), ::lyd_new_ext_term(), ::lyd_new_ext_any() | Additional functionality to lyd_new_* functions to cover top-level nodes in extension instances.
* lyd_insert_attr() | ::lyd_new_meta() | Unify naming used in other functions with the similar functionality.
* - | ::lyd_new_attr() | Added functionality to store the data (temporarily) not connected with schema definitions.
* - | ::lyd_new_attr2() | ^
* - | ::lyd_new_opaq() | ^
* - | ::lyd_new_opaq2() | ^
* - | ::lyd_new_path2() | Supplement functionality to ::lyd_new_path().
* LYD_PATH_OPT_NOPARENTRET | ::lyd_new_path2() | ::lyd_new_path2() returns both the first parent and the wanted node.
* LYD_PATH_OPT_EDIT | ::LYD_NEW_PATH_OPAQ | This functionality was replaced by opaq nodes.
* - | ::lyd_new_ext_path() | Supplement functionality to ::lyd_new_path() covering data defined in extension instances.
* lyd_insert() | ::lyd_insert_child() | Renamed to better distinguish from ::lyd_insert_sibling().
* lyd_change_leaf() | ::lyd_change_term() | Align naming with changed names of data structures.
* - | ::lyd_change_meta() | Transferred functionality of ::lyd_change_term() to metadata.
* - | ::lyd_any_copy_value() | Added functionality.
* lyd_free() | ::lyd_free_tree() | Renamed.
* lyd_free_withsiblings() | ::lyd_free_all() | ^
* - | ::lyd_free_siblings() | Supplement functionality to ::lyd_free_siblings().
* lyd_free_attr() | ::lyd_free_attr_single() | Renamed.
* - | ::lyd_free_attr_siblings() | Supplement functionality to ::lyd_free_attr_single().
* - | ::lyd_free_meta_single() | Added functionality.
* - | ::lyd_free_meta_siblings() | ^
* lyd_unlink() | ::lyd_unlink_tree() | Renamed.
*
*
* Here is the table of other changes in data API.
*
* libyang 1.x | libyang 2.0 | Notes
* :----------------------------|:--------------------------------|:---------------------------------------------------------
* lyd_find_instance() | - | Removed.
* lyd_find_sibling() | - | Removed, functionality can be replaced by ::lyd_find_sibling_val().
* lyd_find_sibling_set() | - | ^
* - | ::lyd_find_sibling_first() | Alternative function to ::lyd_find_sibling_val().
* - | ::lyd_find_meta() | New functionality.
* lyd_wd_default() | ::lyd_is_default() | Renamed to unlink from with-default capability.
* - | ::lyd_parent() | New wrapper to get generic ::lyd_node pointer of the parent.
* - | ::lyd_child(), ::lyd_child_no_keys() | New wrapper to cover all children possibilities hidden behind a generic ::lyd_node structure.
* - | ::lyd_owner_module() | Added functionality.
* - | ::lyd_value_compare() | Added Functionality.
* - | ::lyd_find_target() | Added functionality for the instance-identifier representation.
* lyd_node_module() | - | Not necessary since the connection with the compiled modules is much more straightforward.
* lyd_leaf_type() | - | Not necessary since the real type information is much more clear from the new ::lyd_value.
* lyd_dec64_to_double() | - | Removed as useless.
* lyd_node_should_print() | - | ^
*/

74
doc/transition_2_3.dox Normal file
View file

@ -0,0 +1,74 @@
/**
* @page transition2_3 Transition Manual (2.x -> 3.0)
*
* [TOC]
*
* Non-backwards-compatible changes between libyang version 2 and 3 are rather minor and can be summarized as providing
* structured error information (instead of a single message), unifying **lyd_new_*()** function options, and some
* minor changes such as removing deprecated functions or making a few functions inlined. However, there is another
* large change that has not affected the API, specifically configuration system-ordered lists and leaf-lists are now
* ordered based on their keys/values, respectively. Except for moderately slower performance and negligible increased
* memory requirements, it should not affect existing applications (assuming they do not rely on the previous order of
* these instances).
*
* The complete generated list of changes (without any additional notes) can be found in
* <a href="../compat_report_2_3.html">the compatibility report</a>.
*
* @section transition2_3Logging Logging
*
* Except for some function adjustments, ::ly_err_item has been changed to provide every piece of error information in a
* separate member to allow for easier processing.
*
* Here is the overview of the changed / removed / added functions connected to logging.
*
* libyang 2.x | libyang 3.0 | Notes
* :-------------------------|:-------------------------------------|:-------------------------------------------------------
* ly_last_errmsg() | ::ly_last_logmsg() | Function renamed with the same functionality.
* ly_strerrcode() | ::ly_strerr() | Function renamed with the same functionality.
* ly_errcode() | - | Now requires ::ly_err_last() call.
* ly_errmsg() | - | ^
* ly_errpath() | - | ^
* ly_vecode() | - | ^
*
*
*
* @section transition2_3New Data Creation
*
* libyang 2.x | libyang 3.0 | Notes
* :-------------------------|:-------------------------------------|:-------------------------------------------------------
* lyd_find_xpath3() | ::lyd_find_xpath3() | Optional prefix data parameter added.
* LYD_NEW_PATH_OUTPUT | ::LYD_NEW_VAL_OUTPUT | Some LYD_NEW_PATH_* options now also used for other lyd_new_* functions.
* LYD_NEW_PATH_BIN_VALUE | ::LYD_NEW_VAL_BIN | ^
* LYD_NEW_PATH_CANON_VALUE | ::LYD_NEW_VAL_CANON | ^
* lyd_new_path() | ::lyd_new_path() | All options now in a single bitmap parameter of @ref newvaloptions.
* lyd_new_any() | ::lyd_new_any() | ^
* lyd_new_list() | ::lyd_new_list() | ^
* lyd_new_list2() | ::lyd_new_list2() | ^
* lyd_new_list3() | ::lyd_new_list3() | ^
* lyd_new_meta() | ::lyd_new_meta() | ^
* lyd_new_meta2() | ::lyd_new_meta2() | ^
* lyd_new_term() | ::lyd_new_term() | ^
* lyd_new_list3_bin() | ::lyd_new_list3() | Functionality now merged into the single function.
* lyd_new_list3_canon() | ^ | ^
* lyd_new_list_bin() | ::lyd_new_list() | Functionality now merged into the single function.
* lyd_new_list_canon() | ^ | ^
* lyd_new_term_canon() | ::lyd_new_term() | Functionality now merged into the single function.
*
*
*
* @section transition2_3Minor Other Minor Changes
*
* Except for the function changes below, ::lysc_type now has a copy of the typedef name, if applicable. There
* are use-cases when this information is needed even in the compiled schema tree such as checking the real type of
* a union value.
*
* libyang 2.x | libyang 3.0 | Notes
* :-------------------------|:-------------------------------------|:-------------------------------------------------------
* lyd_child() | ::lyd_child() | Now an inlined function for better performance.
* lyd_get_value() | ::lyd_get_value() | ^
* lyd_parent() | ::lyd_parent() | ^
* lyd_find_xpath4() | ::lyd_find_xpath3() | Previous lyd_find_xpath3 was removed to reduce symbols.
* lyd_target() | - | Deprecated.
* ly_ctx_reset_latests() | - | ^
*
*/

11
libyang.pc.in Normal file
View file

@ -0,0 +1,11 @@
prefix=@CMAKE_INSTALL_PREFIX@
includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@
libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@
Name: @PROJECT_NAME@
Description: @LIBYANG_DESCRIPTION@
Version: @LIBYANG_VERSION@
Requires.private: libpcre2-8
Libs: -L${libdir} -lyang
Libs.private: -lpcre2-8
Cflags: -I${includedir}

View file

@ -0,0 +1,226 @@
unsigned char ietf_datastores_2018_02_14_yang[] = {
0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x69, 0x65, 0x74, 0x66, 0x2d,
0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x73, 0x20, 0x7b,
0x0a, 0x20, 0x20, 0x79, 0x61, 0x6e, 0x67, 0x2d, 0x76, 0x65, 0x72, 0x73,
0x69, 0x6f, 0x6e, 0x20, 0x31, 0x2e, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x6e,
0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x20, 0x22, 0x75, 0x72,
0x6e, 0x3a, 0x69, 0x65, 0x74, 0x66, 0x3a, 0x70, 0x61, 0x72, 0x61, 0x6d,
0x73, 0x3a, 0x78, 0x6d, 0x6c, 0x3a, 0x6e, 0x73, 0x3a, 0x79, 0x61, 0x6e,
0x67, 0x3a, 0x69, 0x65, 0x74, 0x66, 0x2d, 0x64, 0x61, 0x74, 0x61, 0x73,
0x74, 0x6f, 0x72, 0x65, 0x73, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x70, 0x72,
0x65, 0x66, 0x69, 0x78, 0x20, 0x64, 0x73, 0x3b, 0x0a, 0x0a, 0x20, 0x20,
0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x22, 0x49, 0x45, 0x54, 0x46, 0x20, 0x4e,
0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x20, 0x4d, 0x6f, 0x64, 0x65, 0x6c,
0x69, 0x6e, 0x67, 0x20, 0x28, 0x4e, 0x45, 0x54, 0x4d, 0x4f, 0x44, 0x29,
0x20, 0x57, 0x6f, 0x72, 0x6b, 0x69, 0x6e, 0x67, 0x20, 0x47, 0x72, 0x6f,
0x75, 0x70, 0x22, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x63, 0x6f, 0x6e, 0x74,
0x61, 0x63, 0x74, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x22, 0x57, 0x47, 0x20,
0x57, 0x65, 0x62, 0x3a, 0x20, 0x20, 0x20, 0x3c, 0x68, 0x74, 0x74, 0x70,
0x73, 0x3a, 0x2f, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x74, 0x72, 0x61, 0x63,
0x6b, 0x65, 0x72, 0x2e, 0x69, 0x65, 0x74, 0x66, 0x2e, 0x6f, 0x72, 0x67,
0x2f, 0x77, 0x67, 0x2f, 0x6e, 0x65, 0x74, 0x6d, 0x6f, 0x64, 0x2f, 0x3e,
0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x57, 0x47, 0x20, 0x4c, 0x69,
0x73, 0x74, 0x3a, 0x20, 0x20, 0x3c, 0x6d, 0x61, 0x69, 0x6c, 0x74, 0x6f,
0x3a, 0x6e, 0x65, 0x74, 0x6d, 0x6f, 0x64, 0x40, 0x69, 0x65, 0x74, 0x66,
0x2e, 0x6f, 0x72, 0x67, 0x3e, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x3a, 0x20, 0x20, 0x20, 0x4d, 0x61,
0x72, 0x74, 0x69, 0x6e, 0x20, 0x42, 0x6a, 0x6f, 0x72, 0x6b, 0x6c, 0x75,
0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x6d, 0x61, 0x69, 0x6c, 0x74,
0x6f, 0x3a, 0x6d, 0x62, 0x6a, 0x40, 0x74, 0x61, 0x69, 0x6c, 0x2d, 0x66,
0x2e, 0x63, 0x6f, 0x6d, 0x3e, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x3a, 0x20, 0x20, 0x20, 0x4a, 0x75,
0x65, 0x72, 0x67, 0x65, 0x6e, 0x20, 0x53, 0x63, 0x68, 0x6f, 0x65, 0x6e,
0x77, 0x61, 0x65, 0x6c, 0x64, 0x65, 0x72, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c,
0x6d, 0x61, 0x69, 0x6c, 0x74, 0x6f, 0x3a, 0x6a, 0x2e, 0x73, 0x63, 0x68,
0x6f, 0x65, 0x6e, 0x77, 0x61, 0x65, 0x6c, 0x64, 0x65, 0x72, 0x40, 0x6a,
0x61, 0x63, 0x6f, 0x62, 0x73, 0x2d, 0x75, 0x6e, 0x69, 0x76, 0x65, 0x72,
0x73, 0x69, 0x74, 0x79, 0x2e, 0x64, 0x65, 0x3e, 0x0a, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x3a, 0x20, 0x20,
0x20, 0x50, 0x68, 0x69, 0x6c, 0x20, 0x53, 0x68, 0x61, 0x66, 0x65, 0x72,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x3c, 0x6d, 0x61, 0x69, 0x6c, 0x74, 0x6f, 0x3a,
0x70, 0x68, 0x69, 0x6c, 0x40, 0x6a, 0x75, 0x6e, 0x69, 0x70, 0x65, 0x72,
0x2e, 0x6e, 0x65, 0x74, 0x3e, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x3a, 0x20, 0x20, 0x20, 0x4b, 0x65,
0x6e, 0x74, 0x20, 0x57, 0x61, 0x74, 0x73, 0x65, 0x6e, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x3c, 0x6d, 0x61, 0x69, 0x6c, 0x74, 0x6f, 0x3a, 0x6b, 0x77, 0x61,
0x74, 0x73, 0x65, 0x6e, 0x40, 0x6a, 0x75, 0x6e, 0x69, 0x70, 0x65, 0x72,
0x2e, 0x6e, 0x65, 0x74, 0x3e, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x3a, 0x20, 0x20, 0x20, 0x52, 0x6f,
0x62, 0x20, 0x57, 0x69, 0x6c, 0x74, 0x6f, 0x6e, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x3c, 0x72, 0x77, 0x69, 0x6c, 0x74, 0x6f, 0x6e, 0x40, 0x63, 0x69, 0x73,
0x63, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x3e, 0x22, 0x3b, 0x0a, 0x0a, 0x20,
0x20, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x22, 0x54, 0x68, 0x69, 0x73, 0x20, 0x59,
0x41, 0x4e, 0x47, 0x20, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x64,
0x65, 0x66, 0x69, 0x6e, 0x65, 0x73, 0x20, 0x61, 0x20, 0x73, 0x65, 0x74,
0x20, 0x6f, 0x66, 0x20, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x69,
0x65, 0x73, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x69, 0x64, 0x65, 0x6e, 0x74,
0x69, 0x66, 0x79, 0x69, 0x6e, 0x67, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x73, 0x2e, 0x0a,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x43, 0x6f, 0x70, 0x79, 0x72, 0x69,
0x67, 0x68, 0x74, 0x20, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x31, 0x38,
0x20, 0x49, 0x45, 0x54, 0x46, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20,
0x61, 0x6e, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x65, 0x72, 0x73,
0x6f, 0x6e, 0x73, 0x20, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69,
0x65, 0x64, 0x20, 0x61, 0x73, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x61,
0x75, 0x74, 0x68, 0x6f, 0x72, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68,
0x65, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x2e, 0x20, 0x20, 0x41, 0x6c, 0x6c,
0x20, 0x72, 0x69, 0x67, 0x68, 0x74, 0x73, 0x20, 0x72, 0x65, 0x73, 0x65,
0x72, 0x76, 0x65, 0x64, 0x2e, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
0x52, 0x65, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69,
0x6f, 0x6e, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x75, 0x73, 0x65, 0x20, 0x69,
0x6e, 0x20, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x20, 0x61, 0x6e, 0x64,
0x20, 0x62, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x20, 0x66, 0x6f, 0x72, 0x6d,
0x73, 0x2c, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x6f, 0x72, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x20, 0x77, 0x69, 0x74, 0x68, 0x6f, 0x75, 0x74, 0x20,
0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
0x2c, 0x20, 0x69, 0x73, 0x20, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x74, 0x74,
0x65, 0x64, 0x20, 0x70, 0x75, 0x72, 0x73, 0x75, 0x61, 0x6e, 0x74, 0x20,
0x74, 0x6f, 0x2c, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x73, 0x75, 0x62, 0x6a,
0x65, 0x63, 0x74, 0x20, 0x74, 0x6f, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
0x74, 0x68, 0x65, 0x20, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x20,
0x74, 0x65, 0x72, 0x6d, 0x73, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69,
0x6e, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x2c, 0x20, 0x74, 0x68, 0x65, 0x20,
0x53, 0x69, 0x6d, 0x70, 0x6c, 0x69, 0x66, 0x69, 0x65, 0x64, 0x20, 0x42,
0x53, 0x44, 0x20, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x20, 0x73,
0x65, 0x74, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6f, 0x72, 0x74,
0x68, 0x20, 0x69, 0x6e, 0x20, 0x53, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e,
0x20, 0x34, 0x2e, 0x63, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20,
0x49, 0x45, 0x54, 0x46, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x27, 0x73,
0x20, 0x4c, 0x65, 0x67, 0x61, 0x6c, 0x20, 0x50, 0x72, 0x6f, 0x76, 0x69,
0x73, 0x69, 0x6f, 0x6e, 0x73, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x52,
0x65, 0x6c, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x6f, 0x20, 0x49,
0x45, 0x54, 0x46, 0x20, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74,
0x73, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x28, 0x68, 0x74, 0x74, 0x70,
0x73, 0x3a, 0x2f, 0x2f, 0x74, 0x72, 0x75, 0x73, 0x74, 0x65, 0x65, 0x2e,
0x69, 0x65, 0x74, 0x66, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x6c, 0x69, 0x63,
0x65, 0x6e, 0x73, 0x65, 0x2d, 0x69, 0x6e, 0x66, 0x6f, 0x29, 0x2e, 0x0a,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x76,
0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68,
0x69, 0x73, 0x20, 0x59, 0x41, 0x4e, 0x47, 0x20, 0x6d, 0x6f, 0x64, 0x75,
0x6c, 0x65, 0x20, 0x69, 0x73, 0x20, 0x70, 0x61, 0x72, 0x74, 0x20, 0x6f,
0x66, 0x20, 0x52, 0x46, 0x43, 0x20, 0x38, 0x33, 0x34, 0x32, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x20, 0x28, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f,
0x2f, 0x77, 0x77, 0x77, 0x2e, 0x72, 0x66, 0x63, 0x2d, 0x65, 0x64, 0x69,
0x74, 0x6f, 0x72, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x69, 0x6e, 0x66, 0x6f,
0x2f, 0x72, 0x66, 0x63, 0x38, 0x33, 0x34, 0x32, 0x29, 0x3b, 0x20, 0x73,
0x65, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x52, 0x46, 0x43, 0x20, 0x69,
0x74, 0x73, 0x65, 0x6c, 0x66, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66,
0x6f, 0x72, 0x20, 0x66, 0x75, 0x6c, 0x6c, 0x20, 0x6c, 0x65, 0x67, 0x61,
0x6c, 0x20, 0x6e, 0x6f, 0x74, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x22, 0x3b,
0x0a, 0x0a, 0x20, 0x20, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e,
0x20, 0x32, 0x30, 0x31, 0x38, 0x2d, 0x30, 0x32, 0x2d, 0x31, 0x34, 0x20,
0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69,
0x70, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x22, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x76,
0x69, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x52, 0x46, 0x43, 0x20, 0x38, 0x33,
0x34, 0x32, 0x3a, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x20,
0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x44,
0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x20, 0x41, 0x72, 0x63,
0x68, 0x69, 0x74, 0x65, 0x63, 0x74, 0x75, 0x72, 0x65, 0x20, 0x28, 0x4e,
0x4d, 0x44, 0x41, 0x29, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x0a, 0x0a,
0x20, 0x20, 0x2f, 0x2a, 0x0a, 0x20, 0x20, 0x20, 0x2a, 0x20, 0x49, 0x64,
0x65, 0x6e, 0x74, 0x69, 0x74, 0x69, 0x65, 0x73, 0x0a, 0x20, 0x20, 0x20,
0x2a, 0x2f, 0x0a, 0x0a, 0x20, 0x20, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69,
0x74, 0x79, 0x20, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65,
0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x73, 0x63, 0x72,
0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x22, 0x41, 0x62, 0x73, 0x74, 0x72, 0x61, 0x63, 0x74, 0x20, 0x62,
0x61, 0x73, 0x65, 0x20, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79,
0x20, 0x66, 0x6f, 0x72, 0x20, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f,
0x72, 0x65, 0x20, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x69, 0x65,
0x73, 0x2e, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x0a, 0x0a, 0x20, 0x20,
0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x20, 0x63, 0x6f, 0x6e,
0x76, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x20, 0x7b, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x62, 0x61, 0x73, 0x65, 0x20, 0x64, 0x61, 0x74,
0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x41, 0x62, 0x73, 0x74, 0x72,
0x61, 0x63, 0x74, 0x20, 0x62, 0x61, 0x73, 0x65, 0x20, 0x69, 0x64, 0x65,
0x6e, 0x74, 0x69, 0x74, 0x79, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x63, 0x6f,
0x6e, 0x76, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x20, 0x63,
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x61, 0x74, 0x61,
0x73, 0x74, 0x6f, 0x72, 0x65, 0x73, 0x2e, 0x22, 0x3b, 0x0a, 0x20, 0x20,
0x7d, 0x0a, 0x0a, 0x20, 0x20, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74,
0x79, 0x20, 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x7b, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x62, 0x61, 0x73, 0x65, 0x20, 0x63, 0x6f, 0x6e,
0x76, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x3b, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69,
0x6f, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x54, 0x68,
0x65, 0x20, 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x63, 0x6f,
0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20,
0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x22, 0x3b,
0x0a, 0x20, 0x20, 0x7d, 0x0a, 0x0a, 0x20, 0x20, 0x69, 0x64, 0x65, 0x6e,
0x74, 0x69, 0x74, 0x79, 0x20, 0x63, 0x61, 0x6e, 0x64, 0x69, 0x64, 0x61,
0x74, 0x65, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x62, 0x61, 0x73,
0x65, 0x20, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e,
0x61, 0x6c, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x73, 0x63,
0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x22, 0x54, 0x68, 0x65, 0x20, 0x63, 0x61, 0x6e, 0x64, 0x69,
0x64, 0x61, 0x74, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75,
0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x64, 0x61, 0x74, 0x61, 0x73,
0x74, 0x6f, 0x72, 0x65, 0x2e, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x0a,
0x0a, 0x20, 0x20, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x20,
0x73, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x20, 0x7b, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x62, 0x61, 0x73, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x76, 0x65,
0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x3b, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x54, 0x68, 0x65, 0x20,
0x73, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x20, 0x63, 0x6f, 0x6e, 0x66,
0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x64, 0x61,
0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x22, 0x3b, 0x0a, 0x20,
0x20, 0x7d, 0x0a, 0x0a, 0x20, 0x20, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69,
0x74, 0x79, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x20,
0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x62, 0x61, 0x73, 0x65, 0x20, 0x63,
0x6f, 0x6e, 0x76, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x3b,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70,
0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
0x54, 0x68, 0x65, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x64,
0x20, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69,
0x6f, 0x6e, 0x20, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65,
0x2e, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x0a, 0x0a, 0x20, 0x20, 0x69,
0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x20, 0x64, 0x79, 0x6e, 0x61,
0x6d, 0x69, 0x63, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x62, 0x61,
0x73, 0x65, 0x20, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65,
0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69,
0x70, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x22, 0x41, 0x62, 0x73, 0x74, 0x72, 0x61, 0x63, 0x74, 0x20, 0x62, 0x61,
0x73, 0x65, 0x20, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x20,
0x66, 0x6f, 0x72, 0x20, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x20,
0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x20, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x73,
0x2e, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x0a, 0x0a, 0x20, 0x20, 0x69,
0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x20, 0x6f, 0x70, 0x65, 0x72,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x20, 0x7b, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x62, 0x61, 0x73, 0x65, 0x20, 0x64, 0x61, 0x74, 0x61, 0x73,
0x74, 0x6f, 0x72, 0x65, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65,
0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x22, 0x54, 0x68, 0x65, 0x20, 0x6f, 0x70, 0x65,
0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x20, 0x73, 0x74, 0x61,
0x74, 0x65, 0x20, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65,
0x2e, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x0a, 0x0a, 0x20, 0x20, 0x2f,
0x2a, 0x0a, 0x20, 0x20, 0x20, 0x2a, 0x20, 0x54, 0x79, 0x70, 0x65, 0x20,
0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x0a,
0x20, 0x20, 0x20, 0x2a, 0x2f, 0x0a, 0x0a, 0x20, 0x20, 0x74, 0x79, 0x70,
0x65, 0x64, 0x65, 0x66, 0x20, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f,
0x72, 0x65, 0x2d, 0x72, 0x65, 0x66, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x74, 0x79, 0x70, 0x65, 0x20, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69,
0x74, 0x79, 0x72, 0x65, 0x66, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x62, 0x61, 0x73, 0x65, 0x20, 0x64, 0x61, 0x74, 0x61, 0x73,
0x74, 0x6f, 0x72, 0x65, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74,
0x69, 0x6f, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x41,
0x20, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x20, 0x69,
0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x20, 0x72, 0x65, 0x66, 0x65,
0x72, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x7d,
0x0a, 0x7d, 0x0a, 0x00
};

View file

@ -0,0 +1,117 @@
module ietf-datastores {
yang-version 1.1;
namespace "urn:ietf:params:xml:ns:yang:ietf-datastores";
prefix ds;
organization
"IETF Network Modeling (NETMOD) Working Group";
contact
"WG Web: <https://datatracker.ietf.org/wg/netmod/>
WG List: <mailto:netmod@ietf.org>
Author: Martin Bjorklund
<mailto:mbj@tail-f.com>
Author: Juergen Schoenwaelder
<mailto:j.schoenwaelder@jacobs-university.de>
Author: Phil Shafer
<mailto:phil@juniper.net>
Author: Kent Watsen
<mailto:kwatsen@juniper.net>
Author: Rob Wilton
<rwilton@cisco.com>";
description
"This YANG module defines a set of identities for identifying
datastores.
Copyright (c) 2018 IETF Trust and the persons identified as
authors of the code. All rights reserved.
Redistribution and use in source and binary forms, with or
without modification, is permitted pursuant to, and subject to
the license terms contained in, the Simplified BSD License set
forth in Section 4.c of the IETF Trust's Legal Provisions
Relating to IETF Documents
(https://trustee.ietf.org/license-info).
This version of this YANG module is part of RFC 8342
(https://www.rfc-editor.org/info/rfc8342); see the RFC itself
for full legal notices.";
revision 2018-02-14 {
description
"Initial revision.";
reference
"RFC 8342: Network Management Datastore Architecture (NMDA)";
}
/*
* Identities
*/
identity datastore {
description
"Abstract base identity for datastore identities.";
}
identity conventional {
base datastore;
description
"Abstract base identity for conventional configuration
datastores.";
}
identity running {
base conventional;
description
"The running configuration datastore.";
}
identity candidate {
base conventional;
description
"The candidate configuration datastore.";
}
identity startup {
base conventional;
description
"The startup configuration datastore.";
}
identity intended {
base conventional;
description
"The intended configuration datastore.";
}
identity dynamic {
base datastore;
description
"Abstract base identity for dynamic configuration datastores.";
}
identity operational {
base datastore;
description
"The operational state datastore.";
}
/*
* Type definitions
*/
typedef datastore-ref {
type identityref {
base datastore;
}
description
"A datastore identity reference.";
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,457 @@
module ietf-inet-types {
namespace "urn:ietf:params:xml:ns:yang:ietf-inet-types";
prefix "inet";
organization
"IETF NETMOD (NETCONF Data Modeling Language) Working Group";
contact
"WG Web: <http://tools.ietf.org/wg/netmod/>
WG List: <mailto:netmod@ietf.org>
WG Chair: David Kessens
<mailto:david.kessens@nsn.com>
WG Chair: Juergen Schoenwaelder
<mailto:j.schoenwaelder@jacobs-university.de>
Editor: Juergen Schoenwaelder
<mailto:j.schoenwaelder@jacobs-university.de>";
description
"This module contains a collection of generally useful derived
YANG data types for Internet addresses and related things.
Copyright (c) 2013 IETF Trust and the persons identified as
authors of the code. All rights reserved.
Redistribution and use in source and binary forms, with or
without modification, is permitted pursuant to, and subject
to the license terms contained in, the Simplified BSD License
set forth in Section 4.c of the IETF Trust's Legal Provisions
Relating to IETF Documents
(http://trustee.ietf.org/license-info).
This version of this YANG module is part of RFC 6991; see
the RFC itself for full legal notices.";
revision 2013-07-15 {
description
"This revision adds the following new data types:
- ip-address-no-zone
- ipv4-address-no-zone
- ipv6-address-no-zone";
reference
"RFC 6991: Common YANG Data Types";
}
revision 2010-09-24 {
description
"Initial revision.";
reference
"RFC 6021: Common YANG Data Types";
}
/*** collection of types related to protocol fields ***/
typedef ip-version {
type enumeration {
enum unknown {
value "0";
description
"An unknown or unspecified version of the Internet
protocol.";
}
enum ipv4 {
value "1";
description
"The IPv4 protocol as defined in RFC 791.";
}
enum ipv6 {
value "2";
description
"The IPv6 protocol as defined in RFC 2460.";
}
}
description
"This value represents the version of the IP protocol.
In the value set and its semantics, this type is equivalent
to the InetVersion textual convention of the SMIv2.";
reference
"RFC 791: Internet Protocol
RFC 2460: Internet Protocol, Version 6 (IPv6) Specification
RFC 4001: Textual Conventions for Internet Network Addresses";
}
typedef dscp {
type uint8 {
range "0..63";
}
description
"The dscp type represents a Differentiated Services Code Point
that may be used for marking packets in a traffic stream.
In the value set and its semantics, this type is equivalent
to the Dscp textual convention of the SMIv2.";
reference
"RFC 3289: Management Information Base for the Differentiated
Services Architecture
RFC 2474: Definition of the Differentiated Services Field
(DS Field) in the IPv4 and IPv6 Headers
RFC 2780: IANA Allocation Guidelines For Values In
the Internet Protocol and Related Headers";
}
typedef ipv6-flow-label {
type uint32 {
range "0..1048575";
}
description
"The ipv6-flow-label type represents the flow identifier or Flow
Label in an IPv6 packet header that may be used to
discriminate traffic flows.
In the value set and its semantics, this type is equivalent
to the IPv6FlowLabel textual convention of the SMIv2.";
reference
"RFC 3595: Textual Conventions for IPv6 Flow Label
RFC 2460: Internet Protocol, Version 6 (IPv6) Specification";
}
typedef port-number {
type uint16 {
range "0..65535";
}
description
"The port-number type represents a 16-bit port number of an
Internet transport-layer protocol such as UDP, TCP, DCCP, or
SCTP. Port numbers are assigned by IANA. A current list of
all assignments is available from <http://www.iana.org/>.
Note that the port number value zero is reserved by IANA. In
situations where the value zero does not make sense, it can
be excluded by subtyping the port-number type.
In the value set and its semantics, this type is equivalent
to the InetPortNumber textual convention of the SMIv2.";
reference
"RFC 768: User Datagram Protocol
RFC 793: Transmission Control Protocol
RFC 4960: Stream Control Transmission Protocol
RFC 4340: Datagram Congestion Control Protocol (DCCP)
RFC 4001: Textual Conventions for Internet Network Addresses";
}
/*** collection of types related to autonomous systems ***/
typedef as-number {
type uint32;
description
"The as-number type represents autonomous system numbers
which identify an Autonomous System (AS). An AS is a set
of routers under a single technical administration, using
an interior gateway protocol and common metrics to route
packets within the AS, and using an exterior gateway
protocol to route packets to other ASes. IANA maintains
the AS number space and has delegated large parts to the
regional registries.
Autonomous system numbers were originally limited to 16
bits. BGP extensions have enlarged the autonomous system
number space to 32 bits. This type therefore uses an uint32
base type without a range restriction in order to support
a larger autonomous system number space.
In the value set and its semantics, this type is equivalent
to the InetAutonomousSystemNumber textual convention of
the SMIv2.";
reference
"RFC 1930: Guidelines for creation, selection, and registration
of an Autonomous System (AS)
RFC 4271: A Border Gateway Protocol 4 (BGP-4)
RFC 4001: Textual Conventions for Internet Network Addresses
RFC 6793: BGP Support for Four-Octet Autonomous System (AS)
Number Space";
}
/*** collection of types related to IP addresses and hostnames ***/
typedef ip-address {
type union {
type inet:ipv4-address;
type inet:ipv6-address;
}
description
"The ip-address type represents an IP address and is IP
version neutral. The format of the textual representation
implies the IP version. This type supports scoped addresses
by allowing zone identifiers in the address format.";
reference
"RFC 4007: IPv6 Scoped Address Architecture";
}
typedef ipv4-address {
type string {
pattern
'(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}'
+ '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])'
+ '(%[\p{N}\p{L}]+)?';
}
description
"The ipv4-address type represents an IPv4 address in
dotted-quad notation. The IPv4 address may include a zone
index, separated by a % sign.
The zone index is used to disambiguate identical address
values. For link-local addresses, the zone index will
typically be the interface index number or the name of an
interface. If the zone index is not present, the default
zone of the device will be used.
The canonical format for the zone index is the numerical
format";
}
typedef ipv6-address {
type string {
pattern '((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}'
+ '((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|'
+ '(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}'
+ '(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))'
+ '(%[\p{N}\p{L}]+)?';
pattern '(([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|'
+ '((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)'
+ '(%.+)?';
}
description
"The ipv6-address type represents an IPv6 address in full,
mixed, shortened, and shortened-mixed notation. The IPv6
address may include a zone index, separated by a % sign.
The zone index is used to disambiguate identical address
values. For link-local addresses, the zone index will
typically be the interface index number or the name of an
interface. If the zone index is not present, the default
zone of the device will be used.
The canonical format of IPv6 addresses uses the textual
representation defined in Section 4 of RFC 5952. The
canonical format for the zone index is the numerical
format as described in Section 11.2 of RFC 4007.";
reference
"RFC 4291: IP Version 6 Addressing Architecture
RFC 4007: IPv6 Scoped Address Architecture
RFC 5952: A Recommendation for IPv6 Address Text
Representation";
}
typedef ip-address-no-zone {
type union {
type inet:ipv4-address-no-zone;
type inet:ipv6-address-no-zone;
}
description
"The ip-address-no-zone type represents an IP address and is
IP version neutral. The format of the textual representation
implies the IP version. This type does not support scoped
addresses since it does not allow zone identifiers in the
address format.";
reference
"RFC 4007: IPv6 Scoped Address Architecture";
}
typedef ipv4-address-no-zone {
type inet:ipv4-address {
pattern '[0-9\.]*';
}
description
"An IPv4 address without a zone index. This type, derived from
ipv4-address, may be used in situations where the zone is
known from the context and hence no zone index is needed.";
}
typedef ipv6-address-no-zone {
type inet:ipv6-address {
pattern '[0-9a-fA-F:\.]*';
}
description
"An IPv6 address without a zone index. This type, derived from
ipv6-address, may be used in situations where the zone is
known from the context and hence no zone index is needed.";
reference
"RFC 4291: IP Version 6 Addressing Architecture
RFC 4007: IPv6 Scoped Address Architecture
RFC 5952: A Recommendation for IPv6 Address Text
Representation";
}
typedef ip-prefix {
type union {
type inet:ipv4-prefix;
type inet:ipv6-prefix;
}
description
"The ip-prefix type represents an IP prefix and is IP
version neutral. The format of the textual representations
implies the IP version.";
}
typedef ipv4-prefix {
type string {
pattern
'(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}'
+ '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])'
+ '/(([0-9])|([1-2][0-9])|(3[0-2]))';
}
description
"The ipv4-prefix type represents an IPv4 address prefix.
The prefix length is given by the number following the
slash character and must be less than or equal to 32.
A prefix length value of n corresponds to an IP address
mask that has n contiguous 1-bits from the most
significant bit (MSB) and all other bits set to 0.
The canonical format of an IPv4 prefix has all bits of
the IPv4 address set to zero that are not part of the
IPv4 prefix.";
}
typedef ipv6-prefix {
type string {
pattern '((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}'
+ '((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|'
+ '(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}'
+ '(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))'
+ '(/(([0-9])|([0-9]{2})|(1[0-1][0-9])|(12[0-8])))';
pattern '(([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|'
+ '((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)'
+ '(/.+)';
}
description
"The ipv6-prefix type represents an IPv6 address prefix.
The prefix length is given by the number following the
slash character and must be less than or equal to 128.
A prefix length value of n corresponds to an IP address
mask that has n contiguous 1-bits from the most
significant bit (MSB) and all other bits set to 0.
The IPv6 address should have all bits that do not belong
to the prefix set to zero.
The canonical format of an IPv6 prefix has all bits of
the IPv6 address set to zero that are not part of the
IPv6 prefix. Furthermore, the IPv6 address is represented
as defined in Section 4 of RFC 5952.";
reference
"RFC 5952: A Recommendation for IPv6 Address Text
Representation";
}
/*** collection of domain name and URI types ***/
typedef domain-name {
type string {
length "1..253";
pattern
'((([a-zA-Z0-9_]([a-zA-Z0-9\-_]){0,61})?[a-zA-Z0-9]\.)*'
+ '([a-zA-Z0-9_]([a-zA-Z0-9\-_]){0,61})?[a-zA-Z0-9]\.?)'
+ '|\.';
}
description
"The domain-name type represents a DNS domain name. The
name SHOULD be fully qualified whenever possible.
Internet domain names are only loosely specified. Section
3.5 of RFC 1034 recommends a syntax (modified in Section
2.1 of RFC 1123). The pattern above is intended to allow
for current practice in domain name use, and some possible
future expansion. It is designed to hold various types of
domain names, including names used for A or AAAA records
(host names) and other records, such as SRV records. Note
that Internet host names have a stricter syntax (described
in RFC 952) than the DNS recommendations in RFCs 1034 and
1123, and that systems that want to store host names in
schema nodes using the domain-name type are recommended to
adhere to this stricter standard to ensure interoperability.
The encoding of DNS names in the DNS protocol is limited
to 255 characters. Since the encoding consists of labels
prefixed by a length bytes and there is a trailing NULL
byte, only 253 characters can appear in the textual dotted
notation.
The description clause of schema nodes using the domain-name
type MUST describe when and how these names are resolved to
IP addresses. Note that the resolution of a domain-name value
may require to query multiple DNS records (e.g., A for IPv4
and AAAA for IPv6). The order of the resolution process and
which DNS record takes precedence can either be defined
explicitly or may depend on the configuration of the
resolver.
Domain-name values use the US-ASCII encoding. Their canonical
format uses lowercase US-ASCII characters. Internationalized
domain names MUST be A-labels as per RFC 5890.";
reference
"RFC 952: DoD Internet Host Table Specification
RFC 1034: Domain Names - Concepts and Facilities
RFC 1123: Requirements for Internet Hosts -- Application
and Support
RFC 2782: A DNS RR for specifying the location of services
(DNS SRV)
RFC 5890: Internationalized Domain Names in Applications
(IDNA): Definitions and Document Framework";
}
typedef host {
type union {
type inet:ip-address;
type inet:domain-name;
}
description
"The host type represents either an IP address or a DNS
domain name.";
}
typedef uri {
type string;
description
"The uri type represents a Uniform Resource Identifier
(URI) as defined by STD 66.
Objects using the uri type MUST be in US-ASCII encoding,
and MUST be normalized as described by RFC 3986 Sections
6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary
percent-encoding is removed, and all case-insensitive
characters are set to lowercase except for hexadecimal
digits, which are normalized to uppercase as described in
Section 6.2.2.1.
The purpose of this normalization is to help provide
unique URIs. Note that this normalization is not
sufficient to provide uniqueness. Two URIs that are
textually distinct after this normalization may still be
equivalent.
Objects using the uri type may restrict the schemes that
they permit. For example, 'data:' and 'urn:' schemes
might not be appropriate.
A zero-length URI is not a valid URI. This can be used to
express 'URI absent' where required.
In the value set and its semantics, this type is equivalent
to the Uri SMIv2 textual convention defined in RFC 5017.";
reference
"RFC 3986: Uniform Resource Identifier (URI): Generic Syntax
RFC 3305: Report from the Joint W3C/IETF URI Planning Interest
Group: Uniform Resource Identifiers (URIs), URLs,
and Uniform Resource Names (URNs): Clarifications
and Recommendations
RFC 5017: MIB Textual Conventions for Uniform Resource
Identifiers (URIs)";
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,544 @@
module ietf-yang-library {
yang-version 1.1;
namespace "urn:ietf:params:xml:ns:yang:ietf-yang-library";
prefix yanglib;
import ietf-yang-types {
prefix yang;
reference
"RFC 6991: Common YANG Data Types";
}
import ietf-inet-types {
prefix inet;
reference
"RFC 6991: Common YANG Data Types";
}
import ietf-datastores {
prefix ds;
reference
"RFC 8342: Network Management Datastore Architecture
(NMDA)";
}
organization
"IETF NETCONF (Network Configuration) Working Group";
contact
"WG Web: <https://datatracker.ietf.org/wg/netconf/>
WG List: <mailto:netconf@ietf.org>
Author: Andy Bierman
<mailto:andy@yumaworks.com>
Author: Martin Bjorklund
<mailto:mbj@tail-f.com>
Author: Juergen Schoenwaelder
<mailto:j.schoenwaelder@jacobs-university.de>
Author: Kent Watsen
<mailto:kent+ietf@watsen.net>
Author: Robert Wilton
<mailto:rwilton@cisco.com>";
description
"This module provides information about the YANG modules,
datastores, and datastore schemas used by a network
management server.
The key words 'MUST', 'MUST NOT', 'REQUIRED', 'SHALL', 'SHALL
NOT', 'SHOULD', 'SHOULD NOT', 'RECOMMENDED', 'NOT RECOMMENDED',
'MAY', and 'OPTIONAL' in this document are to be interpreted as
described in BCP 14 (RFC 2119) (RFC 8174) when, and only when,
they appear in all capitals, as shown here.
Copyright (c) 2019 IETF Trust and the persons identified as
authors of the code. All rights reserved.
Redistribution and use in source and binary forms, with or
without modification, is permitted pursuant to, and subject
to the license terms contained in, the Simplified BSD License
set forth in Section 4.c of the IETF Trust's Legal Provisions
Relating to IETF Documents
(https://trustee.ietf.org/license-info).
This version of this YANG module is part of RFC 8525; see
the RFC itself for full legal notices.";
revision 2019-01-04 {
description
"Added support for multiple datastores according to the
Network Management Datastore Architecture (NMDA).";
reference
"RFC 8525: YANG Library";
}
revision 2016-04-09 {
description
"Initial revision.";
reference
"RFC 7895: YANG Module Library";
}
/*
* Typedefs
*/
typedef revision-identifier {
type string {
pattern '\d{4}-\d{2}-\d{2}';
}
description
"Represents a specific date in YYYY-MM-DD format.";
}
/*
* Groupings
*/
grouping module-identification-leafs {
description
"Parameters for identifying YANG modules and submodules.";
leaf name {
type yang:yang-identifier;
mandatory true;
description
"The YANG module or submodule name.";
}
leaf revision {
type revision-identifier;
description
"The YANG module or submodule revision date. If no revision
statement is present in the YANG module or submodule, this
leaf is not instantiated.";
}
}
grouping location-leaf-list {
description
"Common leaf-list parameter for the locations of modules and
submodules.";
leaf-list location {
type inet:uri;
description
"Contains a URL that represents the YANG schema
resource for this module or submodule.
This leaf will only be present if there is a URL
available for retrieval of the schema for this entry.";
}
}
grouping module-implementation-parameters {
description
"Parameters for describing the implementation of a module.";
leaf-list feature {
type yang:yang-identifier;
description
"List of all YANG feature names from this module that are
supported by the server, regardless whether they are defined
in the module or any included submodule.";
}
leaf-list deviation {
type leafref {
path "../../module/name";
}
description
"List of all YANG deviation modules used by this server to
modify the conformance of the module associated with this
entry. Note that the same module can be used for deviations
for multiple modules, so the same entry MAY appear within
multiple 'module' entries.
This reference MUST NOT (directly or indirectly)
refer to the module being deviated.
Robust clients may want to make sure that they handle a
situation where a module deviates itself (directly or
indirectly) gracefully.";
}
}
grouping module-set-parameters {
description
"A set of parameters that describe a module set.";
leaf name {
type string;
description
"An arbitrary name of the module set.";
}
list module {
key "name";
description
"An entry in this list represents a module implemented by the
server, as per Section 5.6.5 of RFC 7950, with a particular
set of supported features and deviations.";
reference
"RFC 7950: The YANG 1.1 Data Modeling Language";
uses module-identification-leafs;
leaf namespace {
type inet:uri;
mandatory true;
description
"The XML namespace identifier for this module.";
}
uses location-leaf-list;
list submodule {
key "name";
description
"Each entry represents one submodule within the
parent module.";
uses module-identification-leafs;
uses location-leaf-list;
}
uses module-implementation-parameters;
}
list import-only-module {
key "name revision";
description
"An entry in this list indicates that the server imports
reusable definitions from the specified revision of the
module but does not implement any protocol-accessible
objects from this revision.
Multiple entries for the same module name MAY exist. This
can occur if multiple modules import the same module but
specify different revision dates in the import statements.";
leaf name {
type yang:yang-identifier;
description
"The YANG module name.";
}
leaf revision {
type union {
type revision-identifier;
type string {
length "0";
}
}
description
"The YANG module revision date.
A zero-length string is used if no revision statement
is present in the YANG module.";
}
leaf namespace {
type inet:uri;
mandatory true;
description
"The XML namespace identifier for this module.";
}
uses location-leaf-list;
list submodule {
key "name";
description
"Each entry represents one submodule within the
parent module.";
uses module-identification-leafs;
uses location-leaf-list;
}
}
}
grouping yang-library-parameters {
description
"The YANG library data structure is represented as a grouping
so it can be reused in configuration or another monitoring
data structure.";
list module-set {
key "name";
description
"A set of modules that may be used by one or more schemas.
A module set does not have to be referentially complete,
i.e., it may define modules that contain import statements
for other modules not included in the module set.";
uses module-set-parameters;
}
list schema {
key "name";
description
"A datastore schema that may be used by one or more
datastores.
The schema must be valid and referentially complete, i.e.,
it must contain modules to satisfy all used import
statements for all modules specified in the schema.";
leaf name {
type string;
description
"An arbitrary name of the schema.";
}
leaf-list module-set {
type leafref {
path "../../module-set/name";
}
description
"A set of module-sets that are included in this schema.
If a non-import-only module appears in multiple module
sets, then the module revision and the associated features
and deviations must be identical.";
}
}
list datastore {
key "name";
description
"A datastore supported by this server.
Each datastore indicates which schema it supports.
The server MUST instantiate one entry in this list per
specific datastore it supports.
Each datastore entry with the same datastore schema SHOULD
reference the same schema.";
leaf name {
type ds:datastore-ref;
description
"The identity of the datastore.";
}
leaf schema {
type leafref {
path "../../schema/name";
}
mandatory true;
description
"A reference to the schema supported by this datastore.
All non-import-only modules of the schema are implemented
with their associated features and deviations.";
}
}
}
/*
* Top-level container
*/
container yang-library {
config false;
description
"Container holding the entire YANG library of this server.";
uses yang-library-parameters;
leaf content-id {
type string;
mandatory true;
description
"A server-generated identifier of the contents of the
'/yang-library' tree. The server MUST change the value of
this leaf if the information represented by the
'/yang-library' tree, except '/yang-library/content-id', has
changed.";
}
}
/*
* Notifications
*/
notification yang-library-update {
description
"Generated when any YANG library information on the
server has changed.";
leaf content-id {
type leafref {
path "/yanglib:yang-library/yanglib:content-id";
}
mandatory true;
description
"Contains the YANG library content identifier for the updated
YANG library at the time the notification is generated.";
}
}
/*
* Legacy groupings
*/
grouping module-list {
status deprecated;
description
"The module data structure is represented as a grouping
so it can be reused in configuration or another monitoring
data structure.";
grouping common-leafs {
status deprecated;
description
"Common parameters for YANG modules and submodules.";
leaf name {
type yang:yang-identifier;
status deprecated;
description
"The YANG module or submodule name.";
}
leaf revision {
type union {
type revision-identifier;
type string {
length "0";
}
}
status deprecated;
description
"The YANG module or submodule revision date.
A zero-length string is used if no revision statement
is present in the YANG module or submodule.";
}
}
grouping schema-leaf {
status deprecated;
description
"Common schema leaf parameter for modules and submodules.";
leaf schema {
type inet:uri;
description
"Contains a URL that represents the YANG schema
resource for this module or submodule.
This leaf will only be present if there is a URL
available for retrieval of the schema for this entry.";
}
}
list module {
key "name revision";
status deprecated;
description
"Each entry represents one revision of one module
currently supported by the server.";
uses common-leafs {
status deprecated;
}
uses schema-leaf {
status deprecated;
}
leaf namespace {
type inet:uri;
mandatory true;
status deprecated;
description
"The XML namespace identifier for this module.";
}
leaf-list feature {
type yang:yang-identifier;
status deprecated;
description
"List of YANG feature names from this module that are
supported by the server, regardless of whether they are
defined in the module or any included submodule.";
}
list deviation {
key "name revision";
status deprecated;
description
"List of YANG deviation module names and revisions
used by this server to modify the conformance of
the module associated with this entry. Note that
the same module can be used for deviations for
multiple modules, so the same entry MAY appear
within multiple 'module' entries.
The deviation module MUST be present in the 'module'
list, with the same name and revision values.
The 'conformance-type' value will be 'implement' for
the deviation module.";
uses common-leafs {
status deprecated;
}
}
leaf conformance-type {
type enumeration {
enum implement {
description
"Indicates that the server implements one or more
protocol-accessible objects defined in the YANG module
identified in this entry. This includes deviation
statements defined in the module.
For YANG version 1.1 modules, there is at most one
'module' entry with conformance type 'implement' for a
particular module name, since YANG 1.1 requires that
at most one revision of a module is implemented.
For YANG version 1 modules, there SHOULD NOT be more
than one 'module' entry for a particular module
name.";
}
enum import {
description
"Indicates that the server imports reusable definitions
from the specified revision of the module but does
not implement any protocol-accessible objects from
this revision.
Multiple 'module' entries for the same module name MAY
exist. This can occur if multiple modules import the
same module but specify different revision dates in
the import statements.";
}
}
mandatory true;
status deprecated;
description
"Indicates the type of conformance the server is claiming
for the YANG module identified by this entry.";
}
list submodule {
key "name revision";
status deprecated;
description
"Each entry represents one submodule within the
parent module.";
uses common-leafs {
status deprecated;
}
uses schema-leaf {
status deprecated;
}
}
}
}
/*
* Legacy operational state data nodes
*/
container modules-state {
config false;
status deprecated;
description
"Contains YANG module monitoring information.";
leaf module-set-id {
type string;
mandatory true;
status deprecated;
description
"Contains a server-specific identifier representing
the current set of modules and submodules. The
server MUST change the value of this leaf if the
information represented by the 'module' list instances
has changed.";
}
uses module-list {
status deprecated;
}
}
/*
* Legacy notifications
*/
notification yang-library-change {
status deprecated;
description
"Generated when the set of modules and submodules supported
by the server has changed.";
leaf module-set-id {
type leafref {
path "/yanglib:modules-state/yanglib:module-set-id";
}
mandatory true;
status deprecated;
description
"Contains the module-set-id value representing the
set of modules and submodules supported at the server
at the time the notification is generated.";
}
}
}

View file

@ -0,0 +1,220 @@
unsigned char ietf_yang_metadata_2016_08_05_yang[] = {
0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x69, 0x65, 0x74, 0x66, 0x2d,
0x79, 0x61, 0x6e, 0x67, 0x2d, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74,
0x61, 0x20, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65,
0x20, 0x22, 0x75, 0x72, 0x6e, 0x3a, 0x69, 0x65, 0x74, 0x66, 0x3a, 0x70,
0x61, 0x72, 0x61, 0x6d, 0x73, 0x3a, 0x78, 0x6d, 0x6c, 0x3a, 0x6e, 0x73,
0x3a, 0x79, 0x61, 0x6e, 0x67, 0x3a, 0x69, 0x65, 0x74, 0x66, 0x2d, 0x79,
0x61, 0x6e, 0x67, 0x2d, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61,
0x22, 0x3b, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x20, 0x6d, 0x64, 0x3b,
0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e,
0x20, 0x22, 0x49, 0x45, 0x54, 0x46, 0x20, 0x4e, 0x45, 0x54, 0x4d, 0x4f,
0x44, 0x20, 0x28, 0x4e, 0x45, 0x54, 0x43, 0x4f, 0x4e, 0x46, 0x20, 0x44,
0x61, 0x74, 0x61, 0x20, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x69, 0x6e, 0x67,
0x20, 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x29, 0x20, 0x57,
0x6f, 0x72, 0x6b, 0x69, 0x6e, 0x67, 0x20, 0x47, 0x72, 0x6f, 0x75, 0x70,
0x22, 0x3b, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x0a, 0x22, 0x57,
0x47, 0x20, 0x57, 0x65, 0x62, 0x3a, 0x20, 0x20, 0x20, 0x3c, 0x68, 0x74,
0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x74, 0x72,
0x61, 0x63, 0x6b, 0x65, 0x72, 0x2e, 0x69, 0x65, 0x74, 0x66, 0x2e, 0x6f,
0x72, 0x67, 0x2f, 0x77, 0x67, 0x2f, 0x6e, 0x65, 0x74, 0x6d, 0x6f, 0x64,
0x2f, 0x3e, 0x0a, 0x0a, 0x57, 0x47, 0x20, 0x4c, 0x69, 0x73, 0x74, 0x3a,
0x20, 0x20, 0x3c, 0x6d, 0x61, 0x69, 0x6c, 0x74, 0x6f, 0x3a, 0x6e, 0x65,
0x74, 0x6d, 0x6f, 0x64, 0x40, 0x69, 0x65, 0x74, 0x66, 0x2e, 0x6f, 0x72,
0x67, 0x3e, 0x0a, 0x0a, 0x57, 0x47, 0x20, 0x43, 0x68, 0x61, 0x69, 0x72,
0x3a, 0x20, 0x4c, 0x6f, 0x75, 0x20, 0x42, 0x65, 0x72, 0x67, 0x65, 0x72,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x3c, 0x6d, 0x61, 0x69, 0x6c, 0x74, 0x6f, 0x3a, 0x6c, 0x62, 0x65, 0x72,
0x67, 0x65, 0x72, 0x40, 0x6c, 0x61, 0x62, 0x6e, 0x2e, 0x6e, 0x65, 0x74,
0x3e, 0x0a, 0x0a, 0x57, 0x47, 0x20, 0x43, 0x68, 0x61, 0x69, 0x72, 0x3a,
0x20, 0x4b, 0x65, 0x6e, 0x74, 0x20, 0x57, 0x61, 0x74, 0x73, 0x65, 0x6e,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x3c, 0x6d, 0x61, 0x69, 0x6c, 0x74, 0x6f, 0x3a, 0x6b, 0x77, 0x61, 0x74,
0x73, 0x65, 0x6e, 0x40, 0x6a, 0x75, 0x6e, 0x69, 0x70, 0x65, 0x72, 0x2e,
0x6e, 0x65, 0x74, 0x3e, 0x0a, 0x0a, 0x45, 0x64, 0x69, 0x74, 0x6f, 0x72,
0x3a, 0x20, 0x20, 0x20, 0x4c, 0x61, 0x64, 0x69, 0x73, 0x6c, 0x61, 0x76,
0x20, 0x4c, 0x68, 0x6f, 0x74, 0x6b, 0x61, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x6d, 0x61, 0x69, 0x6c,
0x74, 0x6f, 0x3a, 0x6c, 0x68, 0x6f, 0x74, 0x6b, 0x61, 0x40, 0x6e, 0x69,
0x63, 0x2e, 0x63, 0x7a, 0x3e, 0x22, 0x3b, 0x64, 0x65, 0x73, 0x63, 0x72,
0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x22, 0x54, 0x68, 0x69, 0x73,
0x20, 0x59, 0x41, 0x4e, 0x47, 0x20, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65,
0x20, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x20,
0x27, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x27, 0x20,
0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x74, 0x68,
0x61, 0x74, 0x20, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x73, 0x0a, 0x66, 0x6f,
0x72, 0x20, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x6d,
0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x20, 0x61, 0x6e, 0x6e, 0x6f,
0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x0a, 0x0a, 0x43, 0x6f,
0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x28, 0x63, 0x29, 0x20,
0x32, 0x30, 0x31, 0x36, 0x20, 0x49, 0x45, 0x54, 0x46, 0x20, 0x54, 0x72,
0x75, 0x73, 0x74, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20,
0x70, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x73, 0x20, 0x69, 0x64, 0x65, 0x6e,
0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x20, 0x61, 0x73, 0x0a, 0x61, 0x75,
0x74, 0x68, 0x6f, 0x72, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65,
0x20, 0x63, 0x6f, 0x64, 0x65, 0x2e, 0x20, 0x20, 0x41, 0x6c, 0x6c, 0x20,
0x72, 0x69, 0x67, 0x68, 0x74, 0x73, 0x20, 0x72, 0x65, 0x73, 0x65, 0x72,
0x76, 0x65, 0x64, 0x2e, 0x0a, 0x0a, 0x52, 0x65, 0x64, 0x69, 0x73, 0x74,
0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x61, 0x6e, 0x64,
0x20, 0x75, 0x73, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x73, 0x6f, 0x75, 0x72,
0x63, 0x65, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x62, 0x69, 0x6e, 0x61, 0x72,
0x79, 0x20, 0x66, 0x6f, 0x72, 0x6d, 0x73, 0x2c, 0x20, 0x77, 0x69, 0x74,
0x68, 0x20, 0x6f, 0x72, 0x0a, 0x77, 0x69, 0x74, 0x68, 0x6f, 0x75, 0x74,
0x20, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x2c, 0x20, 0x69, 0x73, 0x20, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x74,
0x74, 0x65, 0x64, 0x20, 0x70, 0x75, 0x72, 0x73, 0x75, 0x61, 0x6e, 0x74,
0x20, 0x74, 0x6f, 0x2c, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x73, 0x75, 0x62,
0x6a, 0x65, 0x63, 0x74, 0x20, 0x74, 0x6f, 0x0a, 0x74, 0x68, 0x65, 0x20,
0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x20, 0x74, 0x65, 0x72, 0x6d,
0x73, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x64, 0x20,
0x69, 0x6e, 0x2c, 0x20, 0x74, 0x68, 0x65, 0x20, 0x53, 0x69, 0x6d, 0x70,
0x6c, 0x69, 0x66, 0x69, 0x65, 0x64, 0x20, 0x42, 0x53, 0x44, 0x20, 0x4c,
0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x20, 0x73, 0x65, 0x74, 0x0a, 0x66,
0x6f, 0x72, 0x74, 0x68, 0x20, 0x69, 0x6e, 0x20, 0x53, 0x65, 0x63, 0x74,
0x69, 0x6f, 0x6e, 0x20, 0x34, 0x2e, 0x63, 0x20, 0x6f, 0x66, 0x20, 0x74,
0x68, 0x65, 0x20, 0x49, 0x45, 0x54, 0x46, 0x20, 0x54, 0x72, 0x75, 0x73,
0x74, 0x27, 0x73, 0x20, 0x4c, 0x65, 0x67, 0x61, 0x6c, 0x20, 0x50, 0x72,
0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x0a, 0x52, 0x65, 0x6c,
0x61, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x6f, 0x20, 0x49, 0x45, 0x54,
0x46, 0x20, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x0a,
0x28, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x74, 0x72, 0x75, 0x73,
0x74, 0x65, 0x65, 0x2e, 0x69, 0x65, 0x74, 0x66, 0x2e, 0x6f, 0x72, 0x67,
0x2f, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x2d, 0x69, 0x6e, 0x66,
0x6f, 0x29, 0x2e, 0x0a, 0x0a, 0x54, 0x68, 0x69, 0x73, 0x20, 0x76, 0x65,
0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x69,
0x73, 0x20, 0x59, 0x41, 0x4e, 0x47, 0x20, 0x6d, 0x6f, 0x64, 0x75, 0x6c,
0x65, 0x20, 0x69, 0x73, 0x20, 0x70, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66,
0x20, 0x52, 0x46, 0x43, 0x20, 0x37, 0x39, 0x35, 0x32, 0x0a, 0x28, 0x68,
0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x72, 0x66,
0x63, 0x2d, 0x65, 0x64, 0x69, 0x74, 0x6f, 0x72, 0x2e, 0x6f, 0x72, 0x67,
0x2f, 0x69, 0x6e, 0x66, 0x6f, 0x2f, 0x72, 0x66, 0x63, 0x37, 0x39, 0x35,
0x32, 0x29, 0x3b, 0x20, 0x73, 0x65, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20,
0x52, 0x46, 0x43, 0x20, 0x69, 0x74, 0x73, 0x65, 0x6c, 0x66, 0x0a, 0x66,
0x6f, 0x72, 0x20, 0x66, 0x75, 0x6c, 0x6c, 0x20, 0x6c, 0x65, 0x67, 0x61,
0x6c, 0x20, 0x6e, 0x6f, 0x74, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x22, 0x3b,
0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x32, 0x30, 0x31,
0x36, 0x2d, 0x30, 0x38, 0x2d, 0x30, 0x35, 0x20, 0x7b, 0x64, 0x65, 0x73,
0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x22, 0x49, 0x6e,
0x69, 0x74, 0x69, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69,
0x6f, 0x6e, 0x2e, 0x22, 0x3b, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e,
0x63, 0x65, 0x20, 0x22, 0x52, 0x46, 0x43, 0x20, 0x37, 0x39, 0x35, 0x32,
0x3a, 0x20, 0x44, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x61,
0x6e, 0x64, 0x20, 0x55, 0x73, 0x69, 0x6e, 0x67, 0x20, 0x4d, 0x65, 0x74,
0x61, 0x64, 0x61, 0x74, 0x61, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x59,
0x41, 0x4e, 0x47, 0x22, 0x3b, 0x7d, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73,
0x69, 0x6f, 0x6e, 0x20, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69,
0x6f, 0x6e, 0x20, 0x7b, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74,
0x20, 0x6e, 0x61, 0x6d, 0x65, 0x3b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69,
0x70, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x22, 0x54, 0x68, 0x69, 0x73, 0x20,
0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x61, 0x6c,
0x6c, 0x6f, 0x77, 0x73, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x64, 0x65, 0x66,
0x69, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61,
0x74, 0x61, 0x20, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x73, 0x20, 0x69, 0x6e, 0x0a, 0x59, 0x41, 0x4e, 0x47, 0x20, 0x6d,
0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x2e, 0x20, 0x20, 0x54, 0x68, 0x65,
0x20, 0x27, 0x6d, 0x64, 0x3a, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74,
0x69, 0x6f, 0x6e, 0x27, 0x20, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65,
0x6e, 0x74, 0x20, 0x63, 0x61, 0x6e, 0x20, 0x61, 0x70, 0x70, 0x65, 0x61,
0x72, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x0a, 0x61, 0x74, 0x20, 0x74, 0x68,
0x65, 0x20, 0x74, 0x6f, 0x70, 0x20, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x20,
0x6f, 0x66, 0x20, 0x61, 0x20, 0x59, 0x41, 0x4e, 0x47, 0x20, 0x6d, 0x6f,
0x64, 0x75, 0x6c, 0x65, 0x20, 0x6f, 0x72, 0x20, 0x73, 0x75, 0x62, 0x6d,
0x6f, 0x64, 0x75, 0x6c, 0x65, 0x2c, 0x20, 0x69, 0x2e, 0x65, 0x2e, 0x2c,
0x20, 0x69, 0x74, 0x0a, 0x62, 0x65, 0x63, 0x6f, 0x6d, 0x65, 0x73, 0x20,
0x61, 0x20, 0x6e, 0x65, 0x77, 0x20, 0x61, 0x6c, 0x74, 0x65, 0x72, 0x6e,
0x61, 0x74, 0x69, 0x76, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65,
0x20, 0x41, 0x42, 0x4e, 0x46, 0x20, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63,
0x74, 0x69, 0x6f, 0x6e, 0x20, 0x72, 0x75, 0x6c, 0x65, 0x20, 0x66, 0x6f,
0x72, 0x0a, 0x27, 0x62, 0x6f, 0x64, 0x79, 0x2d, 0x73, 0x74, 0x6d, 0x74,
0x73, 0x27, 0x20, 0x28, 0x53, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20,
0x31, 0x34, 0x20, 0x69, 0x6e, 0x20, 0x52, 0x46, 0x43, 0x20, 0x37, 0x39,
0x35, 0x30, 0x29, 0x2e, 0x0a, 0x0a, 0x54, 0x68, 0x65, 0x20, 0x61, 0x72,
0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68,
0x65, 0x20, 0x27, 0x6d, 0x64, 0x3a, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61,
0x74, 0x69, 0x6f, 0x6e, 0x27, 0x20, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d,
0x65, 0x6e, 0x74, 0x20, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x73, 0x20,
0x74, 0x68, 0x65, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x0a, 0x6f, 0x66, 0x20,
0x74, 0x68, 0x65, 0x20, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69,
0x6f, 0x6e, 0x2e, 0x20, 0x20, 0x53, 0x79, 0x6e, 0x74, 0x61, 0x63, 0x74,
0x69, 0x63, 0x61, 0x6c, 0x6c, 0x79, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69,
0x73, 0x20, 0x61, 0x20, 0x59, 0x41, 0x4e, 0x47, 0x20, 0x69, 0x64, 0x65,
0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x20, 0x61, 0x73, 0x0a, 0x64,
0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x53, 0x65,
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x36, 0x2e, 0x32, 0x20, 0x6f, 0x66,
0x20, 0x52, 0x46, 0x43, 0x20, 0x37, 0x39, 0x35, 0x30, 0x2e, 0x0a, 0x0a,
0x41, 0x6e, 0x20, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x20, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x20, 0x77, 0x69,
0x74, 0x68, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x27, 0x65, 0x78, 0x74,
0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x27, 0x20, 0x73, 0x74, 0x61, 0x74,
0x65, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x69, 0x6e, 0x68, 0x65, 0x72, 0x69,
0x74, 0x73, 0x0a, 0x74, 0x68, 0x65, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x73,
0x70, 0x61, 0x63, 0x65, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6f, 0x74, 0x68,
0x65, 0x72, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x20, 0x66,
0x72, 0x6f, 0x6d, 0x20, 0x74, 0x68, 0x65, 0x20, 0x59, 0x41, 0x4e, 0x47,
0x20, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x77,
0x68, 0x69, 0x63, 0x68, 0x0a, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x64,
0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x2e, 0x0a, 0x0a, 0x54, 0x68, 0x65,
0x20, 0x64, 0x61, 0x74, 0x61, 0x20, 0x74, 0x79, 0x70, 0x65, 0x20, 0x6f,
0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61,
0x74, 0x69, 0x6f, 0x6e, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x69,
0x73, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x64, 0x20,
0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x61, 0x6d, 0x65, 0x0a,
0x77, 0x61, 0x79, 0x20, 0x61, 0x73, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61,
0x20, 0x6c, 0x65, 0x61, 0x66, 0x20, 0x64, 0x61, 0x74, 0x61, 0x20, 0x6e,
0x6f, 0x64, 0x65, 0x20, 0x75, 0x73, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68,
0x65, 0x20, 0x27, 0x74, 0x79, 0x70, 0x65, 0x27, 0x20, 0x73, 0x74, 0x61,
0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x0a, 0x0a, 0x54, 0x68, 0x65,
0x20, 0x73, 0x65, 0x6d, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x73, 0x20, 0x6f,
0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61,
0x74, 0x69, 0x6f, 0x6e, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6f, 0x74, 0x68,
0x65, 0x72, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61,
0x74, 0x69, 0x6f, 0x6e, 0x20, 0x63, 0x61, 0x6e, 0x20, 0x62, 0x65, 0x0a,
0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x64, 0x20, 0x75, 0x73,
0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x6f, 0x6c, 0x6c,
0x6f, 0x77, 0x69, 0x6e, 0x67, 0x20, 0x73, 0x74, 0x61, 0x6e, 0x64, 0x61,
0x72, 0x64, 0x20, 0x59, 0x41, 0x4e, 0x47, 0x20, 0x73, 0x75, 0x62, 0x73,
0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x20, 0x28, 0x61,
0x6c, 0x6c, 0x0a, 0x61, 0x72, 0x65, 0x20, 0x6f, 0x70, 0x74, 0x69, 0x6f,
0x6e, 0x61, 0x6c, 0x29, 0x3a, 0x20, 0x27, 0x64, 0x65, 0x73, 0x63, 0x72,
0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x27, 0x2c, 0x20, 0x27, 0x69, 0x66,
0x2d, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x27, 0x2c, 0x20, 0x27,
0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x27, 0x2c, 0x0a,
0x27, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x27, 0x2c, 0x20, 0x61, 0x6e,
0x64, 0x20, 0x27, 0x75, 0x6e, 0x69, 0x74, 0x73, 0x27, 0x2e, 0x0a, 0x0a,
0x41, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x61, 0x6e, 0x6e,
0x6f, 0x75, 0x6e, 0x63, 0x65, 0x73, 0x20, 0x73, 0x75, 0x70, 0x70, 0x6f,
0x72, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x20, 0x70, 0x61, 0x72,
0x74, 0x69, 0x63, 0x75, 0x6c, 0x61, 0x72, 0x20, 0x61, 0x6e, 0x6e, 0x6f,
0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x62, 0x79, 0x0a, 0x69, 0x6e,
0x63, 0x6c, 0x75, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20,
0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x77, 0x68,
0x69, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x6e, 0x6e, 0x6f,
0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x73, 0x20, 0x64, 0x65,
0x66, 0x69, 0x6e, 0x65, 0x64, 0x20, 0x61, 0x6d, 0x6f, 0x6e, 0x67, 0x0a,
0x74, 0x68, 0x65, 0x20, 0x61, 0x64, 0x76, 0x65, 0x72, 0x74, 0x69, 0x73,
0x65, 0x64, 0x20, 0x59, 0x41, 0x4e, 0x47, 0x20, 0x6d, 0x6f, 0x64, 0x75,
0x6c, 0x65, 0x73, 0x2c, 0x20, 0x65, 0x2e, 0x67, 0x2e, 0x2c, 0x20, 0x69,
0x6e, 0x20, 0x61, 0x20, 0x4e, 0x45, 0x54, 0x43, 0x4f, 0x4e, 0x46, 0x20,
0x3c, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x3e, 0x0a, 0x6d, 0x65, 0x73, 0x73,
0x61, 0x67, 0x65, 0x20, 0x6f, 0x72, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68,
0x65, 0x20, 0x59, 0x41, 0x4e, 0x47, 0x20, 0x6c, 0x69, 0x62, 0x72, 0x61,
0x72, 0x79, 0x20, 0x28, 0x52, 0x46, 0x43, 0x20, 0x37, 0x39, 0x35, 0x30,
0x29, 0x2e, 0x20, 0x20, 0x54, 0x68, 0x65, 0x20, 0x61, 0x6e, 0x6e, 0x6f,
0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x63, 0x61, 0x6e, 0x0a, 0x74,
0x68, 0x65, 0x6e, 0x20, 0x62, 0x65, 0x20, 0x61, 0x74, 0x74, 0x61, 0x63,
0x68, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x61, 0x6e, 0x79, 0x20, 0x69,
0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x61,
0x20, 0x64, 0x61, 0x74, 0x61, 0x20, 0x6e, 0x6f, 0x64, 0x65, 0x20, 0x64,
0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x61, 0x6e,
0x79, 0x0a, 0x59, 0x41, 0x4e, 0x47, 0x20, 0x6d, 0x6f, 0x64, 0x75, 0x6c,
0x65, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x69, 0x73, 0x20, 0x61, 0x64,
0x76, 0x65, 0x72, 0x74, 0x69, 0x73, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20,
0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x0a,
0x0a, 0x58, 0x4d, 0x4c, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e,
0x67, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x4a, 0x53, 0x4f, 0x4e, 0x20, 0x65,
0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x61,
0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x61,
0x72, 0x65, 0x20, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x20, 0x69,
0x6e, 0x0a, 0x52, 0x46, 0x43, 0x20, 0x37, 0x39, 0x35, 0x32, 0x2e, 0x22,
0x3b, 0x7d, 0x7d, 0x00
};

View file

@ -0,0 +1,80 @@
module ietf-yang-metadata {
namespace "urn:ietf:params:xml:ns:yang:ietf-yang-metadata";
prefix md;
organization
"IETF NETMOD (NETCONF Data Modeling Language) Working Group";
contact
"WG Web: <https://datatracker.ietf.org/wg/netmod/>
WG List: <mailto:netmod@ietf.org>
WG Chair: Lou Berger
<mailto:lberger@labn.net>
WG Chair: Kent Watsen
<mailto:kwatsen@juniper.net>
Editor: Ladislav Lhotka
<mailto:lhotka@nic.cz>";
description
"This YANG module defines an 'extension' statement that allows
for defining metadata annotations.
Copyright (c) 2016 IETF Trust and the persons identified as
authors of the code. All rights reserved.
Redistribution and use in source and binary forms, with or
without modification, is permitted pursuant to, and subject to
the license terms contained in, the Simplified BSD License set
forth in Section 4.c of the IETF Trust's Legal Provisions
Relating to IETF Documents
(http://trustee.ietf.org/license-info).
This version of this YANG module is part of RFC 7952
(http://www.rfc-editor.org/info/rfc7952); see the RFC itself
for full legal notices.";
revision 2016-08-05 {
description
"Initial revision.";
reference
"RFC 7952: Defining and Using Metadata with YANG";
}
extension annotation {
argument name;
description
"This extension allows for defining metadata annotations in
YANG modules. The 'md:annotation' statement can appear only
at the top level of a YANG module or submodule, i.e., it
becomes a new alternative in the ABNF production rule for
'body-stmts' (Section 14 in RFC 7950).
The argument of the 'md:annotation' statement defines the name
of the annotation. Syntactically, it is a YANG identifier as
defined in Section 6.2 of RFC 7950.
An annotation defined with this 'extension' statement inherits
the namespace and other context from the YANG module in which
it is defined.
The data type of the annotation value is specified in the same
way as for a leaf data node using the 'type' statement.
The semantics of the annotation and other documentation can be
specified using the following standard YANG substatements (all
are optional): 'description', 'if-feature', 'reference',
'status', and 'units'.
A server announces support for a particular annotation by
including the module in which the annotation is defined among
the advertised YANG modules, e.g., in a NETCONF <hello>
message or in the YANG library (RFC 7950). The annotation can
then be attached to any instance of a data node defined in any
YANG module that is advertised by the server.
XML encoding and JSON encoding of annotations are defined in
RFC 7952.";
}
}

View file

@ -0,0 +1,651 @@
unsigned char ietf_yang_schema_mount_2019_01_14_yang[] = {
0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x69, 0x65, 0x74, 0x66, 0x2d,
0x79, 0x61, 0x6e, 0x67, 0x2d, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2d,
0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x79, 0x61,
0x6e, 0x67, 0x2d, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x31,
0x2e, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70,
0x61, 0x63, 0x65, 0x20, 0x22, 0x75, 0x72, 0x6e, 0x3a, 0x69, 0x65, 0x74,
0x66, 0x3a, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x3a, 0x78, 0x6d, 0x6c,
0x3a, 0x6e, 0x73, 0x3a, 0x79, 0x61, 0x6e, 0x67, 0x3a, 0x69, 0x65, 0x74,
0x66, 0x2d, 0x79, 0x61, 0x6e, 0x67, 0x2d, 0x73, 0x63, 0x68, 0x65, 0x6d,
0x61, 0x2d, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x3b, 0x0a, 0x20, 0x20,
0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x20, 0x79, 0x61, 0x6e, 0x67, 0x6d,
0x6e, 0x74, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x69, 0x6d, 0x70, 0x6f, 0x72,
0x74, 0x20, 0x69, 0x65, 0x74, 0x66, 0x2d, 0x69, 0x6e, 0x65, 0x74, 0x2d,
0x74, 0x79, 0x70, 0x65, 0x73, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x20, 0x69, 0x6e, 0x65, 0x74, 0x3b,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e,
0x63, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x52, 0x46,
0x43, 0x20, 0x36, 0x39, 0x39, 0x31, 0x3a, 0x20, 0x43, 0x6f, 0x6d, 0x6d,
0x6f, 0x6e, 0x20, 0x59, 0x41, 0x4e, 0x47, 0x20, 0x44, 0x61, 0x74, 0x61,
0x20, 0x54, 0x79, 0x70, 0x65, 0x73, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x7d,
0x0a, 0x0a, 0x20, 0x20, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x69,
0x65, 0x74, 0x66, 0x2d, 0x79, 0x61, 0x6e, 0x67, 0x2d, 0x74, 0x79, 0x70,
0x65, 0x73, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x72, 0x65,
0x66, 0x69, 0x78, 0x20, 0x79, 0x61, 0x6e, 0x67, 0x3b, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x52, 0x46, 0x43, 0x20, 0x36,
0x39, 0x39, 0x31, 0x3a, 0x20, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x20,
0x59, 0x41, 0x4e, 0x47, 0x20, 0x44, 0x61, 0x74, 0x61, 0x20, 0x54, 0x79,
0x70, 0x65, 0x73, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x0a, 0x0a, 0x20,
0x20, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x22, 0x49, 0x45, 0x54, 0x46, 0x20,
0x4e, 0x45, 0x54, 0x4d, 0x4f, 0x44, 0x20, 0x28, 0x4e, 0x45, 0x54, 0x43,
0x4f, 0x4e, 0x46, 0x20, 0x44, 0x61, 0x74, 0x61, 0x20, 0x4d, 0x6f, 0x64,
0x65, 0x6c, 0x69, 0x6e, 0x67, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61,
0x67, 0x65, 0x29, 0x20, 0x57, 0x6f, 0x72, 0x6b, 0x69, 0x6e, 0x67, 0x20,
0x47, 0x72, 0x6f, 0x75, 0x70, 0x22, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x63,
0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x22,
0x57, 0x47, 0x20, 0x57, 0x65, 0x62, 0x3a, 0x20, 0x20, 0x20, 0x3c, 0x68,
0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x74,
0x72, 0x61, 0x63, 0x6b, 0x65, 0x72, 0x2e, 0x69, 0x65, 0x74, 0x66, 0x2e,
0x6f, 0x72, 0x67, 0x2f, 0x77, 0x67, 0x2f, 0x6e, 0x65, 0x74, 0x6d, 0x6f,
0x64, 0x2f, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x57, 0x47, 0x20,
0x4c, 0x69, 0x73, 0x74, 0x3a, 0x20, 0x20, 0x3c, 0x6d, 0x61, 0x69, 0x6c,
0x74, 0x6f, 0x3a, 0x6e, 0x65, 0x74, 0x6d, 0x6f, 0x64, 0x40, 0x69, 0x65,
0x74, 0x66, 0x2e, 0x6f, 0x72, 0x67, 0x3e, 0x0a, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x20, 0x45, 0x64, 0x69, 0x74, 0x6f, 0x72, 0x3a, 0x20, 0x20, 0x20,
0x4d, 0x61, 0x72, 0x74, 0x69, 0x6e, 0x20, 0x42, 0x6a, 0x6f, 0x72, 0x6b,
0x6c, 0x75, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x6d, 0x61, 0x69,
0x6c, 0x74, 0x6f, 0x3a, 0x6d, 0x62, 0x6a, 0x40, 0x74, 0x61, 0x69, 0x6c,
0x2d, 0x66, 0x2e, 0x63, 0x6f, 0x6d, 0x3e, 0x0a, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x20, 0x45, 0x64, 0x69, 0x74, 0x6f, 0x72, 0x3a, 0x20, 0x20, 0x20,
0x4c, 0x61, 0x64, 0x69, 0x73, 0x6c, 0x61, 0x76, 0x20, 0x4c, 0x68, 0x6f,
0x74, 0x6b, 0x61, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x6d, 0x61, 0x69, 0x6c,
0x74, 0x6f, 0x3a, 0x6c, 0x68, 0x6f, 0x74, 0x6b, 0x61, 0x40, 0x6e, 0x69,
0x63, 0x2e, 0x63, 0x7a, 0x3e, 0x22, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x64,
0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x22, 0x54, 0x68, 0x69, 0x73, 0x20, 0x6d, 0x6f, 0x64,
0x75, 0x6c, 0x65, 0x20, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x73, 0x20,
0x61, 0x20, 0x59, 0x41, 0x4e, 0x47, 0x20, 0x65, 0x78, 0x74, 0x65, 0x6e,
0x73, 0x69, 0x6f, 0x6e, 0x20, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65,
0x6e, 0x74, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x63, 0x61, 0x6e, 0x20,
0x62, 0x65, 0x20, 0x75, 0x73, 0x65, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x20, 0x74, 0x6f, 0x20, 0x69, 0x6e, 0x63, 0x6f, 0x72, 0x70, 0x6f, 0x72,
0x61, 0x74, 0x65, 0x20, 0x64, 0x61, 0x74, 0x61, 0x20, 0x6d, 0x6f, 0x64,
0x65, 0x6c, 0x73, 0x20, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x20,
0x69, 0x6e, 0x20, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x20, 0x59, 0x41, 0x4e,
0x47, 0x20, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x20, 0x69, 0x6e,
0x20, 0x61, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x6f, 0x64, 0x75,
0x6c, 0x65, 0x2e, 0x20, 0x20, 0x49, 0x74, 0x20, 0x61, 0x6c, 0x73, 0x6f,
0x20, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x73, 0x20, 0x6f, 0x70, 0x65,
0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x20, 0x73, 0x74, 0x61,
0x74, 0x65, 0x20, 0x64, 0x61, 0x74, 0x61, 0x20, 0x74, 0x68, 0x61, 0x74,
0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x79, 0x20, 0x74, 0x68, 0x65,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x76, 0x65, 0x72, 0x61, 0x6c,
0x6c, 0x20, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x75, 0x72, 0x65, 0x20,
0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, 0x61, 0x74, 0x61, 0x20,
0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2e, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x20, 0x54, 0x68, 0x65, 0x20, 0x6b, 0x65, 0x79, 0x20, 0x77, 0x6f, 0x72,
0x64, 0x73, 0x20, 0x27, 0x4d, 0x55, 0x53, 0x54, 0x27, 0x2c, 0x20, 0x27,
0x4d, 0x55, 0x53, 0x54, 0x20, 0x4e, 0x4f, 0x54, 0x27, 0x2c, 0x20, 0x27,
0x52, 0x45, 0x51, 0x55, 0x49, 0x52, 0x45, 0x44, 0x27, 0x2c, 0x20, 0x27,
0x53, 0x48, 0x41, 0x4c, 0x4c, 0x27, 0x2c, 0x20, 0x27, 0x53, 0x48, 0x41,
0x4c, 0x4c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x4e, 0x4f, 0x54, 0x27,
0x2c, 0x20, 0x27, 0x53, 0x48, 0x4f, 0x55, 0x4c, 0x44, 0x27, 0x2c, 0x20,
0x27, 0x53, 0x48, 0x4f, 0x55, 0x4c, 0x44, 0x20, 0x4e, 0x4f, 0x54, 0x27,
0x2c, 0x20, 0x27, 0x52, 0x45, 0x43, 0x4f, 0x4d, 0x4d, 0x45, 0x4e, 0x44,
0x45, 0x44, 0x27, 0x2c, 0x20, 0x27, 0x4e, 0x4f, 0x54, 0x20, 0x52, 0x45,
0x43, 0x4f, 0x4d, 0x4d, 0x45, 0x4e, 0x44, 0x45, 0x44, 0x27, 0x2c, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x20, 0x27, 0x4d, 0x41, 0x59, 0x27, 0x2c, 0x20,
0x61, 0x6e, 0x64, 0x20, 0x27, 0x4f, 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x41,
0x4c, 0x27, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x64,
0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x61, 0x72, 0x65, 0x20,
0x74, 0x6f, 0x20, 0x62, 0x65, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x70,
0x72, 0x65, 0x74, 0x65, 0x64, 0x20, 0x61, 0x73, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x20, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x64, 0x20,
0x69, 0x6e, 0x20, 0x42, 0x43, 0x50, 0x20, 0x31, 0x34, 0x20, 0x28, 0x52,
0x46, 0x43, 0x20, 0x32, 0x31, 0x31, 0x39, 0x29, 0x20, 0x28, 0x52, 0x46,
0x43, 0x20, 0x38, 0x31, 0x37, 0x34, 0x29, 0x20, 0x77, 0x68, 0x65, 0x6e,
0x2c, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x20, 0x77,
0x68, 0x65, 0x6e, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x68,
0x65, 0x79, 0x20, 0x61, 0x70, 0x70, 0x65, 0x61, 0x72, 0x20, 0x69, 0x6e,
0x20, 0x61, 0x6c, 0x6c, 0x20, 0x63, 0x61, 0x70, 0x69, 0x74, 0x61, 0x6c,
0x73, 0x2c, 0x20, 0x61, 0x73, 0x20, 0x73, 0x68, 0x6f, 0x77, 0x6e, 0x20,
0x68, 0x65, 0x72, 0x65, 0x2e, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
0x43, 0x6f, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x28, 0x63,
0x29, 0x20, 0x32, 0x30, 0x31, 0x39, 0x20, 0x49, 0x45, 0x54, 0x46, 0x20,
0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x74, 0x68,
0x65, 0x20, 0x70, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x73, 0x20, 0x69, 0x64,
0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x20, 0x61, 0x73, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x73,
0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x64, 0x65,
0x2e, 0x20, 0x20, 0x41, 0x6c, 0x6c, 0x20, 0x72, 0x69, 0x67, 0x68, 0x74,
0x73, 0x20, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x2e, 0x0a,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x52, 0x65, 0x64, 0x69, 0x73, 0x74,
0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x61, 0x6e, 0x64,
0x20, 0x75, 0x73, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x73, 0x6f, 0x75, 0x72,
0x63, 0x65, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x62, 0x69, 0x6e, 0x61, 0x72,
0x79, 0x20, 0x66, 0x6f, 0x72, 0x6d, 0x73, 0x2c, 0x20, 0x77, 0x69, 0x74,
0x68, 0x20, 0x6f, 0x72, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x77, 0x69,
0x74, 0x68, 0x6f, 0x75, 0x74, 0x20, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69,
0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2c, 0x20, 0x69, 0x73, 0x20, 0x70,
0x65, 0x72, 0x6d, 0x69, 0x74, 0x74, 0x65, 0x64, 0x20, 0x70, 0x75, 0x72,
0x73, 0x75, 0x61, 0x6e, 0x74, 0x20, 0x74, 0x6f, 0x2c, 0x20, 0x61, 0x6e,
0x64, 0x20, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x20, 0x74, 0x6f,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6c, 0x69,
0x63, 0x65, 0x6e, 0x73, 0x65, 0x20, 0x74, 0x65, 0x72, 0x6d, 0x73, 0x20,
0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x64, 0x20, 0x69, 0x6e,
0x2c, 0x20, 0x74, 0x68, 0x65, 0x20, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x69,
0x66, 0x69, 0x65, 0x64, 0x20, 0x42, 0x53, 0x44, 0x20, 0x4c, 0x69, 0x63,
0x65, 0x6e, 0x73, 0x65, 0x20, 0x73, 0x65, 0x74, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x20, 0x66, 0x6f, 0x72, 0x74, 0x68, 0x20, 0x69, 0x6e, 0x20, 0x53,
0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x34, 0x2e, 0x63, 0x20, 0x6f,
0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x49, 0x45, 0x54, 0x46, 0x20, 0x54,
0x72, 0x75, 0x73, 0x74, 0x27, 0x73, 0x20, 0x4c, 0x65, 0x67, 0x61, 0x6c,
0x20, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x20, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6e,
0x67, 0x20, 0x74, 0x6f, 0x20, 0x49, 0x45, 0x54, 0x46, 0x20, 0x44, 0x6f,
0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x20, 0x28, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x74, 0x72,
0x75, 0x73, 0x74, 0x65, 0x65, 0x2e, 0x69, 0x65, 0x74, 0x66, 0x2e, 0x6f,
0x72, 0x67, 0x2f, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x2d, 0x69,
0x6e, 0x66, 0x6f, 0x29, 0x2e, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
0x54, 0x68, 0x69, 0x73, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x59, 0x41, 0x4e,
0x47, 0x20, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x69, 0x73, 0x20,
0x70, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x52, 0x46, 0x43, 0x20,
0x38, 0x35, 0x32, 0x38, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73,
0x65, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x52, 0x46, 0x43, 0x20, 0x69,
0x74, 0x73, 0x65, 0x6c, 0x66, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x66, 0x75,
0x6c, 0x6c, 0x20, 0x6c, 0x65, 0x67, 0x61, 0x6c, 0x20, 0x6e, 0x6f, 0x74,
0x69, 0x63, 0x65, 0x73, 0x2e, 0x22, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x72,
0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x32, 0x30, 0x31, 0x39,
0x2d, 0x30, 0x31, 0x2d, 0x31, 0x34, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x49, 0x6e, 0x69, 0x74,
0x69, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e,
0x2e, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x66, 0x65,
0x72, 0x65, 0x6e, 0x63, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x22, 0x52, 0x46, 0x43, 0x20, 0x38, 0x35, 0x32, 0x38, 0x3a, 0x20, 0x59,
0x41, 0x4e, 0x47, 0x20, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x20, 0x4d,
0x6f, 0x75, 0x6e, 0x74, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x0a, 0x0a,
0x20, 0x20, 0x2f, 0x2a, 0x0a, 0x20, 0x20, 0x20, 0x2a, 0x20, 0x45, 0x78,
0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x0a, 0x20, 0x20, 0x20,
0x2a, 0x2f, 0x0a, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73,
0x69, 0x6f, 0x6e, 0x20, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x2d, 0x70, 0x6f,
0x69, 0x6e, 0x74, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x61, 0x72,
0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x6c, 0x61, 0x62, 0x65, 0x6c,
0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69,
0x70, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x22, 0x54, 0x68, 0x65, 0x20, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e,
0x74, 0x20, 0x27, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x27, 0x20, 0x69, 0x73,
0x20, 0x61, 0x20, 0x59, 0x41, 0x4e, 0x47, 0x20, 0x69, 0x64, 0x65, 0x6e,
0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x2c, 0x20, 0x69, 0x2e, 0x65, 0x2e,
0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x74,
0x68, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x79,
0x70, 0x65, 0x20, 0x27, 0x79, 0x61, 0x6e, 0x67, 0x3a, 0x79, 0x61, 0x6e,
0x67, 0x2d, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72,
0x27, 0x2e, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x54,
0x68, 0x65, 0x20, 0x27, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x2d, 0x70, 0x6f,
0x69, 0x6e, 0x74, 0x27, 0x20, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65,
0x6e, 0x74, 0x20, 0x4d, 0x55, 0x53, 0x54, 0x20, 0x4e, 0x4f, 0x54, 0x20,
0x62, 0x65, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x61,
0x20, 0x59, 0x41, 0x4e, 0x47, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x31, 0x20, 0x6d,
0x6f, 0x64, 0x75, 0x6c, 0x65, 0x2c, 0x20, 0x6e, 0x65, 0x69, 0x74, 0x68,
0x65, 0x72, 0x20, 0x65, 0x78, 0x70, 0x6c, 0x69, 0x63, 0x69, 0x74, 0x6c,
0x79, 0x20, 0x6e, 0x6f, 0x72, 0x20, 0x76, 0x69, 0x61, 0x20, 0x61, 0x20,
0x27, 0x75, 0x73, 0x65, 0x73, 0x27, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x54, 0x68, 0x65, 0x20,
0x27, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x2d, 0x70, 0x6f, 0x69, 0x6e, 0x74,
0x27, 0x20, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x20,
0x4d, 0x41, 0x59, 0x20, 0x62, 0x65, 0x20, 0x70, 0x72, 0x65, 0x73, 0x65,
0x6e, 0x74, 0x20, 0x61, 0x73, 0x20, 0x61, 0x20, 0x73, 0x75, 0x62, 0x73,
0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x6f, 0x66, 0x20, 0x27, 0x63, 0x6f, 0x6e, 0x74,
0x61, 0x69, 0x6e, 0x65, 0x72, 0x27, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x27,
0x6c, 0x69, 0x73, 0x74, 0x27, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x4d, 0x55,
0x53, 0x54, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x62, 0x65, 0x20, 0x70, 0x72,
0x65, 0x73, 0x65, 0x6e, 0x74, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x77, 0x68,
0x65, 0x72, 0x65, 0x2e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x54, 0x68, 0x65, 0x72, 0x65, 0x20, 0x4d, 0x55, 0x53, 0x54, 0x20, 0x4e,
0x4f, 0x54, 0x20, 0x62, 0x65, 0x20, 0x6d, 0x6f, 0x72, 0x65, 0x20, 0x74,
0x68, 0x61, 0x6e, 0x20, 0x6f, 0x6e, 0x65, 0x20, 0x27, 0x6d, 0x6f, 0x75,
0x6e, 0x74, 0x2d, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x27, 0x20, 0x73, 0x74,
0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x69, 0x6e, 0x20, 0x61,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x67, 0x69, 0x76, 0x65,
0x6e, 0x20, 0x27, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72,
0x27, 0x20, 0x6f, 0x72, 0x20, 0x27, 0x6c, 0x69, 0x73, 0x74, 0x27, 0x20,
0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x0a, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x49, 0x66, 0x20, 0x61, 0x20,
0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x20,
0x69, 0x73, 0x20, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x20, 0x77,
0x69, 0x74, 0x68, 0x69, 0x6e, 0x20, 0x61, 0x20, 0x67, 0x72, 0x6f, 0x75,
0x70, 0x69, 0x6e, 0x67, 0x2c, 0x20, 0x69, 0x74, 0x73, 0x20, 0x6c, 0x61,
0x62, 0x65, 0x6c, 0x20, 0x69, 0x73, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x74,
0x68, 0x65, 0x20, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x77, 0x68,
0x65, 0x72, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x67, 0x72, 0x6f, 0x75,
0x70, 0x69, 0x6e, 0x67, 0x20, 0x69, 0x73, 0x20, 0x75, 0x73, 0x65, 0x64,
0x2e, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x41, 0x20,
0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x20,
0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x73, 0x20, 0x61, 0x20, 0x70, 0x6c,
0x61, 0x63, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6e,
0x6f, 0x64, 0x65, 0x20, 0x68, 0x69, 0x65, 0x72, 0x61, 0x72, 0x63, 0x68,
0x79, 0x20, 0x77, 0x68, 0x65, 0x72, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x20, 0x64, 0x61, 0x74,
0x61, 0x20, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x73, 0x20, 0x6d, 0x61, 0x79,
0x20, 0x62, 0x65, 0x20, 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, 0x65, 0x64,
0x2e, 0x20, 0x20, 0x41, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20,
0x74, 0x68, 0x61, 0x74, 0x20, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65,
0x6e, 0x74, 0x73, 0x20, 0x61, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x77, 0x69, 0x74, 0x68,
0x20, 0x61, 0x20, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x70, 0x6f, 0x69,
0x6e, 0x74, 0x20, 0x70, 0x6f, 0x70, 0x75, 0x6c, 0x61, 0x74, 0x65, 0x73,
0x20, 0x74, 0x68, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x27, 0x2f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2d, 0x6d, 0x6f, 0x75,
0x6e, 0x74, 0x73, 0x2f, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x2d, 0x70, 0x6f,
0x69, 0x6e, 0x74, 0x27, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x77, 0x69,
0x74, 0x68, 0x20, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x20,
0x69, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20,
0x6f, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x77, 0x68,
0x69, 0x63, 0x68, 0x20, 0x64, 0x61, 0x74, 0x61, 0x20, 0x6d, 0x6f, 0x64,
0x65, 0x6c, 0x73, 0x20, 0x61, 0x72, 0x65, 0x20, 0x6d, 0x6f, 0x75, 0x6e,
0x74, 0x65, 0x64, 0x20, 0x61, 0x74, 0x20, 0x65, 0x61, 0x63, 0x68, 0x20,
0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x2e,
0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x4e, 0x6f, 0x74,
0x65, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x27,
0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x2d, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x27,
0x20, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x64,
0x6f, 0x65, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x64, 0x65, 0x66, 0x69,
0x6e, 0x65, 0x20, 0x61, 0x20, 0x6e, 0x65, 0x77, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x64, 0x61, 0x74, 0x61, 0x20, 0x6e, 0x6f, 0x64,
0x65, 0x2e, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x0a, 0x0a, 0x20, 0x20,
0x2f, 0x2a, 0x0a, 0x20, 0x20, 0x20, 0x2a, 0x20, 0x53, 0x74, 0x61, 0x74,
0x65, 0x20, 0x64, 0x61, 0x74, 0x61, 0x20, 0x6e, 0x6f, 0x64, 0x65, 0x73,
0x0a, 0x20, 0x20, 0x20, 0x2a, 0x2f, 0x0a, 0x0a, 0x20, 0x20, 0x63, 0x6f,
0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x20, 0x73, 0x63, 0x68, 0x65,
0x6d, 0x61, 0x2d, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x20, 0x7b, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x20, 0x66,
0x61, 0x6c, 0x73, 0x65, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65,
0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x22, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e,
0x73, 0x20, 0x69, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x20, 0x61, 0x62, 0x6f, 0x75, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20,
0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x75, 0x72, 0x65, 0x20, 0x6f, 0x66,
0x20, 0x74, 0x68, 0x65, 0x20, 0x6f, 0x76, 0x65, 0x72, 0x61, 0x6c, 0x6c,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x6f, 0x75, 0x6e,
0x74, 0x65, 0x64, 0x20, 0x64, 0x61, 0x74, 0x61, 0x20, 0x6d, 0x6f, 0x64,
0x65, 0x6c, 0x20, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74,
0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65,
0x72, 0x76, 0x65, 0x72, 0x2e, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x6c, 0x69, 0x73, 0x74, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61,
0x63, 0x65, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6b,
0x65, 0x79, 0x20, 0x22, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x22, 0x3b,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x73, 0x63, 0x72,
0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x22, 0x54, 0x68, 0x69, 0x73, 0x20, 0x6c, 0x69, 0x73,
0x74, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x73, 0x20, 0x61,
0x20, 0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20,
0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x20, 0x70, 0x72,
0x65, 0x66, 0x69, 0x78, 0x65, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20,
0x61, 0x72, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x58, 0x50, 0x61,
0x74, 0x68, 0x20, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f,
0x6e, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x27, 0x70, 0x61, 0x72, 0x65, 0x6e,
0x74, 0x2d, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x27,
0x20, 0x6c, 0x65, 0x61, 0x66, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68,
0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63,
0x6f, 0x72, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x64, 0x69, 0x6e, 0x67,
0x20, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x20, 0x55,
0x52, 0x49, 0x20, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65,
0x73, 0x2e, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c,
0x65, 0x61, 0x66, 0x20, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x20, 0x7b,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x79, 0x70,
0x65, 0x20, 0x79, 0x61, 0x6e, 0x67, 0x3a, 0x79, 0x61, 0x6e, 0x67, 0x2d,
0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x3b, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x73, 0x63,
0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x4e, 0x61, 0x6d, 0x65, 0x73,
0x70, 0x61, 0x63, 0x65, 0x20, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x2e,
0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x61, 0x66, 0x20, 0x75, 0x72,
0x69, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x74, 0x79, 0x70, 0x65, 0x20, 0x69, 0x6e, 0x65, 0x74, 0x3a, 0x75, 0x72,
0x69, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64,
0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x4e, 0x61,
0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x20, 0x55, 0x52, 0x49, 0x20,
0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x22, 0x3b,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20,
0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x2d, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x20,
0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6b, 0x65, 0x79, 0x20,
0x22, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x6c, 0x61, 0x62, 0x65,
0x6c, 0x22, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64,
0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x45, 0x61, 0x63, 0x68,
0x20, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68,
0x69, 0x73, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x73, 0x70, 0x65, 0x63,
0x69, 0x66, 0x69, 0x65, 0x73, 0x20, 0x61, 0x20, 0x73, 0x63, 0x68, 0x65,
0x6d, 0x61, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x20, 0x70, 0x61, 0x72,
0x74, 0x69, 0x63, 0x75, 0x6c, 0x61, 0x72, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x70,
0x6f, 0x69, 0x6e, 0x74, 0x2e, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x45, 0x61, 0x63, 0x68, 0x20, 0x6d, 0x6f, 0x75,
0x6e, 0x74, 0x20, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x20, 0x4d, 0x55, 0x53,
0x54, 0x20, 0x62, 0x65, 0x20, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64,
0x20, 0x75, 0x73, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x27,
0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x2d, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x27,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x78,
0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x6f,
0x6e, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x6f,
0x64, 0x75, 0x6c, 0x65, 0x73, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x64,
0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x72, 0x76,
0x65, 0x72, 0x27, 0x73, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x59, 0x41, 0x4e, 0x47, 0x20, 0x6c, 0x69, 0x62, 0x72, 0x61,
0x72, 0x79, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x20,
0x77, 0x69, 0x74, 0x68, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d,
0x61, 0x6e, 0x63, 0x65, 0x20, 0x74, 0x79, 0x70, 0x65, 0x20, 0x27, 0x69,
0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x27, 0x2e, 0x22, 0x3b,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x61, 0x66, 0x20,
0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x79, 0x70, 0x65, 0x20, 0x79, 0x61,
0x6e, 0x67, 0x3a, 0x79, 0x61, 0x6e, 0x67, 0x2d, 0x69, 0x64, 0x65, 0x6e,
0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74,
0x69, 0x6f, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x22, 0x4e, 0x61, 0x6d, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x61,
0x20, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x74,
0x61, 0x69, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d,
0x6f, 0x75, 0x6e, 0x74, 0x20, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x2e, 0x22,
0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x61, 0x66, 0x20, 0x6c, 0x61, 0x62,
0x65, 0x6c, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x74, 0x79, 0x70, 0x65, 0x20, 0x79, 0x61, 0x6e, 0x67, 0x3a, 0x79,
0x61, 0x6e, 0x67, 0x2d, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69,
0x65, 0x72, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x4c,
0x61, 0x62, 0x65, 0x6c, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20,
0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x20,
0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x20, 0x75, 0x73, 0x69, 0x6e,
0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x27, 0x6d, 0x6f, 0x75, 0x6e, 0x74,
0x2d, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x27, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x78, 0x74, 0x65, 0x6e,
0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65,
0x61, 0x66, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x20, 0x7b, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x79, 0x70, 0x65,
0x20, 0x62, 0x6f, 0x6f, 0x6c, 0x65, 0x61, 0x6e, 0x3b, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c,
0x74, 0x20, 0x22, 0x74, 0x72, 0x75, 0x65, 0x22, 0x3b, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69,
0x70, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x22, 0x49, 0x66, 0x20, 0x74, 0x68, 0x69, 0x73,
0x20, 0x6c, 0x65, 0x61, 0x66, 0x20, 0x69, 0x73, 0x20, 0x73, 0x65, 0x74,
0x20, 0x74, 0x6f, 0x20, 0x27, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x27, 0x2c,
0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x64, 0x61,
0x74, 0x61, 0x20, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x20, 0x69, 0x6e, 0x20,
0x74, 0x68, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x64, 0x20, 0x73,
0x63, 0x68, 0x65, 0x6d, 0x61, 0x20, 0x61, 0x72, 0x65, 0x20, 0x72, 0x65,
0x61, 0x64, 0x2d, 0x6f, 0x6e, 0x6c, 0x79, 0x20, 0x28, 0x27, 0x63, 0x6f,
0x6e, 0x66, 0x69, 0x67, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x27, 0x29,
0x2c, 0x20, 0x72, 0x65, 0x67, 0x61, 0x72, 0x64, 0x6c, 0x65, 0x73, 0x73,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x69, 0x72, 0x20, 0x27, 0x63, 0x6f,
0x6e, 0x66, 0x69, 0x67, 0x27, 0x20, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72,
0x74, 0x79, 0x2e, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x68, 0x6f, 0x69,
0x63, 0x65, 0x20, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2d, 0x72, 0x65,
0x66, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x6d, 0x61, 0x6e, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x20, 0x74, 0x72,
0x75, 0x65, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x41,
0x6c, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x73, 0x20,
0x66, 0x6f, 0x72, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x79, 0x69,
0x6e, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x63, 0x68, 0x65, 0x6d,
0x61, 0x2e, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x20, 0x69,
0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e,
0x63, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x22, 0x41, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65,
0x74, 0x65, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2d, 0x63, 0x6f, 0x6e, 0x74,
0x61, 0x69, 0x6e, 0x65, 0x64, 0x20, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61,
0x20, 0x69, 0x73, 0x20, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x64, 0x20,
0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x6f, 0x75, 0x6e,
0x74, 0x20, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x2e, 0x22, 0x3b, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x73,
0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x54, 0x68,
0x69, 0x73, 0x20, 0x6e, 0x6f, 0x64, 0x65, 0x20, 0x69, 0x6e, 0x64, 0x69,
0x63, 0x61, 0x74, 0x65, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74,
0x68, 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x68, 0x61,
0x73, 0x20, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x64, 0x20, 0x61, 0x74,
0x20, 0x6c, 0x65, 0x61, 0x73, 0x74, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x65, 0x20,
0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x27, 0x69, 0x65, 0x74, 0x66,
0x2d, 0x79, 0x61, 0x6e, 0x67, 0x2d, 0x6c, 0x69, 0x62, 0x72, 0x61, 0x72,
0x79, 0x27, 0x20, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x6f,
0x75, 0x6e, 0x74, 0x20, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x2c, 0x20, 0x61,
0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x69, 0x74, 0x73, 0x20, 0x69, 0x6e, 0x73, 0x74,
0x61, 0x6e, 0x74, 0x69, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x70, 0x72,
0x6f, 0x76, 0x69, 0x64, 0x65, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x69,
0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x61,
0x62, 0x6f, 0x75, 0x74, 0x20, 0x74, 0x68, 0x65, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x6f,
0x75, 0x6e, 0x74, 0x65, 0x64, 0x20, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61,
0x2e, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x44, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65, 0x6e,
0x74, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x20,
0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x6f, 0x75, 0x6e, 0x74,
0x20, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x20, 0x6d, 0x61, 0x79, 0x20, 0x68,
0x61, 0x76, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65,
0x6e, 0x74, 0x20, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x73, 0x20, 0x6d,
0x6f, 0x75, 0x6e, 0x74, 0x65, 0x64, 0x2e, 0x22, 0x3b, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65,
0x72, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x2d, 0x73, 0x63, 0x68,
0x65, 0x6d, 0x61, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x22, 0x54, 0x68, 0x65, 0x20, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x65,
0x64, 0x20, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x20, 0x74, 0x6f, 0x67,
0x65, 0x74, 0x68, 0x65, 0x72, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x74,
0x68, 0x65, 0x20, 0x27, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x2d, 0x72,
0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x27, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6d,
0x61, 0x6b, 0x65, 0x20, 0x75, 0x70, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
0x63, 0x68, 0x65, 0x6d, 0x61, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68,
0x69, 0x73, 0x20, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x70, 0x6f, 0x69,
0x6e, 0x74, 0x2e, 0x22, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70,
0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x54, 0x68, 0x69, 0x73, 0x20, 0x6e,
0x6f, 0x64, 0x65, 0x20, 0x69, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65,
0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x68, 0x61, 0x73, 0x20, 0x6d, 0x6f,
0x75, 0x6e, 0x74, 0x65, 0x64, 0x20, 0x61, 0x74, 0x20, 0x6c, 0x65, 0x61,
0x73, 0x74, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x6f, 0x64, 0x75,
0x6c, 0x65, 0x20, 0x27, 0x69, 0x65, 0x74, 0x66, 0x2d, 0x79, 0x61, 0x6e,
0x67, 0x2d, 0x6c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x27, 0x20, 0x61,
0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x20,
0x70, 0x6f, 0x69, 0x6e, 0x74, 0x2c, 0x20, 0x61, 0x6e, 0x64, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x69, 0x74, 0x73, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x74, 0x69,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64,
0x65, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x69, 0x6e, 0x66, 0x6f, 0x72,
0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x61, 0x62, 0x6f, 0x75, 0x74,
0x20, 0x74, 0x68, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x65,
0x64, 0x20, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x20, 0x20, 0x57,
0x68, 0x65, 0x6e, 0x20, 0x58, 0x50, 0x61, 0x74, 0x68, 0x20, 0x65, 0x78,
0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x69, 0x6e,
0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x64,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x20, 0x61, 0x72, 0x65,
0x20, 0x65, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x64, 0x2c, 0x20,
0x74, 0x68, 0x65, 0x20, 0x27, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x2d,
0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x27, 0x20, 0x6c,
0x65, 0x61, 0x66, 0x2d, 0x6c, 0x69, 0x73, 0x74, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x73,
0x20, 0x74, 0x61, 0x6b, 0x65, 0x6e, 0x20, 0x69, 0x6e, 0x74, 0x6f, 0x20,
0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2e, 0x0a, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x44,
0x69, 0x66, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x69, 0x6e, 0x73,
0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68,
0x65, 0x20, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x70, 0x6f, 0x69, 0x6e,
0x74, 0x20, 0x4d, 0x55, 0x53, 0x54, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20,
0x74, 0x68, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x61, 0x6d, 0x65, 0x20, 0x73, 0x63,
0x68, 0x65, 0x6d, 0x61, 0x20, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x64,
0x2e, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x6c, 0x65, 0x61, 0x66, 0x2d, 0x6c, 0x69, 0x73, 0x74, 0x20,
0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x2d, 0x72, 0x65, 0x66, 0x65, 0x72,
0x65, 0x6e, 0x63, 0x65, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x79, 0x70, 0x65, 0x20,
0x79, 0x61, 0x6e, 0x67, 0x3a, 0x78, 0x70, 0x61, 0x74, 0x68, 0x31, 0x2e,
0x30, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69,
0x6f, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65,
0x73, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x6c, 0x65,
0x61, 0x66, 0x2d, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x61, 0x72, 0x65, 0x20,
0x58, 0x50, 0x61, 0x74, 0x68, 0x20, 0x31, 0x2e, 0x30, 0x20, 0x65, 0x78,
0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x61, 0x72, 0x65, 0x20, 0x65, 0x76,
0x61, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x74,
0x68, 0x65, 0x20, 0x66, 0x6f, 0x6c, 0x6c, 0x6f, 0x77, 0x69, 0x6e, 0x67,
0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x3a, 0x0a, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x2d, 0x20, 0x54, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x74,
0x65, 0x78, 0x74, 0x20, 0x6e, 0x6f, 0x64, 0x65, 0x20, 0x69, 0x73, 0x20,
0x74, 0x68, 0x65, 0x20, 0x6e, 0x6f, 0x64, 0x65, 0x20, 0x69, 0x6e, 0x20,
0x74, 0x68, 0x65, 0x20, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x64,
0x61, 0x74, 0x61, 0x20, 0x74, 0x72, 0x65, 0x65, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x77, 0x68, 0x65, 0x72, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20,
0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x2d, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x20,
0x69, 0x73, 0x20, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x2e, 0x0a,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x2d, 0x20, 0x54, 0x68, 0x65, 0x20, 0x61, 0x63,
0x63, 0x65, 0x73, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x20, 0x74, 0x72, 0x65,
0x65, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x61, 0x72,
0x65, 0x6e, 0x74, 0x20, 0x64, 0x61, 0x74, 0x61, 0x20, 0x74, 0x72, 0x65,
0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2a, 0x77, 0x69, 0x74, 0x68,
0x6f, 0x75, 0x74, 0x2a, 0x20, 0x61, 0x6e, 0x79, 0x20, 0x6e, 0x6f, 0x64,
0x65, 0x73, 0x20, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x20, 0x69,
0x6e, 0x20, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x20, 0x74, 0x68,
0x61, 0x74, 0x20, 0x61, 0x72, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x73, 0x69,
0x64, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x61, 0x72, 0x65, 0x6e,
0x74, 0x20, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x0a, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x2d, 0x20, 0x54, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x74,
0x65, 0x78, 0x74, 0x20, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e,
0x20, 0x61, 0x6e, 0x64, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74,
0x20, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x61, 0x72, 0x65, 0x20, 0x62, 0x6f,
0x74, 0x68, 0x20, 0x65, 0x71, 0x75, 0x61, 0x6c, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x74, 0x6f, 0x20, 0x31, 0x2e, 0x0a, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x2d, 0x20, 0x54, 0x68, 0x65, 0x20, 0x73, 0x65, 0x74, 0x20, 0x6f, 0x66,
0x20, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x62, 0x69,
0x6e, 0x64, 0x69, 0x6e, 0x67, 0x73, 0x20, 0x69, 0x73, 0x20, 0x65, 0x6d,
0x70, 0x74, 0x79, 0x2e, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x20, 0x54,
0x68, 0x65, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20,
0x6c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x20, 0x69, 0x73, 0x20, 0x74,
0x68, 0x65, 0x20, 0x63, 0x6f, 0x72, 0x65, 0x20, 0x66, 0x75, 0x6e, 0x63,
0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65,
0x64, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x57, 0x33, 0x43,
0x20, 0x58, 0x50, 0x61, 0x74, 0x68, 0x20, 0x31, 0x2e, 0x30, 0x20, 0x64,
0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x28, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77,
0x2e, 0x77, 0x33, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x54, 0x52, 0x2f, 0x31,
0x39, 0x39, 0x39, 0x2f, 0x52, 0x45, 0x43, 0x2d, 0x78, 0x70, 0x61, 0x74,
0x68, 0x2d, 0x31, 0x39, 0x39, 0x39, 0x31, 0x31, 0x31, 0x36, 0x29, 0x20,
0x61, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x65,
0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x64,
0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x53, 0x65,
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x31, 0x30, 0x20, 0x6f, 0x66, 0x20,
0x52, 0x46, 0x43, 0x20, 0x37, 0x39, 0x35, 0x30, 0x2e, 0x0a, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x2d, 0x20, 0x54, 0x68, 0x65, 0x20, 0x73, 0x65, 0x74, 0x20,
0x6f, 0x66, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65,
0x20, 0x64, 0x65, 0x63, 0x6c, 0x61, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e,
0x73, 0x20, 0x69, 0x73, 0x20, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64,
0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x27, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x27,
0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x75, 0x6e, 0x64, 0x65, 0x72, 0x20,
0x27, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2d, 0x6d, 0x6f, 0x75, 0x6e,
0x74, 0x73, 0x27, 0x2e, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x45, 0x61, 0x63,
0x68, 0x20, 0x58, 0x50, 0x61, 0x74, 0x68, 0x20, 0x65, 0x78, 0x70, 0x72,
0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x4d, 0x55, 0x53, 0x54, 0x20,
0x65, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x20, 0x74, 0x6f, 0x20,
0x61, 0x20, 0x6e, 0x6f, 0x64, 0x65, 0x2d, 0x73, 0x65, 0x74, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x28, 0x70, 0x6f, 0x73, 0x73, 0x69, 0x62, 0x6c, 0x79, 0x20,
0x65, 0x6d, 0x70, 0x74, 0x79, 0x29, 0x2e, 0x20, 0x20, 0x46, 0x6f, 0x72,
0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x75, 0x72, 0x70, 0x6f, 0x73, 0x65,
0x73, 0x20, 0x6f, 0x66, 0x20, 0x65, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74,
0x69, 0x6e, 0x67, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x58, 0x50, 0x61, 0x74, 0x68,
0x20, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73,
0x20, 0x77, 0x68, 0x6f, 0x73, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65,
0x78, 0x74, 0x20, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x20, 0x61, 0x72, 0x65,
0x20, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x6f, 0x75, 0x6e, 0x74,
0x65, 0x64, 0x20, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2c, 0x20, 0x74,
0x68, 0x65, 0x20, 0x75, 0x6e, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20,
0x61, 0x6c, 0x6c, 0x20, 0x74, 0x68, 0x65, 0x73, 0x65, 0x20, 0x6e, 0x6f,
0x64, 0x65, 0x2d, 0x73, 0x65, 0x74, 0x73, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74,
0x6f, 0x67, 0x65, 0x74, 0x68, 0x65, 0x72, 0x20, 0x77, 0x69, 0x74, 0x68,
0x20, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x20, 0x6e, 0x6f,
0x64, 0x65, 0x73, 0x20, 0x61, 0x72, 0x65, 0x20, 0x61, 0x64, 0x64, 0x65,
0x64, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x20, 0x64,
0x61, 0x74, 0x61, 0x20, 0x74, 0x72, 0x65, 0x65, 0x2e, 0x0a, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x4e, 0x6f, 0x74, 0x65, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20,
0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x61, 0x73, 0x65, 0x20,
0x27, 0x69, 0x65, 0x74, 0x66, 0x2d, 0x79, 0x61, 0x6e, 0x67, 0x2d, 0x73,
0x63, 0x68, 0x65, 0x6d, 0x61, 0x2d, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x27,
0x20, 0x69, 0x73, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x74, 0x73, 0x65, 0x6c,
0x66, 0x20, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x64, 0x2c, 0x20, 0x61,
0x20, 0x27, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x2d, 0x72, 0x65, 0x66,
0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x27, 0x20, 0x69, 0x6e, 0x20, 0x74,
0x68, 0x65, 0x20, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x64, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x6d, 0x61, 0x79,
0x20, 0x72, 0x65, 0x66, 0x65, 0x72, 0x20, 0x74, 0x6f, 0x20, 0x6e, 0x6f,
0x64, 0x65, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x77, 0x65, 0x72,
0x65, 0x20, 0x62, 0x72, 0x6f, 0x75, 0x67, 0x68, 0x74, 0x20, 0x69, 0x6e,
0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x61, 0x63,
0x63, 0x65, 0x73, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x20, 0x74, 0x72, 0x65,
0x65, 0x20, 0x74, 0x68, 0x72, 0x6f, 0x75, 0x67, 0x68, 0x20, 0x61, 0x20,
0x27, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x2d, 0x72, 0x65, 0x66, 0x65,
0x72, 0x65, 0x6e, 0x63, 0x65, 0x27, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68,
0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x20,
0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x22, 0x3b, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20,
0x7d, 0x0a, 0x7d, 0x0a, 0x00
};

View file

@ -0,0 +1,224 @@
module ietf-yang-schema-mount {
yang-version 1.1;
namespace "urn:ietf:params:xml:ns:yang:ietf-yang-schema-mount";
prefix yangmnt;
import ietf-inet-types {
prefix inet;
reference
"RFC 6991: Common YANG Data Types";
}
import ietf-yang-types {
prefix yang;
reference
"RFC 6991: Common YANG Data Types";
}
organization
"IETF NETMOD (NETCONF Data Modeling Language) Working Group";
contact
"WG Web: <https://datatracker.ietf.org/wg/netmod/>
WG List: <mailto:netmod@ietf.org>
Editor: Martin Bjorklund
<mailto:mbj@tail-f.com>
Editor: Ladislav Lhotka
<mailto:lhotka@nic.cz>";
description
"This module defines a YANG extension statement that can be used
to incorporate data models defined in other YANG modules in a
module. It also defines operational state data that specify the
overall structure of the data model.
The key words 'MUST', 'MUST NOT', 'REQUIRED', 'SHALL', 'SHALL
NOT', 'SHOULD', 'SHOULD NOT', 'RECOMMENDED', 'NOT RECOMMENDED',
'MAY', and 'OPTIONAL' in this document are to be interpreted as
described in BCP 14 (RFC 2119) (RFC 8174) when, and only when,
they appear in all capitals, as shown here.
Copyright (c) 2019 IETF Trust and the persons identified as
authors of the code. All rights reserved.
Redistribution and use in source and binary forms, with or
without modification, is permitted pursuant to, and subject to
the license terms contained in, the Simplified BSD License set
forth in Section 4.c of the IETF Trust's Legal Provisions
Relating to IETF Documents
(https://trustee.ietf.org/license-info).
This version of this YANG module is part of RFC 8528;
see the RFC itself for full legal notices.";
revision 2019-01-14 {
description
"Initial revision.";
reference
"RFC 8528: YANG Schema Mount";
}
/*
* Extensions
*/
extension mount-point {
argument label;
description
"The argument 'label' is a YANG identifier, i.e., it is of the
type 'yang:yang-identifier'.
The 'mount-point' statement MUST NOT be used in a YANG
version 1 module, neither explicitly nor via a 'uses'
statement.
The 'mount-point' statement MAY be present as a substatement
of 'container' and 'list' and MUST NOT be present elsewhere.
There MUST NOT be more than one 'mount-point' statement in a
given 'container' or 'list' statement.
If a mount point is defined within a grouping, its label is
bound to the module where the grouping is used.
A mount point defines a place in the node hierarchy where
other data models may be attached. A server that implements a
module with a mount point populates the
'/schema-mounts/mount-point' list with detailed information on
which data models are mounted at each mount point.
Note that the 'mount-point' statement does not define a new
data node.";
}
/*
* State data nodes
*/
container schema-mounts {
config false;
description
"Contains information about the structure of the overall
mounted data model implemented in the server.";
list namespace {
key "prefix";
description
"This list provides a mapping of namespace prefixes that are
used in XPath expressions of 'parent-reference' leafs to the
corresponding namespace URI references.";
leaf prefix {
type yang:yang-identifier;
description
"Namespace prefix.";
}
leaf uri {
type inet:uri;
description
"Namespace URI reference.";
}
}
list mount-point {
key "module label";
description
"Each entry of this list specifies a schema for a particular
mount point.
Each mount point MUST be defined using the 'mount-point'
extension in one of the modules listed in the server's
YANG library instance with conformance type 'implement'.";
leaf module {
type yang:yang-identifier;
description
"Name of a module containing the mount point.";
}
leaf label {
type yang:yang-identifier;
description
"Label of the mount point defined using the 'mount-point'
extension.";
}
leaf config {
type boolean;
default "true";
description
"If this leaf is set to 'false', then all data nodes in the
mounted schema are read-only ('config false'), regardless
of their 'config' property.";
}
choice schema-ref {
mandatory true;
description
"Alternatives for specifying the schema.";
container inline {
presence
"A complete self-contained schema is mounted at the
mount point.";
description
"This node indicates that the server has mounted at least
the module 'ietf-yang-library' at the mount point, and
its instantiation provides the information about the
mounted schema.
Different instances of the mount point may have
different schemas mounted.";
}
container shared-schema {
presence
"The mounted schema together with the 'parent-reference'
make up the schema for this mount point.";
description
"This node indicates that the server has mounted at least
the module 'ietf-yang-library' at the mount point, and
its instantiation provides the information about the
mounted schema. When XPath expressions in the mounted
schema are evaluated, the 'parent-reference' leaf-list
is taken into account.
Different instances of the mount point MUST have the
same schema mounted.";
leaf-list parent-reference {
type yang:xpath1.0;
description
"Entries of this leaf-list are XPath 1.0 expressions
that are evaluated in the following context:
- The context node is the node in the parent data tree
where the mount-point is defined.
- The accessible tree is the parent data tree
*without* any nodes defined in modules that are
mounted inside the parent schema.
- The context position and context size are both equal
to 1.
- The set of variable bindings is empty.
- The function library is the core function library
defined in the W3C XPath 1.0 document
(http://www.w3.org/TR/1999/REC-xpath-19991116) and
the functions defined in Section 10 of RFC 7950.
- The set of namespace declarations is defined by the
'namespace' list under 'schema-mounts'.
Each XPath expression MUST evaluate to a node-set
(possibly empty). For the purposes of evaluating
XPath expressions whose context nodes are defined in
the mounted schema, the union of all these node-sets
together with ancestor nodes are added to the
accessible data tree.
Note that in the case 'ietf-yang-schema-mount' is
itself mounted, a 'parent-reference' in the mounted
module may refer to nodes that were brought into the
accessible tree through a 'parent-reference' in the
parent schema.";
}
}
}
}
}
}

View file

@ -0,0 +1,635 @@
char ietf_yang_structure_ext_2020_06_17_yang[] = {
0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x69, 0x65, 0x74, 0x66, 0x2d,
0x79, 0x61, 0x6e, 0x67, 0x2d, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x75,
0x72, 0x65, 0x2d, 0x65, 0x78, 0x74, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x79,
0x61, 0x6e, 0x67, 0x2d, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20,
0x31, 0x2e, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x73,
0x70, 0x61, 0x63, 0x65, 0x20, 0x22, 0x75, 0x72, 0x6e, 0x3a, 0x69, 0x65,
0x74, 0x66, 0x3a, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x3a, 0x78, 0x6d,
0x6c, 0x3a, 0x6e, 0x73, 0x3a, 0x79, 0x61, 0x6e, 0x67, 0x3a, 0x69, 0x65,
0x74, 0x66, 0x2d, 0x79, 0x61, 0x6e, 0x67, 0x2d, 0x73, 0x74, 0x72, 0x75,
0x63, 0x74, 0x75, 0x72, 0x65, 0x2d, 0x65, 0x78, 0x74, 0x22, 0x3b, 0x0a,
0x20, 0x20, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x20, 0x73, 0x78, 0x3b,
0x0a, 0x0a, 0x20, 0x20, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61,
0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x22, 0x49, 0x45,
0x54, 0x46, 0x20, 0x4e, 0x45, 0x54, 0x4d, 0x4f, 0x44, 0x20, 0x28, 0x4e,
0x45, 0x54, 0x43, 0x4f, 0x4e, 0x46, 0x20, 0x44, 0x61, 0x74, 0x61, 0x20,
0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x69, 0x6e, 0x67, 0x20, 0x4c, 0x61, 0x6e,
0x67, 0x75, 0x61, 0x67, 0x65, 0x29, 0x20, 0x57, 0x6f, 0x72, 0x6b, 0x69,
0x6e, 0x67, 0x20, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x22, 0x3b, 0x0a, 0x20,
0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x22, 0x57, 0x47, 0x20, 0x57, 0x65, 0x62, 0x3a, 0x20, 0x20, 0x20,
0x3c, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x64, 0x61, 0x74,
0x61, 0x74, 0x72, 0x61, 0x63, 0x6b, 0x65, 0x72, 0x2e, 0x69, 0x65, 0x74,
0x66, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x77, 0x67, 0x2f, 0x6e, 0x65, 0x74,
0x6d, 0x6f, 0x64, 0x2f, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x57,
0x47, 0x20, 0x4c, 0x69, 0x73, 0x74, 0x3a, 0x20, 0x20, 0x3c, 0x6d, 0x61,
0x69, 0x6c, 0x74, 0x6f, 0x3a, 0x6e, 0x65, 0x74, 0x6d, 0x6f, 0x64, 0x40,
0x69, 0x65, 0x74, 0x66, 0x2e, 0x6f, 0x72, 0x67, 0x3e, 0x0a, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x3a, 0x20,
0x20, 0x20, 0x41, 0x6e, 0x64, 0x79, 0x20, 0x42, 0x69, 0x65, 0x72, 0x6d,
0x61, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x6d, 0x61, 0x69, 0x6c, 0x74,
0x6f, 0x3a, 0x61, 0x6e, 0x64, 0x79, 0x40, 0x79, 0x75, 0x6d, 0x61, 0x77,
0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x3e, 0x0a, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x3a, 0x20,
0x20, 0x20, 0x4d, 0x61, 0x72, 0x74, 0x69, 0x6e, 0x20, 0x42, 0x6a, 0x6f,
0x72, 0x6b, 0x6c, 0x75, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x6d,
0x61, 0x69, 0x6c, 0x74, 0x6f, 0x3a, 0x6d, 0x62, 0x6a, 0x2b, 0x69, 0x65,
0x74, 0x66, 0x40, 0x34, 0x36, 0x36, 0x38, 0x2e, 0x73, 0x65, 0x3e, 0x0a,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72,
0x3a, 0x20, 0x20, 0x20, 0x4b, 0x65, 0x6e, 0x74, 0x20, 0x57, 0x61, 0x74,
0x73, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x6d, 0x61, 0x69, 0x6c,
0x74, 0x6f, 0x3a, 0x6b, 0x65, 0x6e, 0x74, 0x2b, 0x69, 0x65, 0x74, 0x66,
0x40, 0x77, 0x61, 0x74, 0x73, 0x65, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x3e,
0x22, 0x3b, 0x0a, 0x20, 0x20, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70,
0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x22, 0x54, 0x68,
0x69, 0x73, 0x20, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x63, 0x6f,
0x6e, 0x74, 0x61, 0x69, 0x6e, 0x73, 0x20, 0x63, 0x6f, 0x6e, 0x63, 0x65,
0x70, 0x74, 0x75, 0x61, 0x6c, 0x20, 0x59, 0x41, 0x4e, 0x47, 0x20, 0x73,
0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
0x73, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69,
0x6e, 0x67, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x61, 0x62, 0x73, 0x74,
0x72, 0x61, 0x63, 0x74, 0x20, 0x64, 0x61, 0x74, 0x61, 0x20, 0x73, 0x74,
0x72, 0x75, 0x63, 0x74, 0x75, 0x72, 0x65, 0x73, 0x2e, 0x0a, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x20, 0x54, 0x68, 0x65, 0x20, 0x6b, 0x65, 0x79, 0x20,
0x77, 0x6f, 0x72, 0x64, 0x73, 0x20, 0x27, 0x4d, 0x55, 0x53, 0x54, 0x27,
0x2c, 0x20, 0x27, 0x4d, 0x55, 0x53, 0x54, 0x20, 0x4e, 0x4f, 0x54, 0x27,
0x2c, 0x20, 0x27, 0x52, 0x45, 0x51, 0x55, 0x49, 0x52, 0x45, 0x44, 0x27,
0x2c, 0x20, 0x27, 0x53, 0x48, 0x41, 0x4c, 0x4c, 0x27, 0x2c, 0x20, 0x27,
0x53, 0x48, 0x41, 0x4c, 0x4c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x4e,
0x4f, 0x54, 0x27, 0x2c, 0x20, 0x27, 0x53, 0x48, 0x4f, 0x55, 0x4c, 0x44,
0x27, 0x2c, 0x20, 0x27, 0x53, 0x48, 0x4f, 0x55, 0x4c, 0x44, 0x20, 0x4e,
0x4f, 0x54, 0x27, 0x2c, 0x20, 0x27, 0x52, 0x45, 0x43, 0x4f, 0x4d, 0x4d,
0x45, 0x4e, 0x44, 0x45, 0x44, 0x27, 0x2c, 0x20, 0x27, 0x4e, 0x4f, 0x54,
0x20, 0x52, 0x45, 0x43, 0x4f, 0x4d, 0x4d, 0x45, 0x4e, 0x44, 0x45, 0x44,
0x27, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x27, 0x4d, 0x41, 0x59,
0x27, 0x2c, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x27, 0x4f, 0x50, 0x54, 0x49,
0x4f, 0x4e, 0x41, 0x4c, 0x27, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x69,
0x73, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x61,
0x72, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65, 0x20, 0x69, 0x6e, 0x74,
0x65, 0x72, 0x70, 0x72, 0x65, 0x74, 0x65, 0x64, 0x20, 0x61, 0x73, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62,
0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x42, 0x43, 0x50, 0x20, 0x31, 0x34,
0x20, 0x28, 0x52, 0x46, 0x43, 0x20, 0x32, 0x31, 0x31, 0x39, 0x29, 0x20,
0x28, 0x52, 0x46, 0x43, 0x20, 0x38, 0x31, 0x37, 0x34, 0x29, 0x20, 0x77,
0x68, 0x65, 0x6e, 0x2c, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6f, 0x6e, 0x6c,
0x79, 0x20, 0x77, 0x68, 0x65, 0x6e, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x20, 0x74, 0x68, 0x65, 0x79, 0x20, 0x61, 0x70, 0x70, 0x65, 0x61, 0x72,
0x20, 0x69, 0x6e, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x63, 0x61, 0x70, 0x69,
0x74, 0x61, 0x6c, 0x73, 0x2c, 0x20, 0x61, 0x73, 0x20, 0x73, 0x68, 0x6f,
0x77, 0x6e, 0x20, 0x68, 0x65, 0x72, 0x65, 0x2e, 0x0a, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x20, 0x43, 0x6f, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74,
0x20, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x32, 0x30, 0x20, 0x49, 0x45,
0x54, 0x46, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x61, 0x6e, 0x64,
0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x73,
0x20, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x20,
0x61, 0x73, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x61, 0x75, 0x74, 0x68,
0x6f, 0x72, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63,
0x6f, 0x64, 0x65, 0x2e, 0x20, 0x20, 0x41, 0x6c, 0x6c, 0x20, 0x72, 0x69,
0x67, 0x68, 0x74, 0x73, 0x20, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65,
0x64, 0x2e, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x52, 0x65, 0x64,
0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x20,
0x61, 0x6e, 0x64, 0x20, 0x75, 0x73, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x73,
0x6f, 0x75, 0x72, 0x63, 0x65, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x62, 0x69,
0x6e, 0x61, 0x72, 0x79, 0x20, 0x66, 0x6f, 0x72, 0x6d, 0x73, 0x2c, 0x20,
0x77, 0x69, 0x74, 0x68, 0x20, 0x6f, 0x72, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x20, 0x77, 0x69, 0x74, 0x68, 0x6f, 0x75, 0x74, 0x20, 0x6d, 0x6f, 0x64,
0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2c, 0x20, 0x69,
0x73, 0x20, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x74, 0x74, 0x65, 0x64, 0x20,
0x70, 0x75, 0x72, 0x73, 0x75, 0x61, 0x6e, 0x74, 0x20, 0x74, 0x6f, 0x2c,
0x20, 0x61, 0x6e, 0x64, 0x20, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74,
0x20, 0x74, 0x6f, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x65,
0x20, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x20, 0x74, 0x65, 0x72,
0x6d, 0x73, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x64,
0x20, 0x69, 0x6e, 0x2c, 0x20, 0x74, 0x68, 0x65, 0x20, 0x53, 0x69, 0x6d,
0x70, 0x6c, 0x69, 0x66, 0x69, 0x65, 0x64, 0x20, 0x42, 0x53, 0x44, 0x20,
0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x20, 0x73, 0x65, 0x74, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6f, 0x72, 0x74, 0x68, 0x20, 0x69,
0x6e, 0x20, 0x53, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x34, 0x2e,
0x63, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x49, 0x45, 0x54,
0x46, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x27, 0x73, 0x20, 0x4c, 0x65,
0x67, 0x61, 0x6c, 0x20, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f,
0x6e, 0x73, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x52, 0x65, 0x6c, 0x61,
0x74, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x6f, 0x20, 0x49, 0x45, 0x54, 0x46,
0x20, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x20, 0x28, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f,
0x74, 0x72, 0x75, 0x73, 0x74, 0x65, 0x65, 0x2e, 0x69, 0x65, 0x74, 0x66,
0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65,
0x2d, 0x69, 0x6e, 0x66, 0x6f, 0x29, 0x2e, 0x0a, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69,
0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x59,
0x41, 0x4e, 0x47, 0x20, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x69,
0x73, 0x20, 0x70, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x52, 0x46,
0x43, 0x20, 0x38, 0x37, 0x39, 0x31, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
0x28, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77,
0x2e, 0x72, 0x66, 0x63, 0x2d, 0x65, 0x64, 0x69, 0x74, 0x6f, 0x72, 0x2e,
0x6f, 0x72, 0x67, 0x2f, 0x69, 0x6e, 0x66, 0x6f, 0x2f, 0x72, 0x66, 0x63,
0x38, 0x37, 0x39, 0x31, 0x29, 0x3b, 0x20, 0x73, 0x65, 0x65, 0x20, 0x74,
0x68, 0x65, 0x20, 0x52, 0x46, 0x43, 0x20, 0x69, 0x74, 0x73, 0x65, 0x6c,
0x66, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x66,
0x75, 0x6c, 0x6c, 0x20, 0x6c, 0x65, 0x67, 0x61, 0x6c, 0x20, 0x6e, 0x6f,
0x74, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x22, 0x3b, 0x0a, 0x0a, 0x20, 0x20,
0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x32, 0x30, 0x32,
0x30, 0x2d, 0x30, 0x36, 0x2d, 0x31, 0x37, 0x20, 0x7b, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f,
0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x49, 0x6e, 0x69,
0x74, 0x69, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f,
0x6e, 0x2e, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x66,
0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x22, 0x52, 0x46, 0x43, 0x20, 0x38, 0x37, 0x39, 0x31, 0x3a, 0x20,
0x59, 0x41, 0x4e, 0x47, 0x20, 0x44, 0x61, 0x74, 0x61, 0x20, 0x53, 0x74,
0x72, 0x75, 0x63, 0x74, 0x75, 0x72, 0x65, 0x20, 0x45, 0x78, 0x74, 0x65,
0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x22, 0x3b, 0x0a, 0x20, 0x20,
0x7d, 0x0a, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69,
0x6f, 0x6e, 0x20, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x75, 0x72, 0x65,
0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x61, 0x72, 0x67, 0x75, 0x6d,
0x65, 0x6e, 0x74, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x7b, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x79, 0x69, 0x6e, 0x2d, 0x65, 0x6c, 0x65,
0x6d, 0x65, 0x6e, 0x74, 0x20, 0x74, 0x72, 0x75, 0x65, 0x3b, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x73,
0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x22, 0x54, 0x68, 0x69, 0x73, 0x20, 0x65, 0x78, 0x74,
0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x73, 0x20, 0x75, 0x73,
0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66,
0x79, 0x20, 0x61, 0x20, 0x59, 0x41, 0x4e, 0x47, 0x20, 0x64, 0x61, 0x74,
0x61, 0x20, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x75, 0x72, 0x65, 0x20,
0x74, 0x68, 0x61, 0x74, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x72, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x73, 0x20, 0x63,
0x6f, 0x6e, 0x63, 0x65, 0x70, 0x74, 0x75, 0x61, 0x6c, 0x20, 0x64, 0x61,
0x74, 0x61, 0x20, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x20, 0x69,
0x6e, 0x20, 0x59, 0x41, 0x4e, 0x47, 0x2e, 0x20, 0x20, 0x49, 0x74, 0x20,
0x69, 0x73, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x20,
0x74, 0x6f, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65,
0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x20, 0x68, 0x69, 0x65, 0x72, 0x61,
0x72, 0x63, 0x68, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x64, 0x61, 0x74, 0x61,
0x20, 0x69, 0x6e, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x74,
0x20, 0x6f, 0x66, 0x20, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c,
0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x20, 0x6f, 0x72, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69,
0x66, 0x69, 0x63, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20,
0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x66, 0x6f, 0x72,
0x6d, 0x61, 0x74, 0x2e, 0x20, 0x20, 0x44, 0x61, 0x74, 0x61, 0x20, 0x64,
0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x73, 0x74,
0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x77, 0x69, 0x74, 0x68, 0x69, 0x6e, 0x20, 0x61,
0x20, 0x27, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x75, 0x72, 0x65, 0x27,
0x20, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x73,
0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x70, 0x65,
0x63, 0x69, 0x66, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x67, 0x65, 0x6e,
0x65, 0x72, 0x69, 0x63, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x73, 0x79, 0x6e, 0x74, 0x61, 0x78, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74,
0x68, 0x65, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x20,
0x59, 0x41, 0x4e, 0x47, 0x20, 0x64, 0x61, 0x74, 0x61, 0x20, 0x73, 0x74,
0x72, 0x75, 0x63, 0x74, 0x75, 0x72, 0x65, 0x2c, 0x20, 0x77, 0x68, 0x6f,
0x73, 0x65, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x69, 0x73, 0x20, 0x74,
0x68, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x61, 0x72,
0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68,
0x65, 0x20, 0x27, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x75, 0x72, 0x65,
0x27, 0x20, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x20,
0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x0a, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x4e, 0x6f, 0x74, 0x65, 0x20,
0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x65, 0x78,
0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x64, 0x6f, 0x65, 0x73,
0x20, 0x6e, 0x6f, 0x74, 0x20, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x20,
0x61, 0x20, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x20, 0x74, 0x79, 0x70, 0x65,
0x2e, 0x20, 0x20, 0x41, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x20, 0x75, 0x73, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x69, 0x73,
0x20, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x4d,
0x55, 0x53, 0x54, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x79, 0x20,
0x74, 0x68, 0x65, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64,
0x69, 0x6e, 0x67, 0x20, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x2c, 0x20, 0x69,
0x6e, 0x63, 0x6c, 0x75, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x65,
0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x20, 0x6d, 0x65, 0x64,
0x69, 0x61, 0x20, 0x74, 0x79, 0x70, 0x65, 0x2c, 0x20, 0x69, 0x66, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69,
0x63, 0x61, 0x62, 0x6c, 0x65, 0x2e, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x54, 0x68, 0x65, 0x20, 0x6d, 0x61, 0x6e, 0x64, 0x61,
0x74, 0x6f, 0x72, 0x79, 0x20, 0x27, 0x6e, 0x61, 0x6d, 0x65, 0x27, 0x20,
0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x20, 0x76, 0x61,
0x6c, 0x75, 0x65, 0x20, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69,
0x65, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x59, 0x41, 0x4e, 0x47, 0x20,
0x64, 0x61, 0x74, 0x61, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x75, 0x72, 0x65, 0x20, 0x74, 0x68,
0x61, 0x74, 0x20, 0x69, 0x73, 0x20, 0x62, 0x65, 0x69, 0x6e, 0x67, 0x20,
0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x2e, 0x0a, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x65, 0x78,
0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x73, 0x20, 0x6f,
0x6e, 0x6c, 0x79, 0x20, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x61, 0x73,
0x20, 0x61, 0x20, 0x74, 0x6f, 0x70, 0x2d, 0x6c, 0x65, 0x76, 0x65, 0x6c,
0x20, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2c, 0x20,
0x69, 0x2e, 0x65, 0x2e, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x67, 0x69, 0x76, 0x65, 0x6e, 0x20, 0x61, 0x73, 0x20, 0x61, 0x20,
0x73, 0x75, 0x62, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74,
0x20, 0x74, 0x6f, 0x20, 0x27, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x27,
0x20, 0x6f, 0x72, 0x20, 0x27, 0x73, 0x75, 0x62, 0x6d, 0x6f, 0x64, 0x75,
0x6c, 0x65, 0x27, 0x2e, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x54, 0x68, 0x65, 0x20, 0x73, 0x75, 0x62, 0x73, 0x74, 0x61, 0x74,
0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68,
0x69, 0x73, 0x20, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e,
0x20, 0x4d, 0x55, 0x53, 0x54, 0x20, 0x66, 0x6f, 0x6c, 0x6c, 0x6f, 0x77,
0x20, 0x74, 0x68, 0x65, 0x20, 0x41, 0x42, 0x4e, 0x46, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x20, 0x62,
0x65, 0x6c, 0x6f, 0x77, 0x2c, 0x20, 0x77, 0x68, 0x65, 0x72, 0x65, 0x20,
0x74, 0x68, 0x65, 0x20, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x20, 0x61, 0x72,
0x65, 0x20, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x20, 0x69, 0x6e,
0x20, 0x52, 0x46, 0x43, 0x20, 0x37, 0x39, 0x35, 0x30, 0x3a, 0x0a, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2a,
0x6d, 0x75, 0x73, 0x74, 0x2d, 0x73, 0x74, 0x6d, 0x74, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x73, 0x74,
0x61, 0x74, 0x75, 0x73, 0x2d, 0x73, 0x74, 0x6d, 0x74, 0x5d, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x64,
0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x73,
0x74, 0x6d, 0x74, 0x5d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x5b, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e,
0x63, 0x65, 0x2d, 0x73, 0x74, 0x6d, 0x74, 0x5d, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2a, 0x28, 0x74, 0x79,
0x70, 0x65, 0x64, 0x65, 0x66, 0x2d, 0x73, 0x74, 0x6d, 0x74, 0x20, 0x2f,
0x20, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x69, 0x6e, 0x67, 0x2d, 0x73, 0x74,
0x6d, 0x74, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x2a, 0x64, 0x61, 0x74, 0x61, 0x2d, 0x64, 0x65, 0x66,
0x2d, 0x73, 0x74, 0x6d, 0x74, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x41, 0x20, 0x59, 0x41, 0x4e, 0x47, 0x20, 0x64, 0x61, 0x74,
0x61, 0x20, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x75, 0x72, 0x65, 0x20,
0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68,
0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73,
0x69, 0x6f, 0x6e, 0x20, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e,
0x74, 0x20, 0x69, 0x73, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x74,
0x68, 0x65, 0x20, 0x73, 0x61, 0x6d, 0x65, 0x20, 0x77, 0x61, 0x79, 0x20,
0x61, 0x73, 0x20, 0x61, 0x6e, 0x20, 0x27, 0x61, 0x6e, 0x79, 0x64, 0x61,
0x74, 0x61, 0x27, 0x20, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x20, 0x20, 0x54,
0x68, 0x69, 0x73, 0x20, 0x6d, 0x65, 0x61, 0x6e, 0x73, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68,
0x65, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68,
0x65, 0x20, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x75, 0x72, 0x65, 0x20,
0x69, 0x73, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x20, 0x61,
0x73, 0x20, 0x61, 0x20, 0x27, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e,
0x65, 0x72, 0x27, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x77, 0x69, 0x74, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x69, 0x6e, 0x73,
0x74, 0x61, 0x6e, 0x74, 0x69, 0x61, 0x74, 0x65, 0x64, 0x20, 0x63, 0x68,
0x69, 0x6c, 0x64, 0x20, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e,
0x74, 0x73, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x20, 0x61,
0x73, 0x20, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x20, 0x6e, 0x6f, 0x64, 0x65,
0x73, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x6f, 0x20,
0x74, 0x68, 0x69, 0x73, 0x20, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x0a, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x54, 0x68, 0x65, 0x20, 0x6d,
0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x61,
0x6e, 0x64, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65,
0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74,
0x68, 0x65, 0x20, 0x59, 0x41, 0x4e, 0x47, 0x20, 0x6d, 0x6f, 0x64, 0x75,
0x6c, 0x65, 0x20, 0x75, 0x73, 0x69, 0x6e, 0x67, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x78, 0x74, 0x65,
0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d,
0x65, 0x6e, 0x74, 0x20, 0x61, 0x72, 0x65, 0x20, 0x61, 0x73, 0x73, 0x69,
0x67, 0x6e, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x65, 0x61, 0x63, 0x68,
0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, 0x61, 0x74, 0x61,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x66, 0x69,
0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x73, 0x74, 0x61, 0x74, 0x65,
0x6d, 0x65, 0x6e, 0x74, 0x73, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74,
0x69, 0x6e, 0x67, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x74, 0x68, 0x65,
0x20, 0x59, 0x41, 0x4e, 0x47, 0x20, 0x64, 0x61, 0x74, 0x61, 0x20, 0x73,
0x74, 0x72, 0x75, 0x63, 0x74, 0x75, 0x72, 0x65, 0x2e, 0x0a, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x54, 0x68, 0x65, 0x20, 0x58, 0x50,
0x61, 0x74, 0x68, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74,
0x20, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x69, 0x73, 0x20,
0x74, 0x68, 0x65, 0x20, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f,
0x6e, 0x20, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x20,
0x69, 0x74, 0x73, 0x65, 0x6c, 0x66, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x73, 0x75, 0x63, 0x68, 0x20, 0x74, 0x68, 0x61, 0x74,
0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x20, 0x6e,
0x6f, 0x64, 0x65, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20,
0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x65, 0x6c, 0x65,
0x6d, 0x65, 0x6e, 0x74, 0x20, 0x61, 0x72, 0x65, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e,
0x74, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x64,
0x61, 0x74, 0x61, 0x2d, 0x64, 0x65, 0x66, 0x2d, 0x73, 0x74, 0x6d, 0x74,
0x20, 0x73, 0x75, 0x62, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e,
0x74, 0x73, 0x20, 0x77, 0x69, 0x74, 0x68, 0x69, 0x6e, 0x20, 0x74, 0x68,
0x69, 0x73, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x78,
0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x20, 0x20, 0x54, 0x68,
0x69, 0x73, 0x20, 0x63, 0x6f, 0x6e, 0x63, 0x65, 0x70, 0x74, 0x75, 0x61,
0x6c, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x69,
0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78,
0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6f, 0x6c, 0x6c, 0x6f, 0x77, 0x69,
0x6e, 0x67, 0x20, 0x59, 0x41, 0x4e, 0x47, 0x20, 0x73, 0x74, 0x61, 0x74,
0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x3a, 0x0a, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x20, 0x6d, 0x75,
0x73, 0x74, 0x2d, 0x73, 0x74, 0x6d, 0x74, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x20, 0x77, 0x68, 0x65,
0x6e, 0x2d, 0x73, 0x74, 0x6d, 0x74, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x20, 0x70, 0x61, 0x74, 0x68,
0x2d, 0x73, 0x74, 0x6d, 0x74, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x20, 0x6d, 0x69, 0x6e, 0x2d, 0x65,
0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x2d, 0x73, 0x74, 0x6d, 0x74,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x2d, 0x20, 0x6d, 0x61, 0x78, 0x2d, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e,
0x74, 0x73, 0x2d, 0x73, 0x74, 0x6d, 0x74, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x20, 0x6d, 0x61, 0x6e,
0x64, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x2d, 0x73, 0x74, 0x6d, 0x74, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2d,
0x20, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x2d, 0x73, 0x74, 0x6d, 0x74,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x2d, 0x20, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x65, 0x64, 0x2d, 0x62, 0x79,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x2d, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x2d, 0x69,
0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x20, 0x64, 0x61,
0x74, 0x61, 0x20, 0x74, 0x79, 0x70, 0x65, 0x0a, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x54, 0x68, 0x65, 0x20, 0x66, 0x6f, 0x6c, 0x6c,
0x6f, 0x77, 0x69, 0x6e, 0x67, 0x20, 0x64, 0x61, 0x74, 0x61, 0x2d, 0x64,
0x65, 0x66, 0x2d, 0x73, 0x74, 0x6d, 0x74, 0x20, 0x73, 0x75, 0x62, 0x73,
0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x20, 0x61, 0x72,
0x65, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x72, 0x61, 0x69, 0x6e, 0x65,
0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x77, 0x68, 0x65,
0x6e, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x69,
0x6e, 0x20, 0x61, 0x20, 0x27, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x75,
0x72, 0x65, 0x27, 0x20, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f,
0x6e, 0x20, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e,
0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x2d, 0x20, 0x54, 0x68, 0x65, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x2d, 0x73,
0x74, 0x6d, 0x74, 0x20, 0x69, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x72,
0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x68,
0x61, 0x76, 0x65, 0x20, 0x61, 0x20, 0x6b, 0x65, 0x79, 0x2d, 0x73, 0x74,
0x6d, 0x74, 0x20, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x2e, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x20,
0x54, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2d, 0x73,
0x74, 0x6d, 0x74, 0x20, 0x69, 0x73, 0x20, 0x69, 0x67, 0x6e, 0x6f, 0x72,
0x65, 0x64, 0x20, 0x69, 0x66, 0x20, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e,
0x74, 0x2e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x3b,
0x0a, 0x20, 0x20, 0x7d, 0x0a, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x74, 0x65,
0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x61, 0x75, 0x67, 0x6d, 0x65, 0x6e,
0x74, 0x2d, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x75, 0x72, 0x65, 0x20,
0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65,
0x6e, 0x74, 0x20, 0x70, 0x61, 0x74, 0x68, 0x20, 0x7b, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x79, 0x69, 0x6e, 0x2d, 0x65, 0x6c, 0x65, 0x6d,
0x65, 0x6e, 0x74, 0x20, 0x74, 0x72, 0x75, 0x65, 0x3b, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x73, 0x63,
0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x22, 0x54, 0x68, 0x69, 0x73, 0x20, 0x65, 0x78, 0x74, 0x65,
0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x73, 0x20, 0x75, 0x73, 0x65,
0x64, 0x20, 0x74, 0x6f, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x79,
0x20, 0x61, 0x6e, 0x20, 0x61, 0x75, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x61,
0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x6f, 0x20, 0x61, 0x20, 0x59, 0x41,
0x4e, 0x47, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x61,
0x74, 0x61, 0x20, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x75, 0x72, 0x65,
0x20, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74,
0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x27, 0x73, 0x74, 0x72, 0x75, 0x63,
0x74, 0x75, 0x72, 0x65, 0x27, 0x20, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d,
0x65, 0x6e, 0x74, 0x2e, 0x20, 0x20, 0x49, 0x74, 0x20, 0x69, 0x73, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x6e,
0x64, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x64, 0x65, 0x73, 0x63, 0x72,
0x69, 0x62, 0x65, 0x20, 0x68, 0x69, 0x65, 0x72, 0x61, 0x72, 0x63, 0x68,
0x69, 0x63, 0x61, 0x6c, 0x20, 0x64, 0x61, 0x74, 0x61, 0x20, 0x69, 0x6e,
0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x74, 0x20, 0x6f, 0x66,
0x20, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74,
0x20, 0x6f, 0x72, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63,
0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x65, 0x6e, 0x63,
0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74,
0x2e, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x54, 0x68,
0x69, 0x73, 0x20, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74,
0x20, 0x68, 0x61, 0x73, 0x20, 0x61, 0x6c, 0x6d, 0x6f, 0x73, 0x74, 0x20,
0x74, 0x68, 0x65, 0x20, 0x73, 0x61, 0x6d, 0x65, 0x20, 0x73, 0x74, 0x72,
0x75, 0x63, 0x74, 0x75, 0x72, 0x65, 0x20, 0x61, 0x73, 0x20, 0x74, 0x68,
0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x27, 0x61, 0x75,
0x67, 0x6d, 0x65, 0x6e, 0x74, 0x2d, 0x73, 0x74, 0x6d, 0x74, 0x27, 0x2e,
0x20, 0x20, 0x44, 0x61, 0x74, 0x61, 0x20, 0x64, 0x65, 0x66, 0x69, 0x6e,
0x69, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d,
0x65, 0x6e, 0x74, 0x73, 0x20, 0x77, 0x69, 0x74, 0x68, 0x69, 0x6e, 0x20,
0x74, 0x68, 0x69, 0x73, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x70,
0x65, 0x63, 0x69, 0x66, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65,
0x6d, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20,
0x67, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, 0x20, 0x73, 0x79, 0x6e, 0x74,
0x61, 0x78, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69,
0x6f, 0x6e, 0x61, 0x6c, 0x20, 0x64, 0x61, 0x74, 0x61, 0x20, 0x74, 0x6f,
0x20, 0x62, 0x65, 0x20, 0x61, 0x64, 0x64, 0x65, 0x64, 0x20, 0x74, 0x6f,
0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69,
0x63, 0x20, 0x59, 0x41, 0x4e, 0x47, 0x20, 0x64, 0x61, 0x74, 0x61, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x74, 0x72, 0x75, 0x63,
0x74, 0x75, 0x72, 0x65, 0x2c, 0x20, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69,
0x66, 0x69, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20,
0x27, 0x70, 0x61, 0x74, 0x68, 0x27, 0x20, 0x61, 0x72, 0x67, 0x75, 0x6d,
0x65, 0x6e, 0x74, 0x2e, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x54, 0x68, 0x65, 0x20, 0x6d, 0x61, 0x6e, 0x64, 0x61, 0x74, 0x6f,
0x72, 0x79, 0x20, 0x27, 0x70, 0x61, 0x74, 0x68, 0x27, 0x20, 0x70, 0x61,
0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x20, 0x76, 0x61, 0x6c, 0x75,
0x65, 0x20, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x73,
0x20, 0x74, 0x68, 0x65, 0x20, 0x59, 0x41, 0x4e, 0x47, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6f, 0x6e, 0x63, 0x65, 0x70, 0x74,
0x75, 0x61, 0x6c, 0x20, 0x64, 0x61, 0x74, 0x61, 0x20, 0x6e, 0x6f, 0x64,
0x65, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x69, 0x73, 0x20, 0x62, 0x65,
0x69, 0x6e, 0x67, 0x20, 0x61, 0x75, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x65,
0x64, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x69, 0x73, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e,
0x74, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20, 0x61, 0x6e, 0x20, 0x61, 0x62,
0x73, 0x6f, 0x6c, 0x75, 0x74, 0x65, 0x2d, 0x73, 0x63, 0x68, 0x65, 0x6d,
0x61, 0x2d, 0x6e, 0x6f, 0x64, 0x65, 0x69, 0x64, 0x20, 0x73, 0x74, 0x72,
0x69, 0x6e, 0x67, 0x2c, 0x20, 0x77, 0x68, 0x65, 0x72, 0x65, 0x20, 0x74,
0x68, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x69,
0x72, 0x73, 0x74, 0x20, 0x6e, 0x6f, 0x64, 0x65, 0x20, 0x69, 0x6e, 0x20,
0x74, 0x68, 0x65, 0x20, 0x61, 0x62, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x65,
0x2d, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2d, 0x6e, 0x6f, 0x64, 0x65,
0x69, 0x64, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x69, 0x64,
0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x73, 0x20, 0x74, 0x68, 0x65,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x59, 0x41, 0x4e, 0x47,
0x20, 0x64, 0x61, 0x74, 0x61, 0x20, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74,
0x75, 0x72, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x61, 0x75, 0x67, 0x6d, 0x65,
0x6e, 0x74, 0x2c, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20,
0x72, 0x65, 0x73, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20,
0x6e, 0x6f, 0x64, 0x65, 0x73, 0x20, 0x69, 0x6e, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x74, 0x72, 0x69,
0x6e, 0x67, 0x20, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65,
0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6e, 0x6f, 0x64, 0x65, 0x20, 0x77,
0x69, 0x74, 0x68, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x59, 0x41,
0x4e, 0x47, 0x20, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x75, 0x72, 0x65,
0x20, 0x74, 0x6f, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x61,
0x75, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x0a, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x65, 0x78, 0x74,
0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x73, 0x20, 0x6f, 0x6e,
0x6c, 0x79, 0x20, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x61, 0x73, 0x20,
0x61, 0x20, 0x74, 0x6f, 0x70, 0x2d, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x20,
0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2c, 0x20, 0x69,
0x2e, 0x65, 0x2e, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x67, 0x69, 0x76, 0x65, 0x6e, 0x20, 0x61, 0x73, 0x20, 0x61, 0x20, 0x73,
0x75, 0x62, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x20,
0x74, 0x6f, 0x20, 0x27, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x27, 0x20,
0x6f, 0x72, 0x20, 0x27, 0x73, 0x75, 0x62, 0x6d, 0x6f, 0x64, 0x75, 0x6c,
0x65, 0x27, 0x2e, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x54, 0x68, 0x65, 0x20, 0x73, 0x75, 0x62, 0x73, 0x74, 0x61, 0x74, 0x65,
0x6d, 0x65, 0x6e, 0x74, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x69,
0x73, 0x20, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x20,
0x4d, 0x55, 0x53, 0x54, 0x20, 0x66, 0x6f, 0x6c, 0x6c, 0x6f, 0x77, 0x20,
0x74, 0x68, 0x65, 0x20, 0x41, 0x42, 0x4e, 0x46, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x20, 0x62, 0x65,
0x6c, 0x6f, 0x77, 0x2c, 0x20, 0x77, 0x68, 0x65, 0x72, 0x65, 0x20, 0x74,
0x68, 0x65, 0x20, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x20, 0x61, 0x72, 0x65,
0x20, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20,
0x52, 0x46, 0x43, 0x20, 0x37, 0x39, 0x35, 0x30, 0x3a, 0x0a, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x73,
0x74, 0x61, 0x74, 0x75, 0x73, 0x2d, 0x73, 0x74, 0x6d, 0x74, 0x5d, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5b,
0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x2d,
0x73, 0x74, 0x6d, 0x74, 0x5d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65,
0x6e, 0x63, 0x65, 0x2d, 0x73, 0x74, 0x6d, 0x74, 0x5d, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x31, 0x2a, 0x28,
0x64, 0x61, 0x74, 0x61, 0x2d, 0x64, 0x65, 0x66, 0x2d, 0x73, 0x74, 0x6d,
0x74, 0x20, 0x2f, 0x20, 0x63, 0x61, 0x73, 0x65, 0x2d, 0x73, 0x74, 0x6d,
0x74, 0x29, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x54,
0x68, 0x65, 0x20, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x6e, 0x61,
0x6d, 0x65, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x73,
0x70, 0x61, 0x63, 0x65, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x66,
0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x59, 0x41, 0x4e, 0x47, 0x20,
0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x75, 0x73, 0x69, 0x6e, 0x67,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x65, 0x20,
0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x73, 0x74,
0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x61, 0x72, 0x65, 0x20,
0x61, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20,
0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x64, 0x6f, 0x63,
0x75, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x6f, 0x72,
0x6d, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20,
0x64, 0x61, 0x74, 0x61, 0x20, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74,
0x69, 0x6f, 0x6e, 0x20, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e,
0x74, 0x73, 0x20, 0x77, 0x69, 0x74, 0x68, 0x69, 0x6e, 0x20, 0x74, 0x68,
0x69, 0x73, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x78,
0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x0a, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x54, 0x68, 0x65, 0x20, 0x58, 0x50, 0x61,
0x74, 0x68, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x20,
0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74,
0x68, 0x65, 0x20, 0x61, 0x75, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x65, 0x64,
0x20, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d,
0x65, 0x6e, 0x74, 0x20, 0x69, 0x74, 0x73, 0x65, 0x6c, 0x66, 0x2c, 0x20,
0x73, 0x75, 0x63, 0x68, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68,
0x65, 0x20, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x20, 0x6e, 0x6f, 0x64, 0x65,
0x73, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, 0x6f, 0x63,
0x75, 0x6d, 0x65, 0x6e, 0x74, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x61, 0x72, 0x65,
0x20, 0x72, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x65, 0x64,
0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, 0x61, 0x74, 0x61,
0x2d, 0x64, 0x65, 0x66, 0x2d, 0x73, 0x74, 0x6d, 0x74, 0x20, 0x73, 0x75,
0x62, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x77, 0x69, 0x74, 0x68, 0x69,
0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x75, 0x67, 0x6d, 0x65, 0x6e,
0x74, 0x65, 0x64, 0x20, 0x27, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x75,
0x72, 0x65, 0x27, 0x20, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e,
0x74, 0x2e, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x54,
0x68, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x20, 0x6e,
0x6f, 0x64, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x27,
0x61, 0x75, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x2d, 0x73, 0x74, 0x72, 0x75,
0x63, 0x74, 0x75, 0x72, 0x65, 0x27, 0x20, 0x73, 0x74, 0x61, 0x74, 0x65,
0x6d, 0x65, 0x6e, 0x74, 0x20, 0x69, 0x73, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x64, 0x65, 0x72, 0x69, 0x76, 0x65, 0x64, 0x20, 0x69,
0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x61, 0x6d, 0x65, 0x20, 0x77,
0x61, 0x79, 0x20, 0x61, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x27, 0x61,
0x75, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x27, 0x20, 0x73, 0x74, 0x61, 0x74,
0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2c, 0x20, 0x61, 0x73, 0x20, 0x64, 0x65,
0x66, 0x69, 0x6e, 0x65, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x69, 0x6e, 0x20, 0x53, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20,
0x36, 0x2e, 0x34, 0x2e, 0x31, 0x20, 0x6f, 0x66, 0x20, 0x5b, 0x52, 0x46,
0x43, 0x37, 0x39, 0x35, 0x30, 0x5d, 0x2e, 0x20, 0x54, 0x68, 0x69, 0x73,
0x20, 0x63, 0x6f, 0x6e, 0x63, 0x65, 0x70, 0x74, 0x75, 0x61, 0x6c, 0x20,
0x6e, 0x6f, 0x64, 0x65, 0x20, 0x69, 0x73, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x69, 0x64, 0x65, 0x72, 0x65,
0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78,
0x74, 0x20, 0x6e, 0x6f, 0x64, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74,
0x68, 0x65, 0x20, 0x66, 0x6f, 0x6c, 0x6c, 0x6f, 0x77, 0x69, 0x6e, 0x67,
0x20, 0x59, 0x41, 0x4e, 0x47, 0x20, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d,
0x65, 0x6e, 0x74, 0x73, 0x3a, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x20, 0x6d, 0x75, 0x73, 0x74,
0x2d, 0x73, 0x74, 0x6d, 0x74, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x20, 0x77, 0x68, 0x65, 0x6e, 0x2d,
0x73, 0x74, 0x6d, 0x74, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x2d, 0x20, 0x70, 0x61, 0x74, 0x68, 0x2d, 0x73,
0x74, 0x6d, 0x74, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x2d, 0x20, 0x6d, 0x69, 0x6e, 0x2d, 0x65, 0x6c, 0x65,
0x6d, 0x65, 0x6e, 0x74, 0x73, 0x2d, 0x73, 0x74, 0x6d, 0x74, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x20,
0x6d, 0x61, 0x78, 0x2d, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73,
0x2d, 0x73, 0x74, 0x6d, 0x74, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x20, 0x6d, 0x61, 0x6e, 0x64, 0x61,
0x74, 0x6f, 0x72, 0x79, 0x2d, 0x73, 0x74, 0x6d, 0x74, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x20, 0x75,
0x6e, 0x69, 0x71, 0x75, 0x65, 0x2d, 0x73, 0x74, 0x6d, 0x74, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x20,
0x6f, 0x72, 0x64, 0x65, 0x72, 0x65, 0x64, 0x2d, 0x62, 0x79, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x20,
0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x2d, 0x69, 0x64, 0x65,
0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x20, 0x64, 0x61, 0x74, 0x61,
0x20, 0x74, 0x79, 0x70, 0x65, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x54, 0x68, 0x65, 0x20, 0x66, 0x6f, 0x6c, 0x6c, 0x6f, 0x77,
0x69, 0x6e, 0x67, 0x20, 0x64, 0x61, 0x74, 0x61, 0x2d, 0x64, 0x65, 0x66,
0x2d, 0x73, 0x74, 0x6d, 0x74, 0x20, 0x73, 0x75, 0x62, 0x73, 0x74, 0x61,
0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x20, 0x61, 0x72, 0x65, 0x20,
0x63, 0x6f, 0x6e, 0x73, 0x74, 0x72, 0x61, 0x69, 0x6e, 0x65, 0x64, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x77, 0x68, 0x65, 0x6e, 0x20,
0x75, 0x73, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x69, 0x6e, 0x20,
0x61, 0x6e, 0x20, 0x27, 0x61, 0x75, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x2d,
0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x75, 0x72, 0x65, 0x27, 0x20, 0x65,
0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x73, 0x74, 0x61,
0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x0a, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x20, 0x54, 0x68,
0x65, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x2d, 0x73, 0x74, 0x6d, 0x74, 0x20,
0x69, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69,
0x72, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20,
0x61, 0x20, 0x6b, 0x65, 0x79, 0x2d, 0x73, 0x74, 0x6d, 0x74, 0x20, 0x64,
0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x2e, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x20, 0x54, 0x68, 0x65,
0x20, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2d, 0x73, 0x74, 0x6d, 0x74,
0x20, 0x69, 0x73, 0x20, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x64, 0x20,
0x69, 0x66, 0x20, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x2e, 0x0a,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x45, 0x78, 0x61, 0x6d,
0x70, 0x6c, 0x65, 0x3a, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20,
0x66, 0x6f, 0x6f, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6d, 0x70,
0x6f, 0x72, 0x74, 0x20, 0x69, 0x65, 0x74, 0x66, 0x2d, 0x79, 0x61, 0x6e,
0x67, 0x2d, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x75, 0x72, 0x65, 0x2d,
0x65, 0x78, 0x74, 0x20, 0x7b, 0x20, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78,
0x20, 0x73, 0x78, 0x3b, 0x20, 0x7d, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73,
0x78, 0x3a, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x75, 0x72, 0x65, 0x20,
0x66, 0x6f, 0x6f, 0x2d, 0x64, 0x61, 0x74, 0x61, 0x20, 0x7b, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x20,
0x66, 0x6f, 0x6f, 0x2d, 0x63, 0x6f, 0x6e, 0x20, 0x7b, 0x20, 0x7d, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65,
0x20, 0x62, 0x61, 0x72, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6d,
0x70, 0x6f, 0x72, 0x74, 0x20, 0x69, 0x65, 0x74, 0x66, 0x2d, 0x79, 0x61,
0x6e, 0x67, 0x2d, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x75, 0x72, 0x65,
0x2d, 0x65, 0x78, 0x74, 0x20, 0x7b, 0x20, 0x70, 0x72, 0x65, 0x66, 0x69,
0x78, 0x20, 0x73, 0x78, 0x3b, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69,
0x6d, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x66, 0x6f, 0x6f, 0x20, 0x7b, 0x20,
0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x20, 0x66, 0x6f, 0x6f, 0x3b, 0x20,
0x7d, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x78, 0x3a, 0x61, 0x75, 0x67,
0x6d, 0x65, 0x6e, 0x74, 0x2d, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x75,
0x72, 0x65, 0x20, 0x2f, 0x66, 0x6f, 0x6f, 0x3a, 0x66, 0x6f, 0x6f, 0x2d,
0x64, 0x61, 0x74, 0x61, 0x2f, 0x66, 0x6f, 0x6f, 0x3a, 0x66, 0x6f, 0x6f,
0x2d, 0x63, 0x6f, 0x6e, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65,
0x61, 0x66, 0x20, 0x61, 0x64, 0x64, 0x2d, 0x6c, 0x65, 0x61, 0x66, 0x31,
0x20, 0x7b, 0x20, 0x74, 0x79, 0x70, 0x65, 0x20, 0x69, 0x6e, 0x74, 0x33,
0x32, 0x3b, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x61, 0x66,
0x20, 0x61, 0x64, 0x64, 0x2d, 0x6c, 0x65, 0x61, 0x66, 0x32, 0x20, 0x7b,
0x20, 0x74, 0x79, 0x70, 0x65, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67,
0x3b, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x0a,
0x7d, 0x0a, 0x00
};

View file

@ -0,0 +1,206 @@
module ietf-yang-structure-ext {
yang-version 1.1;
namespace "urn:ietf:params:xml:ns:yang:ietf-yang-structure-ext";
prefix sx;
organization
"IETF NETMOD (NETCONF Data Modeling Language) Working Group";
contact
"WG Web: <https://datatracker.ietf.org/wg/netmod/>
WG List: <mailto:netmod@ietf.org>
Author: Andy Bierman
<mailto:andy@yumaworks.com>
Author: Martin Bjorklund
<mailto:mbj+ietf@4668.se>
Author: Kent Watsen
<mailto:kent+ietf@watsen.net>";
description
"This module contains conceptual YANG specifications for defining
abstract data structures.
The key words 'MUST', 'MUST NOT', 'REQUIRED', 'SHALL', 'SHALL
NOT', 'SHOULD', 'SHOULD NOT', 'RECOMMENDED', 'NOT RECOMMENDED',
'MAY', and 'OPTIONAL' in this document are to be interpreted as
described in BCP 14 (RFC 2119) (RFC 8174) when, and only when,
they appear in all capitals, as shown here.
Copyright (c) 2020 IETF Trust and the persons identified as
authors of the code. All rights reserved.
Redistribution and use in source and binary forms, with or
without modification, is permitted pursuant to, and subject to
the license terms contained in, the Simplified BSD License set
forth in Section 4.c of the IETF Trust's Legal Provisions
Relating to IETF Documents
(http://trustee.ietf.org/license-info).
This version of this YANG module is part of RFC 8791
(https://www.rfc-editor.org/info/rfc8791); see the RFC itself
for full legal notices.";
revision 2020-06-17 {
description
"Initial revision.";
reference
"RFC 8791: YANG Data Structure Extensions.";
}
extension structure {
argument name {
yin-element true;
}
description
"This extension is used to specify a YANG data structure that
represents conceptual data defined in YANG. It is intended to
describe hierarchical data independent of protocol context or
specific message encoding format. Data definition statements
within a 'structure' extension statement specify the generic
syntax for the specific YANG data structure, whose name is the
argument of the 'structure' extension statement.
Note that this extension does not define a media type. A
specification using this extension MUST specify the message
encoding rules, including the content media type, if
applicable.
The mandatory 'name' parameter value identifies the YANG data
structure that is being defined.
This extension is only valid as a top-level statement, i.e.,
given as a substatement to 'module' or 'submodule'.
The substatements of this extension MUST follow the ABNF
rules below, where the rules are defined in RFC 7950:
*must-stmt
[status-stmt]
[description-stmt]
[reference-stmt]
*(typedef-stmt / grouping-stmt)
*data-def-stmt
A YANG data structure defined with this extension statement is
encoded in the same way as an 'anydata' node. This means
that the name of the structure is encoded as a 'container',
with the instantiated child statements encoded as child nodes
to this node.
The module name and namespace value for the YANG module using
the extension statement are assigned to each of the data
definition statements resulting from the YANG data structure.
The XPath document element is the extension statement itself,
such that the child nodes of the document element are
represented by the data-def-stmt substatements within this
extension. This conceptual document is the context for the
following YANG statements:
- must-stmt
- when-stmt
- path-stmt
- min-elements-stmt
- max-elements-stmt
- mandatory-stmt
- unique-stmt
- ordered-by
- instance-identifier data type
The following data-def-stmt substatements are constrained
when used within a 'structure' extension statement.
- The list-stmt is not required to have a key-stmt defined.
- The config-stmt is ignored if present.
";
}
extension augment-structure {
argument path {
yin-element true;
}
description
"This extension is used to specify an augmentation to a YANG
data structure defined with the 'structure' statement. It is
intended to describe hierarchical data independent of protocol
context or specific message encoding format.
This statement has almost the same structure as the
'augment-stmt'. Data definition statements within this
statement specify the semantics and generic syntax for the
additional data to be added to the specific YANG data
structure, identified by the 'path' argument.
The mandatory 'path' parameter value identifies the YANG
conceptual data node that is being augmented and is
represented as an absolute-schema-nodeid string, where the
first node in the absolute-schema-nodeid string identifies the
YANG data structure to augment, and the rest of the nodes in
the string identifies the node within the YANG structure to
augment.
This extension is only valid as a top-level statement, i.e.,
given as a substatement to 'module' or 'submodule'.
The substatements of this extension MUST follow the ABNF
rules below, where the rules are defined in RFC 7950:
[status-stmt]
[description-stmt]
[reference-stmt]
1*(data-def-stmt / case-stmt)
The module name and namespace value for the YANG module using
the extension statement are assigned to instance document data
conforming to the data definition statements within this
extension.
The XPath document element is the augmented extension
statement itself, such that the child nodes of the document
element are represented by the data-def-stmt substatements
within the augmented 'structure' statement.
The context node of the 'augment-structure' statement is
derived in the same way as the 'augment' statement, as defined
in Section 6.4.1 of [RFC7950]. This conceptual node is
considered the context node for the following YANG statements:
- must-stmt
- when-stmt
- path-stmt
- min-elements-stmt
- max-elements-stmt
- mandatory-stmt
- unique-stmt
- ordered-by
- instance-identifier data type
The following data-def-stmt substatements are constrained
when used within an 'augment-structure' extension statement.
- The list-stmt is not required to have a key-stmt defined.
- The config-stmt is ignored if present.
Example:
module foo {
import ietf-yang-structure-ext { prefix sx; }
sx:structure foo-data {
container foo-con { }
}
}
module bar {
import ietf-yang-structure-ext { prefix sx; }
import foo { prefix foo; }
sx:augment-structure /foo:foo-data/foo:foo-con {
leaf add-leaf1 { type int32; }
leaf add-leaf2 { type string; }
}
}
";
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,474 @@
module ietf-yang-types {
namespace "urn:ietf:params:xml:ns:yang:ietf-yang-types";
prefix "yang";
organization
"IETF NETMOD (NETCONF Data Modeling Language) Working Group";
contact
"WG Web: <http://tools.ietf.org/wg/netmod/>
WG List: <mailto:netmod@ietf.org>
WG Chair: David Kessens
<mailto:david.kessens@nsn.com>
WG Chair: Juergen Schoenwaelder
<mailto:j.schoenwaelder@jacobs-university.de>
Editor: Juergen Schoenwaelder
<mailto:j.schoenwaelder@jacobs-university.de>";
description
"This module contains a collection of generally useful derived
YANG data types.
Copyright (c) 2013 IETF Trust and the persons identified as
authors of the code. All rights reserved.
Redistribution and use in source and binary forms, with or
without modification, is permitted pursuant to, and subject
to the license terms contained in, the Simplified BSD License
set forth in Section 4.c of the IETF Trust's Legal Provisions
Relating to IETF Documents
(http://trustee.ietf.org/license-info).
This version of this YANG module is part of RFC 6991; see
the RFC itself for full legal notices.";
revision 2013-07-15 {
description
"This revision adds the following new data types:
- yang-identifier
- hex-string
- uuid
- dotted-quad";
reference
"RFC 6991: Common YANG Data Types";
}
revision 2010-09-24 {
description
"Initial revision.";
reference
"RFC 6021: Common YANG Data Types";
}
/*** collection of counter and gauge types ***/
typedef counter32 {
type uint32;
description
"The counter32 type represents a non-negative integer
that monotonically increases until it reaches a
maximum value of 2^32-1 (4294967295 decimal), when it
wraps around and starts increasing again from zero.
Counters have no defined 'initial' value, and thus, a
single value of a counter has (in general) no information
content. Discontinuities in the monotonically increasing
value normally occur at re-initialization of the
management system, and at other times as specified in the
description of a schema node using this type. If such
other times can occur, for example, the creation of
a schema node of type counter32 at times other than
re-initialization, then a corresponding schema node
should be defined, with an appropriate type, to indicate
the last discontinuity.
The counter32 type should not be used for configuration
schema nodes. A default statement SHOULD NOT be used in
combination with the type counter32.
In the value set and its semantics, this type is equivalent
to the Counter32 type of the SMIv2.";
reference
"RFC 2578: Structure of Management Information Version 2
(SMIv2)";
}
typedef zero-based-counter32 {
type yang:counter32;
default "0";
description
"The zero-based-counter32 type represents a counter32
that has the defined 'initial' value zero.
A schema node of this type will be set to zero (0) on creation
and will thereafter increase monotonically until it reaches
a maximum value of 2^32-1 (4294967295 decimal), when it
wraps around and starts increasing again from zero.
Provided that an application discovers a new schema node
of this type within the minimum time to wrap, it can use the
'initial' value as a delta. It is important for a management
station to be aware of this minimum time and the actual time
between polls, and to discard data if the actual time is too
long or there is no defined minimum time.
In the value set and its semantics, this type is equivalent
to the ZeroBasedCounter32 textual convention of the SMIv2.";
reference
"RFC 4502: Remote Network Monitoring Management Information
Base Version 2";
}
typedef counter64 {
type uint64;
description
"The counter64 type represents a non-negative integer
that monotonically increases until it reaches a
maximum value of 2^64-1 (18446744073709551615 decimal),
when it wraps around and starts increasing again from zero.
Counters have no defined 'initial' value, and thus, a
single value of a counter has (in general) no information
content. Discontinuities in the monotonically increasing
value normally occur at re-initialization of the
management system, and at other times as specified in the
description of a schema node using this type. If such
other times can occur, for example, the creation of
a schema node of type counter64 at times other than
re-initialization, then a corresponding schema node
should be defined, with an appropriate type, to indicate
the last discontinuity.
The counter64 type should not be used for configuration
schema nodes. A default statement SHOULD NOT be used in
combination with the type counter64.
In the value set and its semantics, this type is equivalent
to the Counter64 type of the SMIv2.";
reference
"RFC 2578: Structure of Management Information Version 2
(SMIv2)";
}
typedef zero-based-counter64 {
type yang:counter64;
default "0";
description
"The zero-based-counter64 type represents a counter64 that
has the defined 'initial' value zero.
A schema node of this type will be set to zero (0) on creation
and will thereafter increase monotonically until it reaches
a maximum value of 2^64-1 (18446744073709551615 decimal),
when it wraps around and starts increasing again from zero.
Provided that an application discovers a new schema node
of this type within the minimum time to wrap, it can use the
'initial' value as a delta. It is important for a management
station to be aware of this minimum time and the actual time
between polls, and to discard data if the actual time is too
long or there is no defined minimum time.
In the value set and its semantics, this type is equivalent
to the ZeroBasedCounter64 textual convention of the SMIv2.";
reference
"RFC 2856: Textual Conventions for Additional High Capacity
Data Types";
}
typedef gauge32 {
type uint32;
description
"The gauge32 type represents a non-negative integer, which
may increase or decrease, but shall never exceed a maximum
value, nor fall below a minimum value. The maximum value
cannot be greater than 2^32-1 (4294967295 decimal), and
the minimum value cannot be smaller than 0. The value of
a gauge32 has its maximum value whenever the information
being modeled is greater than or equal to its maximum
value, and has its minimum value whenever the information
being modeled is smaller than or equal to its minimum value.
If the information being modeled subsequently decreases
below (increases above) the maximum (minimum) value, the
gauge32 also decreases (increases).
In the value set and its semantics, this type is equivalent
to the Gauge32 type of the SMIv2.";
reference
"RFC 2578: Structure of Management Information Version 2
(SMIv2)";
}
typedef gauge64 {
type uint64;
description
"The gauge64 type represents a non-negative integer, which
may increase or decrease, but shall never exceed a maximum
value, nor fall below a minimum value. The maximum value
cannot be greater than 2^64-1 (18446744073709551615), and
the minimum value cannot be smaller than 0. The value of
a gauge64 has its maximum value whenever the information
being modeled is greater than or equal to its maximum
value, and has its minimum value whenever the information
being modeled is smaller than or equal to its minimum value.
If the information being modeled subsequently decreases
below (increases above) the maximum (minimum) value, the
gauge64 also decreases (increases).
In the value set and its semantics, this type is equivalent
to the CounterBasedGauge64 SMIv2 textual convention defined
in RFC 2856";
reference
"RFC 2856: Textual Conventions for Additional High Capacity
Data Types";
}
/*** collection of identifier-related types ***/
typedef object-identifier {
type string {
pattern '(([0-1](\.[1-3]?[0-9]))|(2\.(0|([1-9]\d*))))'
+ '(\.(0|([1-9]\d*)))*';
}
description
"The object-identifier type represents administratively
assigned names in a registration-hierarchical-name tree.
Values of this type are denoted as a sequence of numerical
non-negative sub-identifier values. Each sub-identifier
value MUST NOT exceed 2^32-1 (4294967295). Sub-identifiers
are separated by single dots and without any intermediate
whitespace.
The ASN.1 standard restricts the value space of the first
sub-identifier to 0, 1, or 2. Furthermore, the value space
of the second sub-identifier is restricted to the range
0 to 39 if the first sub-identifier is 0 or 1. Finally,
the ASN.1 standard requires that an object identifier
has always at least two sub-identifiers. The pattern
captures these restrictions.
Although the number of sub-identifiers is not limited,
module designers should realize that there may be
implementations that stick with the SMIv2 limit of 128
sub-identifiers.
This type is a superset of the SMIv2 OBJECT IDENTIFIER type
since it is not restricted to 128 sub-identifiers. Hence,
this type SHOULD NOT be used to represent the SMIv2 OBJECT
IDENTIFIER type; the object-identifier-128 type SHOULD be
used instead.";
reference
"ISO9834-1: Information technology -- Open Systems
Interconnection -- Procedures for the operation of OSI
Registration Authorities: General procedures and top
arcs of the ASN.1 Object Identifier tree";
}
typedef object-identifier-128 {
type object-identifier {
pattern '\d*(\.\d*){1,127}';
}
description
"This type represents object-identifiers restricted to 128
sub-identifiers.
In the value set and its semantics, this type is equivalent
to the OBJECT IDENTIFIER type of the SMIv2.";
reference
"RFC 2578: Structure of Management Information Version 2
(SMIv2)";
}
typedef yang-identifier {
type string {
length "1..max";
pattern '[a-zA-Z_][a-zA-Z0-9\-_.]*';
pattern '.|..|[^xX].*|.[^mM].*|..[^lL].*';
}
description
"A YANG identifier string as defined by the 'identifier'
rule in Section 12 of RFC 6020. An identifier must
start with an alphabetic character or an underscore
followed by an arbitrary sequence of alphabetic or
numeric characters, underscores, hyphens, or dots.
A YANG identifier MUST NOT start with any possible
combination of the lowercase or uppercase character
sequence 'xml'.";
reference
"RFC 6020: YANG - A Data Modeling Language for the Network
Configuration Protocol (NETCONF)";
}
/*** collection of types related to date and time***/
typedef date-and-time {
type string {
pattern '\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?'
+ '(Z|[\+\-]\d{2}:\d{2})';
}
description
"The date-and-time type is a profile of the ISO 8601
standard for representation of dates and times using the
Gregorian calendar. The profile is defined by the
date-time production in Section 5.6 of RFC 3339.
The date-and-time type is compatible with the dateTime XML
schema type with the following notable exceptions:
(a) The date-and-time type does not allow negative years.
(b) The date-and-time time-offset -00:00 indicates an unknown
time zone (see RFC 3339) while -00:00 and +00:00 and Z
all represent the same time zone in dateTime.
(c) The canonical format (see below) of data-and-time values
differs from the canonical format used by the dateTime XML
schema type, which requires all times to be in UTC using
the time-offset 'Z'.
This type is not equivalent to the DateAndTime textual
convention of the SMIv2 since RFC 3339 uses a different
separator between full-date and full-time and provides
higher resolution of time-secfrac.
The canonical format for date-and-time values with a known time
zone uses a numeric time zone offset that is calculated using
the device's configured known offset to UTC time. A change of
the device's offset to UTC time will cause date-and-time values
to change accordingly. Such changes might happen periodically
in case a server follows automatically daylight saving time
(DST) time zone offset changes. The canonical format for
date-and-time values with an unknown time zone (usually
referring to the notion of local time) uses the time-offset
-00:00.";
reference
"RFC 3339: Date and Time on the Internet: Timestamps
RFC 2579: Textual Conventions for SMIv2
XSD-TYPES: XML Schema Part 2: Datatypes Second Edition";
}
typedef timeticks {
type uint32;
description
"The timeticks type represents a non-negative integer that
represents the time, modulo 2^32 (4294967296 decimal), in
hundredths of a second between two epochs. When a schema
node is defined that uses this type, the description of
the schema node identifies both of the reference epochs.
In the value set and its semantics, this type is equivalent
to the TimeTicks type of the SMIv2.";
reference
"RFC 2578: Structure of Management Information Version 2
(SMIv2)";
}
typedef timestamp {
type yang:timeticks;
description
"The timestamp type represents the value of an associated
timeticks schema node at which a specific occurrence
happened. The specific occurrence must be defined in the
description of any schema node defined using this type. When
the specific occurrence occurred prior to the last time the
associated timeticks attribute was zero, then the timestamp
value is zero. Note that this requires all timestamp values
to be reset to zero when the value of the associated timeticks
attribute reaches 497+ days and wraps around to zero.
The associated timeticks schema node must be specified
in the description of any schema node using this type.
In the value set and its semantics, this type is equivalent
to the TimeStamp textual convention of the SMIv2.";
reference
"RFC 2579: Textual Conventions for SMIv2";
}
/*** collection of generic address types ***/
typedef phys-address {
type string {
pattern '([0-9a-fA-F]{2}(:[0-9a-fA-F]{2})*)?';
}
description
"Represents media- or physical-level addresses represented
as a sequence octets, each octet represented by two hexadecimal
numbers. Octets are separated by colons. The canonical
representation uses lowercase characters.
In the value set and its semantics, this type is equivalent
to the PhysAddress textual convention of the SMIv2.";
reference
"RFC 2579: Textual Conventions for SMIv2";
}
typedef mac-address {
type string {
pattern '[0-9a-fA-F]{2}(:[0-9a-fA-F]{2}){5}';
}
description
"The mac-address type represents an IEEE 802 MAC address.
The canonical representation uses lowercase characters.
In the value set and its semantics, this type is equivalent
to the MacAddress textual convention of the SMIv2.";
reference
"IEEE 802: IEEE Standard for Local and Metropolitan Area
Networks: Overview and Architecture
RFC 2579: Textual Conventions for SMIv2";
}
/*** collection of XML-specific types ***/
typedef xpath1.0 {
type string;
description
"This type represents an XPATH 1.0 expression.
When a schema node is defined that uses this type, the
description of the schema node MUST specify the XPath
context in which the XPath expression is evaluated.";
reference
"XPATH: XML Path Language (XPath) Version 1.0";
}
/*** collection of string types ***/
typedef hex-string {
type string {
pattern '([0-9a-fA-F]{2}(:[0-9a-fA-F]{2})*)?';
}
description
"A hexadecimal string with octets represented as hex digits
separated by colons. The canonical representation uses
lowercase characters.";
}
typedef uuid {
type string {
pattern '[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-'
+ '[0-9a-fA-F]{4}-[0-9a-fA-F]{12}';
}
description
"A Universally Unique IDentifier in the string representation
defined in RFC 4122. The canonical representation uses
lowercase characters.
The following is an example of a UUID in string representation:
f81d4fae-7dec-11d0-a765-00a0c91e6bf6
";
reference
"RFC 4122: A Universally Unique IDentifier (UUID) URN
Namespace";
}
typedef dotted-quad {
type string {
pattern
'(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}'
+ '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])';
}
description
"An unsigned 32-bit number expressed in the dotted-quad
notation, i.e., four octets written as decimal numbers
and separated with the '.' (full stop) character.";
}
}

485
models/yang@2022-06-16.h Normal file
View file

@ -0,0 +1,485 @@
char yang_2022_06_16_yang[] = {
0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x79, 0x61, 0x6e, 0x67, 0x20,
0x7b, 0x0a, 0x20, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63,
0x65, 0x20, 0x22, 0x75, 0x72, 0x6e, 0x3a, 0x69, 0x65, 0x74, 0x66, 0x3a,
0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x3a, 0x78, 0x6d, 0x6c, 0x3a, 0x6e,
0x73, 0x3a, 0x79, 0x61, 0x6e, 0x67, 0x3a, 0x31, 0x22, 0x3b, 0x0a, 0x20,
0x20, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x20, 0x79, 0x61, 0x6e, 0x67,
0x3b, 0x0a, 0x20, 0x20, 0x79, 0x61, 0x6e, 0x67, 0x2d, 0x76, 0x65, 0x72,
0x73, 0x69, 0x6f, 0x6e, 0x20, 0x31, 0x2e, 0x31, 0x3b, 0x0a, 0x0a, 0x20,
0x20, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x69, 0x65, 0x74, 0x66,
0x2d, 0x79, 0x61, 0x6e, 0x67, 0x2d, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61,
0x74, 0x61, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x72, 0x65,
0x66, 0x69, 0x78, 0x20, 0x6d, 0x64, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x2d, 0x64, 0x61, 0x74,
0x65, 0x20, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x38, 0x2d, 0x30, 0x35,
0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x0a, 0x0a, 0x20, 0x20, 0x6f, 0x72, 0x67,
0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x22, 0x6c, 0x69, 0x62, 0x79, 0x61, 0x6e, 0x67, 0x22, 0x3b,
0x0a, 0x0a, 0x20, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x22, 0x57, 0x65, 0x62, 0x3a, 0x20, 0x20, 0x20,
0x20, 0x3c, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69,
0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x43, 0x45, 0x53,
0x4e, 0x45, 0x54, 0x2f, 0x6c, 0x69, 0x62, 0x79, 0x61, 0x6e, 0x67, 0x2f,
0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f,
0x72, 0x3a, 0x20, 0x52, 0x61, 0x64, 0x65, 0x6b, 0x20, 0x4b, 0x72, 0x65,
0x6a, 0x63, 0x69, 0x20, 0x3c, 0x72, 0x6b, 0x72, 0x65, 0x6a, 0x63, 0x69,
0x40, 0x63, 0x65, 0x73, 0x6e, 0x65, 0x74, 0x2e, 0x63, 0x7a, 0x3e, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x3a,
0x20, 0x4d, 0x69, 0x63, 0x68, 0x61, 0x6c, 0x20, 0x56, 0x61, 0x73, 0x6b,
0x6f, 0x20, 0x3c, 0x6d, 0x76, 0x61, 0x73, 0x6b, 0x6f, 0x40, 0x63, 0x65,
0x73, 0x6e, 0x65, 0x74, 0x2e, 0x63, 0x7a, 0x3e, 0x22, 0x3b, 0x0a, 0x0a,
0x20, 0x20, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f,
0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x22, 0x54, 0x68, 0x69, 0x73, 0x20,
0x69, 0x73, 0x20, 0x61, 0x20, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x20, 0x6d,
0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x6e,
0x6f, 0x20, 0x64, 0x61, 0x74, 0x61, 0x20, 0x66, 0x6f, 0x72, 0x6d, 0x61,
0x6c, 0x6c, 0x79, 0x20, 0x73, 0x75, 0x70, 0x70, 0x6c, 0x79, 0x69, 0x6e,
0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69,
0x74, 0x69, 0x6f, 0x6e, 0x73, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6f,
0x66, 0x20, 0x76, 0x61, 0x72, 0x69, 0x6f, 0x75, 0x73, 0x20, 0x6d, 0x65,
0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x20, 0x64, 0x65, 0x66, 0x69, 0x6e,
0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x52, 0x46, 0x43, 0x20, 0x36, 0x30,
0x32, 0x30, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x52, 0x46, 0x43, 0x20, 0x37,
0x39, 0x35, 0x30, 0x2e, 0x20, 0x54, 0x68, 0x65, 0x72, 0x65, 0x20, 0x61,
0x72, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x61, 0x64, 0x64, 0x69,
0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x64,
0x61, 0x74, 0x61, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20,
0x6c, 0x69, 0x62, 0x79, 0x61, 0x6e, 0x67, 0x20, 0x64, 0x69, 0x66, 0x66,
0x20, 0x64, 0x61, 0x74, 0x61, 0x20, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74,
0x2e, 0x22, 0x3b, 0x0a, 0x0a, 0x20, 0x20, 0x72, 0x65, 0x76, 0x69, 0x73,
0x69, 0x6f, 0x6e, 0x20, 0x32, 0x30, 0x32, 0x32, 0x2d, 0x30, 0x36, 0x2d,
0x31, 0x36, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x73,
0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x22, 0x41, 0x64, 0x64, 0x65, 0x64, 0x20, 0x74, 0x79,
0x70, 0x65, 0x64, 0x65, 0x66, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x6b, 0x65,
0x79, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x20, 0x74,
0x79, 0x70, 0x65, 0x2e, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x0a, 0x0a,
0x20, 0x20, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x32,
0x30, 0x32, 0x31, 0x2d, 0x30, 0x34, 0x2d, 0x30, 0x37, 0x20, 0x7b, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74,
0x69, 0x6f, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x41,
0x64, 0x64, 0x65, 0x64, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74,
0x61, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x6b, 0x65, 0x79, 0x2d, 0x6c, 0x65,
0x73, 0x73, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x61, 0x6e, 0x64, 0x20,
0x73, 0x74, 0x61, 0x74, 0x65, 0x20, 0x6c, 0x65, 0x61, 0x66, 0x2d, 0x6c,
0x69, 0x73, 0x74, 0x20, 0x64, 0x69, 0x66, 0x66, 0x2e, 0x22, 0x3b, 0x0a,
0x20, 0x20, 0x7d, 0x0a, 0x0a, 0x20, 0x20, 0x72, 0x65, 0x76, 0x69, 0x73,
0x69, 0x6f, 0x6e, 0x20, 0x32, 0x30, 0x32, 0x30, 0x2d, 0x30, 0x36, 0x2d,
0x31, 0x37, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x73,
0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x22, 0x41, 0x64, 0x64, 0x65, 0x64, 0x20, 0x6d, 0x65,
0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x64,
0x69, 0x66, 0x66, 0x2e, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x0a, 0x0a,
0x20, 0x20, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x32,
0x30, 0x31, 0x37, 0x2d, 0x30, 0x32, 0x2d, 0x32, 0x30, 0x20, 0x7b, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74,
0x69, 0x6f, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x41,
0x64, 0x64, 0x65, 0x64, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74,
0x61, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x4e, 0x45, 0x54, 0x43, 0x4f, 0x4e,
0x46, 0x27, 0x73, 0x20, 0x65, 0x64, 0x69, 0x74, 0x2d, 0x63, 0x6f, 0x6e,
0x66, 0x69, 0x67, 0x20, 0x6d, 0x61, 0x6e, 0x69, 0x70, 0x75, 0x6c, 0x61,
0x74, 0x69, 0x6f, 0x6e, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x6f, 0x72,
0x64, 0x65, 0x72, 0x65, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x6c, 0x69, 0x73, 0x74, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6c,
0x65, 0x61, 0x66, 0x2d, 0x6c, 0x69, 0x73, 0x74, 0x73, 0x2e, 0x22, 0x3b,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e,
0x63, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x52, 0x46,
0x43, 0x20, 0x37, 0x39, 0x35, 0x30, 0x3a, 0x20, 0x54, 0x68, 0x65, 0x20,
0x59, 0x41, 0x4e, 0x47, 0x20, 0x31, 0x2e, 0x31, 0x20, 0x44, 0x61, 0x74,
0x61, 0x20, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x69, 0x6e, 0x67, 0x20, 0x4c,
0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x22, 0x3b, 0x0a, 0x20, 0x20,
0x7d, 0x0a, 0x0a, 0x20, 0x20, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f,
0x6e, 0x20, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x32, 0x2d, 0x31, 0x31,
0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x73, 0x63, 0x72,
0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x22, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x20, 0x72, 0x65,
0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x52, 0x46, 0x43, 0x20, 0x36, 0x30,
0x32, 0x30, 0x3a, 0x20, 0x59, 0x41, 0x4e, 0x47, 0x20, 0x2d, 0x20, 0x41,
0x20, 0x44, 0x61, 0x74, 0x61, 0x20, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x69,
0x6e, 0x67, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x20,
0x66, 0x6f, 0x72, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74,
0x68, 0x65, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x20, 0x43,
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e,
0x20, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x20, 0x28, 0x4e,
0x45, 0x54, 0x43, 0x4f, 0x4e, 0x46, 0x29, 0x22, 0x3b, 0x0a, 0x20, 0x20,
0x7d, 0x0a, 0x0a, 0x20, 0x20, 0x74, 0x79, 0x70, 0x65, 0x64, 0x65, 0x66,
0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x2d, 0x69, 0x64,
0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x2d, 0x6b, 0x65, 0x79,
0x73, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x74, 0x79, 0x70, 0x65,
0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3b, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x20, 0x22,
0x52, 0x46, 0x43, 0x37, 0x39, 0x35, 0x30, 0x20, 0x73, 0x65, 0x63, 0x74,
0x69, 0x6f, 0x6e, 0x20, 0x37, 0x2e, 0x38, 0x2e, 0x36, 0x2e, 0x22, 0x3b,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70,
0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
0x54, 0x68, 0x65, 0x20, 0x6b, 0x65, 0x79, 0x20, 0x70, 0x72, 0x65, 0x64,
0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68,
0x65, 0x20, 0x66, 0x75, 0x6c, 0x6c, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61,
0x6e, 0x63, 0x65, 0x2d, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69,
0x65, 0x72, 0x20, 0x62, 0x75, 0x69, 0x6c, 0x74, 0x2d, 0x69, 0x6e, 0x20,
0x74, 0x79, 0x70, 0x65, 0x2e, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x0a,
0x0a, 0x20, 0x20, 0x6d, 0x64, 0x3a, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61,
0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x20,
0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x74, 0x79, 0x70, 0x65, 0x20, 0x65,
0x6e, 0x75, 0x6d, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x7b,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x75, 0x6d, 0x20,
0x66, 0x69, 0x72, 0x73, 0x74, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x65, 0x6e, 0x75, 0x6d, 0x20, 0x6c, 0x61, 0x73, 0x74, 0x3b, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x75, 0x6d, 0x20, 0x62,
0x65, 0x66, 0x6f, 0x72, 0x65, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x65, 0x6e, 0x75, 0x6d, 0x20, 0x61, 0x66, 0x74, 0x65, 0x72, 0x3b,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72,
0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x20, 0x22, 0x52, 0x46,
0x43, 0x37, 0x39, 0x35, 0x30, 0x20, 0x73, 0x65, 0x63, 0x74, 0x69, 0x6f,
0x6e, 0x20, 0x37, 0x2e, 0x38, 0x2e, 0x36, 0x2e, 0x20, 0x61, 0x6e, 0x64,
0x20, 0x73, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x37, 0x2e, 0x37,
0x2e, 0x39, 0x2e, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65,
0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x22, 0x49, 0x6e, 0x20, 0x75, 0x73, 0x65, 0x72,
0x20, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x65, 0x64, 0x20, 0x6c, 0x65, 0x61,
0x66, 0x2d, 0x6c, 0x69, 0x73, 0x74, 0x2c, 0x20, 0x74, 0x68, 0x69, 0x73,
0x20, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x20, 0x63,
0x61, 0x6e, 0x20, 0x62, 0x65, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x74,
0x6f, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x77, 0x68, 0x65, 0x72, 0x65, 0x20, 0x69,
0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6c, 0x65, 0x61, 0x66, 0x2d, 0x6c,
0x69, 0x73, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x6e, 0x74, 0x72,
0x79, 0x20, 0x69, 0x73, 0x20, 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x65,
0x64, 0x2e, 0x20, 0x49, 0x74, 0x20, 0x63, 0x61, 0x6e, 0x20, 0x62, 0x65,
0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x64, 0x75, 0x72, 0x69, 0x6e, 0x67,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x65, 0x20,
0x4e, 0x45, 0x54, 0x43, 0x4f, 0x4e, 0x46, 0x20, 0x3c, 0x65, 0x64, 0x69,
0x74, 0x2d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x3e, 0x20, 0x5c, 0x22,
0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5c, 0x22, 0x20, 0x6f, 0x70, 0x65,
0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x69,
0x6e, 0x73, 0x65, 0x72, 0x74, 0x20, 0x61, 0x20, 0x6e, 0x65, 0x77, 0x20,
0x6c, 0x69, 0x73, 0x74, 0x20, 0x6f, 0x72, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x6c, 0x65, 0x61, 0x66, 0x2d, 0x6c, 0x69, 0x73, 0x74,
0x20, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2c, 0x20, 0x6f, 0x72, 0x20, 0x64,
0x75, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x5c, 0x22, 0x6d, 0x65, 0x72, 0x67,
0x65, 0x5c, 0x22, 0x20, 0x6f, 0x72, 0x20, 0x5c, 0x22, 0x72, 0x65, 0x70,
0x6c, 0x61, 0x63, 0x65, 0x5c, 0x22, 0x20, 0x6f, 0x70, 0x65, 0x72, 0x61,
0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x69, 0x6e, 0x73,
0x65, 0x72, 0x74, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x61,
0x20, 0x6e, 0x65, 0x77, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x6f, 0x72,
0x20, 0x6c, 0x65, 0x61, 0x66, 0x2d, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x65,
0x6e, 0x74, 0x72, 0x79, 0x20, 0x6f, 0x72, 0x20, 0x6d, 0x6f, 0x76, 0x65,
0x20, 0x61, 0x6e, 0x20, 0x65, 0x78, 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67,
0x20, 0x6f, 0x6e, 0x65, 0x2e, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x49, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x76, 0x61, 0x6c,
0x75, 0x65, 0x20, 0x69, 0x73, 0x20, 0x5c, 0x22, 0x62, 0x65, 0x66, 0x6f,
0x72, 0x65, 0x5c, 0x22, 0x20, 0x6f, 0x72, 0x20, 0x5c, 0x22, 0x61, 0x66,
0x74, 0x65, 0x72, 0x5c, 0x22, 0x2c, 0x20, 0x74, 0x68, 0x65, 0x20, 0x5c,
0x22, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5c, 0x22, 0x2f, 0x5c, 0x22, 0x6b,
0x65, 0x79, 0x5c, 0x22, 0x20, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75,
0x74, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x4d, 0x55,
0x53, 0x54, 0x20, 0x61, 0x6c, 0x73, 0x6f, 0x20, 0x62, 0x65, 0x20, 0x75,
0x73, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69,
0x66, 0x79, 0x20, 0x61, 0x6e, 0x20, 0x65, 0x78, 0x69, 0x73, 0x74, 0x69,
0x6e, 0x67, 0x20, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x20, 0x69, 0x6e, 0x20,
0x74, 0x68, 0x65, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x6f, 0x72, 0x20,
0x6c, 0x65, 0x61, 0x66, 0x2d, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x0a, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x49, 0x66, 0x20, 0x6e, 0x6f,
0x20, 0x5c, 0x22, 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x5c, 0x22, 0x20,
0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x20, 0x69, 0x73,
0x20, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x20, 0x69, 0x6e, 0x20,
0x74, 0x68, 0x65, 0x20, 0x5c, 0x22, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65,
0x5c, 0x22, 0x20, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e,
0x2c, 0x20, 0x69, 0x74, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x20, 0x74, 0x6f, 0x20,
0x5c, 0x22, 0x6c, 0x61, 0x73, 0x74, 0x5c, 0x22, 0x2e, 0x22, 0x3b, 0x0a,
0x20, 0x20, 0x7d, 0x0a, 0x0a, 0x20, 0x20, 0x6d, 0x64, 0x3a, 0x61, 0x6e,
0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x76, 0x61, 0x6c,
0x75, 0x65, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x74, 0x79, 0x70,
0x65, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x3b, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x20,
0x22, 0x52, 0x46, 0x43, 0x37, 0x39, 0x35, 0x30, 0x20, 0x73, 0x65, 0x63,
0x74, 0x69, 0x6f, 0x6e, 0x20, 0x37, 0x2e, 0x37, 0x2e, 0x39, 0x2e, 0x22,
0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69,
0x70, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x22, 0x49, 0x6e, 0x20, 0x75, 0x73, 0x65, 0x72, 0x20, 0x6f, 0x72, 0x64,
0x65, 0x72, 0x65, 0x64, 0x20, 0x6c, 0x65, 0x61, 0x66, 0x2d, 0x6c, 0x69,
0x73, 0x74, 0x2c, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x61, 0x74, 0x74,
0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20,
0x62, 0x65, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x69, 0x66, 0x20, 0x74,
0x68, 0x65, 0x20, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6e, 0x73, 0x65,
0x72, 0x74, 0x20, 0x69, 0x73, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x61,
0x6e, 0x64, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x73,
0x20, 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x66, 0x74, 0x65,
0x72, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x65, 0x78, 0x69, 0x73,
0x74, 0x69, 0x6e, 0x67, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63,
0x65, 0x20, 0x74, 0x68, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x6e, 0x65, 0x77, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63,
0x65, 0x20, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 0x20,
0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x65, 0x64, 0x2e, 0x22, 0x3b, 0x0a,
0x20, 0x20, 0x7d, 0x0a, 0x0a, 0x20, 0x20, 0x6d, 0x64, 0x3a, 0x61, 0x6e,
0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6b, 0x65, 0x79,
0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x74, 0x79, 0x70, 0x65, 0x20,
0x75, 0x6e, 0x69, 0x6f, 0x6e, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x74, 0x79, 0x70, 0x65, 0x20, 0x65, 0x6d, 0x70, 0x74, 0x79,
0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x79, 0x70, 0x65,
0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x2d, 0x69, 0x64,
0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x2d, 0x6b, 0x65, 0x79,
0x73, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x20, 0x22,
0x52, 0x46, 0x43, 0x37, 0x39, 0x35, 0x30, 0x20, 0x73, 0x65, 0x63, 0x74,
0x69, 0x6f, 0x6e, 0x20, 0x37, 0x2e, 0x38, 0x2e, 0x36, 0x2e, 0x22, 0x3b,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70,
0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
0x49, 0x6e, 0x20, 0x75, 0x73, 0x65, 0x72, 0x20, 0x6f, 0x72, 0x64, 0x65,
0x72, 0x65, 0x64, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x2c, 0x20, 0x74, 0x68,
0x69, 0x73, 0x20, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65,
0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x75, 0x73, 0x65,
0x64, 0x20, 0x69, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x74, 0x74,
0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x20, 0x69, 0x73, 0x20,
0x75, 0x73, 0x65, 0x64, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x73, 0x70, 0x65,
0x63, 0x69, 0x66, 0x69, 0x65, 0x73, 0x20, 0x62, 0x65, 0x66, 0x6f, 0x72,
0x65, 0x2f, 0x61, 0x66, 0x74, 0x65, 0x72, 0x20, 0x77, 0x68, 0x69, 0x63,
0x68, 0x20, 0x65, 0x78, 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x69,
0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x74, 0x68, 0x65, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6e, 0x65, 0x77, 0x20, 0x69,
0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x73, 0x68, 0x6f, 0x75,
0x6c, 0x64, 0x20, 0x62, 0x65, 0x20, 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74,
0x65, 0x64, 0x2e, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x0a, 0x0a, 0x20,
0x20, 0x6d, 0x64, 0x3a, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69,
0x6f, 0x6e, 0x20, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x20,
0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x74, 0x79, 0x70, 0x65, 0x20, 0x75,
0x6e, 0x69, 0x6f, 0x6e, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x74, 0x79, 0x70, 0x65, 0x20, 0x65, 0x6d, 0x70, 0x74,
0x79, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74,
0x79, 0x70, 0x65, 0x20, 0x75, 0x69, 0x6e, 0x74, 0x33, 0x32, 0x20, 0x7b,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x20, 0x31, 0x2e, 0x2e, 0x6d, 0x61,
0x78, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64,
0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x49, 0x6e, 0x20, 0x6b, 0x65, 0x79,
0x2d, 0x6c, 0x65, 0x73, 0x73, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x6f,
0x72, 0x20, 0x73, 0x74, 0x61, 0x74, 0x65, 0x20, 0x6c, 0x65, 0x61, 0x66,
0x2d, 0x6c, 0x69, 0x73, 0x74, 0x2c, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20,
0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x20, 0x6d, 0x75,
0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x69,
0x66, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x65,
0x20, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x20, 0x69,
0x6e, 0x73, 0x65, 0x72, 0x74, 0x20, 0x69, 0x73, 0x20, 0x75, 0x73, 0x65,
0x64, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66,
0x69, 0x65, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x69, 0x6e, 0x73, 0x74,
0x61, 0x6e, 0x63, 0x65, 0x20, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f,
0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x65, 0x66,
0x6f, 0x72, 0x65, 0x2f, 0x61, 0x66, 0x74, 0x65, 0x72, 0x20, 0x77, 0x68,
0x69, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6e, 0x65, 0x77, 0x20,
0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x73, 0x68, 0x6f,
0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 0x20, 0x69, 0x6e, 0x73, 0x65, 0x72,
0x74, 0x65, 0x64, 0x2e, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x0a, 0x0a,
0x20, 0x20, 0x6d, 0x64, 0x3a, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74,
0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x74, 0x79, 0x70, 0x65,
0x20, 0x65, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e,
0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x75,
0x6d, 0x20, 0x6e, 0x6f, 0x6e, 0x65, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70,
0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x22, 0x54, 0x68, 0x65, 0x20, 0x6e, 0x6f, 0x64, 0x65,
0x20, 0x65, 0x78, 0x69, 0x73, 0x74, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20,
0x62, 0x6f, 0x74, 0x68, 0x20, 0x64, 0x61, 0x74, 0x61, 0x20, 0x74, 0x72,
0x65, 0x65, 0x73, 0x20, 0x62, 0x75, 0x74, 0x20, 0x74, 0x68, 0x65, 0x72,
0x65, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x6e, 0x65, 0x73, 0x74, 0x65,
0x64, 0x20, 0x6e, 0x6f, 0x64, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x61,
0x6e, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x20, 0x6f, 0x70, 0x65, 0x72, 0x61,
0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x20, 0x49, 0x6e, 0x20, 0x63, 0x61, 0x73,
0x65, 0x20, 0x6f, 0x66, 0x20, 0x61, 0x20, 0x6c, 0x65, 0x61, 0x66, 0x2c,
0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x20, 0x69, 0x74, 0x73, 0x20, 0x64, 0x65,
0x66, 0x61, 0x75, 0x6c, 0x74, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x61, 0x67, 0x20, 0x63, 0x68,
0x61, 0x6e, 0x67, 0x65, 0x64, 0x2e, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65,
0x6e, 0x75, 0x6d, 0x20, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x20, 0x7b,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x73,
0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x54, 0x68, 0x65, 0x20,
0x6e, 0x6f, 0x64, 0x65, 0x20, 0x64, 0x69, 0x64, 0x20, 0x6e, 0x6f, 0x74,
0x20, 0x65, 0x78, 0x69, 0x73, 0x74, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68,
0x65, 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x74, 0x72, 0x65, 0x65,
0x20, 0x61, 0x6e, 0x64, 0x20, 0x77, 0x61, 0x73, 0x20, 0x63, 0x72, 0x65,
0x61, 0x74, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73,
0x65, 0x63, 0x6f, 0x6e, 0x64, 0x20, 0x74, 0x72, 0x65, 0x65, 0x2e, 0x22,
0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x75, 0x6d, 0x20, 0x64, 0x65, 0x6c,
0x65, 0x74, 0x65, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f,
0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x22, 0x54, 0x68, 0x65, 0x20, 0x6e, 0x6f, 0x64, 0x65, 0x20, 0x65, 0x78,
0x69, 0x73, 0x74, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65,
0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x74, 0x72, 0x65, 0x65, 0x20,
0x61, 0x6e, 0x64, 0x20, 0x77, 0x61, 0x73, 0x20, 0x64, 0x65, 0x6c, 0x65,
0x74, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
0x65, 0x63, 0x6f, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x72, 0x65, 0x65, 0x2e, 0x22, 0x3b,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x65, 0x6e, 0x75, 0x6d, 0x20, 0x72, 0x65, 0x70, 0x6c,
0x61, 0x63, 0x65, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f,
0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x22, 0x54, 0x68, 0x65, 0x20, 0x6e, 0x6f, 0x64, 0x65, 0x20, 0x76, 0x61,
0x6c, 0x75, 0x65, 0x20, 0x77, 0x61, 0x73, 0x20, 0x63, 0x68, 0x61, 0x6e,
0x67, 0x65, 0x64, 0x20, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6e,
0x6f, 0x64, 0x65, 0x20, 0x77, 0x61, 0x73, 0x20, 0x6d, 0x6f, 0x76, 0x65,
0x64, 0x20, 0x66, 0x6f, 0x72, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x65, 0x61, 0x76, 0x65, 0x73, 0x2f,
0x61, 0x6e, 0x79, 0x78, 0x6d, 0x6c, 0x2f, 0x61, 0x6e, 0x79, 0x64, 0x61,
0x74, 0x61, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x75, 0x73, 0x65, 0x72, 0x2d,
0x6f, 0x72, 0x64, 0x65, 0x72, 0x65, 0x64, 0x20, 0x6c, 0x69, 0x73, 0x74,
0x73, 0x2f, 0x6c, 0x65, 0x61, 0x66, 0x2d, 0x6c, 0x69, 0x73, 0x74, 0x73,
0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x72, 0x65, 0x73, 0x70, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x6c,
0x79, 0x2e, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72,
0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x20, 0x22, 0x52, 0x46,
0x43, 0x36, 0x32, 0x34, 0x31, 0x20, 0x73, 0x65, 0x63, 0x74, 0x69, 0x6f,
0x6e, 0x20, 0x37, 0x2e, 0x32, 0x2e, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x4f, 0x70, 0x65, 0x72,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x61, 0x20, 0x6e,
0x6f, 0x64, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x61, 0x20, 0x64, 0x69, 0x66,
0x66, 0x2e, 0x20, 0x49, 0x66, 0x20, 0x61, 0x20, 0x6e, 0x6f, 0x64, 0x65,
0x20, 0x68, 0x61, 0x73, 0x20, 0x6e, 0x6f, 0x20, 0x6f, 0x70, 0x65, 0x72,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x69, 0x6e, 0x68, 0x65,
0x72, 0x69, 0x74, 0x65, 0x64, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x69,
0x74, 0x73, 0x20, 0x6e, 0x65, 0x61, 0x72, 0x65, 0x73, 0x74, 0x20, 0x70,
0x61, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x61,
0x6e, 0x20, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x54, 0x6f, 0x70, 0x2d,
0x6c, 0x65, 0x76, 0x65, 0x6c, 0x20, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x20,
0x6d, 0x75, 0x73, 0x74, 0x20, 0x61, 0x6c, 0x77, 0x61, 0x79, 0x73, 0x20,
0x68, 0x61, 0x76, 0x65, 0x20, 0x61, 0x6e, 0x20, 0x6f, 0x70, 0x65, 0x72,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x55, 0x73, 0x65, 0x72, 0x2d, 0x6f, 0x72, 0x64, 0x65,
0x72, 0x65, 0x64, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x73, 0x2f, 0x6c, 0x65,
0x61, 0x66, 0x2d, 0x6c, 0x69, 0x73, 0x74, 0x73, 0x20, 0x77, 0x69, 0x74,
0x68, 0x20, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20,
0x27, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x27, 0x20, 0x61, 0x6e, 0x64,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x27, 0x72, 0x65, 0x70,
0x6c, 0x61, 0x63, 0x65, 0x27, 0x20, 0x4d, 0x55, 0x53, 0x54, 0x20, 0x61,
0x6c, 0x73, 0x6f, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x74, 0x68, 0x65,
0x20, 0x27, 0x6b, 0x65, 0x79, 0x27, 0x2c, 0x20, 0x27, 0x76, 0x61, 0x6c,
0x75, 0x65, 0x27, 0x2c, 0x20, 0x6f, 0x72, 0x20, 0x27, 0x70, 0x6f, 0x73,
0x69, 0x74, 0x69, 0x6f, 0x6e, 0x27, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x20, 0x64,
0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x2e, 0x20, 0x49, 0x74, 0x20, 0x73,
0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x73, 0x20, 0x74, 0x68, 0x65,
0x20, 0x70, 0x72, 0x65, 0x63, 0x65, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x69,
0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x49, 0x6e, 0x20, 0x63, 0x61, 0x73, 0x65, 0x20,
0x74, 0x68, 0x65, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x6f, 0x66,
0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61,
0x74, 0x61, 0x20, 0x69, 0x73, 0x20, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2c,
0x20, 0x74, 0x68, 0x65, 0x20, 0x6e, 0x6f, 0x64, 0x65, 0x20, 0x77, 0x61,
0x73, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x72, 0x65,
0x61, 0x74, 0x65, 0x64, 0x2f, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x20, 0x6f,
0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20,
0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x0a, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x41, 0x6c, 0x6c, 0x20, 0x74, 0x68,
0x65, 0x20, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73,
0x20, 0x6b, 0x65, 0x65, 0x70, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x65,
0x61, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x65, 0x64, 0x69,
0x74, 0x2d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x20, 0x6f, 0x70, 0x65,
0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x73, 0x69, 0x6d, 0x69,
0x6c, 0x61, 0x72, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x20, 0x62, 0x75,
0x74, 0x20, 0x73, 0x6f, 0x6d, 0x65, 0x20, 0x61, 0x72, 0x65, 0x20, 0x66,
0x75, 0x72, 0x74, 0x68, 0x65, 0x72, 0x20, 0x72, 0x65, 0x73, 0x74, 0x72,
0x69, 0x63, 0x74, 0x65, 0x64, 0x2c, 0x20, 0x6d, 0x65, 0x61, 0x6e, 0x69,
0x6e, 0x67, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x68,
0x65, 0x79, 0x20, 0x61, 0x72, 0x65, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20,
0x66, 0x6f, 0x72, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x20, 0x61, 0x20, 0x73,
0x75, 0x62, 0x73, 0x65, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x75, 0x73, 0x65,
0x2d, 0x63, 0x61, 0x73, 0x65, 0x73, 0x2e, 0x22, 0x3b, 0x0a, 0x20, 0x20,
0x7d, 0x0a, 0x0a, 0x20, 0x20, 0x6d, 0x64, 0x3a, 0x61, 0x6e, 0x6e, 0x6f,
0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x72, 0x69, 0x67, 0x2d,
0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x20, 0x7b, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x74, 0x79, 0x70, 0x65, 0x20, 0x62, 0x6f, 0x6f, 0x6c, 0x65,
0x61, 0x6e, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x73, 0x63,
0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x22, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69,
0x6f, 0x6e, 0x20, 0x61, 0x62, 0x6f, 0x75, 0x74, 0x20, 0x74, 0x68, 0x65,
0x20, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x20, 0x64, 0x65,
0x66, 0x61, 0x75, 0x6c, 0x74, 0x20, 0x73, 0x74, 0x61, 0x74, 0x65, 0x20,
0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6e, 0x6f, 0x64, 0x65, 0x2e,
0x22, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x0a, 0x0a, 0x20, 0x20, 0x6d, 0x64,
0x3a, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20,
0x6f, 0x72, 0x69, 0x67, 0x2d, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x7b,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x74, 0x79, 0x70, 0x65, 0x20, 0x73, 0x74,
0x72, 0x69, 0x6e, 0x67, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65,
0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x22, 0x50, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75,
0x73, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x61,
0x20, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x20, 0x6c, 0x65, 0x61,
0x66, 0x2e, 0x20, 0x41, 0x6c, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x69,
0x76, 0x65, 0x6c, 0x79, 0x2c, 0x20, 0x69, 0x74, 0x73, 0x20, 0x6d, 0x65,
0x61, 0x6e, 0x69, 0x6e, 0x67, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x61, 0x6d, 0x65,
0x20, 0x61, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x5c, 0x22, 0x76, 0x61,
0x6c, 0x75, 0x65, 0x5c, 0x22, 0x20, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62,
0x75, 0x74, 0x65, 0x20, 0x62, 0x75, 0x74, 0x20, 0x69, 0x64, 0x65, 0x6e,
0x74, 0x69, 0x66, 0x69, 0x65, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6f,
0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x6c, 0x65, 0x61, 0x66, 0x2d, 0x6c, 0x69, 0x73, 0x74,
0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x72, 0x61,
0x74, 0x68, 0x65, 0x72, 0x20, 0x74, 0x68, 0x61, 0x6e, 0x20, 0x74, 0x68,
0x65, 0x20, 0x6e, 0x65, 0x77, 0x20, 0x6f, 0x6e, 0x65, 0x2e, 0x22, 0x3b,
0x0a, 0x20, 0x20, 0x7d, 0x0a, 0x0a, 0x20, 0x20, 0x6d, 0x64, 0x3a, 0x61,
0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x72,
0x69, 0x67, 0x2d, 0x6b, 0x65, 0x79, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x74, 0x79, 0x70, 0x65, 0x20, 0x75, 0x6e, 0x69, 0x6f, 0x6e, 0x20,
0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x79, 0x70, 0x65,
0x20, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x74, 0x79, 0x70, 0x65, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61,
0x6e, 0x63, 0x65, 0x2d, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69,
0x65, 0x72, 0x2d, 0x6b, 0x65, 0x79, 0x73, 0x3b, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x73, 0x63, 0x72,
0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x22, 0x49, 0x74, 0x73, 0x20, 0x6d, 0x65, 0x61, 0x6e, 0x69, 0x6e,
0x67, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x61, 0x6d,
0x65, 0x20, 0x61, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x5c, 0x22, 0x6b,
0x65, 0x79, 0x5c, 0x22, 0x20, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75,
0x74, 0x65, 0x20, 0x62, 0x75, 0x74, 0x20, 0x69, 0x64, 0x65, 0x6e, 0x74,
0x69, 0x66, 0x69, 0x65, 0x73, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x74, 0x68, 0x65, 0x20, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61,
0x6c, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61,
0x6e, 0x63, 0x65, 0x20, 0x72, 0x61, 0x74, 0x68, 0x65, 0x72, 0x20, 0x74,
0x68, 0x61, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6e, 0x65, 0x77, 0x20,
0x6f, 0x6e, 0x65, 0x2e, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 0x0a, 0x0a,
0x20, 0x20, 0x6d, 0x64, 0x3a, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74,
0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x72, 0x69, 0x67, 0x2d, 0x70, 0x6f, 0x73,
0x69, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20,
0x74, 0x79, 0x70, 0x65, 0x20, 0x75, 0x6e, 0x69, 0x6f, 0x6e, 0x20, 0x7b,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x79, 0x70,
0x65, 0x20, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x3b, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x79, 0x70, 0x65, 0x20, 0x75, 0x69,
0x6e, 0x74, 0x33, 0x32, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x61, 0x6e, 0x67, 0x65,
0x20, 0x31, 0x2e, 0x2e, 0x6d, 0x61, 0x78, 0x3b, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70,
0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
0x49, 0x74, 0x73, 0x20, 0x6d, 0x65, 0x61, 0x6e, 0x69, 0x6e, 0x67, 0x20,
0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x61, 0x6d, 0x65, 0x20,
0x61, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x5c, 0x22, 0x70, 0x6f, 0x73,
0x69, 0x74, 0x69, 0x6f, 0x6e, 0x5c, 0x22, 0x20, 0x61, 0x74, 0x74, 0x72,
0x69, 0x62, 0x75, 0x74, 0x65, 0x20, 0x62, 0x75, 0x74, 0x20, 0x69, 0x64,
0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x73, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6f, 0x72, 0x69, 0x67,
0x69, 0x6e, 0x61, 0x6c, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x69, 0x6e,
0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x72, 0x61, 0x74, 0x68, 0x65,
0x72, 0x20, 0x74, 0x68, 0x61, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6e,
0x65, 0x77, 0x20, 0x6f, 0x6e, 0x65, 0x2e, 0x22, 0x3b, 0x0a, 0x20, 0x20,
0x7d, 0x0a, 0x7d, 0x0a, 0x00
};

195
models/yang@2022-06-16.yang Normal file
View file

@ -0,0 +1,195 @@
module yang {
namespace "urn:ietf:params:xml:ns:yang:1";
prefix yang;
yang-version 1.1;
import ietf-yang-metadata {
prefix md;
revision-date 2016-08-05;
}
organization
"libyang";
contact
"Web: <https://github.com/CESNET/libyang/>
Author: Radek Krejci <rkrejci@cesnet.cz>
Author: Michal Vasko <mvasko@cesnet.cz>";
description
"This is a dummy module with no data formally supplying the definitions
of various metadata defined in RFC 6020 and RFC 7950. There are
additional metadata used in libyang diff data format.";
revision 2022-06-16 {
description
"Added typedef for key metadata type.";
}
revision 2021-04-07 {
description
"Added metadata for key-less list and state leaf-list diff.";
}
revision 2020-06-17 {
description
"Added metadata for diff.";
}
revision 2017-02-20 {
description
"Added metadata for NETCONF's edit-config manipulation with ordered
lists and leaf-lists.";
reference
"RFC 7950: The YANG 1.1 Data Modeling Language";
}
revision 2016-02-11 {
description
"Initial revision";
reference
"RFC 6020: YANG - A Data Modeling Language for
the Network Configuration Protocol (NETCONF)";
}
typedef instance-identifier-keys {
type string;
reference "RFC7950 section 7.8.6.";
description
"The key predicates of the full instance-identifier built-in type.";
}
md:annotation insert {
type enumeration {
enum first;
enum last;
enum before;
enum after;
}
reference "RFC7950 section 7.8.6. and section 7.7.9.";
description
"In user ordered leaf-list, this attribute can be used to control
where in the leaf-list the entry is inserted. It can be used during
the NETCONF <edit-config> \"create\" operations to insert a new list or
leaf-list entry, or during \"merge\" or \"replace\" operations to insert
a new list or leaf-list entry or move an existing one.
If the value is \"before\" or \"after\", the \"value\"/\"key\" attribute
MUST also be used to specify an existing entry in the list or leaf-list.
If no \"insert\" attribute is present in the \"create\" operation, it
defaults to \"last\".";
}
md:annotation value {
type string;
reference "RFC7950 section 7.7.9.";
description
"In user ordered leaf-list, this attribute must be used if the attribute
insert is used and specifies before/after which existing instance the
new instance should be inserted.";
}
md:annotation key {
type union {
type empty;
type instance-identifier-keys;
}
reference "RFC7950 section 7.8.6.";
description
"In user ordered list, this attribute must be used if the attribute
insert is used and specifies before/after which existing instance the
new instance should be inserted.";
}
md:annotation position {
type union {
type empty;
type uint32 {
range 1..max;
}
}
description
"In key-less list or state leaf-list, this attribute must be used if
the attribute insert is used and specifies the instance position
before/after which the new instance should be inserted.";
}
md:annotation operation {
type enumeration {
enum none {
description
"The node existed in both data trees but there is a nested node
with another operation. In case of a leaf, only its default
flag changed.";
}
enum create {
description
"The node did not exist in the first tree and was created in the
second tree.";
}
enum delete {
description
"The node existed in the first tree and was deleted in the second
tree.";
}
enum replace {
description
"The node value was changed or the node was moved for
leaves/anyxml/anydata and user-ordered lists/leaf-lists,
respectively.";
}
}
reference "RFC6241 section 7.2.";
description
"Operation of a node in a diff. If a node has no operation,
it is inherited from its nearest parent with an operation.
Top-level nodes must always have an operation.
User-ordered lists/leaf-lists with operation 'create' and
'replace' MUST also have the 'key', 'value', or 'position'
metadata defined. It specifies the preceding instance.
In case the value of this metadata is empty, the node was
created/moved on the first position.
All the operations keep the meaning of edit-config operations
with similar names but some are further restricted, meaning
they are used for only a subset of use-cases.";
}
md:annotation orig-default {
type boolean;
description
"Information about the previous default state of the node.";
}
md:annotation orig-value {
type string;
description
"Previous value of a changed leaf. Alternatively, its meaning
is the same as the \"value\" attribute but identifies the original
leaf-list instance rather than the new one.";
}
md:annotation orig-key {
type union {
type empty;
type instance-identifier-keys;
}
description
"Its meaning is the same as the \"key\" attribute but identifies
the original list instance rather than the new one.";
}
md:annotation orig-position {
type union {
type empty;
type uint32 {
range 1..max;
}
}
description
"Its meaning is the same as the \"position\" attribute but identifies
the original list instance rather than the new one.";
}
}

1413
src/context.c Normal file

File diff suppressed because it is too large Load diff

673
src/context.h Normal file
View file

@ -0,0 +1,673 @@
/**
* @file context.h
* @author Radek Krejci <rkrejci@cesnet.cz>
* @author Michal Vasko <mvasko@cesnet.cz>
* @brief internal context structures and functions
*
* Copyright (c) 2015 - 2023 CESNET, z.s.p.o.
*
* This source code is licensed under BSD 3-Clause License (the "License").
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*/
#ifndef LY_CONTEXT_H_
#define LY_CONTEXT_H_
#include <stdint.h>
#include "log.h"
#include "parser_schema.h"
#include "tree_data.h"
#ifdef __cplusplus
extern "C" {
#endif
struct lys_module;
/**
* @page howtoContext Context
*
* The context concept allows callers to work in environments with different sets of YANG modules.
*
* The first step with libyang is to create a new context using ::ly_ctx_new(). It returns a handler used in the following work.
* Note that the context is supposed to provide a stable environment for work with the data. Therefore the caller should prepare
* a complete context and after starting working with the data, the context and its content should not change. If it does,
* in most cases it leads to the context being recompiled and any parsed data invalid. Despite the API not enforcing this
* approach, it may change in future versions in the form of a locking mechanism which would allow further
* optimization of data manipulation. Also note that modules cannot be removed from their context. If you need to change the set
* of the schema modules in the context, the recommended way is to create a new context. To remove the context, there is ::ly_ctx_destroy() function.
*
* The context has [several options](@ref contextoptions) changing behavior when processing YANG modules being inserted. The
* specific behavior is mentioned below. All the options can be set as a parameter when the context is being created or later
* with ::ly_ctx_set_options().
*
* When creating a new context, another optional parameter is search_dir It provide directory where libyang
* will automatically search for YANG modules being imported or included. There is actually a set of search paths which can be later
* modified using ::ly_ctx_set_searchdir(), ::ly_ctx_unset_searchdir() and ::ly_ctx_unset_searchdir_last() functions. Before the values
* in the set are used, also the current working directory is (non-recursively) searched. For the case of the explicitly set
* search directories, they are searched recursively - all their subdirectories (and symlinks) are taken into account. Searching
* in the current working directory can be avoided with the context's ::LY_CTX_DISABLE_SEARCHDIR_CWD option.
* Searching in all the context's search dirs (without removing them) can be avoided with the context's
* ::LY_CTX_DISABLE_SEARCHDIRS option (or via ::ly_ctx_set_options()). This automatic searching can be preceded
* by a custom module searching callback (::ly_module_imp_clb) set via ::ly_ctx_set_module_imp_clb(). The algorithm of
* searching in search dirs is also available via API as ::lys_search_localfile() function.
*
* YANG modules are added into the context using [parser functions](@ref howtoSchemaParsers) - \b lys_parse*().
* Alternatively, also ::ly_ctx_load_module() can be used - in that case the ::ly_module_imp_clb or automatic
* search in search directories and in the current working directory is used, as described above. YANG submodules cannot be loaded
* or even validated directly, they are loaded always only as includes of YANG modules. Explicitly parsed/loaded modules are
* handled as implemented - libyang is able to instantiate data representing such a module. The modules loaded implicitly, are
* not implemented and serve only as a source of grouping or typedef definitions. Context can hold multiple revisions of the same
* YANG module, but only one of them can be implemented. Details about the difference between implemented and imported modules
* can be found on @ref howtoSchema page. This behavior can be changed with the context's ::LY_CTX_ALL_IMPLEMENTED option, which
* causes that all the parsed modules, whether loaded explicitly or implicitly, are set to be implemented. Note, that as
* a consequence of this option, only a single revision of any module can be present in the context in this case. Also, a less
* crude option ::LY_CTX_REF_IMPLEMENTED can be used to implement only referenced modules that should also be implemented.
*
* When loading/importing a module without revision, the latest revision of the required module is supposed to load.
* For a context, the first time the latest revision of a module is requested, it is properly searched for and loaded.
* However, when this module is requested (without revision) the second time, the one found previously is returned.
* This has the advantage of not searching for the module repeatedly but there is a drawback in case the content of search
* directories is updated and a later revision become available.
*
* Context holds all the schema modules internally. To get a specific module, use ::ly_ctx_get_module() (or some of its
* variants). If you need to do something with all the modules in the context, it is advised to iterate over them using
* ::ly_ctx_get_module_iter(). Alternatively, the ::ly_ctx_get_yanglib_data() function can be used to get complex information about the schemas in the context
* in the form of data tree defined by <a href="https://tools.ietf.org/html/rfc7895">ietf-yang-library</a> module.
*
* YANG data can be parsed by \b lyd_parse_*() functions. Note, that functions for schema have \b lys_
* prefix (or \b lysp_ for the parsed and \b lysc_ for the compiled schema - for details see @ref howtoSchema page) while
* functions for instance data have \b lyd_ prefix. Details about data formats or handling data without the appropriate
* YANG module in context can be found on @ref howtoData page.
*
* Besides the YANG modules, context holds also [error information](@ref howtoErrors) and
* [database of strings](@ref howtoContextDict), both connected with the processed YANG modules and data.
*
* - @subpage howtoErrors
* - @subpage howtoContextDict
*
* \note API for this group of functions is available in the [context module](@ref context).
*
* Functions List
* --------------
*
* - ::ly_ctx_new()
* - ::ly_ctx_destroy()
*
* - ::ly_ctx_set_searchdir()
* - ::ly_ctx_get_searchdirs()
* - ::ly_ctx_unset_searchdir()
* - ::ly_ctx_unset_searchdir_last()
*
* - ::ly_ctx_set_options()
* - ::ly_ctx_get_options()
* - ::ly_ctx_unset_options()
*
* - ::ly_ctx_set_module_imp_clb()
* - ::ly_ctx_get_module_imp_clb()
*
* - ::ly_ctx_load_module()
* - ::ly_ctx_get_module_iter()
* - ::ly_ctx_get_module()
* - ::ly_ctx_get_module_ns()
* - ::ly_ctx_get_module_implemented()
* - ::ly_ctx_get_module_implemented_ns()
* - ::ly_ctx_get_module_latest()
* - ::ly_ctx_get_module_latest_ns()
* - ::ly_ctx_get_submodule()
* - ::ly_ctx_get_submodule_latest()
* - ::ly_ctx_get_submodule2()
* - ::ly_ctx_get_submodule2_latest()
*
* - ::ly_ctx_get_yanglib_data()
*
* - ::ly_ctx_get_change_count()
* - ::ly_ctx_internal_modules_count()
*
* - ::lys_search_localfile()
* - ::lys_set_implemented()
*
*/
/**
* @defgroup context Context
* @{
*
* Structures and functions to manipulate with the libyang context containers.
*
* The \em context concept allows callers to work in environments with different sets of YANG schemas.
* More detailed information can be found at @ref howtoContext page.
*/
/**
* @struct ly_ctx
* @brief libyang context handler.
*/
struct ly_ctx;
/**
* @ingroup context
* @defgroup contextoptions Context options
*
* Options to change context behavior.
*
* @{
*/
#define LY_CTX_ALL_IMPLEMENTED 0x01 /**< All the imported modules of the schema being parsed are implemented. */
#define LY_CTX_REF_IMPLEMENTED 0x02 /**< Implement all imported modules "referenced" from an implemented module.
Normally, leafrefs, augment and deviation targets are implemented as
specified by YANG 1.1. In addition to this, implement any modules of
nodes referenced by when and must conditions and by any default values.
Generally, only if all these modules are implemented, the explicitly
implemented modules can be properly used and instantiated in data. */
#define LY_CTX_NO_YANGLIBRARY 0x04 /**< Do not internally implement ietf-yang-library module. The option
causes that function ::ly_ctx_get_yanglib_data() does not work (returns ::LY_EINVAL) until
the ietf-yang-library module is loaded manually. While any revision
of this schema can be loaded with this option, note that the only
revisions implemented by ::ly_ctx_get_yanglib_data() are 2016-06-21 and 2019-01-04.
This option cannot be changed on existing context. */
#define LY_CTX_DISABLE_SEARCHDIRS 0x08 /**< Do not search for schemas in context's searchdirs neither in current
working directory. It is entirely skipped and the only way to get
schema data for imports or for ::ly_ctx_load_module() is to use the
callbacks provided by caller via ::ly_ctx_set_module_imp_clb() */
#define LY_CTX_DISABLE_SEARCHDIR_CWD 0x10 /**< Do not automatically search for schemas in current working
directory, which is by default searched automatically (despite not
recursively). */
#define LY_CTX_PREFER_SEARCHDIRS 0x20 /**< When searching for schema, prefer searchdirs instead of user callback. */
#define LY_CTX_SET_PRIV_PARSED 0x40 /**< For all compiled nodes, their private objects (::lysc_node.priv) are used
by libyang as a reference to the corresponding parsed node (::lysp_node).
The exception are \"case\" statements, which are omitted (shorthand),
in that case the private objects are set to NULL.
So if this option is set, the user must not change private objects.
Setting this option by ::ly_ctx_set_options() may result in context recompilation.
Resetting this option by ::ly_ctx_unset_options() cause that private
objects will be set to NULL. */
#define LY_CTX_EXPLICIT_COMPILE 0x80 /**< If this flag is set, the compiled modules and their schema nodes are
not automatically updated (compiled) on any context changes. In other words, they do
not immediately take effect. To do that, call ::ly_ctx_compile(). Changes
requiring compilation include adding new modules, changing their features,
and implementing parsed-only modules. This option allows efficient compiled
context creation without redundant recompilations. */
#define LY_CTX_ENABLE_IMP_FEATURES 0x0100 /**< By default, all features of newly implemented imported modules of
a module that is being loaded are disabled. With this flag they all become
enabled. */
#define LY_CTX_LEAFREF_EXTENDED 0x0200 /**< By default, path attribute of leafref accepts only path as defined in RFC 7950.
By using this option, the path attribute will also allow using XPath functions as deref() */
#define LY_CTX_LEAFREF_LINKING 0x0400 /**< Link valid leafref nodes with its target during validation if leafref node is not using
'require-instance false;'. It also enables usage of
[lyd_leafref_get_links](@ref lyd_leafref_get_links) and
[lyd_leafref_link_node_tree](@ref lyd_leafref_link_node_tree) APIs. */
#define LY_CTX_BUILTIN_PLUGINS_ONLY 0x0800 /**< By default, context uses all available plugins for types and extensions,
both included and external. This options prevents all included plugins to be
loaded except for built-in YANG types so all derived types will use these and
for all purposes behave as the base type. The option can be used for cases when
invalid data needs to be stored in YANG node values. */
/** @} contextoptions */
/**
* @brief Create libyang context.
*
* Context is used to hold all information about schemas. Usually, the application is supposed
* to work with a single context in which libyang is holding all schemas (and other internal
* information) according to which the data trees will be processed and validated. So, the schema
* trees are tightly connected with the specific context and they are held by the context internally
* - caller does not need to keep pointers to the schemas returned by ::lys_parse(), context knows
* about them. The data trees created with \b lyd_parse_*() are still connected with the specific context,
* but they are not internally held by the context. The data tree just points and lean on some data
* held by the context (schema tree, string dictionary, etc.). Therefore, in case of data trees, caller
* is supposed to keep pointers returned by the \b lyd_parse_*() functions and manage the data tree on its own. This
* also affects the number of instances of both tree types. While you can have only one instance of
* specific schema connected with a single context, number of data tree instances is not connected.
*
* @param[in] search_dir Directory (or directories) where libyang will search for the imported or included modules
* and submodules. If no such directory is available, NULL is accepted. Several directories can be specified,
* delimited by colon ":" (on Windows, use semicolon ";" instead).
* @param[in] options Context options, see @ref contextoptions.
* @param[out] new_ctx Pointer to the created libyang context if LY_SUCCESS returned.
* @return LY_ERR return value.
*/
LIBYANG_API_DECL LY_ERR ly_ctx_new(const char *search_dir, uint16_t options, struct ly_ctx **new_ctx);
/**
* @brief Create libyang context according to the provided yang-library data in a file.
*
* This function loads the yang-library data from the given path. If you need to pass the data as
* string, use ::::ly_ctx_new_ylmem(). Both functions extend functionality of ::ly_ctx_new() by loading
* modules specified in the ietf-yang-library form into the context being created.
* The preferred tree model revision is 2019-01-04. However, only the first module-set is processed and loaded
* into the context. If there are no matching nodes from this tree, the legacy tree (originally from model revision 2016-04-09)
* is processed. Note, that the modules are loaded the same way as in case of ::ly_ctx_load_module(), so the schema paths in the
* yang-library data are ignored and the modules are loaded from the context's search locations. On the other hand, YANG features
* of the modules are set as specified in the yang-library data.
* To get yang library data from a libyang context, use ::ly_ctx_get_yanglib_data().
*
* @param[in] search_dir Directory where libyang will search for the imported or included modules and submodules.
* If no such directory is available, NULL is accepted.
* @param[in] path Path to the file containing yang-library-data in the specified format
* @param[in] format Format of the data in the provided file.
* @param[in] options Context options, see @ref contextoptions.
* @param[in,out] ctx If *ctx is not NULL, the existing libyang context is modified. Otherwise, a pointer to a
* newly created context is returned here if LY_SUCCESS.
* @return LY_ERR return value
*/
LIBYANG_API_DECL LY_ERR ly_ctx_new_ylpath(const char *search_dir, const char *path, LYD_FORMAT format, int options,
struct ly_ctx **ctx);
/**
* @brief Create libyang context according to the provided yang-library data in a string.
*
* Details in ::ly_ctx_new_ylpath().
*
* @param[in] search_dir Directory where libyang will search for the imported or included modules and submodules.
* If no such directory is available, NULL is accepted.
* @param[in] data String containing yang-library data in the specified format.
* @param[in] format Format of the data in the provided file.
* @param[in] options Context options, see @ref contextoptions.
* @param[in,out] ctx If *ctx is not NULL, the existing libyang context is modified. Otherwise, a pointer to a
* newly created context is returned here if LY_SUCCESS.
* @return LY_ERR return value
*/
LIBYANG_API_DECL LY_ERR ly_ctx_new_ylmem(const char *search_dir, const char *data, LYD_FORMAT format, int options,
struct ly_ctx **ctx);
/**
* @brief Create libyang context according to the provided yang-library data in a data tree.
*
* Details in ::ly_ctx_new_ylpath().
*
* @param[in] search_dir Directory where libyang will search for the imported or included modules and submodules.
* If no such directory is available, NULL is accepted.
* @param[in] tree Data tree containing yang-library data.
* @param[in] options Context options, see @ref contextoptions.
* @param[in,out] ctx If *ctx is not NULL, the existing libyang context is modified. Otherwise, a pointer to a
* newly created context is returned here if LY_SUCCESS.
* @return LY_ERR return value
*/
LIBYANG_API_DECL LY_ERR ly_ctx_new_yldata(const char *search_dir, const struct lyd_node *tree, int options,
struct ly_ctx **ctx);
/**
* @brief Compile (recompile) the context applying all the performed changes after the last context compilation.
* Should be used only if ::LY_CTX_EXPLICIT_COMPILE option is set, has no effect otherwise.
*
* @param[in] ctx Context to compile.
* @return LY_ERR return value.
*/
LIBYANG_API_DECL LY_ERR ly_ctx_compile(struct ly_ctx *ctx);
/**
* @brief Add the search path into libyang context
*
* To reset search paths set in the context, use ::ly_ctx_unset_searchdir() and then
* set search paths again.
*
* @param[in] ctx Context to be modified.
* @param[in] search_dir New search path to add to the current paths previously set in ctx.
* @return LY_ERR return value.
*/
LIBYANG_API_DECL LY_ERR ly_ctx_set_searchdir(struct ly_ctx *ctx, const char *search_dir);
/**
* @brief Clean the search path(s) from the libyang context
*
* To remove the recently added search path(s), use ::ly_ctx_unset_searchdir_last().
*
* @param[in] ctx Context to be modified.
* @param[in] value Searchdir to be removed, use NULL to remove them all.
* @return LY_ERR return value
*/
LIBYANG_API_DECL LY_ERR ly_ctx_unset_searchdir(struct ly_ctx *ctx, const char *value);
/**
* @brief Remove the least recently added search path(s) from the libyang context.
*
* To remove a specific search path by its value, use ::ly_ctx_unset_searchdir().
*
* @param[in] ctx Context to be modified.
* @param[in] count Number of the searchdirs to be removed (starting by the least recently added).
* If the value is higher then the actual number of search paths, all paths are removed and no error is returned.
* Value 0 does not change the search path set.
* @return LY_ERR return value
*/
LIBYANG_API_DECL LY_ERR ly_ctx_unset_searchdir_last(struct ly_ctx *ctx, uint32_t count);
/**
* @brief Get the NULL-terminated list of the search paths in libyang context. Do not modify the result!
*
* @param[in] ctx Context to query.
* @return NULL-terminated list (array) of the search paths, NULL if no searchpath was set.
* Do not modify the provided data in any way!
*/
LIBYANG_API_DECL const char * const *ly_ctx_get_searchdirs(const struct ly_ctx *ctx);
/**
* @brief Get the currently set context's options.
*
* @param[in] ctx Context to query.
* @return Combination of all the currently set context's options, see @ref contextoptions.
*/
LIBYANG_API_DECL uint16_t ly_ctx_get_options(const struct ly_ctx *ctx);
/**
* @brief Set some of the context's options, see @ref contextoptions.
* @param[in] ctx Context to be modified.
* @param[in] option Combination of the context's options to be set, see @ref contextoptions.
* If there is to be a change to ::LY_CTX_SET_PRIV_PARSED, the context will be recompiled
* and all ::lysc_node.priv in the modules will be overwritten, see ::LY_CTX_SET_PRIV_PARSED.
* @return LY_ERR value.
*/
LIBYANG_API_DECL LY_ERR ly_ctx_set_options(struct ly_ctx *ctx, uint16_t option);
/**
* @brief Unset some of the context's options, see @ref contextoptions.
* @param[in] ctx Context to be modified.
* @param[in] option Combination of the context's options to be unset, see @ref contextoptions.
* @return LY_ERR value.
*/
LIBYANG_API_DECL LY_ERR ly_ctx_unset_options(struct ly_ctx *ctx, uint16_t option);
/**
* @brief Get the change count of the context (module set) during its life-time.
*
* @param[in] ctx Context to be examined.
* @return Context change count.
*/
LIBYANG_API_DECL uint16_t ly_ctx_get_change_count(const struct ly_ctx *ctx);
/**
* @brief Get the hash of all the modules in the context. Since order of the modules is significant,
* even when 2 contexts have the same modules but loaded in a different order, the hash will differ.
*
* Hash consists of all module names (1), their revisions (2), all enabled features (3), and their
* imported/implemented state (4).
*
* @param[in] ctx Context to be examined.
* @return Context modules hash.
*/
LIBYANG_API_DECL uint32_t ly_ctx_get_modules_hash(const struct ly_ctx *ctx);
/**
* @brief Callback for freeing returned module data in #ly_module_imp_clb.
*
* @param[in] module_data Data to free.
* @param[in] user_data User-supplied callback data, same as for #ly_module_imp_clb.
*/
typedef void (*ly_module_imp_data_free_clb)(void *module_data, void *user_data);
/**
* @brief Callback for retrieving missing included or imported models in a custom way.
*
* When @p submod_name is provided, the submodule is requested instead of the module (in this case only
* the module name without its revision is provided).
*
* If an @arg free_module_data callback is provided, it will be used later to free the allegedly const data
* which were returned by this callback.
*
* @param[in] mod_name Missing module name.
* @param[in] mod_rev Optional missing module revision. If NULL and submod_name is not provided, the latest revision is
* requested, the parsed module is then marked by the latest_revision flag.
* @param[in] submod_name Optional missing submodule name.
* @param[in] submod_rev Optional missing submodule revision. If NULL and submod_name is provided, the latest revision is
* requested, the parsed submodule is then marked by the latest_revision flag.
* @param[in] user_data User-supplied callback data.
* @param[out] format Format of the returned module data.
* @param[out] module_data Requested module data.
* @param[out] free_module_data Callback for freeing the returned module data. If not set, the data will be left untouched.
* @return LY_ERR value. If the returned value differs from LY_SUCCESS, libyang continue in trying to get the module data
* according to the settings of its mechanism to search for the imported/included schemas.
*/
typedef LY_ERR (*ly_module_imp_clb)(const char *mod_name, const char *mod_rev, const char *submod_name, const char *submod_rev,
void *user_data, LYS_INFORMAT *format, const char **module_data, ly_module_imp_data_free_clb *free_module_data);
/**
* @brief Get the custom callback for missing import/include module retrieval.
*
* @param[in] ctx Context to read from.
* @param[in] user_data Optional pointer for getting the user-supplied callback data.
* @return Callback or NULL if not set.
*/
LIBYANG_API_DECL ly_module_imp_clb ly_ctx_get_module_imp_clb(const struct ly_ctx *ctx, void **user_data);
/**
* @brief Set missing include or import module callback. It is meant to be used when the models
* are not locally available (such as when downloading modules from a NETCONF server), it should
* not be required in other cases.
*
* @param[in] ctx Context that will use this callback.
* @param[in] clb Callback responsible for returning the missing model.
* @param[in] user_data Arbitrary data that will always be passed to the callback @p clb.
*/
LIBYANG_API_DECL void ly_ctx_set_module_imp_clb(struct ly_ctx *ctx, ly_module_imp_clb clb, void *user_data);
/**
* @brief Callback for getting arbitrary run-time data required by an extension instance.
*
* @param[in] ext Compiled extension instance.
* @param[in] user_data User-supplied callback data.
* @param[out] ext_data Provided extension instance data.
* @param[out] ext_data_free Whether the extension instance should free @p ext_data or not.
* @return LY_ERR value.
*/
typedef LY_ERR (*ly_ext_data_clb)(const struct lysc_ext_instance *ext, void *user_data, void **ext_data,
ly_bool *ext_data_free);
/**
* @brief Set callback providing run-time extension instance data. The expected data depend on the extension.
* Data expected by internal extensions:
*
* - *ietf-yang-schema-mount:mount-point* (struct lyd_node \*\*ext_data)\n
* Operational data tree with at least `ietf-yang-library` data describing the mounted schema and
* `ietf-yang-schema-mount` **validated** data describing the specific mount point
* ([ref](https://datatracker.ietf.org/doc/html/rfc8528#section-3.3)).
*
* @param[in] ctx Context that will use this callback.
* @param[in] clb Callback responsible for returning the extension instance data.
* @param[in] user_data Arbitrary data that will always be passed to the callback @p clb.
*/
LIBYANG_API_DECL ly_ext_data_clb ly_ctx_set_ext_data_clb(struct ly_ctx *ctx, ly_ext_data_clb clb, void *user_data);
/**
* @brief Get YANG module of the given name and revision.
*
* @param[in] ctx Context to work in.
* @param[in] name Name of the YANG module to get.
* @param[in] revision Requested revision date of the YANG module to get. If not specified,
* the schema with no revision is returned, if it is present in the context.
* @return Pointer to the YANG module, NULL if no schema in the context follows the name and revision requirements.
*/
LIBYANG_API_DECL struct lys_module *ly_ctx_get_module(const struct ly_ctx *ctx, const char *name, const char *revision);
/**
* @brief Get the latest revision of the YANG module specified by its name.
*
* YANG modules with no revision are supposed to be the oldest one.
*
* @param[in] ctx Context where to search.
* @param[in] name Name of the YANG module to get.
* @return The latest revision of the specified YANG module in the given context, NULL if no YANG module of the
* given name is present in the context.
*/
LIBYANG_API_DECL struct lys_module *ly_ctx_get_module_latest(const struct ly_ctx *ctx, const char *name);
/**
* @brief Get the (only) implemented YANG module specified by its name.
*
* @param[in] ctx Context where to search.
* @param[in] name Name of the YANG module to get.
* @return The only implemented YANG module revision of the given name in the given context. NULL if there is no
* implemented module of the given name.
*/
LIBYANG_API_DECL struct lys_module *ly_ctx_get_module_implemented(const struct ly_ctx *ctx, const char *name);
/**
* @brief Iterate over all modules in the given context.
*
* @param[in] ctx Context with the modules.
* @param[in,out] index Index of the next module to get. Value of 0 starts from the beginning.
* The value is updated with each call, so to iterate over all modules the same variable is supposed
* to be used in all calls starting with value 0.
* @return Next context module, NULL if the last was already returned.
*/
LIBYANG_API_DECL struct lys_module *ly_ctx_get_module_iter(const struct ly_ctx *ctx, uint32_t *index);
/**
* @brief Get YANG module of the given namespace and revision.
*
* @param[in] ctx Context to work in.
* @param[in] ns Namespace of the YANG module to get.
* @param[in] revision Requested revision date of the YANG module to get. If not specified,
* the schema with no revision is returned, if it is present in the context.
* @return Pointer to the YANG module, NULL if no schema in the context follows the namespace and revision requirements.
*/
LIBYANG_API_DECL struct lys_module *ly_ctx_get_module_ns(const struct ly_ctx *ctx, const char *ns, const char *revision);
/**
* @brief Get the latest revision of the YANG module specified by its namespace.
*
* YANG modules with no revision are supposed to be the oldest one.
*
* @param[in] ctx Context where to search.
* @param[in] ns Namespace of the YANG module to get.
* @return The latest revision of the specified YANG module in the given context, NULL if no YANG module of the
* given namespace is present in the context.
*/
LIBYANG_API_DECL struct lys_module *ly_ctx_get_module_latest_ns(const struct ly_ctx *ctx, const char *ns);
/**
* @brief Get the (only) implemented YANG module specified by its namespace.
*
* @param[in] ctx Context where to search.
* @param[in] ns Namespace of the YANG module to get.
* @return The only implemented YANG module revision of the given namespace in the given context. NULL if there is no
* implemented module of the given namespace.
*/
LIBYANG_API_DECL struct lys_module *ly_ctx_get_module_implemented_ns(const struct ly_ctx *ctx, const char *ns);
/**
* @brief Get a specific submodule from context. If its belongs-to module is known, use ::ly_ctx_get_submodule2().
*
* @param[in] ctx libyang context to search in.
* @param[in] submodule Submodule name to find.
* @param[in] revision Revision of the submodule to find, NULL for a submodule without a revision.
* @return Found submodule, NULL if there is none.
*/
LIBYANG_API_DECL const struct lysp_submodule *ly_ctx_get_submodule(const struct ly_ctx *ctx, const char *submodule,
const char *revision);
/**
* @brief Get the latests revision of a submodule from context. If its belongs-to module is known,
* use ::ly_ctx_get_submodule2_latest().
*
* @param[in] ctx libyang context to search in.
* @param[in] submodule Submodule name to find.
* @return Found submodule, NULL if there is none.
*/
LIBYANG_API_DECL const struct lysp_submodule *ly_ctx_get_submodule_latest(const struct ly_ctx *ctx, const char *submodule);
/**
* @brief Get a specific submodule from a module. If the belongs-to module is not known, use ::ly_ctx_get_submodule().
*
* @param[in] module Belongs-to module to search in.
* @param[in] submodule Submodule name to find.
* @param[in] revision Revision of the submodule to find, NULL for a submodule without a revision.
* @return Found submodule, NULL if there is none.
*/
LIBYANG_API_DECL const struct lysp_submodule *ly_ctx_get_submodule2(const struct lys_module *module, const char *submodule,
const char *revision);
/**
* @brief Get the latest revision of a submodule from a module. If the belongs-to module is not known,
* use ::ly_ctx_get_submodule_latest().
*
* @param[in] module Belongs-to module to search in.
* @param[in] submodule Submodule name to find.
* @return Found submodule, NULL if there is none.
*/
LIBYANG_API_DECL const struct lysp_submodule *ly_ctx_get_submodule2_latest(const struct lys_module *module,
const char *submodule);
/**
* @brief Learn the number of internal modules of a context. Internal modules
* is considered one that was loaded during the context creation.
*
* @param[in] ctx libyang context to examine.
* @return Number of internal modules.
*/
LIBYANG_API_DECL uint32_t ly_ctx_internal_modules_count(const struct ly_ctx *ctx);
/**
* @brief Try to find the model in the searchpaths of \p ctx and load it into it. If custom missing
* module callback is set, it is used instead.
*
* The context itself is searched for the requested module first. If \p revision is not specified
* (the module of the latest revision is requested) and there is implemented revision of the requested
* module in the context, this implemented revision is returned despite there might be a newer revision.
* This behavior is cause by the fact that it is not possible to have multiple implemented revisions of
* the same module in the context.
*
* @param[in] ctx Context to add to.
* @param[in] name Name of the module to load.
* @param[in] revision Optional revision date of the module. If not specified, the latest revision is loaded.
* @param[in] features Optional array of features ended with NULL to be enabled if the module is being implemented.
* The feature string '*' enables all and array of length 1 with only the terminating NULL explicitly disables all
* the features. In case the parameter is NULL, the features are untouched - left disabled in newly loaded module or
* with the current features settings in case the module is already present in the context.
* @return Pointer to the data model structure, NULL if not found or some error occurred.
*/
LIBYANG_API_DECL struct lys_module *ly_ctx_load_module(struct ly_ctx *ctx, const char *name, const char *revision,
const char **features);
/**
* @brief Get data of the internal ietf-yang-library module with information about all the loaded modules.
* ietf-yang-library module must be loaded.
*
* Note that "/ietf-yang-library:yang-library/datastore" list instances are not created and should be
* appended by the caller. There is a single "/ietf-yang-library:yang-library/schema" instance created
* with the key value "complete".
*
* If the data identifier can be limited to the existence and changes of this context, the following
* last 2 parameters can be used:
*
* "%u" as @p content_id_format and ::ly_ctx_get_change_count() as its parameter;
* "%u" as @p content_id_format and ::ly_ctx_get_modules_hash() as its parameter.
*
* @param[in] ctx Context with the modules.
* @param[out] root Generated yang-library data.
* @param[in] content_id_format Format string (printf-like) for the yang-library data identifier, which is
* the "content_id" node in the 2019-01-04 revision of ietf-yang-library.
* @param[in] ... Parameters for @p content_id_format.
* @return LY_ERR value
*/
LIBYANG_API_DECL LY_ERR ly_ctx_get_yanglib_data(const struct ly_ctx *ctx, struct lyd_node **root,
const char *content_id_format, ...);
/**
* @brief Free all internal structures of the specified context.
*
* The function should be used before terminating the application to destroy
* and free all structures internally used by libyang. If the caller uses
* multiple contexts, the function should be called for each used context.
*
* All instance data are supposed to be freed before destroying the context using ::lyd_free_all(), for example.
* Data models (schemas) are destroyed automatically as part of ::ly_ctx_destroy() call.
*
* Note that the data stored by user into the ::lysc_node.priv pointer are kept
* untouched and the caller is responsible for freeing this private data.
*
* @param[in] ctx libyang context to destroy
*/
LIBYANG_API_DECL void ly_ctx_destroy(struct ly_ctx *ctx);
/** @} context */
#ifdef __cplusplus
}
#endif
#endif /* LY_CONTEXT_H_ */

271
src/dict.c Normal file
View file

@ -0,0 +1,271 @@
/**
* @file dict.c
* @author Radek Krejci <rkrejci@cesnet.cz>
* @author Michal Vasko <mvasko@cesnet.cz>
* @brief libyang dictionary for storing strings
*
* Copyright (c) 2015 - 2023 CESNET, z.s.p.o.
*
* This source code is licensed under BSD 3-Clause License (the "License").
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*/
#include "dict.h"
#include <assert.h>
#include <pthread.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "compat.h"
#include "log.h"
#include "ly_common.h"
/* starting size of the dictionary */
#define LYDICT_MIN_SIZE 1024
/**
* @brief Comparison callback for dictionary's hash table
*
* Implementation of ::lyht_value_equal_cb.
*/
static ly_bool
lydict_val_eq(void *val1_p, void *val2_p, ly_bool UNUSED(mod), void *cb_data)
{
const char *str1, *str2;
size_t *len1;
LY_CHECK_ARG_RET(NULL, val1_p, val2_p, cb_data, 0);
str1 = ((struct ly_dict_rec *)val1_p)->value;
str2 = ((struct ly_dict_rec *)val2_p)->value;
len1 = cb_data;
LY_CHECK_ERR_RET(!str1, LOGARG(NULL, val1_p), 0);
LY_CHECK_ERR_RET(!str2, LOGARG(NULL, val2_p), 0);
if (!strncmp(str1, str2, *len1) && !str2[*len1]) {
return 1;
}
return 0;
}
void
lydict_init(struct ly_dict *dict)
{
LY_CHECK_ARG_RET(NULL, dict, );
dict->hash_tab = lyht_new(LYDICT_MIN_SIZE, sizeof(struct ly_dict_rec), lydict_val_eq, NULL, 1);
LY_CHECK_ERR_RET(!dict->hash_tab, LOGINT(NULL), );
pthread_mutex_init(&dict->lock, NULL);
}
void
lydict_clean(struct ly_dict *dict)
{
struct ly_dict_rec *dict_rec = NULL;
struct ly_ht_rec *rec = NULL;
uint32_t hlist_idx;
uint32_t rec_idx;
LY_CHECK_ARG_RET(NULL, dict, );
LYHT_ITER_ALL_RECS(dict->hash_tab, hlist_idx, rec_idx, rec) {
/*
* this should not happen, all records inserted into
* dictionary are supposed to be removed using lydict_remove()
* before calling lydict_clean()
*/
dict_rec = (struct ly_dict_rec *)rec->val;
LOGWRN(NULL, "String \"%s\" not freed from the dictionary, refcount %" PRIu32 ".", dict_rec->value, dict_rec->refcount);
/* if record wasn't removed before free string allocated for that record */
#ifdef NDEBUG
free(dict_rec->value);
#endif
}
/* free table and destroy mutex */
lyht_free(dict->hash_tab, NULL);
pthread_mutex_destroy(&dict->lock);
}
static ly_bool
lydict_resize_val_eq(void *val1_p, void *val2_p, ly_bool mod, void *UNUSED(cb_data))
{
const char *str1, *str2;
LY_CHECK_ARG_RET(NULL, val1_p, val2_p, 0);
str1 = ((struct ly_dict_rec *)val1_p)->value;
str2 = ((struct ly_dict_rec *)val2_p)->value;
LY_CHECK_ERR_RET(!str1, LOGARG(NULL, val1_p), 0);
LY_CHECK_ERR_RET(!str2, LOGARG(NULL, val2_p), 0);
if (mod) {
/* used when inserting new values */
if (strcmp(str1, str2) == 0) {
return 1;
}
} else {
/* used when finding the original value again in the resized table */
if (str1 == str2) {
return 1;
}
}
return 0;
}
LIBYANG_API_DEF LY_ERR
lydict_remove(const struct ly_ctx *ctx, const char *value)
{
LY_ERR ret = LY_SUCCESS;
size_t len;
uint32_t hash;
struct ly_dict_rec rec, *match = NULL;
char *val_p;
if (!ctx || !value) {
return LY_SUCCESS;
}
LOGDBG(LY_LDGDICT, "removing \"%s\"", value);
len = strlen(value);
hash = lyht_hash(value, len);
/* create record for lyht_find call */
rec.value = (char *)value;
rec.refcount = 0;
pthread_mutex_lock((pthread_mutex_t *)&ctx->dict.lock);
/* set len as data for compare callback */
lyht_set_cb_data(ctx->dict.hash_tab, (void *)&len);
/* check if value is already inserted */
ret = lyht_find(ctx->dict.hash_tab, &rec, hash, (void **)&match);
if (ret == LY_SUCCESS) {
LY_CHECK_ERR_GOTO(!match, LOGINT(ctx), finish);
/* if value is already in dictionary, decrement reference counter */
match->refcount--;
if (match->refcount == 0) {
/*
* remove record
* save pointer to stored string before lyht_remove to
* free it after it is removed from hash table
*/
val_p = match->value;
ret = lyht_remove_with_resize_cb(ctx->dict.hash_tab, &rec, hash, lydict_resize_val_eq);
free(val_p);
LY_CHECK_ERR_GOTO(ret, LOGINT(ctx), finish);
}
} else if (ret == LY_ENOTFOUND) {
LOGERR(ctx, LY_ENOTFOUND, "Value \"%s\" was not found in the dictionary.", value);
} else {
LOGINT(ctx);
}
finish:
pthread_mutex_unlock((pthread_mutex_t *)&ctx->dict.lock);
return ret;
}
LY_ERR
dict_insert(const struct ly_ctx *ctx, char *value, size_t len, ly_bool zerocopy, const char **str_p)
{
LY_ERR ret = LY_SUCCESS;
struct ly_dict_rec *match = NULL, rec;
uint32_t hash;
LOGDBG(LY_LDGDICT, "inserting \"%.*s\"", (int)len, value);
hash = lyht_hash(value, len);
/* set len as data for compare callback */
lyht_set_cb_data(ctx->dict.hash_tab, (void *)&len);
/* create record for lyht_insert */
rec.value = value;
rec.refcount = 1;
ret = lyht_insert_with_resize_cb(ctx->dict.hash_tab, (void *)&rec, hash, lydict_resize_val_eq, (void **)&match);
if (ret == LY_EEXIST) {
match->refcount++;
if (zerocopy) {
free(value);
}
ret = LY_SUCCESS;
} else if (ret == LY_SUCCESS) {
if (!zerocopy) {
/*
* allocate string for new record
* record is already inserted in hash table
*/
match->value = malloc(sizeof *match->value * (len + 1));
LY_CHECK_ERR_RET(!match->value, LOGMEM(ctx), LY_EMEM);
if (len) {
memcpy(match->value, value, len);
}
match->value[len] = '\0';
}
} else {
/* lyht_insert returned error */
if (zerocopy) {
free(value);
}
return ret;
}
if (str_p) {
*str_p = match->value;
}
return ret;
}
LIBYANG_API_DEF LY_ERR
lydict_insert(const struct ly_ctx *ctx, const char *value, size_t len, const char **str_p)
{
LY_ERR result;
LY_CHECK_ARG_RET(ctx, ctx, str_p, LY_EINVAL);
if (!value) {
*str_p = NULL;
return LY_SUCCESS;
}
if (!len) {
len = strlen(value);
}
pthread_mutex_lock((pthread_mutex_t *)&ctx->dict.lock);
result = dict_insert(ctx, (char *)value, len, 0, str_p);
pthread_mutex_unlock((pthread_mutex_t *)&ctx->dict.lock);
return result;
}
LIBYANG_API_DEF LY_ERR
lydict_insert_zc(const struct ly_ctx *ctx, char *value, const char **str_p)
{
LY_ERR result;
LY_CHECK_ARG_RET(ctx, ctx, str_p, LY_EINVAL);
if (!value) {
*str_p = NULL;
return LY_SUCCESS;
}
pthread_mutex_lock((pthread_mutex_t *)&ctx->dict.lock);
result = dict_insert(ctx, value, strlen(value), 1, str_p);
pthread_mutex_unlock((pthread_mutex_t *)&ctx->dict.lock);
return result;
}

122
src/dict.h Normal file
View file

@ -0,0 +1,122 @@
/**
* @file dict.h
* @author Radek Krejci <rkrejci@cesnet.cz>
* @brief libyang dictionary
*
* Copyright (c) 2015-2018 CESNET, z.s.p.o.
*
* This source code is licensed under BSD 3-Clause License (the "License").
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*/
#ifndef LY_DICT_H_
#define LY_DICT_H_
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include "log.h"
#ifdef __cplusplus
extern "C" {
#endif
/* dummy context structure */
struct ly_ctx;
/**
* @page howtoContextDict Context Dictionary
*
* Context includes dictionary to store strings more effectively. The most of strings repeats quite often in schema
* as well as data trees. Therefore, instead of allocating those strings each time they appear, libyang stores them
* as records in the dictionary. The basic API to the context dictionary is public, so even a caller application can
* use the dictionary.
*
* To insert a string into the dictionary, caller can use ::lydict_insert() (adding a constant string) or
* ::lydict_insert_zc() (for dynamically allocated strings that won't be used by the caller after its insertion into
* the dictionary). Both functions provide the pointer to the inserted string in the dictionary record.
*
* To remove (reference of the) string from the context dictionary, ::lydict_remove() is supposed to be used.
*
* \note Incorrect usage of the dictionary can break libyang functionality.
*
* \note API for this group of functions is described in the [Dictionary module](@ref dict).
*
* Functions List
* --------------
* - ::lydict_insert()
* - ::lydict_insert_zc()
* - ::lydict_remove()
*/
/**
* @defgroup dict Dictionary
* @{
*
* Publicly visible functions and values of the libyang dictionary. They provide
* access to the strings stored in the libyang context. More detailed information can be found at
* @ref howtoContextDict page.
*/
/**
* @brief Insert string into dictionary. If the string is already present,
* only a reference counter is incremented and no memory allocation is
* performed.
*
* @param[in] ctx libyang context handler
* @param[in] value String to be stored in the dictionary. If NULL, function does nothing.
* @param[in] len Number of bytes to store. The value is not required to be
* NULL terminated string, the len parameter says number of bytes stored in
* dictionary. The specified number of bytes is duplicated and terminating NULL
* byte is added automatically. If \p len is 0, it is count automatically using strlen().
* @param[out] str_p Optional parameter to get pointer to the string corresponding to the @p value and stored in dictionary.
* @return LY_SUCCESS in case of successful insertion into dictionary, note that the function does not return LY_EEXIST.
* @return LY_EINVAL in case of invalid input parameters.
* @return LY_EMEM in case of memory allocation failure.
*/
LIBYANG_API_DECL LY_ERR lydict_insert(const struct ly_ctx *ctx, const char *value, size_t len, const char **str_p);
/**
* @brief Insert string into dictionary - zerocopy version. If the string is
* already present, only a reference counter is incremented and no memory
* allocation is performed. This insert function variant avoids duplication of
* specified value - it is inserted into the dictionary directly.
*
* @param[in] ctx libyang context handler
* @param[in] value NULL-terminated string to be stored in the dictionary. If
* the string is not present in dictionary, the pointer is directly used by the
* dictionary. Otherwise, the reference counter is incremented and the value is
* freed. So, after calling the function, caller is supposed to not use the
* value address anymore. If NULL, function does nothing.
* @param[out] str_p Optional parameter to get pointer to the string corresponding to the @p value and stored in dictionary.
* @return LY_SUCCESS in case of successful insertion into dictionary, note that the function does not return LY_EEXIST.
* @return LY_EINVAL in case of invalid input parameters.
* @return LY_EMEM in case of memory allocation failure.
*/
LIBYANG_API_DECL LY_ERR lydict_insert_zc(const struct ly_ctx *ctx, char *value, const char **str_p);
/**
* @brief Remove specified string from the dictionary. It decrement reference
* counter for the string and if it is zero, the string itself is freed.
*
* @param[in] ctx libyang context handler
* @param[in] value String to be freed. Note, that not only the string itself
* must match the stored value, but also the address is being compared and the
* counter is decremented only if it matches. If NULL, function does nothing.
* @return LY_SUCCESS if the value was found and removed (or refcount decreased).
* @return LY_ENOTFOUND if the value was not found.
* @return LY_ERR on other errors.
*/
LIBYANG_API_DECL LY_ERR lydict_remove(const struct ly_ctx *ctx, const char *value);
/** @} dict */
#ifdef __cplusplus
}
#endif
#endif /* LY_DICT_H_ */

2347
src/diff.c Normal file

File diff suppressed because it is too large Load diff

62
src/diff.h Normal file
View file

@ -0,0 +1,62 @@
/**
* @file diff.h
* @author Michal Vasko <mvasko@cesnet.cz>
* @brief internal diff header
*
* Copyright (c) 2020 CESNET, z.s.p.o.
*
* This source code is licensed under BSD 3-Clause License (the "License").
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*/
#ifndef LY_DIFF_H_
#define LY_DIFF_H_
#include <stdint.h>
#include "log.h"
struct lyd_node;
/**
* @brief Internal structure for storing current (virtual) user-ordered instances order.
*/
struct lyd_diff_userord {
const struct lysc_node *schema; /**< User-ordered list/leaf-list schema node. */
uint64_t pos; /**< Current position in the second tree. */
const struct lyd_node **inst; /**< Sized array of current instance order. */
};
/**
* @brief Diff operations.
*/
enum lyd_diff_op {
LYD_DIFF_OP_CREATE, /**< Subtree created. */
LYD_DIFF_OP_DELETE, /**< Subtree deleted. */
LYD_DIFF_OP_REPLACE, /**< Node value changed or (leaf-)list instance moved. */
LYD_DIFF_OP_NONE /**< No change of an existing inner node or default flag change of a term node. */
};
/**
* @brief Add a new change into diff.
*
* @param[in] node Node (subtree) to add into diff.
* @param[in] op Operation to set.
* @param[in] orig_default Original default metadata to set.
* @param[in] orig_value Original value metadata to set.
* @param[in] key Key metadata to set.
* @param[in] value Value metadata to set.
* @param[in] position Position metadata to set.
* @param[in] orig_key Original key metadata to set.
* @param[in] orig_position Original position metadata to set.
* @param[in,out] diff Diff to append to.
* @return LY_ERR value.
*/
LIBYANG_API_DECL LY_ERR lyd_diff_add(const struct lyd_node *node, enum lyd_diff_op op, const char *orig_default, const char *orig_value,
const char *key, const char *value, const char *position, const char *orig_key, const char *orig_position,
struct lyd_node **diff);
#endif /* LY_DIFF_H_ */

534
src/hash_table.c Normal file
View file

@ -0,0 +1,534 @@
/**
* @file hash_table.c
* @author Radek Krejci <rkrejci@cesnet.cz>
* @author Michal Vasko <mvasko@cesnet.cz>
* @brief libyang generic hash table implementation
*
* Copyright (c) 2015 - 2023 CESNET, z.s.p.o.
*
* This source code is licensed under BSD 3-Clause License (the "License").
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*/
#include "hash_table.h"
#include <assert.h>
#include <pthread.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "compat.h"
#include "dict.h"
#include "log.h"
#include "ly_common.h"
LIBYANG_API_DEF uint32_t
lyht_hash_multi(uint32_t hash, const char *key_part, size_t len)
{
uint32_t i;
if (key_part && len) {
for (i = 0; i < len; ++i) {
hash += key_part[i];
hash += (hash << 10);
hash ^= (hash >> 6);
}
} else {
hash += (hash << 3);
hash ^= (hash >> 11);
hash += (hash << 15);
}
return hash;
}
LIBYANG_API_DEF uint32_t
lyht_hash(const char *key, size_t len)
{
uint32_t hash;
hash = lyht_hash_multi(0, key, len);
return lyht_hash_multi(hash, NULL, len);
}
static LY_ERR
lyht_init_hlists_and_records(struct ly_ht *ht)
{
struct ly_ht_rec *rec;
uint32_t i;
ht->recs = calloc(ht->size, ht->rec_size);
LY_CHECK_ERR_RET(!ht->recs, LOGMEM(NULL), LY_EMEM);
for (i = 0; i < ht->size; i++) {
rec = lyht_get_rec(ht->recs, ht->rec_size, i);
if (i != ht->size) {
rec->next = i + 1;
} else {
rec->next = LYHT_NO_RECORD;
}
}
ht->hlists = malloc(sizeof(ht->hlists[0]) * ht->size);
LY_CHECK_ERR_RET(!ht->hlists, free(ht->recs); LOGMEM(NULL), LY_EMEM);
for (i = 0; i < ht->size; i++) {
ht->hlists[i].first = LYHT_NO_RECORD;
ht->hlists[i].last = LYHT_NO_RECORD;
}
ht->first_free_rec = 0;
return LY_SUCCESS;
}
LIBYANG_API_DEF struct ly_ht *
lyht_new(uint32_t size, uint16_t val_size, lyht_value_equal_cb val_equal, void *cb_data, uint16_t resize)
{
struct ly_ht *ht;
/* check that 2^x == size (power of 2) */
assert(size && !(size & (size - 1)));
assert(val_equal && val_size);
assert(resize == 0 || resize == 1);
if (size < LYHT_MIN_SIZE) {
size = LYHT_MIN_SIZE;
}
ht = malloc(sizeof *ht);
LY_CHECK_ERR_RET(!ht, LOGMEM(NULL), NULL);
ht->used = 0;
ht->size = size;
ht->val_equal = val_equal;
ht->cb_data = cb_data;
ht->resize = resize;
ht->rec_size = SIZEOF_LY_HT_REC + val_size;
if (lyht_init_hlists_and_records(ht) != LY_SUCCESS) {
free(ht);
return NULL;
}
return ht;
}
LIBYANG_API_DEF lyht_value_equal_cb
lyht_set_cb(struct ly_ht *ht, lyht_value_equal_cb new_val_equal)
{
lyht_value_equal_cb prev;
prev = ht->val_equal;
ht->val_equal = new_val_equal;
return prev;
}
LIBYANG_API_DEF void *
lyht_set_cb_data(struct ly_ht *ht, void *new_cb_data)
{
void *prev;
prev = ht->cb_data;
ht->cb_data = new_cb_data;
return prev;
}
LIBYANG_API_DEF struct ly_ht *
lyht_dup(const struct ly_ht *orig)
{
struct ly_ht *ht;
LY_CHECK_ARG_RET(NULL, orig, NULL);
ht = lyht_new(orig->size, orig->rec_size - SIZEOF_LY_HT_REC, orig->val_equal, orig->cb_data, orig->resize ? 1 : 0);
if (!ht) {
return NULL;
}
memcpy(ht->hlists, orig->hlists, sizeof(ht->hlists[0]) * orig->size);
memcpy(ht->recs, orig->recs, (size_t)orig->size * orig->rec_size);
ht->used = orig->used;
return ht;
}
LIBYANG_API_DEF void
lyht_free(struct ly_ht *ht, void (*val_free)(void *val_p))
{
struct ly_ht_rec *rec;
uint32_t hlist_idx;
uint32_t rec_idx;
if (!ht) {
return;
}
if (val_free) {
LYHT_ITER_ALL_RECS(ht, hlist_idx, rec_idx, rec) {
val_free(&rec->val);
}
}
free(ht->hlists);
free(ht->recs);
free(ht);
}
/**
* @brief Resize a hash table.
*
* @param[in] ht Hash table to resize.
* @param[in] operation Operation to perform. 1 to enlarge, -1 to shrink, 0 to only rehash all records.
* @return LY_ERR value.
*/
static LY_ERR
lyht_resize(struct ly_ht *ht, int operation, int check)
{
struct ly_ht_rec *rec;
struct ly_ht_hlist *old_hlists;
unsigned char *old_recs;
uint32_t old_first_free_rec;
uint32_t i, old_size;
uint32_t rec_idx;
old_hlists = ht->hlists;
old_recs = ht->recs;
old_size = ht->size;
old_first_free_rec = ht->first_free_rec;
if (operation > 0) {
/* double the size */
ht->size <<= 1;
} else if (operation < 0) {
/* half the size */
ht->size >>= 1;
}
if (lyht_init_hlists_and_records(ht) != LY_SUCCESS) {
ht->hlists = old_hlists;
ht->recs = old_recs;
ht->size = old_size;
ht->first_free_rec = old_first_free_rec;
return LY_EMEM;
}
/* reset used, it will increase again */
ht->used = 0;
/* add all the old records into the new records array */
for (i = 0; i < old_size; i++) {
for (rec_idx = old_hlists[i].first, rec = lyht_get_rec(old_recs, ht->rec_size, rec_idx);
rec_idx != LYHT_NO_RECORD;
rec_idx = rec->next, rec = lyht_get_rec(old_recs, ht->rec_size, rec_idx)) {
LY_ERR ret;
if (check) {
ret = lyht_insert(ht, rec->val, rec->hash, NULL);
} else {
ret = lyht_insert_no_check(ht, rec->val, rec->hash, NULL);
}
assert(!ret);
(void)ret;
}
}
/* final touches */
free(old_recs);
free(old_hlists);
return LY_SUCCESS;
}
/**
* @brief Search for a record with specific value and hash.
*
* @param[in] ht Hash table to search in.
* @param[in] val_p Pointer to the value to find.
* @param[in] hash Hash to find.
* @param[in] mod Whether the operation modifies the hash table (insert or remove) or not (find).
* @param[in] val_equal Callback for checking value equivalence.
* @param[out] crec_p Optional found first record.
* @param[out] col Optional collision number of @p rec_p, 0 for no collision.
* @param[out] rec_p Found exact matching record, may be a collision of @p crec_p.
* @return LY_ENOTFOUND if no record found,
* @return LY_SUCCESS if record was found.
*/
static LY_ERR
lyht_find_rec(const struct ly_ht *ht, void *val_p, uint32_t hash, ly_bool mod, lyht_value_equal_cb val_equal,
struct ly_ht_rec **crec_p, uint32_t *col, struct ly_ht_rec **rec_p)
{
uint32_t hlist_idx = hash & (ht->size - 1);
struct ly_ht_rec *rec;
uint32_t rec_idx;
if (crec_p) {
*crec_p = NULL;
}
if (col) {
*col = 0;
}
*rec_p = NULL;
LYHT_ITER_HLIST_RECS(ht, hlist_idx, rec_idx, rec) {
if ((rec->hash == hash) && val_equal(val_p, &rec->val, mod, ht->cb_data)) {
if (crec_p) {
*crec_p = rec;
}
*rec_p = rec;
return LY_SUCCESS;
}
if (col) {
*col = *col + 1;
}
}
/* not found even in collisions */
return LY_ENOTFOUND;
}
LIBYANG_API_DEF LY_ERR
lyht_find(const struct ly_ht *ht, void *val_p, uint32_t hash, void **match_p)
{
struct ly_ht_rec *rec;
lyht_find_rec(ht, val_p, hash, 0, ht->val_equal, NULL, NULL, &rec);
if (rec && match_p) {
*match_p = rec->val;
}
return rec ? LY_SUCCESS : LY_ENOTFOUND;
}
LIBYANG_API_DEF LY_ERR
lyht_find_with_val_cb(const struct ly_ht *ht, void *val_p, uint32_t hash, lyht_value_equal_cb val_equal, void **match_p)
{
struct ly_ht_rec *rec;
lyht_find_rec(ht, val_p, hash, 0, val_equal ? val_equal : ht->val_equal, NULL, NULL, &rec);
if (rec && match_p) {
*match_p = rec->val;
}
return rec ? LY_SUCCESS : LY_ENOTFOUND;
}
LIBYANG_API_DEF LY_ERR
lyht_find_next_with_collision_cb(const struct ly_ht *ht, void *val_p, uint32_t hash,
lyht_value_equal_cb collision_val_equal, void **match_p)
{
struct ly_ht_rec *rec, *crec;
uint32_t rec_idx;
uint32_t i;
/* find the record of the previously found value */
if (lyht_find_rec(ht, val_p, hash, 1, ht->val_equal, &crec, &i, &rec)) {
/* not found, cannot happen */
LOGINT_RET(NULL);
}
for (rec_idx = rec->next, rec = lyht_get_rec(ht->recs, ht->rec_size, rec_idx);
rec_idx != LYHT_NO_RECORD;
rec_idx = rec->next, rec = lyht_get_rec(ht->recs, ht->rec_size, rec_idx)) {
if (rec->hash != hash) {
continue;
}
if (collision_val_equal) {
if (collision_val_equal(val_p, &rec->val, 0, ht->cb_data)) {
/* even the value matches */
if (match_p) {
*match_p = rec->val;
}
return LY_SUCCESS;
}
} else if (ht->val_equal(val_p, &rec->val, 0, ht->cb_data)) {
/* even the value matches */
if (match_p) {
*match_p = rec->val;
}
return LY_SUCCESS;
}
}
/* the last equal value was already returned */
return LY_ENOTFOUND;
}
LIBYANG_API_DEF LY_ERR
lyht_find_next(const struct ly_ht *ht, void *val_p, uint32_t hash, void **match_p)
{
return lyht_find_next_with_collision_cb(ht, val_p, hash, NULL, match_p);
}
static LY_ERR
_lyht_insert_with_resize_cb(struct ly_ht *ht, void *val_p, uint32_t hash, lyht_value_equal_cb resize_val_equal,
void **match_p, int check)
{
uint32_t hlist_idx = hash & (ht->size - 1);
LY_ERR r, ret = LY_SUCCESS;
struct ly_ht_rec *rec, *prev_rec;
lyht_value_equal_cb old_val_equal = NULL;
uint32_t rec_idx;
if (check) {
if (lyht_find_rec(ht, val_p, hash, 1, ht->val_equal, NULL, NULL, &rec) == LY_SUCCESS) {
if (rec && match_p) {
*match_p = rec->val;
}
return LY_EEXIST;
}
}
rec_idx = ht->first_free_rec;
assert(rec_idx < ht->size);
rec = lyht_get_rec(ht->recs, ht->rec_size, rec_idx);
ht->first_free_rec = rec->next;
if (ht->hlists[hlist_idx].first == LYHT_NO_RECORD) {
ht->hlists[hlist_idx].first = rec_idx;
} else {
prev_rec = lyht_get_rec(ht->recs, ht->rec_size, ht->hlists[hlist_idx].last);
prev_rec->next = rec_idx;
}
rec->next = LYHT_NO_RECORD;
ht->hlists[hlist_idx].last = rec_idx;
rec->hash = hash;
memcpy(&rec->val, val_p, ht->rec_size - SIZEOF_LY_HT_REC);
if (match_p) {
*match_p = (void *)&rec->val;
}
/* check size & enlarge if needed */
++ht->used;
if (ht->resize) {
r = (ht->used * LYHT_HUNDRED_PERCENTAGE) / ht->size;
if ((ht->resize == 1) && (r >= LYHT_FIRST_SHRINK_PERCENTAGE)) {
/* enable shrinking */
ht->resize = 2;
}
if ((ht->resize == 2) && (r >= LYHT_ENLARGE_PERCENTAGE)) {
if (resize_val_equal) {
old_val_equal = lyht_set_cb(ht, resize_val_equal);
}
/* enlarge */
ret = lyht_resize(ht, 1, check);
/* if hash_table was resized, we need to find new matching value */
if ((ret == LY_SUCCESS) && match_p) {
ret = lyht_find(ht, val_p, hash, match_p);
assert(!ret);
}
if (resize_val_equal) {
lyht_set_cb(ht, old_val_equal);
}
}
}
return ret;
}
LIBYANG_API_DEF LY_ERR
lyht_insert_with_resize_cb(struct ly_ht *ht, void *val_p, uint32_t hash, lyht_value_equal_cb resize_val_equal,
void **match_p)
{
return _lyht_insert_with_resize_cb(ht, val_p, hash, resize_val_equal, match_p, 1);
}
LIBYANG_API_DEF LY_ERR
lyht_insert(struct ly_ht *ht, void *val_p, uint32_t hash, void **match_p)
{
return _lyht_insert_with_resize_cb(ht, val_p, hash, NULL, match_p, 1);
}
LIBYANG_API_DEF LY_ERR
lyht_insert_no_check(struct ly_ht *ht, void *val_p, uint32_t hash, void **match_p)
{
return _lyht_insert_with_resize_cb(ht, val_p, hash, NULL, match_p, 0);
}
LIBYANG_API_DEF LY_ERR
lyht_remove_with_resize_cb(struct ly_ht *ht, void *val_p, uint32_t hash, lyht_value_equal_cb resize_val_equal)
{
struct ly_ht_rec *found_rec, *prev_rec, *rec;
uint32_t hlist_idx = hash & (ht->size - 1);
LY_ERR r, ret = LY_SUCCESS;
lyht_value_equal_cb old_val_equal = NULL;
uint32_t prev_rec_idx;
uint32_t rec_idx;
if (lyht_find_rec(ht, val_p, hash, 1, ht->val_equal, NULL, NULL, &found_rec)) {
LOGARG(NULL, hash);
return LY_ENOTFOUND;
}
prev_rec_idx = LYHT_NO_RECORD;
LYHT_ITER_HLIST_RECS(ht, hlist_idx, rec_idx, rec) {
if (rec == found_rec) {
break;
}
prev_rec_idx = rec_idx;
}
if (prev_rec_idx == LYHT_NO_RECORD) {
ht->hlists[hlist_idx].first = rec->next;
if (rec->next == LYHT_NO_RECORD) {
ht->hlists[hlist_idx].last = LYHT_NO_RECORD;
}
} else {
prev_rec = lyht_get_rec(ht->recs, ht->rec_size, prev_rec_idx);
prev_rec->next = rec->next;
if (rec->next == LYHT_NO_RECORD) {
ht->hlists[hlist_idx].last = prev_rec_idx;
}
}
rec->next = ht->first_free_rec;
ht->first_free_rec = rec_idx;
/* check size & shrink if needed */
--ht->used;
if (ht->resize == 2) {
r = (ht->used * LYHT_HUNDRED_PERCENTAGE) / ht->size;
if ((r < LYHT_SHRINK_PERCENTAGE) && (ht->size > LYHT_MIN_SIZE)) {
if (resize_val_equal) {
old_val_equal = lyht_set_cb(ht, resize_val_equal);
}
/* shrink */
ret = lyht_resize(ht, -1, 1);
if (resize_val_equal) {
lyht_set_cb(ht, old_val_equal);
}
}
}
return ret;
}
LIBYANG_API_DEF LY_ERR
lyht_remove(struct ly_ht *ht, void *val_p, uint32_t hash)
{
return lyht_remove_with_resize_cb(ht, val_p, hash, NULL);
}
LIBYANG_API_DEF uint32_t
lyht_get_fixed_size(uint32_t item_count)
{
if (item_count == 0) {
return 1;
}
/* return next power of 2 (greater or equal) */
item_count--;
item_count |= item_count >> 1;
item_count |= item_count >> 2;
item_count |= item_count >> 4;
item_count |= item_count >> 8;
item_count |= item_count >> 16;
return item_count + 1;
}

259
src/hash_table.h Normal file
View file

@ -0,0 +1,259 @@
/**
* @file hash_table.h
* @author Radek Krejci <rkrejci@cesnet.cz>
* @author Michal Vasko <mvasko@cesnet.cz>
* @brief libyang hash table
*
* Copyright (c) 2015 - 2023 CESNET, z.s.p.o.
*
* This source code is licensed under BSD 3-Clause License (the "License").
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*/
#ifndef LY_HASH_TABLE_H_
#define LY_HASH_TABLE_H_
#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#include "log.h"
/**
* @struct ly_ht
* @brief libyang hash table.
*/
struct ly_ht;
/**
* @brief Compute hash from (several) string(s).
*
* Usage:
* - init hash to 0
* - repeatedly call ::lyht_hash_multi(), provide hash from the last call
* - call ::lyht_hash_multi() with key_part = NULL to finish the hash
*
* @param[in] hash Previous hash.
* @param[in] key_part Next key to hash,
* @param[in] len Length of @p key_part.
* @return Hash with the next key.
*/
LIBYANG_API_DECL uint32_t lyht_hash_multi(uint32_t hash, const char *key_part, size_t len);
/**
* @brief Compute hash from a string.
*
* Bob Jenkin's one-at-a-time hash
* http://www.burtleburtle.net/bob/hash/doobs.html
*
* Spooky hash is faster, but it works only for little endian architectures.
*
* @param[in] key Key to hash.
* @param[in] len Length of @p key.
* @return Hash of the key.
*/
LIBYANG_API_DECL uint32_t lyht_hash(const char *key, size_t len);
/**
* @brief Callback for checking hash table values equivalence.
*
* @param[in] val1_p Pointer to the first value, the one being searched (inserted/removed).
* @param[in] val2_p Pointer to the second value, the one stored in the hash table.
* @param[in] mod Whether the operation modifies the hash table (insert or remove) or not (find).
* @param[in] cb_data User callback data.
* @return false (non-equal) or true (equal).
*/
typedef ly_bool (*lyht_value_equal_cb)(void *val1_p, void *val2_p, ly_bool mod, void *cb_data);
/**
* @brief Create new hash table.
*
* @param[in] size Starting size of the hash table (capacity of values), must be power of 2.
* @param[in] val_size Size in bytes of value (the stored hashed item).
* @param[in] val_equal Callback for checking value equivalence.
* @param[in] cb_data User data always passed to @p val_equal.
* @param[in] resize Whether to resize the table on too few/too many records taken.
* @return Empty hash table, NULL on error.
*/
LIBYANG_API_DECL struct ly_ht *lyht_new(uint32_t size, uint16_t val_size, lyht_value_equal_cb val_equal, void *cb_data,
uint16_t resize);
/**
* @brief Set hash table value equal callback.
*
* @param[in] ht Hash table to modify.
* @param[in] new_val_equal New callback for checking value equivalence.
* @return Previous callback for checking value equivalence.
*/
LIBYANG_API_DECL lyht_value_equal_cb lyht_set_cb(struct ly_ht *ht, lyht_value_equal_cb new_val_equal);
/**
* @brief Set hash table value equal callback user data.
*
* @param[in] ht Hash table to modify.
* @param[in] new_cb_data New data for values callback.
* @return Previous data for values callback.
*/
LIBYANG_API_DECL void *lyht_set_cb_data(struct ly_ht *ht, void *new_cb_data);
/**
* @brief Make a duplicate of an existing hash table.
*
* @param[in] orig Original hash table to duplicate.
* @return Duplicated hash table @p orig, NULL on error.
*/
LIBYANG_API_DECL struct ly_ht *lyht_dup(const struct ly_ht *orig);
/**
* @brief Free a hash table.
*
* @param[in] ht Hash table to be freed.
* @param[in] val_free Optional callback for freeing all the stored values, @p val_p is a pointer to a stored value.
*/
LIBYANG_API_DECL void lyht_free(struct ly_ht *ht, void (*val_free)(void *val_p));
/**
* @brief Find a value in a hash table.
*
* @param[in] ht Hash table to search in.
* @param[in] val_p Pointer to the value to find.
* @param[in] hash Hash of the stored value.
* @param[out] match_p Pointer to the matching value, optional.
* @return LY_SUCCESS if value was found,
* @return LY_ENOTFOUND if not found.
*/
LIBYANG_API_DECL LY_ERR lyht_find(const struct ly_ht *ht, void *val_p, uint32_t hash, void **match_p);
/**
* @brief Find a value in a hash table but use a custom val_equal callback.
*
* @param[in] ht Hash table to search in.
* @param[in] val_p Pointer to the value to find.
* @param[in] hash Hash of the stored value.
* @param[in] val_equal Callback for checking value equivalence.
* @param[out] match_p Pointer to the matching value, optional.
* @return LY_SUCCESS if value was found,
* @return LY_ENOTFOUND if not found.
*/
LIBYANG_API_DECL LY_ERR lyht_find_with_val_cb(const struct ly_ht *ht, void *val_p, uint32_t hash,
lyht_value_equal_cb val_equal, void **match_p);
/**
* @brief Find another equal value in the hash table.
*
* @param[in] ht Hash table to search in.
* @param[in] val_p Pointer to the previously found value in @p ht.
* @param[in] hash Hash of the previously found value.
* @param[out] match_p Pointer to the matching value, optional.
* @return LY_SUCCESS if value was found,
* @return LY_ENOTFOUND if not found.
*/
LIBYANG_API_DECL LY_ERR lyht_find_next(const struct ly_ht *ht, void *val_p, uint32_t hash, void **match_p);
/**
* @brief Find another equal value in the hash table. Same functionality as ::lyht_find_next()
* but allows to specify a collision val equal callback to be used for checking for matching colliding values.
*
* @param[in] ht Hash table to search in.
* @param[in] val_p Pointer to the previously found value in @p ht.
* @param[in] hash Hash of the previously found value.
* @param[in] collision_val_equal Val equal callback to use for checking collisions.
* @param[out] match_p Pointer to the matching value, optional.
* @return LY_SUCCESS if value was found,
* @return LY_ENOTFOUND if not found.
*/
LIBYANG_API_DECL LY_ERR lyht_find_next_with_collision_cb(const struct ly_ht *ht, void *val_p, uint32_t hash,
lyht_value_equal_cb collision_val_equal, void **match_p);
/**
* @brief Insert a value into a hash table.
*
* @param[in] ht Hash table to insert into.
* @param[in] val_p Pointer to the value to insert. Be careful, if the values stored in the hash table
* are pointers, @p val_p must be a pointer to a pointer.
* @param[in] hash Hash of the stored value.
* @param[out] match_p Pointer to the stored value, optional
* @return LY_SUCCESS on success,
* @return LY_EEXIST in case the value is already present.
* @return LY_EMEM in case of memory allocation failure.
*/
LIBYANG_API_DECL LY_ERR lyht_insert(struct ly_ht *ht, void *val_p, uint32_t hash, void **match_p);
/**
* @brief Insert a value into a hash table, without checking whether the value has already been inserted.
*
* @param[in] ht Hash table to insert into.
* @param[in] val_p Pointer to the value to insert. Be careful, if the values stored in the hash table
* are pointers, @p val_p must be a pointer to a pointer.
* @param[in] hash Hash of the stored value.
* @param[out] match_p Pointer to the stored value, optional
* @return LY_SUCCESS on success,
* @return LY_EMEM in case of memory allocation failure.
*/
LIBYANG_API_DECL LY_ERR lyht_insert_no_check(struct ly_ht *ht, void *val_p, uint32_t hash, void **match_p);
/**
* @brief Insert a value into hash table. Same functionality as ::lyht_insert()
* but allows to specify a temporary val equal callback to be used in case the hash table
* will be resized after successful insertion.
*
* @param[in] ht Hash table to insert into.
* @param[in] val_p Pointer to the value to insert. Be careful, if the values stored in the hash table
* are pointers, @p val_p must be a pointer to a pointer.
* @param[in] hash Hash of the stored value.
* @param[in] resize_val_equal Val equal callback to use for resizing.
* @param[out] match_p Pointer to the stored value, optional
* @return LY_SUCCESS on success,
* @return LY_EEXIST in case the value is already present.
* @return LY_EMEM in case of memory allocation failure.
*/
LIBYANG_API_DECL LY_ERR lyht_insert_with_resize_cb(struct ly_ht *ht, void *val_p, uint32_t hash,
lyht_value_equal_cb resize_val_equal, void **match_p);
/**
* @brief Remove a value from a hash table.
*
* @param[in] ht Hash table to remove from.
* @param[in] val_p Pointer to value to be removed. Be careful, if the values stored in the hash table
* are pointers, @p val_p must be a pointer to a pointer.
* @param[in] hash Hash of the stored value.
* @return LY_SUCCESS on success,
* @return LY_ENOTFOUND if value was not found.
*/
LIBYANG_API_DECL LY_ERR lyht_remove(struct ly_ht *ht, void *val_p, uint32_t hash);
/**
* @brief Remove a value from a hash table. Same functionality as ::lyht_remove()
* but allows to specify a temporary val equal callback to be used in case the hash table
* will be resized after successful removal.
*
* @param[in] ht Hash table to remove from.
* @param[in] val_p Pointer to value to be removed. Be careful, if the values stored in the hash table
* are pointers, @p val_p must be a pointer to a pointer.
* @param[in] hash Hash of the stored value.
* @param[in] resize_val_equal Val equal callback to use for resizing.
* @return LY_SUCCESS on success,
* @return LY_ENOTFOUND if value was not found.
*/
LIBYANG_API_DECL LY_ERR lyht_remove_with_resize_cb(struct ly_ht *ht, void *val_p, uint32_t hash,
lyht_value_equal_cb resize_val_equal);
/**
* @brief Get suitable size of a hash table for a fixed number of items.
*
* @param[in] item_count Number of stored items.
* @return Hash table size.
*/
LIBYANG_API_DECL uint32_t lyht_get_fixed_size(uint32_t item_count);
#ifdef __cplusplus
}
#endif
#endif /* LY_HASH_TABLE_H_ */

146
src/hash_table_internal.h Normal file
View file

@ -0,0 +1,146 @@
/**
* @file hash_table_internal.h
* @author Radek Krejci <rkrejci@cesnet.cz>
* @author Michal Vasko <mvasko@cesnet.cz>
* @brief libyang hash table internal header
*
* Copyright (c) 2015 - 2023 CESNET, z.s.p.o.
*
* This source code is licensed under BSD 3-Clause License (the "License").
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*/
#ifndef LY_HASH_TABLE_INTERNAL_H_
#define LY_HASH_TABLE_INTERNAL_H_
#include <pthread.h>
#include <stddef.h>
#include <stdint.h>
#include "compat.h"
#include "hash_table.h"
/** reference value for 100% */
#define LYHT_HUNDRED_PERCENTAGE 100
/** when the table is at least this much percent full, it is enlarged (double the size) */
#define LYHT_ENLARGE_PERCENTAGE 75
/** only once the table is this much percent full, enable shrinking */
#define LYHT_FIRST_SHRINK_PERCENTAGE 50
/** when the table is less than this much percent full, it is shrunk (half the size) */
#define LYHT_SHRINK_PERCENTAGE 25
/** never shrink beyond this size */
#define LYHT_MIN_SIZE 8
/**
* @brief Generic hash table record.
*/
struct ly_ht_rec {
uint32_t hash; /* hash of the value */
uint32_t next; /* index of next collision */
unsigned char val[1]; /* arbitrary-size value */
} _PACKED;
/* real size, without taking the val[1] in account */
#define SIZEOF_LY_HT_REC (sizeof(struct ly_ht_rec) - 1)
struct ly_ht_hlist {
uint32_t first;
uint32_t last;
};
/**
* @brief (Very) generic hash table.
*
* This structure implements a hash table, providing fast accesses to stored
* values from their hash.
*
* The hash table structure contains 2 pointers to tables that are allocated
* at initialization:
* - a table of records: each record is composed of a struct ly_ht_rec header,
* followed by the user value. The header contains the hash value and a
* next index that can be used to chain records.
* - a table of list heads: each list head entry contains the index of the
* first record in the records table whose hash (modulo hash table size)
* is equal to the index of the list head entry. The other matching records
* are chained together.
*
* The unused records are chained in first_free_rec, which contains the index
* of the first unused record entry in the records table.
*
* The LYHT_NO_RECORD magic value is used when an index points to nothing.
*/
struct ly_ht {
uint32_t used; /* number of values stored in the hash table (filled records) */
uint32_t size; /* always holds 2^x == size (is power of 2), actually number of records allocated */
lyht_value_equal_cb val_equal; /* callback for testing value equivalence */
void *cb_data; /* user data callback arbitrary value */
uint16_t resize; /* 0 - resizing is disabled, *
* 1 - enlarging is enabled, *
* 2 - both shrinking and enlarging is enabled */
uint16_t rec_size; /* real size (in bytes) of one record for accessing recs array */
uint32_t first_free_rec; /* index of the first free record */
struct ly_ht_hlist *hlists; /* pointer to the hlists table */
unsigned char *recs; /* pointer to the hash table itself (array of struct ht_rec) */
};
/* index that points to nothing */
#define LYHT_NO_RECORD UINT32_MAX
/* get the record associated to */
static inline struct ly_ht_rec *
lyht_get_rec(unsigned char *recs, uint16_t rec_size, uint32_t idx)
{
return (struct ly_ht_rec *)&recs[idx * rec_size];
}
/* Iterate all records in a hlist */
#define LYHT_ITER_HLIST_RECS(ht, hlist_idx, rec_idx, rec) \
for (rec_idx = ht->hlists[hlist_idx].first, \
rec = lyht_get_rec(ht->recs, ht->rec_size, rec_idx); \
rec_idx != LYHT_NO_RECORD; \
rec_idx = rec->next, \
rec = lyht_get_rec(ht->recs, ht->rec_size, rec_idx))
/* Iterate all records in the hash table */
#define LYHT_ITER_ALL_RECS(ht, hlist_idx, rec_idx, rec) \
for (hlist_idx = 0; hlist_idx < ht->size; hlist_idx++) \
LYHT_ITER_HLIST_RECS(ht, hlist_idx, rec_idx, rec)
/**
* @brief Dictionary hash table record.
*/
struct ly_dict_rec {
char *value; /**< stored string */
uint32_t refcount; /**< reference count of the string */
};
/**
* @brief Dictionary for storing repeated strings.
*/
struct ly_dict {
struct ly_ht *hash_tab;
pthread_mutex_t lock;
};
/**
* @brief Initiate content (non-zero values) of the dictionary
*
* @param[in] dict Dictionary table to initiate
*/
void lydict_init(struct ly_dict *dict);
/**
* @brief Cleanup the dictionary content
*
* @param[in] dict Dictionary table to cleanup
*/
void lydict_clean(struct ly_dict *dict);
#endif /* LY_HASH_TABLE_INTERNAL_H_ */

329
src/in.c Normal file
View file

@ -0,0 +1,329 @@
/**
* @file in.c
* @author Radek Krejci <rkrejci@cesnet.cz>
* @brief libyang input functions.
*
* Copyright (c) 2015 - 2020 CESNET, z.s.p.o.
*
* This source code is licensed under BSD 3-Clause License (the "License").
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*/
#define _GNU_SOURCE
#define _POSIX_C_SOURCE 200809L /* strdup, strndup */
#include "in.h"
#include "in_internal.h"
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "compat.h"
#include "dict.h"
#include "log.h"
#include "ly_common.h"
#include "parser_data.h"
#include "parser_internal.h"
#include "set.h"
#include "tree.h"
#include "tree_data.h"
#include "tree_data_internal.h"
#include "tree_schema.h"
#include "tree_schema_internal.h"
LIBYANG_API_DEF LY_IN_TYPE
ly_in_type(const struct ly_in *in)
{
LY_CHECK_ARG_RET(NULL, in, LY_IN_ERROR);
return in->type;
}
LIBYANG_API_DEF LY_ERR
ly_in_reset(struct ly_in *in)
{
LY_CHECK_ARG_RET(NULL, in, LY_EINVAL);
in->current = in->func_start = in->start;
in->line = 1;
return LY_SUCCESS;
}
LIBYANG_API_DEF LY_ERR
ly_in_new_fd(int fd, struct ly_in **in)
{
size_t length;
char *addr;
LY_CHECK_ARG_RET(NULL, fd >= 0, in, LY_EINVAL);
LY_CHECK_RET(ly_mmap(NULL, fd, &length, (void **)&addr));
if (!addr) {
LOGERR(NULL, LY_EINVAL, "Empty input file.");
return LY_EINVAL;
}
*in = calloc(1, sizeof **in);
LY_CHECK_ERR_RET(!*in, LOGMEM(NULL); ly_munmap(addr, length), LY_EMEM);
(*in)->type = LY_IN_FD;
(*in)->method.fd = fd;
(*in)->current = (*in)->start = (*in)->func_start = addr;
(*in)->line = 1;
(*in)->length = length;
return LY_SUCCESS;
}
LIBYANG_API_DEF int
ly_in_fd(struct ly_in *in, int fd)
{
int prev_fd;
size_t length;
const char *addr;
LY_CHECK_ARG_RET(NULL, in, in->type == LY_IN_FD, -1);
prev_fd = in->method.fd;
if (fd != -1) {
LY_CHECK_RET(ly_mmap(NULL, fd, &length, (void **)&addr), -1);
if (!addr) {
LOGERR(NULL, LY_EINVAL, "Empty input file.");
return -1;
}
ly_munmap((char *)in->start, in->length);
in->method.fd = fd;
in->current = in->start = addr;
in->line = 1;
in->length = length;
}
return prev_fd;
}
LIBYANG_API_DEF LY_ERR
ly_in_new_file(FILE *f, struct ly_in **in)
{
LY_CHECK_ARG_RET(NULL, f, in, LY_EINVAL);
LY_CHECK_RET(ly_in_new_fd(fileno(f), in));
/* convert the LY_IN_FD input handler into the LY_IN_FILE */
(*in)->type = LY_IN_FILE;
(*in)->method.f = f;
return LY_SUCCESS;
}
LIBYANG_API_DEF FILE *
ly_in_file(struct ly_in *in, FILE *f)
{
FILE *prev_f;
LY_CHECK_ARG_RET(NULL, in, in->type == LY_IN_FILE, NULL);
prev_f = in->method.f;
if (f) {
/* convert LY_IN_FILE handler into LY_IN_FD to be able to update it via ly_in_fd() */
in->type = LY_IN_FD;
in->method.fd = fileno(prev_f);
if (ly_in_fd(in, fileno(f)) == -1) {
in->type = LY_IN_FILE;
in->method.f = prev_f;
return NULL;
}
/* if success, convert the result back */
in->type = LY_IN_FILE;
in->method.f = f;
}
return prev_f;
}
LIBYANG_API_DEF LY_ERR
ly_in_new_memory(const char *str, struct ly_in **in)
{
LY_CHECK_ARG_RET(NULL, str, in, LY_EINVAL);
*in = calloc(1, sizeof **in);
LY_CHECK_ERR_RET(!*in, LOGMEM(NULL), LY_EMEM);
(*in)->type = LY_IN_MEMORY;
(*in)->start = (*in)->current = (*in)->func_start = str;
(*in)->line = 1;
return LY_SUCCESS;
}
LIBYANG_API_DEF const char *
ly_in_memory(struct ly_in *in, const char *str)
{
const char *data;
LY_CHECK_ARG_RET(NULL, in, in->type == LY_IN_MEMORY, NULL);
data = in->current;
if (str) {
in->start = in->current = str;
in->line = 1;
}
return data;
}
LIBYANG_API_DEF LY_ERR
ly_in_new_filepath(const char *filepath, size_t len, struct ly_in **in)
{
LY_ERR ret;
char *fp;
int fd;
LY_CHECK_ARG_RET(NULL, filepath, in, LY_EINVAL);
if (len) {
fp = strndup(filepath, len);
} else {
fp = strdup(filepath);
}
fd = open(fp, O_RDONLY);
LY_CHECK_ERR_RET(fd == -1, LOGERR(NULL, LY_ESYS, "Failed to open file \"%s\" (%s).", fp, strerror(errno)); free(fp),
LY_ESYS);
LY_CHECK_ERR_RET(ret = ly_in_new_fd(fd, in), free(fp), ret);
/* convert the LY_IN_FD input handler into the LY_IN_FILE */
(*in)->type = LY_IN_FILEPATH;
(*in)->method.fpath.fd = fd;
(*in)->method.fpath.filepath = fp;
return LY_SUCCESS;
}
LIBYANG_API_DEF const char *
ly_in_filepath(struct ly_in *in, const char *filepath, size_t len)
{
int fd, prev_fd;
char *fp = NULL;
LY_CHECK_ARG_RET(NULL, in, in->type == LY_IN_FILEPATH, filepath ? NULL : ((void *)-1));
if (!filepath) {
return in->method.fpath.filepath;
}
if (len) {
fp = strndup(filepath, len);
} else {
fp = strdup(filepath);
}
/* replace filepath */
fd = open(fp, O_RDONLY);
LY_CHECK_ERR_RET(!fd, LOGERR(NULL, LY_ESYS, "Failed to open file \"%s\" (%s).", fp, strerror(errno)); free(fp), NULL);
/* convert LY_IN_FILEPATH handler into LY_IN_FD to be able to update it via ly_in_fd() */
in->type = LY_IN_FD;
prev_fd = ly_in_fd(in, fd);
LY_CHECK_ERR_RET(prev_fd == -1, in->type = LY_IN_FILEPATH; free(fp), NULL);
/* and convert the result back */
in->type = LY_IN_FILEPATH;
close(prev_fd);
free(in->method.fpath.filepath);
in->method.fpath.fd = fd;
in->method.fpath.filepath = fp;
return NULL;
}
LIBYANG_API_DEF size_t
ly_in_parsed(const struct ly_in *in)
{
LY_CHECK_ARG_RET(NULL, in, 0);
return in->current - in->func_start;
}
LIBYANG_API_DEF void
ly_in_free(struct ly_in *in, ly_bool destroy)
{
if (!in) {
return;
} else if (in->type == LY_IN_ERROR) {
LOGINT(NULL);
return;
}
if (destroy) {
if (in->type == LY_IN_MEMORY) {
free((char *)in->start);
} else {
ly_munmap((char *)in->start, in->length);
if (in->type == LY_IN_FILE) {
fclose(in->method.f);
} else {
close(in->method.fd);
if (in->type == LY_IN_FILEPATH) {
free(in->method.fpath.filepath);
}
}
}
} else if (in->type != LY_IN_MEMORY) {
ly_munmap((char *)in->start, in->length);
if (in->type == LY_IN_FILEPATH) {
close(in->method.fpath.fd);
free(in->method.fpath.filepath);
}
}
free(in);
}
LIBYANG_API_DEF LY_ERR
ly_in_read(struct ly_in *in, void *buf, size_t count)
{
LY_CHECK_ARG_RET(NULL, in, buf, LY_EINVAL);
if (in->length && (in->length - (in->current - in->start) < count)) {
/* EOF */
return LY_EDENIED;
}
if (count) {
memcpy(buf, in->current, count);
}
in->current += count;
return LY_SUCCESS;
}
LIBYANG_API_DEF LY_ERR
ly_in_skip(struct ly_in *in, size_t count)
{
LY_CHECK_ARG_RET(NULL, in, LY_EINVAL);
if (in->length && (in->length - (in->current - in->start) < count)) {
/* EOF */
return LY_EDENIED;
}
in->current += count;
return LY_SUCCESS;
}

252
src/in.h Normal file
View file

@ -0,0 +1,252 @@
/**
* @file in.h
* @author Radek Krejci <rkrejci@cesnet.cz>
* @brief libyang input structures and functions
*
* Copyright (c) 2020 CESNET, z.s.p.o.
*
* This source code is licensed under BSD 3-Clause License (the "License").
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*/
#ifndef LY_IN_H_
#define LY_IN_H_
#include <stdio.h>
#include "log.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @page howtoInput Input Processing
*
* libyang provides a mechanism to generalize work with the inputs (and [outputs](@ref howtoOutput)) of
* the different types. The ::ly_in handler can be created providing necessary information connected with the specific
* input type and then used throughout the parser functions processing the input data. Using a generic input handler avoids
* need to have a set of functions for each parser functionality and results in simpler API.
*
* The API allows to alter the source of the data behind the handler by another source. Also resetting a seekable source
* input is possible with ::ly_in_reset() to re-read the input.
*
* @note
* Currently, libyang supports only reading data from standard (disk) file, not from sockets, pipes, etc. The reason is
* that the parsers expects all the data to be present in the file (input data are complete). In future, we would like
* to change the internal mechanism and support sequential processing of the input data. In XML wording - we have DOM
* parser, but in future we would like to move to something like a SAX parser.
*
* @note
* This mechanism was introduced in libyang 2.0. To simplify transition from libyang 1.0 to version 2.0 and also for
* some simple use case where using the input handler would be an overkill, there are some basic parsers functions
* that do not require input handler. But remember, that functionality of these function can be limited in particular cases
* in contrast to the functions using input handlers.
*
* Functions List
* --------------
* - ::ly_in_new_fd()
* - ::ly_in_new_file()
* - ::ly_in_new_filepath()
* - ::ly_in_new_memory()
*
* - ::ly_in_fd()
* - ::ly_in_file()
* - ::ly_in_filepath()
* - ::ly_in_memory()
*
* - ::ly_in_type()
* - ::ly_in_parsed()
*
* - ::ly_in_reset()
* - ::ly_in_free()
*
* libyang Parsers List
* --------------------
* - @subpage howtoSchemaParsers
* - @subpage howtoDataParsers
*/
/**
* @struct ly_in
* @brief Parser input structure specifying where the data are read.
*/
struct ly_in;
/**
* @brief Types of the parser's inputs
*/
typedef enum LY_IN_TYPE {
LY_IN_ERROR = -1, /**< error value to indicate failure of the functions returning LY_IN_TYPE */
LY_IN_FD, /**< file descriptor printer */
LY_IN_FILE, /**< FILE stream parser */
LY_IN_FILEPATH, /**< filepath parser */
LY_IN_MEMORY /**< memory parser */
} LY_IN_TYPE;
/**
* @brief Get input type of the input handler.
*
* @param[in] in Input handler.
* @return Type of the parser's input.
*/
LIBYANG_API_DECL LY_IN_TYPE ly_in_type(const struct ly_in *in);
/**
* @brief Reset the input medium to read from its beginning, so the following parser function will read from the object's beginning.
*
* Note that in case the underlying output is not seekable (stream referring a pipe/FIFO/socket or the callback output type),
* nothing actually happens despite the function succeeds. Also note that the medium is not returned to the state it was when
* the handler was created. For example, file is seeked into the offset zero, not to the offset where it was opened when
* ::ly_in_new_file() was called.
*
* @param[in] in Input handler.
* @return LY_SUCCESS in case of success
* @return LY_ESYS in case of failure
*/
LIBYANG_API_DECL LY_ERR ly_in_reset(struct ly_in *in);
/**
* @brief Create input handler using file descriptor.
*
* @param[in] fd File descriptor to use.
* @param[out] in Created input handler supposed to be passed to different ly*_parse() functions.
* @return LY_SUCCESS in case of success
* @return LY_ERR value in case of failure.
*/
LIBYANG_API_DECL LY_ERR ly_in_new_fd(int fd, struct ly_in **in);
/**
* @brief Get or reset file descriptor input handler.
*
* @param[in] in Input handler.
* @param[in] fd Optional value of a new file descriptor for the handler. If -1, only the current file descriptor value is returned.
* @return Previous value of the file descriptor. Note that caller is responsible for closing the returned file descriptor in case of setting new descriptor @p fd.
* @return -1 in case of error when setting up the new file descriptor.
*/
LIBYANG_API_DECL int ly_in_fd(struct ly_in *in, int fd);
/**
* @brief Create input handler using file stream.
*
* @param[in] f File stream to use.
* @param[out] in Created input handler supposed to be passed to different ly*_parse() functions.
* @return LY_SUCCESS in case of success
* @return LY_ERR value in case of failure.
*/
LIBYANG_API_DECL LY_ERR ly_in_new_file(FILE *f, struct ly_in **in);
/**
* @brief Get or reset file stream input handler.
*
* @param[in] in Input handler.
* @param[in] f Optional new file stream for the handler. If NULL, only the current file stream is returned.
* @return NULL in case of invalid argument or an error when setting up the new input file, original input handler @p in is untouched in this case.
* @return Previous file stream of the handler. Note that caller is responsible for closing the returned stream in case of setting new stream @p f.
*/
LIBYANG_API_DECL FILE *ly_in_file(struct ly_in *in, FILE *f);
/**
* @brief Create input handler using memory to read data.
*
* @param[in] str Pointer where to start reading data. The input data are expected to be NULL-terminated.
* Note that in case the destroy argument of ::ly_in_free() is used, the input string is passed to free(),
* so if it is really a static string, do not use the destroy argument!
* @param[out] in Created input handler supposed to be passed to different ly*_parse() functions.
* @return LY_SUCCESS in case of success
* @return LY_ERR value in case of failure.
*/
LIBYANG_API_DECL LY_ERR ly_in_new_memory(const char *str, struct ly_in **in);
/**
* @brief Get or change memory where the data are read from.
*
* @param[in] in Input handler.
* @param[in] str String containing the data to read. The input data are expected to be NULL-terminated.
* Note that in case the destroy argument of ::ly_in_free() is used, the input string is passed to free(),
* so if it is really a static string, do not use the destroy argument!
* @return Previous starting address to read data from. Note that the caller is responsible to free
* the data in case of changing string pointer @p str.
*/
LIBYANG_API_DECL const char *ly_in_memory(struct ly_in *in, const char *str);
/**
* @brief Create input handler file of the given filename.
*
* @param[in] filepath Path of the file where to read data.
* @param[in] len Optional number of bytes to use from @p filepath. If 0, the @p filepath is considered to be NULL-terminated and
* the whole string is taken into account.
* @param[out] in Created input handler supposed to be passed to different ly*_parse() functions.
* @return LY_SUCCESS in case of success
* @return LY_ERR value in case of failure.
*/
LIBYANG_API_DECL LY_ERR ly_in_new_filepath(const char *filepath, size_t len, struct ly_in **in);
/**
* @brief Get or change the filepath of the file where the parser reads the data.
*
* Note that in case of changing the filepath, the current file is closed and a new one is
* created/opened instead of renaming the previous file. Also note that the previous filepath
* string is returned only in case of not changing it's value.
*
* @param[in] in Input handler.
* @param[in] filepath Optional new filepath for the handler. If and only if NULL, the current filepath string is returned.
* @param[in] len Optional number of bytes to use from @p filepath. If 0, the @p filepath is considered to be NULL-terminated and
* the whole string is taken into account.
* @return Previous filepath string in case the @p filepath argument is NULL.
* @return NULL if changing filepath succeedes and ((void *)-1) otherwise.
*/
LIBYANG_API_DECL const char *ly_in_filepath(struct ly_in *in, const char *filepath, size_t len);
/**
* @brief Get the number of parsed bytes by the last function.
*
* @param[in] in In structure used.
* @return Number of parsed bytes.
*/
LIBYANG_API_DECL size_t ly_in_parsed(const struct ly_in *in);
/**
* @brief Free the input handler.
*
* @param[in] in Input handler to free.
* @param[in] destroy Flag to free the input data buffer (for LY_IN_MEMORY) or to
* close stream/file descriptor (for LY_IN_FD and LY_IN_FILE)
*/
LIBYANG_API_DECL void ly_in_free(struct ly_in *in, ly_bool destroy);
/**
* @brief Read bytes from an input.
*
* Does not count new lines, which is expected from the caller who has better idea about
* the content of the read data and can better optimize counting.
*
* @param[in] in Input structure.
* @param[in] buf Destination buffer.
* @param[in] count Number of bytes to read.
* @return LY_SUCCESS on success,
* @return LY_EDENIED on EOF.
*/
LIBYANG_API_DECL LY_ERR ly_in_read(struct ly_in *in, void *buf, size_t count);
/**
* @brief Just skip bytes in an input.
*
* Does not count new lines, which is expected from the caller who has better idea about
* the content of the skipped data and can better optimize counting.
*
* @param[in] in Input structure.
* @param[in] count Number of bytes to skip.
* @return LY_SUCCESS on success,
* @return LY_EDENIED on EOF.
*/
LIBYANG_API_DECL LY_ERR ly_in_skip(struct ly_in *in, size_t count);
#ifdef __cplusplus
}
#endif
#endif /* LY_IN_H_ */

50
src/in_internal.h Normal file
View file

@ -0,0 +1,50 @@
/**
* @file in_internal.h
* @author Radek Krejci <rkrejci@cesnet.cz>
* @author Michal Vasko <mvasko@cesnet.cz>
* @brief Internal structures and functions for libyang parsers
*
* Copyright (c) 2020 - 2023 CESNET, z.s.p.o.
*
* This source code is licensed under BSD 3-Clause License (the "License").
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*/
#ifndef LY_IN_INTERNAL_H_
#define LY_IN_INTERNAL_H_
#include "in.h"
/**
* @brief Parser input structure specifying where the data are read.
*/
struct ly_in {
LY_IN_TYPE type; /**< type of the output to select the output method */
const char *current; /**< Current position in the input data */
const char *func_start; /**< Input data position when the last parser function was executed */
const char *start; /**< Input data start */
size_t length; /**< mmap() length (if used) */
union {
int fd; /**< file descriptor for LY_IN_FD type */
FILE *f; /**< file structure for LY_IN_FILE and LY_IN_FILEPATH types */
struct {
int fd; /**< file descriptor for LY_IN_FILEPATH */
char *filepath; /**< stored original filepath */
} fpath; /**< filepath structure for LY_IN_FILEPATH */
} method; /**< type-specific information about the output */
uint64_t line; /**< current line of the input */
};
/**
* @brief Increment line counter.
* @param[in] IN The input handler.
*/
#define LY_IN_NEW_LINE(IN) \
(IN)->line++
#endif /* LY_IN_INTERNAL_H_ */

1096
src/json.c Normal file

File diff suppressed because it is too large Load diff

150
src/json.h Normal file
View file

@ -0,0 +1,150 @@
/**
* @file json.h
* @author Radek Krejci <rkrejci@cesnet.cz>
* @author Michal Vasko <mvasko@cesnet.cz>
* @brief Generic JSON format parser routines.
*
* Copyright (c) 2020 - 2023 CESNET, z.s.p.o.
*
* This source code is licensed under BSD 3-Clause License (the "License").
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*/
#ifndef LY_JSON_H_
#define LY_JSON_H_
#include <stddef.h>
#include <stdint.h>
#include "log.h"
#include "set.h"
struct ly_ctx;
struct ly_in;
#define LYJSON_STRING_BUF_START 24
#define LYJSON_STRING_BUF_STEP 128
/* Macro to test if character is whitespace */
#define is_jsonws(c) (c == 0x20 || c == 0x9 || c == 0xa || c == 0xd)
/* Macro to test if character is valid string character */
#define is_jsonstrchar(c) (c == 0x20 || c == 0x21 || (c >= 0x23 && c <= 0x5b) || (c >= 0x5d && c <= 0x10ffff))
/* Macro to push JSON parser status */
#define LYJSON_STATUS_PUSH_RET(CTX, STATUS) \
LY_CHECK_RET(ly_set_add(&CTX->status, (void *)(uintptr_t)(STATUS), 1, NULL))
/* Macro to pop JSON parser status */
#define LYJSON_STATUS_POP(CTX) \
assert(CTX->status.count); CTX->status.count--;
/**
* @brief Status of the parser providing information what is expected next (which function is supposed to be called).
*/
enum LYJSON_PARSER_STATUS {
LYJSON_ERROR = 0, /* JSON parser error - value is used as an error return code */
LYJSON_OBJECT, /* JSON object */
LYJSON_OBJECT_NEXT, /* JSON object next item */
LYJSON_OBJECT_CLOSED, /* JSON object closed */
LYJSON_ARRAY, /* JSON array */
LYJSON_ARRAY_NEXT, /* JSON array next item */
LYJSON_ARRAY_CLOSED, /* JSON array closed */
LYJSON_OBJECT_NAME, /* JSON object name */
LYJSON_NUMBER, /* JSON number value */
LYJSON_STRING, /* JSON string value */
LYJSON_TRUE, /* JSON true value */
LYJSON_FALSE, /* JSON false value */
LYJSON_NULL, /* JSON null value */
LYJSON_END /* end of input data */
};
struct lyjson_ctx {
const struct ly_ctx *ctx;
struct ly_in *in; /* input structure */
struct ly_set status; /* stack of ::LYJSON_PARSER_STATUS values corresponding to the JSON items being processed */
const char *value; /* ::LYJSON_STRING, ::LYJSON_NUMBER, ::LYJSON_OBJECT_NAME */
size_t value_len; /* ::LYJSON_STRING, ::LYJSON_NUMBER, ::LYJSON_OBJECT_NAME */
ly_bool dynamic; /* ::LYJSON_STRING, ::LYJSON_NUMBER, ::LYJSON_OBJECT_NAME */
struct {
enum LYJSON_PARSER_STATUS status;
uint32_t status_count;
const char *value;
size_t value_len;
ly_bool dynamic;
const char *input;
} backup;
};
/**
* @brief Get string representation of the JSON context status (token).
*
* @param[in] status Context status (aka JSON token)
* @return String representation of the @p status.
*/
const char *lyjson_token2str(enum LYJSON_PARSER_STATUS status);
/**
* @brief Get current status of the parser.
*
* @param[in] jsonctx JSON parser context to check.
* @return ::LYJSON_PARSER_STATUS according to the last parsed token.
*/
enum LYJSON_PARSER_STATUS lyjson_ctx_status(struct lyjson_ctx *jsonctx);
/**
* @brief Get current nesting (object/array) depth.
*
* @param[in] jsonctx JSON parser context to check.
* @return Current nesting depth.
*/
uint32_t lyjson_ctx_depth(struct lyjson_ctx *jsonctx);
/**
* @brief Create a new JSON parser context and start parsing.
*
* @param[in] ctx libyang context.
* @param[in] in JSON string data to parse.
* @param[in] subtree Whether this is a special case of parsing a subtree (starting with object name).
* @param[out] jsonctx New JSON parser context with status referring the parsed value.
* @return LY_ERR value.
*/
LY_ERR lyjson_ctx_new(const struct ly_ctx *ctx, struct ly_in *in, struct lyjson_ctx **jsonctx);
/**
* @brief Move to the next JSON artifact and update parser status.
*
* @param[in] jsonctx XML context to move.
* @param[out] status Optional parameter to provide new parser status
* @return LY_ERR value.
*/
LY_ERR lyjson_ctx_next(struct lyjson_ctx *jsonctx, enum LYJSON_PARSER_STATUS *status);
/**
* @brief Backup the JSON parser context's state To restore the backup, use ::lyjson_ctx_restore().
*
* @param[in] jsonctx JSON parser context to backup.
*/
void lyjson_ctx_backup(struct lyjson_ctx *jsonctx);
/**
* @brief Restore the JSON parser context's state from the backup created by ::lyjson_ctx_backup().
*
* @param[in] jsonctx JSON parser context to restore.
*/
void lyjson_ctx_restore(struct lyjson_ctx *jsonctx);
/**
* @brief Remove the allocated working memory of the context.
*
* @param[in] jsonctx JSON parser context to clear.
*/
void lyjson_ctx_free(struct lyjson_ctx *jsonctx);
#endif /* LY_JSON_H_ */

178
src/libyang.h Normal file
View file

@ -0,0 +1,178 @@
/**
* @file libyang.h
* @author Radek Krejci <rkrejci@cesnet.cz>
* @author Michal Vasko <mvasko@cesnet.cz>
* @brief The main libyang public header.
*
* Copyright (c) 2015 - 2024 CESNET, z.s.p.o.
*
* This source code is licensed under BSD 3-Clause License (the "License").
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*/
#ifndef LY_LIBYANG_H_
#define LY_LIBYANG_H_
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#include "context.h"
#include "dict.h"
#include "in.h"
#include "log.h"
#include "metadata.h"
#include "out.h"
#include "parser_data.h"
#include "parser_schema.h"
#include "printer_data.h"
#include "printer_schema.h"
#include "set.h"
#include "tree.h"
#include "tree_data.h"
#include "tree_schema.h"
/**
* @brief libyang v3 compatibility macros with v2.
*/
#define ly_strerrcode ly_strerr
#define ly_last_errmsg ly_last_logmsg
#define ly_errcode(ctx) (ly_err_last(ctx) ? ly_err_last(ctx)->err : 0)
#define ly_errmsg(ctx) (ly_err_last(ctx) ? ly_err_last(ctx)->msg : NULL)
#define ly_errpath(ctx) (ly_err_last(ctx) ? (ly_err_last(ctx)->data_path ? ly_err_last(ctx)->data_path : ly_err_last(ctx)->schema_path) : NULL)
#define ly_vecode(ctx) (ly_err_last(ctx) ? ly_err_last(ctx)->vecode : 0)
/*
* The following headers are supposed to be included explicitly:
* - hash_table.h
* - metadata.h
* - plugins_types.h
* - plugins_exts.h
*/
/**
* @mainpage About
*
* libyang is a library implementing processing of the YANG schemas and data modeled by the YANG language. The
* library is implemented in C for GNU/Linux and provides C API.
*
* @section about-features Main Features
*
* - [Parsing (and validating) schemas](@ref howtoSchema) in YANG format.
* - [Parsing (and validating) schemas](@ref howtoSchema) in YIN format.
* - [Parsing, validating and printing instance data](@ref howtoData) in XML format.
* - [Parsing, validating and printing instance data](@ref howtoData) in JSON format
* ([RFC 7951](https://tools.ietf.org/html/rfc7951)).
* - [Manipulation with the instance data](@ref howtoDataManipulation).
* - Support for [default values in the instance data](@ref howtoDataWD) ([RFC 6243](https://tools.ietf.org/html/rfc6243)).
* - Support for [YANG extensions and user types](@ref howtoPlugins).
* - Support for [YANG Metadata](@ref howtoDataMetadata) ([RFC 7952](https://tools.ietf.org/html/rfc6243)).
* - Support for [YANG Schema Mount](@ref howtoDataMountpoint) ([RFC 8528](https://tools.ietf.org/html/rfc8528)).
*
* The current implementation covers YANG 1.0 ([RFC 6020](https://tools.ietf.org/html/rfc6020)) as well as
* YANG 1.1 ([RFC 7950](https://tools.ietf.org/html/rfc7950)).
*
* @section about-license License
*
* Copyright (c) 2015-2024 CESNET, z.s.p.o.
*
* (The BSD 3-Clause License)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name of the Company nor the names of its contributors
* may be used to endorse or promote products derived from this
* software without specific prior written permission.
*/
/**
* @page howto libyang API Overview
*
* @section howtoGeneral General notes
*
* libyang is primarily intended for handling data modeled by YANG modeling language, so the library is supposed to be optimized
* for this purpose. However, as a side effect, the library has to be able precisely process YANG modules. Thus, it is usable by
* YANG module authors to validate their modules and schemas in the development process.
*
* - @subpage howtoStructures
* - @subpage howtoErrors
* - @subpage howtoLogger
* - @subpage howtoThreads
* - @subpage howtoContext
* - @subpage howtoInput
* - @subpage howtoOutput
* - @subpage howtoSchema
* - @subpage howtoData
* - @subpage howtoXPath
* - @subpage howtoPlugins
*/
/**
* @page howtoStructures Data Structures
*
* @section sizedarrays Sized Arrays
*
* The structure starts with 32bit number storing size of the array - the number of the items inside. The size is part of the
* array to have it allocated together with the array itself only when it is needed. However, the pointers to the array always
* points after the 32b number, so items can be accessed directly as for standard C arrays. Because of a known size (available
* via ::LY_ARRAY_COUNT macro), it is not terminated by any special byte (sequence), so there is also no limitation for specific
* content of the stored records (e.g. that first byte must not be NULL).
*
* The sized arrays must be carefully freed (which should be done anyway only internally), since pointers to the sized arrays used
* in libyang structures, does not point to the beginning of the allocated space.
*
* - ::LY_ARRAY_COUNT
* - ::LY_ARRAY_FOR
*
* @section struct_lists Lists
*
* The lists are structures connected via a `next` and `prev` pointers. Iterating over the siblings can be simply done by
* ::LY_LIST_FOR macro. Examples of such structures are ::lyd_node or ::lysc_node.
*
* The `prev` pointer is always filled. In case there is just a single item in the list, the `prev` pointer points to the
* item itself. Otherwise, the `prev` pointer of the first item points to the last item of the list. In contrast, the
* `next` pointer of the last item in the list is always NULL.
*/
/**
* @page howtoThreads Threading Limitations
*
* @section context Context
*
* It is safe to read from ::ly_ctx structure concurrently and use its dictionary, which is protected by a lock.
* Thread-safe functions include any ones working with data trees (only context dictionary is accessed) and all
* the `ly_ctx_get_*()` functions. Generally, they are the functions with `const` context parameter.
*
* @section data Data Trees
*
* Data trees are not internally synchronized so the general safe practice of a single writer **or** several concurrent
* readers should be followed. Specifically, only the functions with non-const ::lyd_node parameters modify the node(s)
* and no concurrent execution of such functions should be allowed on a single data tree or subtrees of one.
*/
/**
* @internal
* @page internals Developers' Notes
* @tableofcontents
*
* Following texts describes various internal subsystems and mechanism in libyang which are hidden from external users, but important
* for libyang developers. The texts should explain various decisions made and internal processes utilized in libyang.
*/
#ifdef __cplusplus
}
#endif
#endif /* LY_LIBYANG_H_ */

985
src/log.c Normal file
View file

@ -0,0 +1,985 @@
/**
* @file log.c
* @author Radek Krejci <rkrejci@cesnet.cz>
* @author Michal Vasko <mvasko@cesnet.cz>
* @brief Logger routines implementations
*
* Copyright (c) 2015 - 2023 CESNET, z.s.p.o.
*
* This source code is licensed under BSD 3-Clause License (the "License").
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*/
#define _GNU_SOURCE /* asprintf, strdup */
#include "log.h"
#include <assert.h>
#include <inttypes.h>
#include <pthread.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "compat.h"
#include "in_internal.h"
#include "ly_common.h"
#include "plugins_exts.h"
#include "set.h"
#include "tree_data.h"
#include "tree_data_internal.h"
#include "tree_schema.h"
#include "tree_schema_internal.h"
ATOMIC_T ly_ll = (uint_fast32_t)LY_LLWRN;
ATOMIC_T ly_log_opts = (uint_fast32_t)(LY_LOLOG | LY_LOSTORE_LAST);
THREAD_LOCAL uint32_t *temp_ly_log_opts;
static ly_log_clb log_clb;
THREAD_LOCAL char last_msg[LY_LAST_MSG_SIZE];
#ifndef NDEBUG
ATOMIC_T ly_ldbg_groups = 0;
#endif
THREAD_LOCAL struct ly_log_location_s log_location = {0};
LIBYANG_API_DEF const char *
ly_strerr(LY_ERR err)
{
/* ignore plugin flag */
err &= ~LY_EPLUGIN;
switch (err) {
case LY_SUCCESS:
return "Success";
case LY_EMEM:
return "Out of memory";
case LY_ESYS:
return "System call failed";
case LY_EINVAL:
return "Invalid value";
case LY_EEXIST:
return "Already exists";
case LY_ENOTFOUND:
return "Not found";
case LY_EINT:
return "Internal error";
case LY_EVALID:
return "Validation failed";
case LY_EDENIED:
return "Operation denied";
case LY_EINCOMPLETE:
return "Operation incomplete";
case LY_ERECOMPILE:
return "Recompilation required";
case LY_ENOT:
return "Negative result";
case LY_EOTHER:
return "Another failure reason";
case LY_EPLUGIN:
break;
}
/* unreachable */
return "Unknown";
}
LIBYANG_API_DEF const char *
ly_strvecode(LY_VECODE vecode)
{
switch (vecode) {
case LYVE_SUCCESS:
return "Success";
case LYVE_SYNTAX:
return "General syntax error";
case LYVE_SYNTAX_YANG:
return "YANG syntax error";
case LYVE_SYNTAX_YIN:
return "YIN syntax error";
case LYVE_REFERENCE:
return "Reference error";
case LYVE_XPATH:
return "XPath error";
case LYVE_SEMANTICS:
return "Semantic error";
case LYVE_SYNTAX_XML:
return "XML syntax error";
case LYVE_SYNTAX_JSON:
return "JSON syntax error";
case LYVE_DATA:
return "YANG data error";
case LYVE_OTHER:
return "Another error";
}
/* unreachable */
return "Unknown";
}
LIBYANG_API_DEF const char *
ly_last_logmsg(void)
{
return last_msg;
}
LIBYANG_API_DEF LY_ERR
ly_err_new(struct ly_err_item **err, LY_ERR ecode, LY_VECODE vecode, char *data_path, char *apptag,
const char *err_format, ...)
{
char *msg = NULL;
struct ly_err_item *e;
if (!err || (ecode == LY_SUCCESS)) {
/* nothing to do */
return ecode;
}
e = calloc(1, sizeof *e);
LY_CHECK_ERR_RET(!e, LOGMEM(NULL), LY_EMEM);
e->prev = (*err) ? (*err)->prev : e;
if (*err) {
(*err)->prev->next = e;
}
/* fill in the information */
e->level = LY_LLERR;
e->err = ecode;
e->vecode = vecode;
e->data_path = data_path;
e->apptag = apptag;
if (err_format) {
va_list print_args;
va_start(print_args, err_format);
if (vasprintf(&msg, err_format, print_args) == -1) {
/* we don't have anything more to do, just set msg to NULL to avoid undefined content,
* still keep the information about the original error instead of LY_EMEM or other printf's error */
msg = NULL;
}
va_end(print_args);
}
e->msg = msg;
if (!(*err)) {
*err = e;
}
return e->err;
}
/**
* @brief Get error record from error hash table of a context for the current thread.
*
* @param[in] ctx Context to use.
* @return Thread error record, if any.
*/
static struct ly_ctx_err_rec *
ly_err_get_rec(const struct ly_ctx *ctx)
{
struct ly_ctx_err_rec rec, *match;
/* prepare record */
rec.tid = pthread_self();
/* get the pointer to the matching record */
if (lyht_find(ctx->err_ht, &rec, lyht_hash((void *)&rec.tid, sizeof rec.tid), (void **)&match)) {
return NULL;
}
return match;
}
/**
* @brief Insert new error record to error hash table of a context for the current thread.
*
* @param[in] ctx Context to use.
* @return Thread error record.
*/
static struct ly_ctx_err_rec *
ly_err_new_rec(const struct ly_ctx *ctx)
{
struct ly_ctx_err_rec new, *rec;
LY_ERR r;
/* insert a new record */
new.err = NULL;
new.tid = pthread_self();
/* reuse lock */
/* LOCK */
pthread_mutex_lock((pthread_mutex_t *)&ctx->lyb_hash_lock);
r = lyht_insert(ctx->err_ht, &new, lyht_hash((void *)&new.tid, sizeof new.tid), (void **)&rec);
/* UNLOCK */
pthread_mutex_unlock((pthread_mutex_t *)&ctx->lyb_hash_lock);
return r ? NULL : rec;
}
LIBYANG_API_DEF const struct ly_err_item *
ly_err_first(const struct ly_ctx *ctx)
{
struct ly_ctx_err_rec *rec;
LY_CHECK_ARG_RET(NULL, ctx, NULL);
/* get the pointer to the matching record */
rec = ly_err_get_rec(ctx);
return rec ? rec->err : NULL;
}
LIBYANG_API_DEF const struct ly_err_item *
ly_err_last(const struct ly_ctx *ctx)
{
struct ly_ctx_err_rec *rec;
LY_CHECK_ARG_RET(NULL, ctx, NULL);
/* get the pointer to the matching record */
if (!(rec = ly_err_get_rec(ctx))) {
return NULL;
}
return rec->err ? rec->err->prev : NULL;
}
void
ly_err_move(struct ly_ctx *src_ctx, struct ly_ctx *trg_ctx)
{
struct ly_ctx_err_rec *rec;
struct ly_err_item *err = NULL;
/* get and remove the errors from src */
rec = ly_err_get_rec(src_ctx);
if (rec) {
err = rec->err;
rec->err = NULL;
}
/* set them for trg */
if (!(rec = ly_err_get_rec(trg_ctx))) {
if (!(rec = ly_err_new_rec(trg_ctx))) {
LOGINT(NULL);
ly_err_free(err);
return;
}
}
ly_err_free(rec->err);
rec->err = err;
}
LIBYANG_API_DEF void
ly_err_free(void *ptr)
{
struct ly_err_item *e, *next;
/* clean the error list */
LY_LIST_FOR_SAFE(ptr, next, e) {
free(e->msg);
free(e->data_path);
free(e->schema_path);
free(e->apptag);
free(e);
}
}
LIBYANG_API_DEF void
ly_err_clean(struct ly_ctx *ctx, struct ly_err_item *eitem)
{
struct ly_ctx_err_rec *rec;
struct ly_err_item *e;
if (!(rec = ly_err_get_rec(ctx))) {
return;
}
if (rec->err == eitem) {
eitem = NULL;
}
if (!eitem) {
/* free all err */
ly_err_free(rec->err);
rec->err = NULL;
} else {
/* disconnect the error */
for (e = rec->err; e && (e->next != eitem); e = e->next) {}
assert(e);
e->next = NULL;
rec->err->prev = e;
/* free this err and newer */
ly_err_free(eitem);
}
}
LIBYANG_API_DEF LY_LOG_LEVEL
ly_log_level(LY_LOG_LEVEL level)
{
LY_LOG_LEVEL prev = ATOMIC_LOAD_RELAXED(ly_ll);
ATOMIC_STORE_RELAXED(ly_ll, level);
return prev;
}
LIBYANG_API_DEF uint32_t
ly_log_options(uint32_t opts)
{
uint32_t prev = ATOMIC_LOAD_RELAXED(ly_log_opts);
ATOMIC_STORE_RELAXED(ly_log_opts, opts);
return prev;
}
LIBYANG_API_DEF uint32_t *
ly_temp_log_options(uint32_t *opts)
{
uint32_t *prev_lo = temp_ly_log_opts;
temp_ly_log_opts = opts;
return prev_lo;
}
LIBYANG_API_DEF uint32_t
ly_log_dbg_groups(uint32_t dbg_groups)
{
#ifndef NDEBUG
uint32_t prev = ATOMIC_LOAD_RELAXED(ly_ldbg_groups);
ATOMIC_STORE_RELAXED(ly_ldbg_groups, dbg_groups);
return prev;
#else
(void)dbg_groups;
return 0;
#endif
}
LIBYANG_API_DEF void
ly_set_log_clb(ly_log_clb clb)
{
log_clb = clb;
}
LIBYANG_API_DEF ly_log_clb
ly_get_log_clb(void)
{
return log_clb;
}
void
ly_log_location(const struct lysc_node *scnode, const struct lyd_node *dnode, const char *spath, const struct ly_in *in)
{
if (scnode) {
ly_set_add(&log_location.scnodes, (void *)scnode, 1, NULL);
}
if (dnode || (!scnode && !spath && !in)) {
ly_set_add(&log_location.dnodes, (void *)dnode, 1, NULL);
}
if (spath) {
char *s = strdup(spath);
LY_CHECK_ERR_RET(!s, LOGMEM(NULL), );
ly_set_add(&log_location.spaths, s, 1, NULL);
}
if (in) {
ly_set_add(&log_location.inputs, (void *)in, 1, NULL);
}
}
void
ly_log_location_revert(uint32_t scnode_steps, uint32_t dnode_steps, uint32_t spath_steps, uint32_t in_steps)
{
for (uint32_t i = scnode_steps; i && log_location.scnodes.count; i--) {
log_location.scnodes.count--;
}
for (uint32_t i = dnode_steps; i && log_location.dnodes.count; i--) {
log_location.dnodes.count--;
}
for (uint32_t i = spath_steps; i && log_location.spaths.count; i--) {
ly_set_rm_index(&log_location.spaths, log_location.spaths.count - 1, free);
}
for (uint32_t i = in_steps; i && log_location.inputs.count; i--) {
log_location.inputs.count--;
}
/* deallocate the empty sets */
if (scnode_steps && !log_location.scnodes.count) {
ly_set_erase(&log_location.scnodes, NULL);
}
if (dnode_steps && !log_location.dnodes.count) {
ly_set_erase(&log_location.dnodes, NULL);
}
if (spath_steps && !log_location.spaths.count) {
ly_set_erase(&log_location.spaths, free);
}
if (in_steps && !log_location.inputs.count) {
ly_set_erase(&log_location.inputs, NULL);
}
}
const struct lyd_node *
ly_log_location_dnode(uint32_t idx)
{
if (idx < log_location.dnodes.count) {
return log_location.dnodes.dnodes[idx];
}
return NULL;
}
uint32_t
ly_log_location_dnode_count(void)
{
return log_location.dnodes.count;
}
/**
* @brief Store generated error in a context.
*
* @param[in] ctx Context to use.
* @param[in] level Message log level.
* @param[in] err Error number.
* @param[in] vecode Error validation error code.
* @param[in] msg Error message, always spent.
* @param[in] data_path Error data path, always spent.
* @param[in] schema_path Error schema path, always spent.
* @param[in] line Error input line, if any.
* @param[in] apptag Error app tag, always spent.
* @return LY_ERR value.
*/
static LY_ERR
log_store(const struct ly_ctx *ctx, LY_LOG_LEVEL level, LY_ERR err, LY_VECODE vecode, char *msg, char *data_path,
char *schema_path, uint64_t line, char *apptag)
{
struct ly_ctx_err_rec *rec;
struct ly_err_item *e, *last;
assert(ctx && (level < LY_LLVRB));
if (!(rec = ly_err_get_rec(ctx))) {
if (!(rec = ly_err_new_rec(ctx))) {
goto mem_fail;
}
}
e = rec->err;
if (!e) {
/* if we are only to fill in path, there must have been an error stored */
assert(msg);
e = calloc(1, sizeof *e);
LY_CHECK_GOTO(!e, mem_fail);
e->prev = e;
e->next = NULL;
rec->err = e;
} else if (!msg) {
/* only filling the path */
assert(data_path || schema_path);
/* find last error */
e = e->prev;
do {
if (e->level == LY_LLERR) {
/* fill the path */
if (data_path) {
free(e->data_path);
e->data_path = data_path;
} else {
free(e->schema_path);
e->schema_path = schema_path;
}
return LY_SUCCESS;
}
e = e->prev;
} while (e->prev->next);
/* last error was not found */
assert(0);
} else if ((temp_ly_log_opts && ((*temp_ly_log_opts & LY_LOSTORE_LAST) == LY_LOSTORE_LAST)) ||
(!temp_ly_log_opts && ((ATOMIC_LOAD_RELAXED(ly_log_opts) & LY_LOSTORE_LAST) == LY_LOSTORE_LAST))) {
/* overwrite last message */
free(e->msg);
free(e->data_path);
free(e->schema_path);
free(e->apptag);
} else {
/* store new message */
last = e->prev;
e->prev = calloc(1, sizeof *e);
LY_CHECK_GOTO(!e->prev, mem_fail);
e = e->prev;
e->prev = last;
e->next = NULL;
last->next = e;
}
/* fill in the information */
e->level = level;
e->err = err;
e->vecode = vecode;
e->msg = msg;
e->data_path = data_path;
e->schema_path = schema_path;
e->line = line;
e->apptag = apptag;
return LY_SUCCESS;
mem_fail:
LOGMEM(NULL);
free(msg);
free(data_path);
free(schema_path);
free(apptag);
return LY_EMEM;
}
/**
* @brief Log data path/schema path/line to stderr after the message has been printed.
*
* @param[in] data_path Error data path.
* @param[in] schema_path Error schema path.
* @param[in] line Error input line.
*/
static void
log_stderr_path_line(const char *data_path, const char *schema_path, uint64_t line)
{
ly_bool par = 0;
if (data_path) {
fprintf(stderr, "%sdata path: %s", " (", data_path);
par = 1;
}
if (schema_path) {
fprintf(stderr, "%sschemadata path: %s", par ? ", " : " (", schema_path);
par = 1;
}
if (line) {
fprintf(stderr, "%sline: %" PRIu64, par ? ", " : " (", line);
par = 1;
}
fprintf(stderr, par ? ")\n" : "\n");
}
/**
* @brief Log a message.
*
* @param[in] ctx Context to use.
* @param[in] level Message log level.
* @param[in] err Error number.
* @param[in] vecode Error validation error code.
* @param[in] data_path Error data path, always spent.
* @param[in] schema_path Error schema path, always spent.
* @param[in] line Error input line, if any.
* @param[in] apptag Error app tag.
* @param[in] format Error message format.
* @param[in] args Error message format arguments.
*/
static void
log_vprintf(const struct ly_ctx *ctx, LY_LOG_LEVEL level, LY_ERR err, LY_VECODE vecode, char *data_path,
char *schema_path, uint64_t line, const char *apptag, const char *format, va_list args)
{
char *dyn_msg = NULL;
const char *msg;
ly_bool free_strs = 1, lolog, lostore;
/* learn effective logger options */
if (temp_ly_log_opts) {
lolog = *temp_ly_log_opts & LY_LOLOG;
lostore = *temp_ly_log_opts & LY_LOSTORE;
} else {
lolog = ATOMIC_LOAD_RELAXED(ly_log_opts) & LY_LOLOG;
lostore = ATOMIC_LOAD_RELAXED(ly_log_opts) & LY_LOSTORE;
}
if (level > ATOMIC_LOAD_RELAXED(ly_ll)) {
/* do not print or store the message */
goto cleanup;
}
if (err == LY_EMEM) {
/* no not use more dynamic memory */
vsnprintf(last_msg, LY_LAST_MSG_SIZE, format, args);
msg = last_msg;
} else {
/* print into a single message */
if (vasprintf(&dyn_msg, format, args) == -1) {
LOGMEM(ctx);
goto cleanup;
}
msg = dyn_msg;
/* store as the last message */
strncpy(last_msg, msg, LY_LAST_MSG_SIZE - 1);
}
/* store the error/warning in the context (if we need to store errors internally, it does not matter what are
* the user log options), if the message is not dynamic, it would most likely fail to store (no memory) */
if ((level < LY_LLVRB) && ctx && lostore && dyn_msg) {
free_strs = 0;
if (log_store(ctx, level, err, vecode, dyn_msg, data_path, schema_path, line, apptag ? strdup(apptag) : NULL)) {
goto cleanup;
}
}
/* if we are only storing errors internally, never print the message (yet) */
if (lolog) {
if (log_clb) {
log_clb(level, msg, data_path, schema_path, line);
} else {
fprintf(stderr, "libyang[%d]: ", level);
fprintf(stderr, "%s", msg);
log_stderr_path_line(data_path, schema_path, line);
}
}
cleanup:
if (free_strs) {
free(data_path);
free(schema_path);
free(dyn_msg);
}
}
#ifndef NDEBUG
void
ly_log_dbg(uint32_t group, const char *format, ...)
{
char *dbg_format;
const char *str_group;
va_list ap;
if (!(ATOMIC_LOAD_RELAXED(ly_ldbg_groups) & group)) {
return;
}
switch (group) {
case LY_LDGDICT:
str_group = "DICT";
break;
case LY_LDGXPATH:
str_group = "XPATH";
break;
case LY_LDGDEPSETS:
str_group = "DEPSETS";
break;
default:
LOGINT(NULL);
return;
}
if (asprintf(&dbg_format, "%s: %s", str_group, format) == -1) {
LOGMEM(NULL);
return;
}
va_start(ap, format);
log_vprintf(NULL, LY_LLDBG, 0, 0, NULL, NULL, 0, NULL, dbg_format, ap);
va_end(ap);
free(dbg_format);
}
#endif
void
ly_log(const struct ly_ctx *ctx, LY_LOG_LEVEL level, LY_ERR err, const char *format, ...)
{
va_list ap;
va_start(ap, format);
log_vprintf(ctx, level, err, 0, NULL, NULL, 0, NULL, format, ap);
va_end(ap);
}
/**
* @brief Append a schema node name to a generated data path, only if it fits.
*
* @param[in,out] str Generated path to update.
* @param[in] snode Schema node to append.
* @param[in] parent Last printed data node.
* @return LY_ERR value.
*/
static LY_ERR
ly_vlog_build_path_append(char **str, const struct lysc_node *snode, const struct lyd_node *parent)
{
const struct lys_module *mod, *prev_mod;
uint32_t len, new_len;
void *mem;
if (snode->nodetype & (LYS_CHOICE | LYS_CASE)) {
/* schema-only node */
return LY_SUCCESS;
} else if (lysc_data_parent(snode) != lyd_node_schema(parent)) {
/* not a direct descendant node */
return LY_SUCCESS;
}
/* get module to print, if any */
mod = snode->module;
prev_mod = lyd_node_module(parent);
if (prev_mod == mod) {
mod = NULL;
}
/* realloc string */
len = *str ? strlen(*str) : 0;
new_len = len + 1 + (mod ? strlen(mod->name) + 1 : 0) + strlen(snode->name);
mem = realloc(*str, new_len + 1);
LY_CHECK_ERR_RET(!mem, LOGMEM(LYD_CTX(parent)), LY_EMEM);
*str = mem;
/* print the last schema node */
sprintf(*str + len, "/%s%s%s", mod ? mod->name : "", mod ? ":" : "", snode->name);
return LY_SUCCESS;
}
LY_ERR
ly_vlog_build_data_path(const struct ly_ctx *ctx, char **path)
{
LY_ERR rc = LY_SUCCESS;
const struct lyd_node *dnode = NULL;
*path = NULL;
if (log_location.dnodes.count) {
dnode = log_location.dnodes.objs[log_location.dnodes.count - 1];
if (!dnode) {
/* special root node */
assert(log_location.dnodes.count == 1);
*path = strdup("/");
LY_CHECK_ERR_GOTO(!*path, LOGMEM(ctx); rc = LY_EMEM, cleanup);
goto cleanup;
}
if (dnode->parent || !lysc_data_parent(dnode->schema)) {
/* data node with all of its parents */
*path = lyd_path(log_location.dnodes.objs[log_location.dnodes.count - 1], LYD_PATH_STD, NULL, 0);
LY_CHECK_ERR_GOTO(!*path, LOGMEM(ctx); rc = LY_EMEM, cleanup);
} else {
/* data parsers put all the parent nodes in the set, but they are not connected */
*path = lyd_path_set(&log_location.dnodes, LYD_PATH_STD);
LY_CHECK_ERR_GOTO(!*path, LOGMEM(ctx); rc = LY_EMEM, cleanup);
}
}
/* sometimes the last node is not created yet and we only have the schema node */
if (log_location.scnodes.count) {
rc = ly_vlog_build_path_append(path, log_location.scnodes.objs[log_location.scnodes.count - 1], dnode);
LY_CHECK_GOTO(rc, cleanup);
}
cleanup:
if (rc) {
free(*path);
*path = NULL;
}
return rc;
}
/**
* @brief Build log path/input line from the stored log location information.
*
* @param[in] ctx Context to use.
* @param[out] data_path Generated data path.
* @param[out] schema_path Generated data path.
* @param[out] line Input line.
* @return LY_ERR value.
*/
static LY_ERR
ly_vlog_build_path_line(const struct ly_ctx *ctx, char **data_path, char **schema_path, uint64_t *line)
{
*data_path = NULL;
*schema_path = NULL;
*line = 0;
if (log_location.spaths.count && ((const char *)(log_location.spaths.objs[log_location.spaths.count - 1]))[0]) {
/* simply get what is in the provided path string */
*schema_path = strdup(log_location.spaths.objs[log_location.spaths.count - 1]);
LY_CHECK_ERR_RET(!*schema_path, LOGMEM(ctx), LY_EMEM);
} else {
/* data/schema node */
if (log_location.dnodes.count) {
LY_CHECK_RET(ly_vlog_build_data_path(ctx, data_path));
} else if (log_location.scnodes.count) {
*schema_path = lysc_path(log_location.scnodes.objs[log_location.scnodes.count - 1], LYSC_PATH_LOG, NULL, 0);
LY_CHECK_ERR_RET(!*schema_path, LOGMEM(ctx), LY_EMEM);
}
}
/* line */
if (log_location.inputs.count) {
*line = ((struct ly_in *)log_location.inputs.objs[log_location.inputs.count - 1])->line;
}
return LY_SUCCESS;
}
void
ly_vlog(const struct ly_ctx *ctx, const char *apptag, LY_VECODE code, const char *format, ...)
{
va_list ap;
char *data_path = NULL, *schema_path = NULL;
uint64_t line = 0;
if (ctx) {
ly_vlog_build_path_line(ctx, &data_path, &schema_path, &line);
}
va_start(ap, format);
log_vprintf(ctx, LY_LLERR, LY_EVALID, code, data_path, schema_path, line, apptag, format, ap);
/* path is spent and should not be freed! */
va_end(ap);
}
/**
* @brief Print a log message from an extension plugin callback.
*
* @param[in] ctx libyang context to store the error record. If not provided, the error is just printed.
* @param[in] plugin_name Name of the plugin generating the message.
* @param[in] level Log message level (error, warning, etc.)
* @param[in] err Error type code.
* @param[in] data_path Error data path, always spent.
* @param[in] schema_path Error schema path, always spent.
* @param[in] line Error input line, if any.
* @param[in] format Format string to print.
* @param[in] ap Var arg list for @p format.
*/
static void
ly_ext_log(const struct ly_ctx *ctx, const char *plugin_name, LY_LOG_LEVEL level, LY_ERR err, char *data_path,
char *schema_path, uint64_t line, const char *format, va_list ap)
{
char *plugin_msg;
if (ATOMIC_LOAD_RELAXED(ly_ll) < level) {
return;
}
if (asprintf(&plugin_msg, "Ext plugin \"%s\": %s", plugin_name, format) == -1) {
LOGMEM(ctx);
return;
}
log_vprintf(ctx, level, (level == LY_LLERR ? LY_EPLUGIN : 0) | err, LYVE_OTHER, data_path, schema_path, line, NULL,
plugin_msg, ap);
free(plugin_msg);
}
LIBYANG_API_DEF void
lyplg_ext_parse_log(const struct lysp_ctx *pctx, const struct lysp_ext_instance *ext, LY_LOG_LEVEL level, LY_ERR err,
const char *format, ...)
{
va_list ap;
char *data_path, *schema_path;
uint64_t line;
ly_vlog_build_path_line(PARSER_CTX(pctx), &data_path, &schema_path, &line);
va_start(ap, format);
ly_ext_log(PARSER_CTX(pctx), ext->record->plugin.id, level, err, data_path, schema_path, line, format, ap);
va_end(ap);
}
LIBYANG_API_DEF void
lyplg_ext_compile_log(const struct lysc_ctx *cctx, const struct lysc_ext_instance *ext, LY_LOG_LEVEL level, LY_ERR err,
const char *format, ...)
{
va_list ap;
char *schema_path = NULL;
if (cctx && !(schema_path = strdup(cctx->path))) {
LOGMEM(cctx->ctx);
return;
}
va_start(ap, format);
ly_ext_log(ext->module->ctx, ext->def->plugin->id, level, err, NULL, schema_path, 0, format, ap);
va_end(ap);
}
LIBYANG_API_DEF void
lyplg_ext_compile_log_path(const char *path, const struct lysc_ext_instance *ext, LY_LOG_LEVEL level, LY_ERR err,
const char *format, ...)
{
va_list ap;
char *schema_path = NULL;
if (path && !(schema_path = strdup(path))) {
LOGMEM(ext->module->ctx);
return;
}
va_start(ap, format);
ly_ext_log(ext->module->ctx, ext->def->plugin->id, level, err, NULL, schema_path, 0, format, ap);
va_end(ap);
}
/**
* @brief Serves only for creating ap.
*/
static void
_lyplg_ext_compile_log_err(const struct ly_err_item *eitem, const struct lysc_ext_instance *ext, ...)
{
va_list ap;
char *data_path = NULL, *schema_path = NULL;
if (eitem->data_path) {
data_path = strdup(eitem->data_path);
}
if (eitem->schema_path) {
schema_path = strdup(eitem->schema_path);
}
va_start(ap, ext);
ly_ext_log(ext->module->ctx, ext->def->plugin->id, eitem->level, eitem->err, data_path, schema_path, eitem->line, "%s", ap);
va_end(ap);
}
LIBYANG_API_DEF void
lyplg_ext_compile_log_err(const struct ly_err_item *eitem, const struct lysc_ext_instance *ext)
{
_lyplg_ext_compile_log_err(eitem, ext, eitem->msg);
}
/**
* @brief Exact same functionality as ::ly_err_print() but has variable arguments so log_vprintf() can be called.
*/
static void
_ly_err_print(const struct ly_ctx *ctx, const struct ly_err_item *eitem, const char *format, ...)
{
va_list ap;
char *data_path = NULL, *schema_path = NULL;
LY_CHECK_ARG_RET(ctx, eitem, );
if (eitem->data_path) {
data_path = strdup(eitem->data_path);
}
if (eitem->schema_path) {
schema_path = strdup(eitem->schema_path);
}
va_start(ap, format);
log_vprintf(ctx, eitem->level, eitem->err, eitem->vecode, data_path, schema_path, eitem->line, eitem->apptag, format, ap);
va_end(ap);
}
LIBYANG_API_DEF void
ly_err_print(const struct ly_ctx *ctx, const struct ly_err_item *eitem)
{
/* String ::ly_err_item.msg cannot be used directly because it may contain the % character */
_ly_err_print(ctx, eitem, "%s", eitem->msg);
}

361
src/log.h Normal file
View file

@ -0,0 +1,361 @@
/**
* @file log.h
* @author Radek Krejci <rkrejci@cesnet.cz>
* @author Michal Vasko <mvasko@cesnet.cz>
* @brief Logger manipulation routines and error definitions.
*
* Copyright (c) 2015 - 2022 CESNET, z.s.p.o.
*
* This source code is licensed under BSD 3-Clause License (the "License").
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*/
#ifndef LY_LOG_H_
#define LY_LOG_H_
#include <stdint.h>
#include "ly_config.h"
#ifdef __cplusplus
extern "C" {
#endif
/* dummy context structure */
struct ly_ctx;
/**
* @brief Type to indicate boolean value.
*
* Do not test for actual value. Instead, handle it as true/false value in condition.
*/
typedef uint8_t ly_bool;
/**
* @page howtoLogger Information Logging
*
* The libyang logger is supposed to process all the messages (and some other accompanied information) generated by the performed
* functions. According to the logger settings, the information can be printed, stored or further processed by a callback
* functions.
*
* The logger is tightly connected with [errors handling](@ref howtoErrors), because when an error appears, the logger (according
* to [logger options](@ref logopts)) generates error records available via libyang context.
*
* There are 4 verbosity levels defined as ::LY_LOG_LEVEL. The level can be changed by the ::ly_log_level() function.
* By default, the verbosity level is set to #LY_LLERR value, so only the errors are processed.
*
* By default, all libyang messages are printed to `stderr`. However, the callers are able to set their own logging callback
* function (::ly_log_clb). In that case, instead of printing messages, libyang passes error level, message and path (if any) to
* the caller's callback function set via ::ly_set_log_clb(). In case of error level, the error information is still
* automatically stored and available via the [error handling functions](@ref howtoErrors).
*
* With [logging options](@ref logopts) set via ::ly_log_options(), the caller can modify what is done with all the messages.
* Default flags are ::LY_LOLOG and ::LY_LOSTORE_LAST so that messages are logged and the last one is stored. If you set the flag
* ::LY_LOSTORE, all the messages will be stored. Be careful because unless you regularly clean them, the error list in context
* will grow indefinitely.
*
* As a separate group, there are @ref dbggroup to select group of debugging messages to print. The options can be set via
* ::ly_log_dbg_groups() function, but note that the options take effect only in case the libyang is compiled in
* [Debug build mode](@ref build).
*
* \note API for this group of functions is described in the [logger module](@ref log).
*
* Functions List
* --------------
* - ::ly_log_level()
* - ::ly_log_dbg_groups()
* - ::ly_log_options()
* - ::ly_set_log_clb()
* - ::ly_get_log_clb()
*
*/
/**
* @defgroup log Logger
* @{
*
* Publicly visible functions and values of the libyang logger. For more
* information, see @ref howtoLogger.
*/
/**
* @typedef LY_LOG_LEVEL
* @brief Verbosity levels of the libyang logger.
*/
typedef enum {
LY_LLERR = 0, /**< Print only error messages. */
LY_LLWRN = 1, /**< Print error and warning messages, default value. */
LY_LLVRB = 2, /**< Besides errors and warnings, print some other verbose messages. */
LY_LLDBG = 3 /**< Print all messages including some development debug messages (be careful,
without subsequently calling ::ly_log_dbg_groups() no debug messages will be printed!). */
} LY_LOG_LEVEL;
/**
* @brief Set logger verbosity level.
*
* To get the current value, the function must be called twice resetting the level by the received value.
*
* @param[in] level Verbosity level.
* @return Previous verbosity level.
*/
LIBYANG_API_DECL LY_LOG_LEVEL ly_log_level(LY_LOG_LEVEL level);
/**
* @ingroup log
* @defgroup logopts Logging options
*
* Logging option bits of libyang.
*
* Can be set via ::ly_log_options().
*
* @{
*/
#define LY_LOLOG 0x01 /**< Log messages normally, using callback if set. If not set, messages will
not be printed by libyang. */
#define LY_LOSTORE 0x02 /**< Store any generated errors or warnings, never verbose or debug messages.
Note that if #LY_LOLOG is not set then verbose and debug messages are always lost. */
#define LY_LOSTORE_LAST 0x06 /**< Store any generated errors or warnings but only the last message, always overwrite
the previous one. */
/**
* @}
*/
/**
* @brief Set logger options. Default is #LY_LOLOG | #LY_LOSTORE_LAST.
*
* To get the current value, the function must be called twice resetting the level by the received value.
*
* @param[in] opts Bitfield of @ref logopts.
* @return Previous logger options.
*/
LIBYANG_API_DECL uint32_t ly_log_options(uint32_t opts);
/**
* @brief Set temporary thread-safe logger options overwriting those set by ::ly_log_options().
*
* @param[in] opts Pointer to the temporary @ref logopts. If NULL, restores the effect of global logger options.
* @return Previous temporary options.
*/
LIBYANG_API_DECL uint32_t *ly_temp_log_options(uint32_t *opts);
/**
* @ingroup log
* @defgroup dbggroup Debug messages groups
*
* Categories of the debug messages.
*
* Allows to show only the selected group(s) of the debug messages.
*
* @{
*/
#define LY_LDGDICT 0x01 /**< Dictionary additions and deletions. */
#define LY_LDGXPATH 0x02 /**< XPath parsing end evaluation. */
#define LY_LDGDEPSETS 0x04 /**< Dependency module sets for schema compilation. */
/**
* @}
*/
/**
* @brief Enable specific debugging messages (independent of log level).
*
* To get the current value, the function must be called twice resetting the level by the received value.
* Note: does not have any effect on non-debug (Release) builds
*
* @param[in] dbg_groups Bitfield of enabled debug message groups (see @ref dbggroup).
* @return Previous options bitfield.
*/
LIBYANG_API_DECL uint32_t ly_log_dbg_groups(uint32_t dbg_groups);
/**
* @brief Logger callback.
*
* @param[in] level Log level of the message.
* @param[in] msg Message.
* @param[in] data_path Optional data path of the related node.
* @param[in] schema_path Optional schema path of the related node.
* @param[in] line Optional related input line.
*/
typedef void (*ly_log_clb)(LY_LOG_LEVEL level, const char *msg, const char *data_path, const char *schema_path,
uint64_t line);
/**
* @brief Set logger callback.
*
* @param[in] clb Logging callback.
*/
LIBYANG_API_DECL void ly_set_log_clb(ly_log_clb clb);
/**
* @brief Get logger callback.
*
* @return Logger callback (can be NULL).
*/
LIBYANG_API_DECL ly_log_clb ly_get_log_clb(void);
/** @} log */
/**
* @page howtoErrors Errors Handling
*
* The most of the API functions directly returns error code in the form of ::LY_ERR value. In addition, if the ::LY_EVALID error
* arises, additional [validation error code](@ref ::LY_VECODE) is provided to categorize validation failures into several groups.
*
* All the errors arisen in connection with manipulation with the [context](@ref howtoContext), [YANG modules](@ref howtoSchema)
* or [YANG data](@ref howtoData), are recorded into the context and can be examined for the more detailed information. These
* records are stored as ::ly_err_item structures and they are not only context-specific, but also thread-specific.
*
* Storing error information is tightly connected with
* [logging](@ref howtoLogger). So the @ref logopts control if and which errors are stored in the context. By default, only the
* last error is recorded, so a new error replaces the previous one. This can be changed with ::LY_LOSTORE option set via
* ::ly_log_options(). Then, the errors are stored as a list preserving the previous error records. The stored records can be
* accessed using ::ly_err_last() or ::ly_err_first() functions. The ::ly_err_clean() is used to remove error records from the
* context.
*
* To print a specific error information via libyang logger, there is ::ly_err_print().
*
* \note API for this group of functions is described in the [error information module](@ref errors).
*/
/**
* @defgroup errors Error information
*
* Structures and functions to allow error information processing.
*
* @{
*/
/**
* @typedef LY_ERR
* @brief libyang's error codes returned by the libyang functions.
*/
typedef enum {
LY_SUCCESS = 0, /**< no error, not set by functions, included just to complete #LY_ERR enumeration */
LY_EMEM, /**< Memory allocation failure */
LY_ESYS, /**< System call failure */
LY_EINVAL, /**< Invalid value */
LY_EEXIST, /**< Item already exists */
LY_ENOTFOUND, /**< Item does not exists */
LY_EINT, /**< Internal error */
LY_EVALID, /**< Validation failure */
LY_EDENIED, /**< Operation is not allowed */
LY_EINCOMPLETE, /**< The operation did not fail, but for some reason it was not possible to finish it completely.
According to the specific use case, the caller is usually supposed to perform the operation again. */
LY_ERECOMPILE, /**< The operation did not fail, but requires context recompilation before it can be completed.
According to the specific use case, the caller should react appropriately. */
LY_ENOT, /**< Negative result */
LY_EOTHER, /**< Unknown error */
LY_EPLUGIN = 128/**< Error reported by a plugin - the highest bit in the first byte is set.
This value is used ORed with one of the other LY_ERR value and can be simply masked. */
} LY_ERR;
/**
* @ingroup log
* @typedef LY_VECODE
* @brief libyang's codes of validation error. Whenever ly_errno is set to LY_EVALID, the ly_vecode is also set
* to the appropriate LY_VECODE value.
*/
typedef enum {
LYVE_SUCCESS = 0, /**< no error */
LYVE_SYNTAX, /**< generic syntax error */
LYVE_SYNTAX_YANG, /**< YANG-related syntax error */
LYVE_SYNTAX_YIN, /**< YIN-related syntax error */
LYVE_REFERENCE, /**< invalid referencing or using an item */
LYVE_XPATH, /**< invalid XPath expression */
LYVE_SEMANTICS, /**< generic semantic error */
LYVE_SYNTAX_XML, /**< XML-related syntax error */
LYVE_SYNTAX_JSON, /**< JSON-related syntax error */
LYVE_DATA, /**< YANG data does not reflect some of the module restrictions */
LYVE_OTHER /**< Unknown error */
} LY_VECODE;
/**
* @brief Libyang full error structure.
*/
struct ly_err_item {
LY_LOG_LEVEL level; /**< error (message) log level */
LY_ERR err; /**< error code number */
LY_VECODE vecode; /**< validation error code, if any */
char *msg; /**< error message */
char *data_path; /**< error data path related to the error, if any */
char *schema_path; /**< error schema path related to the error, if any */
uint64_t line; /**< input line the error occured on, if available */
char *apptag; /**< error-app-tag, if any */
struct ly_err_item *next; /**< next error item */
struct ly_err_item *prev; /**< previous error item, points to the last item for the ifrst item */
};
/**
* @brief Get human-readable error message for an error code.
*
* @param[in] err Error code.
* @return String error message.
*/
LIBYANG_API_DECL const char *ly_strerr(LY_ERR err);
/**
* @brief Get human-readable error message for a validation error code.
*
* @param[in] vecode Validation error code.
* @return String error message.
*/
LIBYANG_API_DECL const char *ly_strvecode(LY_VECODE vecode);
/**
* @brief Get the last (thread-specific) full logged error message.
*
* This function is useful for getting errors from functions that do not have any context accessible and includes
* any additional information such as the path or line where the error occurred.
*
* @return Last generated error message.
*/
LIBYANG_API_DECL const char *ly_last_logmsg(void);
/**
* @brief Get the first (thread, context-specific) generated error structure.
*
* @param[in] ctx Relative context.
* @return First error structure, NULL if none available.
*/
LIBYANG_API_DECL const struct ly_err_item *ly_err_first(const struct ly_ctx *ctx);
/**
* @brief Get the latest (thread, context-specific) generated error structure.
*
* @param[in] ctx Relative context.
* @return Last error structure, NULL if none available.
*/
LIBYANG_API_DECL const struct ly_err_item *ly_err_last(const struct ly_ctx *ctx);
/**
* @brief Print the error structure as if just generated.
*
* @param[in] ctx Optional context to store the message in.
* @param[in] eitem Error item structure to print.
*/
LIBYANG_API_DECL void ly_err_print(const struct ly_ctx *ctx, const struct ly_err_item *eitem);
/**
* @brief Free error structures from a context.
*
* If @p eitem is not set, free all the error structures.
*
* @param[in] ctx Relative context.
* @param[in] eitem Oldest error structure to remove, optional.
*/
LIBYANG_API_DECL void ly_err_clean(struct ly_ctx *ctx, struct ly_err_item *eitem);
/** @} errors */
#ifdef __cplusplus
}
#endif
#endif /* LY_LOG_H_ */

941
src/ly_common.c Normal file
View file

@ -0,0 +1,941 @@
/**
* @file ly_common.c
* @author Michal Vasko <mvasko@cesnet.cz>
* @brief common internal definitions for libyang
*
* Copyright (c) 2018 - 2024 CESNET, z.s.p.o.
*
* This source code is licensed under BSD 3-Clause License (the "License").
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*/
#define _GNU_SOURCE
#include "ly_common.h"
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef _WIN32
# ifdef HAVE_MMAP
# include <sys/mman.h>
# endif
#else
# include <io.h>
#endif
#include <sys/stat.h>
#include <unistd.h>
#include "compat.h"
#include "tree_schema_internal.h"
#include "version.h"
#include "xml.h"
LIBYANG_API_DEF struct ly_version ly_version_so = {
.major = LY_VERSION_MAJOR,
.minor = LY_VERSION_MINOR,
.micro = LY_VERSION_MICRO,
.str = LY_VERSION
};
LIBYANG_API_DEF struct ly_version ly_version_proj = {
.major = LY_PROJ_VERSION_MAJOR,
.minor = LY_PROJ_VERSION_MINOR,
.micro = LY_PROJ_VERSION_MICRO,
.str = LY_PROJ_VERSION
};
void *
ly_realloc(void *ptr, size_t size)
{
void *new_mem;
new_mem = realloc(ptr, size);
if (!new_mem) {
free(ptr);
}
return new_mem;
}
char *
ly_strnchr(const char *s, int c, size_t len)
{
for ( ; len && (*s != (char)c); ++s, --len) {}
return len ? (char *)s : NULL;
}
int
ly_strncmp(const char *refstr, const char *str, size_t str_len)
{
int rc = strncmp(refstr, str, str_len);
if (!rc && (refstr[str_len] == '\0')) {
return 0;
} else {
return rc ? rc : 1;
}
}
LY_ERR
ly_strntou8(const char *nptr, size_t len, uint8_t *ret)
{
uint8_t num = 0, dig;
uint16_t dec_pow;
if (len > 3) {
/* overflow for sure */
return LY_EDENIED;
}
dec_pow = 1;
for ( ; len && isdigit(nptr[len - 1]); --len) {
dig = nptr[len - 1] - 48;
if (LY_OVERFLOW_MUL(UINT8_MAX, dig, dec_pow)) {
return LY_EDENIED;
}
dig *= dec_pow;
if (LY_OVERFLOW_ADD(UINT8_MAX, num, dig)) {
return LY_EDENIED;
}
num += dig;
dec_pow *= 10;
}
if (len) {
return LY_EVALID;
}
*ret = num;
return LY_SUCCESS;
}
LY_ERR
ly_value_prefix_next(const char *str_begin, const char *str_end, uint32_t *len, ly_bool *is_prefix, const char **str_next)
{
const char *stop, *prefix;
size_t bytes_read;
uint32_t c;
ly_bool prefix_found;
LY_ERR ret = LY_SUCCESS;
assert(len && is_prefix && str_next);
#define IS_AT_END(PTR, STR_END) (STR_END ? PTR == STR_END : !(*PTR))
*str_next = NULL;
*is_prefix = 0;
*len = 0;
if (!str_begin || !(*str_begin) || (str_begin == str_end)) {
return ret;
}
stop = str_begin;
prefix = NULL;
prefix_found = 0;
do {
/* look for the beginning of the YANG value */
do {
LY_CHECK_RET(ly_getutf8(&stop, &c, &bytes_read));
} while (!is_xmlqnamestartchar(c) && !IS_AT_END(stop, str_end));
if (IS_AT_END(stop, str_end)) {
break;
}
/* maybe the prefix was found */
prefix = stop - bytes_read;
/* look for the the end of the prefix */
do {
LY_CHECK_RET(ly_getutf8(&stop, &c, &bytes_read));
} while (is_xmlqnamechar(c) && !IS_AT_END(stop, str_end));
prefix_found = c == ':' ? 1 : 0;
/* if it wasn't the prefix, keep looking */
} while (!IS_AT_END(stop, str_end) && !prefix_found);
if ((str_begin == prefix) && prefix_found) {
/* prefix found at the beginning of the input string */
*is_prefix = 1;
*str_next = IS_AT_END(stop, str_end) ? NULL : stop;
*len = (stop - bytes_read) - str_begin;
} else if ((str_begin != prefix) && (prefix_found)) {
/* there is a some string before prefix */
*str_next = prefix;
*len = prefix - str_begin;
} else {
/* no prefix found */
*len = stop - str_begin;
}
#undef IS_AT_END
return ret;
}
LY_ERR
ly_getutf8(const char **input, uint32_t *utf8_char, size_t *bytes_read)
{
uint32_t c, aux;
size_t len;
c = (*input)[0];
if (!(c & 0x80)) {
/* one byte character */
len = 1;
if ((c < 0x20) && (c != 0x9) && (c != 0xa) && (c != 0xd)) {
goto error;
}
} else if ((c & 0xe0) == 0xc0) {
/* two bytes character */
len = 2;
aux = (*input)[1];
if ((aux & 0xc0) != 0x80) {
goto error;
}
c = ((c & 0x1f) << 6) | (aux & 0x3f);
if (c < 0x80) {
goto error;
}
} else if ((c & 0xf0) == 0xe0) {
/* three bytes character */
len = 3;
c &= 0x0f;
for (uint64_t i = 1; i <= 2; i++) {
aux = (*input)[i];
if ((aux & 0xc0) != 0x80) {
goto error;
}
c = (c << 6) | (aux & 0x3f);
}
if ((c < 0x800) || ((c > 0xd7ff) && (c < 0xe000)) || (c > 0xfffd)) {
goto error;
}
} else if ((c & 0xf8) == 0xf0) {
/* four bytes character */
len = 4;
c &= 0x07;
for (uint64_t i = 1; i <= 3; i++) {
aux = (*input)[i];
if ((aux & 0xc0) != 0x80) {
goto error;
}
c = (c << 6) | (aux & 0x3f);
}
if ((c < 0x1000) || (c > 0x10ffff)) {
goto error;
}
} else {
goto error;
}
(*utf8_char) = c;
(*input) += len;
if (bytes_read) {
(*bytes_read) = len;
}
return LY_SUCCESS;
error:
if (bytes_read) {
(*bytes_read) = 0;
}
return LY_EINVAL;
}
/**
* @brief Check whether an UTF-8 string is equal to a hex string after a bitwise and.
*
* (input & 0x[arg1][arg3][arg5]...) == 0x[arg2][arg4][arg6]...
*
* @param[in] input UTF-8 string.
* @param[in] bytes Number of bytes to compare.
* @param[in] ... 2x @p bytes number of bytes to perform bitwise and and equality operations.
* @return Result of the operation.
*/
static int
ly_utf8_and_equal(const char *input, int bytes, ...)
{
va_list ap;
int i, and, byte;
va_start(ap, bytes);
for (i = 0; i < bytes; ++i) {
and = va_arg(ap, int);
byte = va_arg(ap, int);
/* compare each byte */
if (((uint8_t)input[i] & and) != (uint8_t)byte) {
return 0;
}
}
va_end(ap);
return 1;
}
/**
* @brief Check whether an UTF-8 string is smaller than a hex string.
*
* input < 0x[arg1][arg2]...
*
* @param[in] input UTF-8 string.
* @param[in] bytes Number of bytes to compare.
* @param[in] ... @p bytes number of bytes to compare with.
* @return Result of the operation.
*/
static int
ly_utf8_less(const char *input, int bytes, ...)
{
va_list ap;
int i, byte;
va_start(ap, bytes);
for (i = 0; i < bytes; ++i) {
byte = va_arg(ap, int);
/* compare until bytes differ */
if ((uint8_t)input[i] > (uint8_t)byte) {
return 0;
} else if ((uint8_t)input[i] < (uint8_t)byte) {
return 1;
}
}
va_end(ap);
/* equals */
return 0;
}
/**
* @brief Check whether an UTF-8 string is greater than a hex string.
*
* input > 0x[arg1][arg2]...
*
* @param[in] input UTF-8 string.
* @param[in] bytes Number of bytes to compare.
* @param[in] ... @p bytes number of bytes to compare with.
* @return Result of the operation.
*/
static int
ly_utf8_greater(const char *input, int bytes, ...)
{
va_list ap;
int i, byte;
va_start(ap, bytes);
for (i = 0; i < bytes; ++i) {
byte = va_arg(ap, int);
/* compare until bytes differ */
if ((uint8_t)input[i] > (uint8_t)byte) {
return 1;
} else if ((uint8_t)input[i] < (uint8_t)byte) {
return 0;
}
}
va_end(ap);
/* equals */
return 0;
}
LY_ERR
ly_checkutf8(const char *input, size_t in_len, size_t *utf8_len)
{
size_t len;
if (!(input[0] & 0x80)) {
/* one byte character */
len = 1;
if (ly_utf8_less(input, 1, 0x20) && (input[0] != 0x9) && (input[0] != 0xa) && (input[0] != 0xd)) {
/* invalid control characters */
return LY_EINVAL;
}
} else if (((input[0] & 0xe0) == 0xc0) && (in_len > 1)) {
/* two bytes character */
len = 2;
/* (input < 0xC280) || (input > 0xDFBF) || ((input & 0xE0C0) != 0xC080) */
if (ly_utf8_less(input, 2, 0xC2, 0x80) || ly_utf8_greater(input, 2, 0xDF, 0xBF) ||
!ly_utf8_and_equal(input, 2, 0xE0, 0xC0, 0xC0, 0x80)) {
return LY_EINVAL;
}
} else if (((input[0] & 0xf0) == 0xe0) && (in_len > 2)) {
/* three bytes character */
len = 3;
/* (input >= 0xEDA080) && (input <= 0xEDBFBF) */
if (!ly_utf8_less(input, 3, 0xED, 0xA0, 0x80) && !ly_utf8_greater(input, 3, 0xED, 0xBF, 0xBF)) {
/* reject UTF-16 surrogates */
return LY_EINVAL;
}
/* (input < 0xE0A080) || (input > 0xEFBFBF) || ((input & 0xF0C0C0) != 0xE08080) */
if (ly_utf8_less(input, 3, 0xE0, 0xA0, 0x80) || ly_utf8_greater(input, 3, 0xEF, 0xBF, 0xBF) ||
!ly_utf8_and_equal(input, 3, 0xF0, 0xE0, 0xC0, 0x80, 0xC0, 0x80)) {
return LY_EINVAL;
}
} else if (((input[0] & 0xf8) == 0xf0) && (in_len > 3)) {
/* four bytes character */
len = 4;
/* (input < 0xF0908080) || (input > 0xF48FBFBF) || ((input & 0xF8C0C0C0) != 0xF0808080) */
if (ly_utf8_less(input, 4, 0xF0, 0x90, 0x80, 0x80) || ly_utf8_greater(input, 4, 0xF4, 0x8F, 0xBF, 0xBF) ||
!ly_utf8_and_equal(input, 4, 0xF8, 0xF0, 0xC0, 0x80, 0xC0, 0x80, 0xC0, 0x80)) {
return LY_EINVAL;
}
} else {
return LY_EINVAL;
}
*utf8_len = len;
return LY_SUCCESS;
}
LY_ERR
ly_pututf8(char *dst, uint32_t value, size_t *bytes_written)
{
if (value < 0x80) {
/* one byte character */
if ((value < 0x20) &&
(value != 0x09) &&
(value != 0x0a) &&
(value != 0x0d)) {
/* valid UTF8 but not YANG string character */
return LY_EINVAL;
}
dst[0] = value;
(*bytes_written) = 1;
} else if (value < 0x800) {
/* two bytes character */
dst[0] = 0xc0 | (value >> 6);
dst[1] = 0x80 | (value & 0x3f);
(*bytes_written) = 2;
} else if (value < 0xfffe) {
/* three bytes character */
if (((value & 0xf800) == 0xd800) ||
((value >= 0xfdd0) && (value <= 0xfdef))) {
/* exclude surrogate blocks %xD800-DFFF */
/* exclude noncharacters %xFDD0-FDEF */
return LY_EINVAL;
}
dst[0] = 0xe0 | (value >> 12);
dst[1] = 0x80 | ((value >> 6) & 0x3f);
dst[2] = 0x80 | (value & 0x3f);
(*bytes_written) = 3;
} else if (value < 0x10fffe) {
if ((value & 0xffe) == 0xffe) {
/* exclude noncharacters %xFFFE-FFFF, %x1FFFE-1FFFF, %x2FFFE-2FFFF, %x3FFFE-3FFFF, %x4FFFE-4FFFF,
* %x5FFFE-5FFFF, %x6FFFE-6FFFF, %x7FFFE-7FFFF, %x8FFFE-8FFFF, %x9FFFE-9FFFF, %xAFFFE-AFFFF,
* %xBFFFE-BFFFF, %xCFFFE-CFFFF, %xDFFFE-DFFFF, %xEFFFE-EFFFF, %xFFFFE-FFFFF, %x10FFFE-10FFFF */
return LY_EINVAL;
}
/* four bytes character */
dst[0] = 0xf0 | (value >> 18);
dst[1] = 0x80 | ((value >> 12) & 0x3f);
dst[2] = 0x80 | ((value >> 6) & 0x3f);
dst[3] = 0x80 | (value & 0x3f);
(*bytes_written) = 4;
} else {
return LY_EINVAL;
}
return LY_SUCCESS;
}
/**
* @brief Static table of the UTF8 characters lengths according to their first byte.
*/
static const unsigned char utf8_char_length_table[] = {
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 1, 1
};
size_t
ly_utf8len(const char *str, size_t bytes)
{
size_t len = 0;
const char *ptr = str;
while (((size_t)(ptr - str) < bytes) && *ptr) {
++len;
ptr += utf8_char_length_table[((unsigned char)(*ptr))];
}
return len;
}
int
LY_VCODE_INSTREXP_len(const char *str)
{
int len = 0;
if (!str) {
return len;
} else if (!str[0]) {
return 1;
}
for (len = 1; len < LY_VCODE_INSTREXP_MAXLEN && str[len]; ++len) {}
return len;
}
#ifdef HAVE_MMAP
LY_ERR
ly_mmap(struct ly_ctx *ctx, int fd, size_t *length, void **addr)
{
struct stat sb;
long pagesize;
size_t m;
assert(length);
assert(addr);
assert(fd >= 0);
if (fstat(fd, &sb) == -1) {
LOGERR(ctx, LY_ESYS, "Failed to stat the file descriptor (%s) for the mmap().", strerror(errno));
return LY_ESYS;
}
if (!S_ISREG(sb.st_mode)) {
LOGERR(ctx, LY_EINVAL, "File to mmap() is not a regular file.");
return LY_ESYS;
}
if (!sb.st_size) {
*addr = NULL;
return LY_SUCCESS;
}
pagesize = sysconf(_SC_PAGESIZE);
m = sb.st_size % pagesize;
if (m && (pagesize - m >= 1)) {
/* there will be enough space (at least 1 byte) after the file content mapping to provide zeroed NULL-termination byte */
*length = sb.st_size + 1;
*addr = mmap(NULL, *length, PROT_READ, MAP_PRIVATE, fd, 0);
} else {
/* there will not be enough bytes after the file content mapping for the additional bytes and some of them
* would overflow into another page that would not be zerroed and any access into it would generate SIGBUS.
* Therefore we have to do the following hack with double mapping. First, the required number of bytes
* (including the additinal bytes) is required as anonymous and thus they will be really provided (actually more
* because of using whole pages) and also initialized by zeros. Then, the file is mapped to the same address
* where the anonymous mapping starts. */
*length = sb.st_size + pagesize;
*addr = mmap(NULL, *length, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
*addr = mmap(*addr, sb.st_size, PROT_READ, MAP_PRIVATE | MAP_FIXED, fd, 0);
}
if (*addr == MAP_FAILED) {
LOGERR(ctx, LY_ESYS, "mmap() failed (%s).", strerror(errno));
return LY_ESYS;
}
return LY_SUCCESS;
}
LY_ERR
ly_munmap(void *addr, size_t length)
{
if (munmap(addr, length)) {
return LY_ESYS;
}
return LY_SUCCESS;
}
#else
LY_ERR
ly_mmap(struct ly_ctx *ctx, int fd, size_t *length, void **addr)
{
struct stat sb;
size_t m;
assert(length);
assert(addr);
assert(fd >= 0);
#if _WIN32
if (_setmode(fd, _O_BINARY) == -1) {
LOGERR(ctx, LY_ESYS, "Failed to switch the file descriptor to binary mode.", strerror(errno));
return LY_ESYS;
}
#endif
if (fstat(fd, &sb) == -1) {
LOGERR(ctx, LY_ESYS, "Failed to stat the file descriptor (%s) for the mmap().", strerror(errno));
return LY_ESYS;
}
if (!S_ISREG(sb.st_mode)) {
LOGERR(ctx, LY_EINVAL, "File to mmap() is not a regular file.");
return LY_ESYS;
}
if (!sb.st_size) {
*addr = NULL;
return LY_SUCCESS;
}
/* On Windows, the mman-win32 mmap() emulation uses CreateFileMapping and MapViewOfFile, and these functions
* do not allow mapping more than "length of file" bytes for PROT_READ. Remapping existing mappings is not allowed, either.
* At that point the path of least resistance is just reading the file in as-is. */
m = sb.st_size + 1;
char *buf = calloc(m, 1);
if (!buf) {
LOGERR(ctx, LY_ESYS, "ly_mmap: malloc() failed (%s).", strerror(errno));
}
*addr = buf;
*length = m;
lseek(fd, 0, SEEK_SET);
ssize_t to_read = m - 1;
while (to_read > 0) {
ssize_t n = read(fd, buf, to_read);
if (n == 0) {
return LY_SUCCESS;
} else if (n < 0) {
if (errno == EINTR) {
continue; // can I get this on Windows?
}
LOGERR(ctx, LY_ESYS, "ly_mmap: read() failed (%s).", strerror(errno));
}
to_read -= n;
buf += n;
}
return LY_SUCCESS;
}
LY_ERR
ly_munmap(void *addr, size_t length)
{
(void)length;
free(addr);
return LY_SUCCESS;
}
#endif
LY_ERR
ly_strcat(char **dest, const char *format, ...)
{
va_list fp;
char *addition = NULL;
size_t len;
va_start(fp, format);
len = vasprintf(&addition, format, fp);
len += (*dest ? strlen(*dest) : 0) + 1;
if (*dest) {
*dest = ly_realloc(*dest, len);
if (!*dest) {
va_end(fp);
return LY_EMEM;
}
*dest = strcat(*dest, addition);
free(addition);
} else {
*dest = addition;
}
va_end(fp);
return LY_SUCCESS;
}
LY_ERR
ly_parse_int(const char *val_str, size_t val_len, int64_t min, int64_t max, int base, int64_t *ret)
{
LY_ERR rc = LY_SUCCESS;
char *ptr, *str;
int64_t i;
LY_CHECK_ARG_RET(NULL, val_str, val_str[0], val_len, LY_EINVAL);
/* duplicate the value */
str = strndup(val_str, val_len);
LY_CHECK_RET(!str, LY_EMEM);
/* parse the value to avoid accessing following bytes */
errno = 0;
i = strtoll(str, &ptr, base);
if (errno || (ptr == str)) {
/* invalid string */
rc = LY_EVALID;
} else if ((i < min) || (i > max)) {
/* invalid number */
rc = LY_EDENIED;
} else if (*ptr) {
while (isspace(*ptr)) {
++ptr;
}
if (*ptr) {
/* invalid characters after some number */
rc = LY_EVALID;
}
}
/* cleanup */
free(str);
if (!rc) {
*ret = i;
}
return rc;
}
LY_ERR
ly_parse_uint(const char *val_str, size_t val_len, uint64_t max, int base, uint64_t *ret)
{
LY_ERR rc = LY_SUCCESS;
char *ptr, *str;
uint64_t u;
LY_CHECK_ARG_RET(NULL, val_str, val_str[0], val_len, LY_EINVAL);
/* duplicate the value to avoid accessing following bytes */
str = strndup(val_str, val_len);
LY_CHECK_RET(!str, LY_EMEM);
/* parse the value */
errno = 0;
u = strtoull(str, &ptr, base);
if (errno || (ptr == str)) {
/* invalid string */
rc = LY_EVALID;
} else if ((u > max) || (u && (str[0] == '-'))) {
/* invalid number */
rc = LY_EDENIED;
} else if (*ptr) {
while (isspace(*ptr)) {
++ptr;
}
if (*ptr) {
/* invalid characters after some number */
rc = LY_EVALID;
}
}
/* cleanup */
free(str);
if (!rc) {
*ret = u;
}
return rc;
}
/**
* @brief Parse an identifier.
*
* ;; An identifier MUST NOT start with (('X'|'x') ('M'|'m') ('L'|'l'))
* identifier = (ALPHA / "_")
* *(ALPHA / DIGIT / "_" / "-" / ".")
*
* @param[in,out] id Identifier to parse. When returned, it points to the first character which is not part of the identifier.
* @return LY_ERR value: LY_SUCCESS or LY_EINVAL in case of invalid starting character.
*/
static LY_ERR
lys_parse_id(const char **id)
{
assert(id && *id);
if (!is_yangidentstartchar(**id)) {
return LY_EINVAL;
}
++(*id);
while (is_yangidentchar(**id)) {
++(*id);
}
return LY_SUCCESS;
}
LY_ERR
ly_parse_nodeid(const char **id, const char **prefix, size_t *prefix_len, const char **name, size_t *name_len)
{
assert(id && *id);
assert(prefix && prefix_len);
assert(name && name_len);
*prefix = *id;
*prefix_len = 0;
*name = NULL;
*name_len = 0;
LY_CHECK_RET(lys_parse_id(id));
if (**id == ':') {
/* there is prefix */
*prefix_len = *id - *prefix;
++(*id);
*name = *id;
LY_CHECK_RET(lys_parse_id(id));
*name_len = *id - *name;
} else {
/* there is no prefix, so what we have as prefix now is actually the name */
*name = *prefix;
*name_len = *id - *name;
*prefix = NULL;
}
return LY_SUCCESS;
}
LY_ERR
ly_parse_instance_predicate(const char **pred, size_t limit, LYD_FORMAT format,
const char **prefix, size_t *prefix_len, const char **id, size_t *id_len, const char **value, size_t *value_len,
const char **errmsg)
{
LY_ERR ret = LY_EVALID;
const char *in = *pred;
size_t offset = 1;
uint8_t expr = 0; /* 0 - position predicate; 1 - leaf-list-predicate; 2 - key-predicate */
char quot;
assert(in[0] == '[');
*prefix = *id = *value = NULL;
*prefix_len = *id_len = *value_len = 0;
/* leading *WSP */
for ( ; isspace(in[offset]); offset++) {}
if (isdigit(in[offset])) {
/* pos: "[" *WSP positive-integer-value *WSP "]" */
if (in[offset] == '0') {
/* zero */
*errmsg = "The position predicate cannot be zero.";
goto error;
}
/* positive-integer-value */
*value = &in[offset++];
for ( ; isdigit(in[offset]); offset++) {}
*value_len = &in[offset] - *value;
} else if (in[offset] == '.') {
/* leaf-list-predicate: "[" *WSP "." *WSP "=" *WSP quoted-string *WSP "]" */
*id = &in[offset];
*id_len = 1;
offset++;
expr = 1;
} else if (in[offset] == '-') {
/* typically negative value */
*errmsg = "Invalid instance predicate format (negative position or invalid node-identifier).";
goto error;
} else {
/* key-predicate: "[" *WSP node-identifier *WSP "=" *WSP quoted-string *WSP "]" */
in = &in[offset];
if (ly_parse_nodeid(&in, prefix, prefix_len, id, id_len)) {
*errmsg = "Invalid node-identifier.";
goto error;
}
if ((format == LYD_XML) && !(*prefix)) {
/* all node names MUST be qualified with explicit namespace prefix */
*errmsg = "Missing prefix of a node name.";
goto error;
}
offset = in - *pred;
in = *pred;
expr = 2;
}
if (expr) {
/* *WSP "=" *WSP quoted-string *WSP "]" */
for ( ; isspace(in[offset]); offset++) {}
if (in[offset] != '=') {
if (expr == 1) {
*errmsg = "Unexpected character instead of \'=\' in leaf-list-predicate.";
} else { /* 2 */
*errmsg = "Unexpected character instead of \'=\' in key-predicate.";
}
goto error;
}
offset++;
for ( ; isspace(in[offset]); offset++) {}
/* quoted-string */
quot = in[offset++];
if ((quot != '\'') && (quot != '\"')) {
*errmsg = "String value is not quoted.";
goto error;
}
*value = &in[offset];
for ( ; offset < limit && (in[offset] != quot || (offset && in[offset - 1] == '\\')); offset++) {}
if (in[offset] == quot) {
*value_len = &in[offset] - *value;
offset++;
} else {
*errmsg = "Value is not terminated quoted-string.";
goto error;
}
}
/* *WSP "]" */
for ( ; isspace(in[offset]); offset++) {}
if (in[offset] != ']') {
if (expr == 0) {
*errmsg = "Predicate (pos) is not terminated by \']\' character.";
} else if (expr == 1) {
*errmsg = "Predicate (leaf-list-predicate) is not terminated by \']\' character.";
} else { /* 2 */
*errmsg = "Predicate (key-predicate) is not terminated by \']\' character.";
}
goto error;
}
offset++;
if (offset <= limit) {
*pred = &in[offset];
return LY_SUCCESS;
}
/* we read after the limit */
*errmsg = "Predicate is incomplete.";
*prefix = *id = *value = NULL;
*prefix_len = *id_len = *value_len = 0;
offset = limit;
ret = LY_EINVAL;
error:
*pred = &in[offset];
return ret;
}

677
src/ly_common.h Normal file
View file

@ -0,0 +1,677 @@
/**
* @file ly_common.h
* @author Radek Krejci <rkrejci@cesnet.cz>
* @author Michal Vasko <mvasko@cesnet.cz>
* @brief common internal definitions for libyang
*
* Copyright (c) 2015 - 2024 CESNET, z.s.p.o.
*
* This source code is licensed under BSD 3-Clause License (the "License").
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*/
#ifndef LY_COMMON_H_
#define LY_COMMON_H_
#include <pthread.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include "compat.h"
#include "context.h"
#include "hash_table_internal.h"
#include "log.h"
#include "ly_config.h"
#include "schema_compile.h"
#include "set.h"
#include "tree_data.h"
struct ly_ctx;
struct ly_in;
struct lysc_node;
#if __STDC_VERSION__ >= 201112 && !defined __STDC_NO_THREADS__
# define THREAD_LOCAL _Thread_local
#elif defined __GNUC__ || \
defined __SUNPRO_C || \
defined __xlC__
# define THREAD_LOCAL __thread
#elif defined _MSC_VER
# define THREAD_LOCAL __declspec(thread)
#else
# error "Cannot define THREAD_LOCAL"
#endif
/** platform-specific environment variable path separator */
#ifndef _WIN32
# define PATH_SEPARATOR ":"
#else
# define PATH_SEPARATOR ";"
#endif
#define GETMACRO1(_1, NAME, ...) NAME
#define GETMACRO2(_1, _2, NAME, ...) NAME
#define GETMACRO3(_1, _2, _3, NAME, ...) NAME
#define GETMACRO4(_1, _2, _3, _4, NAME, ...) NAME
#define GETMACRO5(_1, _2, _3, _4, _5, NAME, ...) NAME
#define GETMACRO6(_1, _2, _3, _4, _5, _6, NAME, ...) NAME
#define GETMACRO7(_1, _2, _3, _4, _5, _6, _7, NAME, ...) NAME
#define VOIDPTR_C(var) ((void *)(uintptr_t)(var))
#define VOIDPTR2_C(var) ((void **)(uintptr_t)(var))
/******************************************************************************
* Logger
*****************************************************************************/
/** size of the last message buffer */
#define LY_LAST_MSG_SIZE 512
extern ATOMIC_T ly_ll;
extern ATOMIC_T ly_log_opts;
struct ly_log_location_s {
struct ly_set inputs; /**< Set of const struct ly_in *in pointers providing the input handler with the line information (LIFO) */
struct ly_set scnodes; /**< Set of const struct lysc_node *scnode pointers providing the compiled schema node to generate path (LIFO) */
struct ly_set dnodes; /**< Set of const struct lyd_node *dnode pointers providing the data node to generate path (LIFO) */
struct ly_set spaths; /**< Set of schema path strings (LIFO) */
};
/**
* @brief Print a log message and store it into the context (if provided).
*
* @param[in] ctx libyang context to store the error record. If not provided, the error is just printed.
* @param[in] level Log message level (error, warning, etc.)
* @param[in] err Error code.
* @param[in] format Format string to print.
*/
void ly_log(const struct ly_ctx *ctx, LY_LOG_LEVEL level, LY_ERR err, const char *format, ...) _FORMAT_PRINTF(4, 5);
/**
* @brief Generate data path based on the data and schema nodes stored in the log location.
*
* @param[in] ctx Context for logging.
* @param[out] path Generated data path.
* @return LY_ERR value.
*/
LY_ERR ly_vlog_build_data_path(const struct ly_ctx *ctx, char **path);
/**
* @brief Print Validation error and store it into the context (if provided).
*
* @param[in] ctx libyang context to store the error record. If not provided, the error is just printed.
* @param[in] apptag Optional specific error-app-tag.
* @param[in] code Validation error code.
* @param[in] format Format string to print.
*/
void ly_vlog(const struct ly_ctx *ctx, const char *apptag, LY_VECODE code, const char *format, ...) _FORMAT_PRINTF(4, 5);
/**
* @brief Move error items from source to target context replacing any previous ones.
*
* @param[in] src_ctx Source context to read errors from.
* @param[in] trg_ctx Target context to set the errors for.
*/
void ly_err_move(struct ly_ctx *src_ctx, struct ly_ctx *trg_ctx);
/**
* @brief Logger location data setter.
*
* If all the parameter are NULL, a root @p dnode is added (NULL).
*
* @param[in] scnode Compiled schema node.
* @param[in] dnode Data node.
* @param[in] spath Direct schema path string to print.
* @param[in] in Input handler (providing line number).
*/
void ly_log_location(const struct lysc_node *scnode, const struct lyd_node *dnode,
const char *spath, const struct ly_in *in);
/**
* @brief Revert the specific logger location data by number of changes made by ::ly_log_location().
*
* @param[in] scnode_steps Number of items in ::ly_log_location_s.scnodes to forget.
* @param[in] dnode_steps Number of items in ::ly_log_location_s.dnodes to forget.
* @param[in] spath_steps Number of path strings in ::ly_log_location_s.spaths to forget.
* @param[in] in_steps Number of input handlers ::ly_log_location_s.inputs to forget.
*/
void ly_log_location_revert(uint32_t scnode_steps, uint32_t dnode_steps, uint32_t spath_steps, uint32_t in_steps);
/**
* @brief Get the stored data node for logging at the index.
*
* @param[in] idx Index of the data node.
* @return Logged data node, NULL if out of range.
*/
const struct lyd_node *ly_log_location_dnode(uint32_t idx);
/**
* @brief Get the count of stored data nodes for logging.
*
* @return Count of the data nodes.
*/
uint32_t ly_log_location_dnode_count(void);
/**
* @brief Update location schema/data nodes for logger, not provided arguments (NULLs) are kept (does not override).
*
* @param[in] SCNODE Compiled schema node.
* @param[in] DNODE Data node.
*/
#define LOG_LOCSET(SCNODE, DNODE) \
ly_log_location(SCNODE, DNODE, NULL, NULL)
/**
* @brief Update location schema/data nodes for logger, not provided arguments (NULLs) are kept (does not override).
*
* @param[in] SCNODE_STEPS Number of the compiled schema nodes to remove from the stack.
* @param[in] DNODE_STEPS Number of the data nodes to remove from the stack.
*/
#define LOG_LOCBACK(SCNODE_STEPS, DNODE_STEPS) \
ly_log_location_revert(SCNODE_STEPS, DNODE_STEPS, 0, 0)
#define LOGERR(ctx, errno, ...) ly_log(ctx, LY_LLERR, errno, __VA_ARGS__)
#define LOGWRN(ctx, ...) ly_log(ctx, LY_LLWRN, 0, __VA_ARGS__)
#define LOGVRB(...) ly_log(NULL, LY_LLVRB, 0, __VA_ARGS__)
#ifdef NDEBUG
# define LOGDBG(dbg_group, ...)
#else
void ly_log_dbg(uint32_t group, const char *format, ...);
# define LOGDBG(dbg_group, ...) ly_log_dbg(dbg_group, __VA_ARGS__);
#endif
/**
* Simple EMEM message, it can be safely stored in ::ly_err_item structures without problems when freeing.
*/
#define LY_EMEM_MSG "Memory allocation failed."
#ifdef LOGMEM
/* overwrite shadow definition from tree_edit.h */
#undef LOGMEM
#endif
#define LOGMEM(CTX) LOGERR(CTX, LY_EMEM, "Memory allocation failed (%s()).", __func__)
#define LOGINT(CTX) LOGERR(CTX, LY_EINT, "Internal error (%s:%d).", __FILE__, __LINE__)
#define LOGARG(CTX, ARG) LOGERR(CTX, LY_EINVAL, "Invalid argument %s (%s()).", #ARG, __func__)
#define LOGVAL(CTX, ...) ly_vlog(CTX, NULL, __VA_ARGS__)
#define LOGVAL_APPTAG(CTX, APPTAG, ...) ly_vlog(CTX, APPTAG, __VA_ARGS__)
#define LOGMEM_RET(CTX) LOGMEM(CTX); return LY_EMEM
#define LOGINT_RET(CTX) LOGINT(CTX); return LY_EINT
#define LOGARG_RET(CTX) LOGARG(CTX); return LY_EINVAL
/*
* Common code to check return value and perform appropriate action.
*/
#define LY_CHECK_GOTO(COND, GOTO) if ((COND)) {goto GOTO;}
#define LY_CHECK_ERR_GOTO(COND, ERR, GOTO) if ((COND)) {ERR; goto GOTO;}
#define LY_CHECK_RET1(RETVAL) {LY_ERR ret__ = RETVAL;if (ret__ != LY_SUCCESS) {return ret__;}}
#define LY_CHECK_RET2(COND, RETVAL) if ((COND)) {return RETVAL;}
#define LY_CHECK_RET(...) GETMACRO2(__VA_ARGS__, LY_CHECK_RET2, LY_CHECK_RET1, DUMMY)(__VA_ARGS__)
#define LY_CHECK_ERR_RET(COND, ERR, RETVAL) if ((COND)) {ERR; return RETVAL;}
#define LY_CHECK_ARG_GOTO1(CTX, ARG, GOTO) if (!(ARG)) {LOGARG(CTX, ARG);goto GOTO;}
#define LY_CHECK_ARG_GOTO2(CTX, ARG1, ARG2, GOTO) LY_CHECK_ARG_GOTO1(CTX, ARG1, GOTO);LY_CHECK_ARG_GOTO1(CTX, ARG2, GOTO)
#define LY_CHECK_ARG_GOTO3(CTX, ARG1, ARG2, ARG3, GOTO) LY_CHECK_ARG_GOTO2(CTX, ARG1, ARG2, GOTO);LY_CHECK_ARG_GOTO1(CTX, ARG3, GOTO)
#define LY_CHECK_ARG_GOTO4(CTX, ARG1, ARG2, ARG3, ARG4, GOTO) LY_CHECK_ARG_GOTO3(CTX, ARG1, ARG2, ARG3, GOTO);\
LY_CHECK_ARG_GOTO1(CTX, ARG4, GOTO)
#define LY_CHECK_ARG_GOTO(CTX, ...) GETMACRO5(__VA_ARGS__, LY_CHECK_ARG_GOTO4, LY_CHECK_ARG_GOTO3, LY_CHECK_ARG_GOTO2, \
LY_CHECK_ARG_GOTO1)(CTX, __VA_ARGS__)
#define LY_CHECK_ARG_RET1(CTX, ARG, RETVAL) if (!(ARG)) {LOGARG(CTX, ARG);return RETVAL;}
#define LY_CHECK_ARG_RET2(CTX, ARG1, ARG2, RETVAL) LY_CHECK_ARG_RET1(CTX, ARG1, RETVAL);LY_CHECK_ARG_RET1(CTX, ARG2, RETVAL)
#define LY_CHECK_ARG_RET3(CTX, ARG1, ARG2, ARG3, RETVAL) LY_CHECK_ARG_RET2(CTX, ARG1, ARG2, RETVAL);LY_CHECK_ARG_RET1(CTX, ARG3, RETVAL)
#define LY_CHECK_ARG_RET4(CTX, ARG1, ARG2, ARG3, ARG4, RETVAL) LY_CHECK_ARG_RET3(CTX, ARG1, ARG2, ARG3, RETVAL);\
LY_CHECK_ARG_RET1(CTX, ARG4, RETVAL)
#define LY_CHECK_ARG_RET5(CTX, ARG1, ARG2, ARG3, ARG4, ARG5, RETVAL) LY_CHECK_ARG_RET4(CTX, ARG1, ARG2, ARG3, ARG4, RETVAL);\
LY_CHECK_ARG_RET1(CTX, ARG5, RETVAL)
#define LY_CHECK_ARG_RET6(CTX, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, RETVAL) LY_CHECK_ARG_RET5(CTX, ARG1, ARG2, ARG3, ARG4, ARG5, RETVAL);\
LY_CHECK_ARG_RET1(CTX, ARG6, RETVAL)
#define LY_CHECK_ARG_RET(CTX, ...) GETMACRO7(__VA_ARGS__, LY_CHECK_ARG_RET6, LY_CHECK_ARG_RET5, LY_CHECK_ARG_RET4, \
LY_CHECK_ARG_RET3, LY_CHECK_ARG_RET2, LY_CHECK_ARG_RET1, DUMMY) (CTX, __VA_ARGS__)
#define LY_CHECK_CTX_EQUAL_RET2(CTX1, CTX2, RETVAL) if ((CTX1) && (CTX2) && ((CTX1) != (CTX2))) \
{LOGERR(CTX1, LY_EINVAL, "Different contexts mixed in a single function call."); return RETVAL;}
#define LY_CHECK_CTX_EQUAL_RET3(CTX1, CTX2, CTX3, RETVAL) LY_CHECK_CTX_EQUAL_RET2(CTX1, CTX2, RETVAL); \
LY_CHECK_CTX_EQUAL_RET2(CTX2, CTX3, RETVAL); LY_CHECK_CTX_EQUAL_RET2(CTX1, CTX3, RETVAL)
#define LY_CHECK_CTX_EQUAL_RET(CTX, ...) GETMACRO3(__VA_ARGS__, LY_CHECK_CTX_EQUAL_RET3, LY_CHECK_CTX_EQUAL_RET2, \
DUMMY) (CTX, __VA_ARGS__)
/* count sequence size for LY_VCODE_INCHILDSTMT validation error code */
int LY_VCODE_INSTREXP_len(const char *str);
/* default maximum characters to print in LY_VCODE_INCHILDSTMT */
#define LY_VCODE_INSTREXP_MAXLEN 20
#define LY_VCODE_INCHAR LYVE_SYNTAX, "Invalid character 0x%hhx."
#define LY_VCODE_INSTREXP LYVE_SYNTAX, "Invalid character sequence \"%.*s\", expected %s."
#define LY_VCODE_EOF LYVE_SYNTAX, "Unexpected end-of-input."
#define LY_VCODE_NTERM LYVE_SYNTAX, "%s not terminated."
#define LY_VCODE_NSUPP LYVE_SYNTAX, "%s not supported."
#define LY_VCODE_MOD_SUBOMD LYVE_SYNTAX, "Invalid keyword \"%s\", expected \"module\" or \"submodule\"."
#define LY_VCODE_TRAILING_MOD LYVE_SYNTAX, "Trailing garbage \"%.*s%s\" after module, expected end-of-input."
#define LY_VCODE_TRAILING_SUBMOD LYVE_SYNTAX, "Trailing garbage \"%.*s%s\" after submodule, expected end-of-input."
#define LY_VCODE_INVAL_MINMAX LYVE_SEMANTICS, "Invalid combination of min-elements and max-elements: min value %" PRIu32 " is bigger than the max value %" PRIu32 "."
#define LY_VCODE_NAME_COL LYVE_SEMANTICS, "Name collision between %s of name \"%s\"."
#define LY_VCODE_NAME2_COL LYVE_SEMANTICS, "Name collision between %s and %s of name \"%s\"."
#define LY_VCODE_INSTMT LYVE_SYNTAX_YANG, "Invalid keyword \"%s\"."
#define LY_VCODE_INCHILDSTMT LYVE_SYNTAX_YANG, "Invalid keyword \"%s\" as a child of \"%s\"."
#define LY_VCODE_INCHILDSTMT2 LYVE_SYNTAX_YANG, "Invalid keyword \"%s\" as a child of \"%s\" - the statement is allowed only in YANG 1.1 modules."
#define LY_VCODE_INCHILDSTMSCOMB LYVE_SYNTAX_YANG, "Invalid combination of keywords \"%s\" and \"%s\" as substatements of \"%s\"."
#define LY_VCODE_DUPSTMT LYVE_SYNTAX_YANG, "Duplicate keyword \"%s\"."
#define LY_VCODE_DUPIDENT LYVE_SYNTAX_YANG, "Duplicate identifier \"%s\" of %s statement."
#define LY_VCODE_DUPIDENT2 LYVE_SYNTAX_YANG, "Duplicate identifier \"%s\" of %s statement - %s."
#define LY_VCODE_INVAL LYVE_SYNTAX_YANG, "Invalid value \"%.*s\" of \"%s\"."
#define LY_VCODE_MISSTMT LYVE_SYNTAX_YANG, "Missing mandatory keyword \"%s\" as a child of \"%s\"."
#define LY_VCODE_MISSCHILDSTMT LYVE_SYNTAX_YANG, "Missing %s substatement for %s%s."
#define LY_VCODE_INORD LYVE_SYNTAX_YANG, "Invalid keyword \"%s\", it cannot appear after \"%s\"."
#define LY_VCODE_OOB LYVE_SYNTAX_YANG, "Value \"%.*s\" is out of \"%s\" bounds."
#define LY_VCODE_INDEV LYVE_SYNTAX_YANG, "Deviate \"%s\" does not support keyword \"%s\"."
#define LY_VCODE_INREGEXP LYVE_SYNTAX_YANG, "Regular expression \"%s\" is not valid (\"%s\": %s)."
#define LY_VCODE_INSUBELEM2 LYVE_SYNTAX_YIN, "Invalid sub-elemnt \"%s\" of \"%s\" element - this sub-element is allowed only in modules with version 1.1 or newer."
#define LY_VCODE_INVAL_YIN LYVE_SYNTAX_YIN, "Invalid value \"%s\" of \"%s\" attribute in \"%s\" element."
#define LY_VCODE_UNEXP_SUBELEM LYVE_SYNTAX_YIN, "Unexpected sub-element \"%.*s\" of \"%s\" element."
#define LY_VCODE_INDEV_YIN LYVE_SYNTAX_YIN, "Deviate of this type doesn't allow \"%s\" as it's sub-element."
#define LY_VCODE_INORDER_YIN LYVE_SYNTAX_YIN, "Invalid order of %s\'s sub-elements \"%s\" can't appear after \"%s\"."
#define LY_VCODE_OOB_YIN LYVE_SYNTAX_YIN, "Value \"%s\" of \"%s\" attribute in \"%s\" element is out of bounds."
#define LY_VCODE_INCHILDSTMSCOMB_YIN LYVE_SYNTAX_YIN, "Invalid combination of sub-elemnts \"%s\" and \"%s\" in \"%s\" element."
#define LY_VCODE_DUP_ATTR LYVE_SYNTAX_YIN, "Duplicit definition of \"%s\" attribute in \"%s\" element."
#define LY_VCODE_UNEXP_ATTR LYVE_SYNTAX_YIN, "Unexpected attribute \"%.*s\" of \"%s\" element."
#define LY_VCODE_MAND_SUBELEM LYVE_SYNTAX_YIN, "Missing mandatory sub-element \"%s\" of \"%s\" element."
#define LY_VCODE_FIRT_SUBELEM LYVE_SYNTAX_YIN, "Sub-element \"%s\" of \"%s\" element must be defined as it's first sub-element."
#define LY_VCODE_SUBELEM_REDEF LYVE_SYNTAX_YIN, "Redefinition of \"%s\" sub-element in \"%s\" element."
#define LY_VCODE_XP_EOE LYVE_XPATH, "Unterminated string delimited with %c (%.15s)."
#define LY_VCODE_XP_INEXPR LYVE_XPATH, "Invalid character '%c'[%" PRIu32 "] of expression \'%s\'."
#define LY_VCODE_XP_EOF LYVE_XPATH, "Unexpected XPath expression end."
#define LY_VCODE_XP_INTOK LYVE_XPATH, "Unexpected XPath token \"%s\" (\"%.15s\")."
#define LY_VCODE_XP_INTOK2 LYVE_XPATH, "Unexpected XPath token \"%s\" (\"%.15s\"), expected \"%s\"."
#define LY_VCODE_XP_INFUNC LYVE_XPATH, "Unknown XPath function \"%.*s\"."
#define LY_VCODE_XP_INARGCOUNT LYVE_XPATH, "Invalid number of arguments (%" PRIu32 ") for the XPath function %.*s."
#define LY_VCODE_XP_INARGTYPE LYVE_XPATH, "Wrong type of argument #%d (%s) for the XPath function %s."
#define LY_VCODE_XP_INCTX LYVE_XPATH, "Invalid context type %s in %s."
#define LY_VCODE_XP_INOP_1 LYVE_XPATH, "Cannot apply XPath operation %s on %s."
#define LY_VCODE_XP_INOP_2 LYVE_XPATH, "Cannot apply XPath operation %s on %s and %s."
#define LY_VCODE_XP_INMOD LYVE_XPATH, "Unknown/non-implemented module \"%.*s\"."
#define LY_VCODE_XP_DEPTH LYVE_XPATH, "The maximum nesting of expressions has been exceeded."
#define LY_VCODE_DEV_NOT_PRESENT LYVE_REFERENCE, "Invalid deviation %s \"%s\" property \"%s\" which is not present."
#define LY_VCODE_NOWHEN LYVE_DATA, "When condition \"%s\" not satisfied."
#define LY_VCODE_NOMAND LYVE_DATA, "Mandatory node \"%s\" instance does not exist."
#define LY_VCODE_DUP LYVE_DATA, "Duplicate instance of \"%s\"."
#define LY_VCODE_DUPCASE LYVE_DATA, "Data for both cases \"%s\" and \"%s\" exist."
#define LY_VCODE_UNEXPNODE LYVE_DATA, "Unexpected data %s node \"%s\" found."
#define LY_VCODE_NOKEY LYVE_DATA, "List instance is missing its key \"%s\"."
#define LY_ERRMSG_NOPATTERN /* LYVE_DATA */ "Unsatisfied pattern - \"%.*s\" does not conform to %s\"%s\"."
#define LY_ERRMSG_NOLENGTH /* LYVE_DATA */ "Unsatisfied length - string \"%.*s\" length is not allowed."
#define LY_ERRMSG_NORANGE /* LYVE_DATA */ "Unsatisfied range - value \"%.*s\" is out of the allowed range."
/* RFC 7950 section 15 errors */
#define LY_VCODE_NOUNIQ LYVE_DATA, "Unique data leaf(s) \"%s\" not satisfied in \"%s\" and \"%s\"."
#define LY_VCODE_NOMAX LYVE_DATA, "Too many \"%s\" instances."
#define LY_VCODE_NOMIN LYVE_DATA, "Too few \"%s\" instances."
#define LY_VCODE_NOMUST LYVE_DATA, "Must condition \"%s\" not satisfied."
#define LY_VCODE_NOMAND_CHOIC LYVE_DATA, "Mandatory choice \"%s\" data do not exist."
/* RFC 7950 section 15 error messages used in type plugin validation callbacks */
#define LY_ERRMSG_NOLREF_VAL /* LYVE_DATA */ "Invalid leafref value \"%s\" - no target instance \"%s\" with the same value."
#define LY_ERRMSG_NOINST /* LYVE_DATA */ "Invalid instance-identifier \"%s\" value - required instance not found."
/******************************************************************************
* Context
*****************************************************************************/
/**
* @brief Context error hash table record.
*/
struct ly_ctx_err_rec {
struct ly_err_item *err; /** pointer to the error items, if any */
pthread_t tid; /** pthread thread ID */
};
/**
* @brief Context of the YANG schemas
*/
struct ly_ctx {
struct ly_dict dict; /**< dictionary to effectively store strings used in the context related structures */
struct ly_set search_paths; /**< set of directories where to search for schema's imports/includes */
struct ly_set list; /**< set of loaded YANG schemas */
ly_module_imp_clb imp_clb; /**< optional callback for retrieving missing included or imported models */
void *imp_clb_data; /**< optional private data for ::ly_ctx.imp_clb */
struct lys_glob_unres unres; /**< global unres, should be empty unless there are modules prepared for
compilation if ::LY_CTX_EXPLICIT_COMPILE flag is set */
uint16_t change_count; /**< count of changes of the context, on some changes it could be incremented
more times */
uint16_t flags; /**< context settings, see @ref contextoptions */
ly_ext_data_clb ext_clb; /**< optional callback for providing extension-specific run-time data for extensions */
void *ext_clb_data; /**< optional private data for ::ly_ctx.ext_clb */
struct ly_ht *err_ht; /**< hash table of thread-specific list of errors related to the context */
pthread_mutex_t lyb_hash_lock; /**< lock for storing LYB schema hashes in schema nodes */
struct ly_ht *leafref_links_ht; /**< hash table of leafref links between term data nodes */
struct ly_set plugins_types; /**< context specific set of type plugins */
struct ly_set plugins_extensions; /**< contets specific set of extension plugins */
};
/**
* @brief Get the (only) implemented YANG module specified by its name.
*
* @param[in] ctx Context where to search.
* @param[in] name Name of the YANG module to get.
* @param[in] name_len Optional length of the @p name. If zero, NULL-terminated name is expected.
* @return The only implemented YANG module revision of the given name in the given context. NULL if there is no
* implemented module of the given name.
*/
struct lys_module *ly_ctx_get_module_implemented2(const struct ly_ctx *ctx, const char *name, size_t name_len);
/******************************************************************************
* Generic useful functions.
*****************************************************************************/
/**
* @brief Insert string into dictionary.
*
* @param[in] CTX libyang context.
* @param[in] STRING string to store.
* @param[in] LEN length of the string in WORD to store.
* @param[in,out] DYNAMIC Set to 1 if @p STRING is dynamically allocated, 0 otherwise.
* If set to 1, zerocopy version of lydict_insert is used.
* @param[out] TARGET pointer is set to @p STRING value stored in the dictionary.
*/
#define INSERT_STRING_RET(CTX, STRING, LEN, DYNAMIC, TARGET) \
if (DYNAMIC) { \
LY_CHECK_RET(lydict_insert_zc(CTX, (char *)(STRING), &(TARGET))); \
} else { \
LY_CHECK_RET(lydict_insert(CTX, LEN ? (STRING) : "", LEN, &(TARGET))); \
} \
DYNAMIC = 0
/**
* @brief Wrapper for realloc() call. The only difference is that if it fails to
* allocate the requested memory, the original memory is freed as well.
*
* @param[in] ptr Memory to reallocate.
* @param[in] size New size of the memory block.
* @return Pointer to the new memory, NULL on error.
*/
void *ly_realloc(void *ptr, size_t size);
/**
* @brief Just like strchr() function except limit the number of examined characters.
*
* @param[in] s String to search in.
* @param[in] c Character to search for.
* @param[in] len Limit the search to this number of characters in @p s.
* @return Pointer to first @p c occurrence in @p s, NULL if not found in first @p len characters.
*/
char *ly_strnchr(const char *s, int c, size_t len);
/**
* @brief Compare NULL-terminated @p refstr with @p str_len bytes from @p str.
*
* @param[in] refstr NULL-terminated string which must match @p str_len bytes from @p str followed by NULL-byte.
* @param[in] str String to compare.
* @param[in] str_len Number of bytes to take into comparison from @p str.
* @return An integer less than, equal to, or greater than zero if @p refstr matches,
* respectively, to be less than, to match, or be greater than @p str.
*/
int ly_strncmp(const char *refstr, const char *str, size_t str_len);
/**
* @brief Similar functionality to strtoul() except number length in the string
* must be specified and the whole number must be parsed for success.
*
* @param[in] nptr Number string.
* @param[in] len Number string length starting at @p nptr.
* @param[out] ret Parsed number.
* @return LY_EDENIED on overflow.
* @return LY_EVALID on encountering a non-digit character.
* @return LY_SUCCESS on success.
*/
LY_ERR ly_strntou8(const char *nptr, size_t len, uint8_t *ret);
/**
* @brief Get all possible value prefixes from an YANG value by iteratively returning specific substrings.
*
* The function looks for possible prefix ending in a colon at the beginning of @p str_begin.
* If @p str_begin does not contain the prefix at the beginning, then either:
* 1. Returns the entire input string if the input string does not contain the prefix at all.
* 2. Returns a substring before the prefix. The substring is terminated by any character
* that is not allowed to be present in prefix (except colon).
*
* Examples of inputs and outputs are shown in the table below.
* Output string @p str_next is used in the next iteration as input parameter @p str_begin.
@verbatim
| INPUT | OUTPUT |
| | iteration 1 | iteration 2 | iteration 3 |
|------------------------------ |------------------|------------------|-----------------|
| /namespace_prefix:some_string | / | namespace_prefix | some_string |
| namespace_prefix:some_string | namespace_prefix | some_string | NULL |
| /some_string | /some_string | NULL | NULL |
@endverbatim
*
*
* @param[in] str_begin Begin of the input string.
* @param[in] str_end Length of the @p str_begin. If set to NULL then the @p str_begin must be NULL-terminated string.
* @param[out] len Number of bytes (length) of the found prefix/substring starting at @p str_begin.
* @param[out] is_prefix Type of substring found. Set to True for prefix, otherwise False.
* @param[out] str_next Remaining string starting after prefix/substring and ending with @p str_end.
* If the @p is_prefix is set to True then the colon character is skipped.
* If no string remains, it is set to NULL.
* @return LY_ERR value.
*/
LY_ERR ly_value_prefix_next(const char *str_begin, const char *str_end, uint32_t *len, ly_bool *is_prefix,
const char **str_next);
/**
* @brief Wrapper around strlen() to handle NULL strings.
*/
#define ly_strlen(STR) (STR ? strlen(STR) : 0)
/**
* @brief Compile-time strlen() for string constants.
*
* Use to avoid magic numbers usage
*/
#define ly_strlen_const(STR) (sizeof STR - 1)
/**
* @brief Macro to simply put couple of string length and the string as
* printf's arguments for %.*s. Use only with constant strings.
*/
#define LY_PRI_LENSTR(STR) (int)ly_strlen_const(STR), STR
#define ly_sizeofarray(ARRAY) (sizeof ARRAY / sizeof *ARRAY)
/**
* @brief Check for overflow during the addition of two unsigned integers.
*/
#define LY_OVERFLOW_ADD(MAX, X, Y) (X > MAX - Y)
/**
* @brief Check for overflow during the multiplication of two unsigned integers.
*/
#define LY_OVERFLOW_MUL(MAX, X, Y) (X > MAX / Y)
/*
* Numerical bases for use in functions like strtoll() instead of magic numbers
*/
#define LY_BASE_DEC 10 /**< Decimal numeral base */
#define LY_BASE_OCT 8 /**< Octal numeral base */
#define LY_BASE_HEX 16 /**< Hexadecimal numeral base */
/**
* Maximal length of (needed storage for) a number encoded as a string.
*
* Applies not only for standard numbers, but also for YANG's decimal64.
*/
#define LY_NUMBER_MAXLEN 22
/**
* @brief Get UTF8 code point of the next character in the input string.
*
* @param[in,out] input Input string to process, updated according to the processed/read data.
* @param[out] utf8_char UTF8 code point of the next character.
* @param[out] bytes_read Number of bytes used to encode the read utf8_char.
* @return LY_ERR value
*/
LY_ERR ly_getutf8(const char **input, uint32_t *utf8_char, size_t *bytes_read);
/**
* @brief Check an UTF-8 character is valid.
*
* @param[in] input Input string to process.
* @param[in] in_len Bytes left to read in @p input.
* @param[out] utf8_len Length of a valid UTF-8 character.
* @return LY_SUCCESS on success
* @return LY_EINVAL in case of invalid UTF-8 character.
*/
LY_ERR ly_checkutf8(const char *input, size_t in_len, size_t *utf8_len);
/**
* @brief Store UTF-8 character specified as 4byte integer into the dst buffer.
*
* UTF-8 mapping:
* 00000000 -- 0000007F: 0xxxxxxx
* 00000080 -- 000007FF: 110xxxxx 10xxxxxx
* 00000800 -- 0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx
* 00010000 -- 001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
*
* Includes checking for valid characters (following RFC 7950, sec 9.4)
*
* @param[in,out] dst Destination buffer to store the UTF-8 character, must provide enough space (up to 4 bytes) for storing the UTF-8 character.
* @param[in] value 32b value of the UTF-8 character to store.
* @param[out] bytes_written Number of bytes written into @p dst (size of the written UTF-8 character).
* @return LY_SUCCESS on success
* @return LY_EINVAL in case of invalid UTF-8 @p value to store.
*/
LY_ERR ly_pututf8(char *dst, uint32_t value, size_t *bytes_written);
/**
* @brief Get number of characters in the @p str, taking multibyte characters into account.
*
* @param[in] str String to examine.
* @param[in] bytes Number of valid bytes that are supposed to be taken into account in @p str.
* This parameter is useful mainly for non NULL-terminated strings. In case of NULL-terminated
* string, strlen() can be used.
* @return Number of characters in (possibly) multibyte characters string.
*/
size_t ly_utf8len(const char *str, size_t bytes);
/**
* @brief Parse signed integer with possible limitation.
*
* @param[in] val_str String value containing signed integer, note that
* nothing else than whitespaces are expected after the value itself.
* @param[in] val_len Length of the @p val_str string.
* @param[in] min Limitation for the value which must not be lower than min.
* @param[in] max Limitation for the value which must not be higher than max.
* @param[in] base Numeric base for parsing:
* 0 - to accept decimal, octal, hexadecimal (e.g. in default value)
* 10 - to accept only decimal (e.g. data instance value)
* @param[out] ret Resulting value.
* @return LY_ERR value:
* LY_EDENIED - the value breaks the limits,
* LY_EVALID - string contains invalid value,
* LY_SUCCESS - successful parsing.
*/
LY_ERR ly_parse_int(const char *val_str, size_t val_len, int64_t min, int64_t max, int base, int64_t *ret);
/**
* @brief Parse unsigned integer with possible limitation.
*
* @param[in] val_str String value containing unsigned integer, note that
* nothing else than whitespaces are expected after the value itself.
* @param[in] val_len Length of the @p val_str string.
* @param[in] max Limitation for the value which must not be higher than max.
* @param[in] base Numeric base for parsing:
* 0 - to accept decimal, octal, hexadecimal (e.g. in default value)
* 10 - to accept only decimal (e.g. data instance value)
* @param[out] ret Resulting value.
* @return LY_ERR value:
* LY_EDENIED - the value breaks the limits,
* LY_EVALID - string contains invalid value,
* LY_SUCCESS - successful parsing.
*/
LY_ERR ly_parse_uint(const char *val_str, size_t val_len, uint64_t max, int base, uint64_t *ret);
/**
* @brief Parse a node-identifier.
*
* node-identifier = [prefix ":"] identifier
*
* @param[in,out] id Identifier to parse. When returned, it points to the first character which is not part of the identifier.
* @param[out] prefix Node's prefix, NULL if there is not any.
* @param[out] prefix_len Length of the node's prefix, 0 if there is not any.
* @param[out] name Node's name.
* @param[out] name_len Length of the node's name.
* @return LY_ERR value: LY_SUCCESS or LY_EINVAL in case of invalid character in the id.
*/
LY_ERR ly_parse_nodeid(const char **id, const char **prefix, size_t *prefix_len, const char **name, size_t *name_len);
/**
* @brief parse instance-identifier's predicate, supports key-predicate, leaf-list-predicate and pos rules from YANG ABNF Grammar.
*
* @param[in,out] pred Predicate string (including the leading '[') to parse. The string is updated according to what was parsed
* (even for error case, so it can be used to determine which substring caused failure).
* @param[in] limit Limiting length of the @p pred. Function expects NULL terminated string which is not overread.
* The limit value is not checked with each character, so it can be overread and the failure is detected later.
* @param[in] format Input format of the data containing the @p pred.
* @param[out] prefix Start of the node-identifier's prefix if any, NULL in case of pos or leaf-list-predicate rules.
* @param[out] prefix_len Length of the parsed @p prefix.
* @param[out] id Start of the node-identifier's identifier string, NULL in case of pos rule, "." in case of leaf-list-predicate rule.
* @param[out] id_len Length of the parsed @p id.
* @param[out] value Start of the quoted-string (without quotation marks), not NULL in case of success.
* @param[out] value_len Length of the parsed @p value.
* @param[out] errmsg Error message string in case of error.
* @return LY_SUCCESS in case a complete predicate was parsed.
* @return LY_EVALID in case of invalid predicate form.
* @return LY_EINVAL in case of reaching @p limit when parsing @p pred.
*/
LY_ERR ly_parse_instance_predicate(const char **pred, size_t limit, LYD_FORMAT format,
const char **prefix, size_t *prefix_len, const char **id, size_t *id_len,
const char **value, size_t *value_len, const char **errmsg);
/**
* @brief mmap(2) wrapper to map input files into memory to unify parsing.
*
* The address space is allocate only for reading.
*
* @param[in] ctx libyang context for logging
* @param[in] fd Open file descriptor of a file to map.
* @param[out] length Allocated size.
* @param[out] addr Address where the file is mapped.
* @return LY_ERR value.
*/
LY_ERR ly_mmap(struct ly_ctx *ctx, int fd, size_t *length, void **addr);
/**
* @brief munmap(2) wrapper to free the memory mapped by ::ly_mmap()
*
* @param[in] addr Address where the input file is mapped.
* @param[in] length Allocated size of the address space.
* @return LY_ERR value.
*/
LY_ERR ly_munmap(void *addr, size_t length);
/**
* @brief Concatenate formating string to the @p dest.
*
* @param[in,out] dest String to be concatenated by @p format.
* Note that the input string can be reallocated during concatenation.
* @param[in] format Formating string (as for printf) which is supposed to be added after @p dest.
* @return LY_SUCCESS or LY_EMEM.
*/
LY_ERR ly_strcat(char **dest, const char *format, ...) _FORMAT_PRINTF(2, 3);
#endif /* LY_COMMON_H_ */

75
src/ly_config.h.in Normal file
View file

@ -0,0 +1,75 @@
/**
* @file ly_config.h
* @author Radek Krejci <rkrejci@cesnet.cz>
* @uathor Michal Vasko <mvasko@cesnet.cz>
* @brief Various variables provided by cmake and compile time options.
*
* Copyright (c) 2021 - 2024 CESNET, z.s.p.o.
*
* This source code is licensed under BSD 3-Clause License (the "License").
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*/
#ifndef LY_CONFIG_H_
#define LY_CONFIG_H_
#ifdef _WIN32
/* headers are broken on Windows, which means that some of them simply *have* to come first */
# include <winsock2.h>
# include <ws2tcpip.h>
#endif
/** size of fixed_mem in lyd_value, minimum is 8 (B) */
#define LYD_VALUE_FIXED_MEM_SIZE @LYD_VALUE_SIZE@
/** plugins */
#define LYPLG_SUFFIX "@CMAKE_SHARED_MODULE_SUFFIX@"
#define LYPLG_SUFFIX_LEN (sizeof LYPLG_SUFFIX - 1)
#define LYPLG_TYPE_DIR "@PLUGINS_DIR_TYPES@"
#define LYPLG_EXT_DIR "@PLUGINS_DIR_EXTENSIONS@"
/** atomic compiler operations, to be able to use uint32_t */
#ifndef _WIN32
# define LY_ATOMIC_INC_BARRIER(var) __sync_fetch_and_add(&(var), 1)
# define LY_ATOMIC_DEC_BARRIER(var) __sync_fetch_and_sub(&(var), 1)
#else
# include <windows.h>
# define LY_ATOMIC_INC_BARRIER(var) InterlockedExchangeAdd(&(var), 1)
# define LY_ATOMIC_DEC_BARRIER(var) InterlockedExchangeAdd(&(var), -1)
#endif
/** printf compiler attribute */
#ifdef __GNUC__
# define _FORMAT_PRINTF(FORM, ARGS) __attribute__((format (printf, FORM, ARGS)))
#else
# define _FORMAT_PRINTF(FORM, ARGS)
#endif
/** Exporting symbols to a shared library and importing back afterwards
*
* - use LIBYANG_API_DECL to mark a declaration in the public header
* - use LIBYANG_API_DEF to mark a definition (in the source code for the actual implementaiton)
* */
#ifdef _MSC_VER
# ifndef STATIC
# define LIBYANG_API_DEF __declspec(dllexport)
# ifdef LIBYANG_BUILD
# define LIBYANG_API_DECL __declspec(dllexport)
# else
# define LIBYANG_API_DECL __declspec(dllimport)
# endif
# endif
#else
/*
* If the compiler supports attribute to mark objects as hidden, mark all
* objects as hidden and export only objects explicitly marked to be part of
* the public API.
*/
# define LIBYANG_API_DEF __attribute__((visibility("default")))
# define LIBYANG_API_DECL
#endif
#endif /* LY_CONFIG_H_ */

125
src/lyb.c Normal file
View file

@ -0,0 +1,125 @@
/**
* @file lyb.c
* @author Michal Vasko <mvasko@cesnet.cz>
* @brief LYB format common functionality.
*
* Copyright (c) 2021 CESNET, z.s.p.o.
*
* This source code is licensed under BSD 3-Clause License (the "License").
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*/
#include "lyb.h"
#include <assert.h>
#include <pthread.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "compat.h"
#include "ly_common.h"
#include "tree_schema.h"
/**
* @brief Generate single hash for a schema node to be used for LYB data.
*
* @param[in] node Node to hash.
* @param[in] collision_id Collision ID of the hash to generate.
* @return Generated hash.
*/
static LYB_HASH
lyb_generate_hash(const struct lysc_node *node, uint8_t collision_id)
{
const struct lys_module *mod = node->module;
uint32_t full_hash;
LYB_HASH hash;
/* generate full hash */
full_hash = lyht_hash_multi(0, mod->name, strlen(mod->name));
full_hash = lyht_hash_multi(full_hash, node->name, strlen(node->name));
if (collision_id) {
size_t ext_len;
if (collision_id > strlen(mod->name)) {
/* fine, we will not hash more bytes, just use more bits from the hash than previously */
ext_len = strlen(mod->name);
} else {
/* use one more byte from the module name than before */
ext_len = collision_id;
}
full_hash = lyht_hash_multi(full_hash, mod->name, ext_len);
}
full_hash = lyht_hash_multi(full_hash, NULL, 0);
/* use the shortened hash */
hash = full_hash & (LYB_HASH_MASK >> collision_id);
/* add collision identificator */
hash |= LYB_HASH_COLLISION_ID >> collision_id;
return hash;
}
LYB_HASH
lyb_get_hash(const struct lysc_node *node, uint8_t collision_id)
{
/* hashes must be cached */
assert(node->hash[0]);
if (collision_id < LYS_NODE_HASH_COUNT) {
/* read from cache */
return node->hash[collision_id];
}
/* generate */
return lyb_generate_hash(node, collision_id);
}
/**
* @brief Module DFS callback filling all cached hashes of a schema node.
*/
static LY_ERR
lyb_cache_node_hash_cb(struct lysc_node *node, void *UNUSED(data), ly_bool *UNUSED(dfs_continue))
{
if (node->hash[0]) {
/* already cached, stop the DFS */
return LY_EEXIST;
}
for (uint8_t i = 0; i < LYS_NODE_HASH_COUNT; ++i) {
/* store the hash in the cache */
node->hash[i] = lyb_generate_hash(node, i);
}
return LY_SUCCESS;
}
void
lyb_cache_module_hash(const struct lys_module *mod)
{
/* LOCK */
pthread_mutex_lock(&mod->ctx->lyb_hash_lock);
/* store all cached hashes for all the nodes */
lysc_module_dfs_full(mod, lyb_cache_node_hash_cb, NULL);
/* UNLOCK */
pthread_mutex_unlock(&mod->ctx->lyb_hash_lock);
}
ly_bool
lyb_has_schema_model(const struct lysc_node *node, const struct lys_module **models)
{
LY_ARRAY_COUNT_TYPE u;
LY_ARRAY_FOR(models, u) {
if (node->module == models[u]) {
return 1;
}
}
return 0;
}

199
src/lyb.h Normal file
View file

@ -0,0 +1,199 @@
/**
* @file lyb.h
* @author Michal Vasko <mvasko@cesnet.cz>
* @brief Header for LYB format printer & parser
*
* Copyright (c) 2020 - 2022 CESNET, z.s.p.o.
*
* This source code is licensed under BSD 3-Clause License (the "License").
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*/
#ifndef LY_LYB_H_
#define LY_LYB_H_
#include <stddef.h>
#include <stdint.h>
#include "parser_internal.h"
struct ly_ctx;
struct lysc_node;
/*
* LYB format
*
* Unlike XML or JSON, it is binary format so most data are represented in similar way but in binary.
* Some notable differences:
*
* - schema nodes are identified based on their hash instead of their string name. In case of collisions
* an array of hashes is created with each next hash one bit shorter until a unique sequence of all these
* hashes is found and then all of them are stored.
*
* - tree structure is represented as individual strictly bounded "siblings". Each "siblings" begins
* with its metadata, which consist of 1) the whole "sibling" length in bytes and 2) number
* of included metadata chunks of nested "siblings".
*
* - since length of a "sibling" is not known before it is printed, holes are first written and
* after the "sibling" is printed, they are filled with actual valid metadata. As a consequence,
* LYB data cannot be directly printed into streams!
*
* - data are preceded with information about all the used modules. It is needed because of
* possible augments and deviations which must be known beforehand, otherwise schema hashes
* could be matched to the wrong nodes.
*
* This is a short summary of the format:
* @verbatim
sb = siblings_start
se = siblings_end
siblings = zero-LYB_SIZE_BYTES | (sb instance+ se)
instance = node_type model hash node
model = 16bit_zero | (model_name_length model_name revision)
node = opaq | leaflist | list | any | inner | leaf
opaq = opaq_data siblings
leaflist = sb leaf+ se
list = sb (node_header siblings)+ se
any = node_header anydata_data
inner = node_header siblings
leaf = node_header term_value
node_header = metadata node_flags
@endverbatim
*/
/**
* @brief LYB data node type
*/
enum lylyb_node_type {
LYB_NODE_TOP, /**< top-level node */
LYB_NODE_CHILD, /**< child node with a parent */
LYB_NODE_OPAQ, /**< opaque node */
LYB_NODE_EXT /**< nested extension data node */
};
/**
* @brief LYB format parser context
*/
struct lylyb_ctx {
const struct ly_ctx *ctx;
uint64_t line; /* current line */
struct ly_in *in; /* input structure */
const struct lys_module **models;
struct lyd_lyb_sibling {
size_t written;
size_t position;
uint16_t inner_chunks;
} *siblings;
LY_ARRAY_COUNT_TYPE sibling_size;
/* LYB printer only */
struct lyd_lyb_sib_ht {
struct lysc_node *first_sibling;
struct ly_ht *ht;
} *sib_hts;
};
/**
* @brief Destructor for the lylyb_ctx structure
*/
void lyd_lyb_ctx_free(struct lyd_ctx *lydctx);
/* just a shortcut */
#define LYB_LAST_SIBLING(lybctx) lybctx->siblings[LY_ARRAY_COUNT(lybctx->siblings) - 1]
/* struct lyd_lyb_sibling allocation step */
#define LYB_SIBLING_STEP 4
/* current LYB format version */
#define LYB_VERSION_NUM 0x05
/* LYB format version mask of the header byte */
#define LYB_VERSION_MASK 0x0F
/**
* LYB schema hash constants
*
* Hash is divided to collision ID and hash itself.
*
* @anchor collisionid
*
* First bits are collision ID until 1 is found. The rest is truncated 32b hash.
* 1xxx xxxx - collision ID 0 (no collisions)
* 01xx xxxx - collision ID 1 (collision ID 0 hash collided)
* 001x xxxx - collision ID 2 ...
*
* When finding a match for a unique schema (siblings) hash (sequence of hashes with increasing collision ID), the highest
* collision ID can be read from the last hash (LYB parser).
*
* To learn what is the highest collision ID of a hash that must be included in a unique schema (siblings) hash,
* collisions with all the preceding sibling schema hashes must be checked (LYB printer).
*/
/* Number of bits the whole hash will take (including hash collision ID) */
#define LYB_HASH_BITS 8
/* Masking 32b hash (collision ID 0) */
#define LYB_HASH_MASK 0x7f
/* Type for storing the whole hash (used only internally, publicly defined directly) */
#define LYB_HASH uint8_t
/* Need to move this first >> collision number (from 0) to get collision ID hash part */
#define LYB_HASH_COLLISION_ID 0x80
/* How many bytes are reserved for one data chunk SIZE (8B is maximum) */
#define LYB_SIZE_BYTES 2
/* Maximum size that will be written into LYB_SIZE_BYTES (must be large enough) */
#define LYB_SIZE_MAX UINT16_MAX
/* How many bytes are reserved for one data chunk inner chunk count */
#define LYB_INCHUNK_BYTES 2
/* Maximum size that will be written into LYB_INCHUNK_BYTES (must be large enough) */
#define LYB_INCHUNK_MAX UINT16_MAX
/* Just a helper macro */
#define LYB_META_BYTES (LYB_INCHUNK_BYTES + LYB_SIZE_BYTES)
/* model revision as XXXX XXXX XXXX XXXX (2B) (year is offset from 2000)
* YYYY YYYM MMMD DDDD */
#define LYB_REV_YEAR_OFFSET 2000
#define LYB_REV_YEAR_MASK 0xfe00U
#define LYB_REV_YEAR_SHIFT 9
#define LYB_REV_MONTH_MASK 0x01E0U
#define LYB_REV_MONTH_SHIFT 5
#define LYB_REV_DAY_MASK 0x001fU
/**
* @brief Get single hash for a schema node to be used for LYB data. Read from cache, if possible.
*
* @param[in] node Node to hash.
* @param[in] collision_id Collision ID of the hash to generate, see @ref collisionid.
* @return Generated hash.
*/
LYB_HASH lyb_get_hash(const struct lysc_node *node, uint8_t collision_id);
/**
* @brief Fill the hash cache of all the schema nodes of a module.
*
* @param[in] mod Module to process.
*/
void lyb_cache_module_hash(const struct lys_module *mod);
/**
* @brief Check whether a node's module is in a module array.
*
* @param[in] node Node to check.
* @param[in] models Modules in a sized array.
* @return Boolean value whether @p node's module was found in the given @p models array.
*/
ly_bool lyb_has_schema_model(const struct lysc_node *node, const struct lys_module **models);
#endif /* LY_LYB_H_ */

788
src/out.c Normal file
View file

@ -0,0 +1,788 @@
/**
* @file out.c
* @author Radek Krejci <rkrejci@cesnet.cz>
* @brief libyang output functions.
*
* Copyright (c) 2015 - 2020 CESNET, z.s.p.o.
*
* This source code is licensed under BSD 3-Clause License (the "License").
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*/
#define _GNU_SOURCE /* asprintf, strdup */
#include "out.h"
#include "out_internal.h"
#include <assert.h>
#include <errno.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "compat.h"
#include "log.h"
#include "ly_common.h"
#include "metadata.h"
#include "printer_data.h"
#include "tree_data.h"
#include "tree_schema.h"
/**
* @brief Align the desired size to 1 KB.
*/
#define REALLOC_CHUNK(NEW_SIZE) \
NEW_SIZE + (1024 - (NEW_SIZE % 1024))
LIBYANG_API_DEF ly_bool
lyd_node_should_print(const struct lyd_node *node, uint32_t options)
{
const struct lyd_node *elem;
if (options & LYD_PRINT_WD_TRIM) {
/* do not print default nodes */
if (node->flags & LYD_DEFAULT) {
/* implicit default node/NP container with only default nodes */
return 0;
} else if (node->schema && (node->schema->nodetype & LYD_NODE_TERM)) {
if (lyd_is_default(node)) {
/* explicit default node */
return 0;
}
} else if (lysc_is_np_cont(node->schema)) {
if (options & LYD_PRINT_KEEPEMPTYCONT) {
/* explicit request to print, redundant to check */
return 1;
}
LY_LIST_FOR(lyd_child(node), elem) {
if (lyd_node_should_print(elem, options)) {
return 1;
}
}
/* NP container without any printed children (such as other NP containers with only nodes set to their default values) */
return 0;
}
} else if ((node->flags & LYD_DEFAULT) && (node->schema->nodetype == LYS_CONTAINER)) {
if (options & LYD_PRINT_KEEPEMPTYCONT) {
/* explicit request to print */
return 1;
}
/* avoid empty default containers */
LYD_TREE_DFS_BEGIN(node, elem) {
if ((elem != node) && lyd_node_should_print(elem, options)) {
return 1;
}
assert(elem->flags & LYD_DEFAULT);
LYD_TREE_DFS_END(node, elem)
}
return 0;
} else if ((node->flags & LYD_DEFAULT) && !(options & LYD_PRINT_WD_MASK) && !(node->schema->flags & LYS_CONFIG_R)) {
/* LYD_PRINT_WD_EXPLICIT, find out if this is some input/output */
if (!(node->schema->flags & (LYS_IS_INPUT | LYS_IS_OUTPUT | LYS_IS_NOTIF)) && (node->schema->flags & LYS_CONFIG_W)) {
/* print only if it contains status data in its subtree */
LYD_TREE_DFS_BEGIN(node, elem) {
if ((elem->schema->nodetype != LYS_CONTAINER) || (elem->schema->flags & LYS_PRESENCE)) {
if (elem->schema->flags & LYS_CONFIG_R) {
return 1;
}
}
LYD_TREE_DFS_END(node, elem)
}
}
return 0;
}
return 1;
}
LIBYANG_API_DEF ly_bool
lyd_metadata_should_print(const struct lyd_meta *meta)
{
return !lyd_meta_is_internal(meta);
}
LIBYANG_API_DEF LY_OUT_TYPE
ly_out_type(const struct ly_out *out)
{
LY_CHECK_ARG_RET(NULL, out, LY_OUT_ERROR);
return out->type;
}
LIBYANG_API_DEF LY_ERR
ly_out_new_clb(ly_write_clb writeclb, void *user_data, struct ly_out **out)
{
LY_CHECK_ARG_RET(NULL, out, writeclb, LY_EINVAL);
*out = calloc(1, sizeof **out);
LY_CHECK_ERR_RET(!*out, LOGMEM(NULL), LY_EMEM);
(*out)->type = LY_OUT_CALLBACK;
(*out)->method.clb.func = writeclb;
(*out)->method.clb.arg = user_data;
return LY_SUCCESS;
}
LIBYANG_API_DEF ly_write_clb
ly_out_clb(struct ly_out *out, ly_write_clb writeclb)
{
ly_write_clb prev_clb;
LY_CHECK_ARG_RET(NULL, out, out->type == LY_OUT_CALLBACK, NULL);
prev_clb = out->method.clb.func;
if (writeclb) {
out->method.clb.func = writeclb;
}
return prev_clb;
}
LIBYANG_API_DEF void *
ly_out_clb_arg(struct ly_out *out, void *arg)
{
void *prev_arg;
LY_CHECK_ARG_RET(NULL, out, out->type == LY_OUT_CALLBACK, NULL);
prev_arg = out->method.clb.arg;
if (arg) {
out->method.clb.arg = arg;
}
return prev_arg;
}
LIBYANG_API_DEF LY_ERR
ly_out_new_fd(int fd, struct ly_out **out)
{
LY_CHECK_ARG_RET(NULL, out, fd != -1, LY_EINVAL);
*out = calloc(1, sizeof **out);
LY_CHECK_ERR_RET(!*out, LOGMEM(NULL), LY_EMEM);
(*out)->type = LY_OUT_FD;
(*out)->method.fd = fd;
return LY_SUCCESS;
}
LIBYANG_API_DEF int
ly_out_fd(struct ly_out *out, int fd)
{
int prev_fd;
LY_CHECK_ARG_RET(NULL, out, out->type <= LY_OUT_FDSTREAM, -1);
if (out->type == LY_OUT_FDSTREAM) {
prev_fd = out->method.fdstream.fd;
} else { /* LY_OUT_FD */
prev_fd = out->method.fd;
}
if (fd != -1) {
/* replace output stream */
if (out->type == LY_OUT_FDSTREAM) {
int streamfd;
FILE *stream;
streamfd = dup(fd);
if (streamfd < 0) {
LOGERR(NULL, LY_ESYS, "Unable to duplicate provided file descriptor (%d) for printing the output (%s).", fd, strerror(errno));
return -1;
}
stream = fdopen(streamfd, "a");
if (!stream) {
LOGERR(NULL, LY_ESYS, "Unable to open provided file descriptor (%d) for printing the output (%s).", fd, strerror(errno));
close(streamfd);
return -1;
}
/* close only the internally created stream, file descriptor is returned and supposed to be closed by the caller */
fclose(out->method.fdstream.f);
out->method.fdstream.f = stream;
out->method.fdstream.fd = streamfd;
} else { /* LY_OUT_FD */
out->method.fd = fd;
}
}
return prev_fd;
}
LIBYANG_API_DEF LY_ERR
ly_out_new_file(FILE *f, struct ly_out **out)
{
LY_CHECK_ARG_RET(NULL, out, f, LY_EINVAL);
*out = calloc(1, sizeof **out);
LY_CHECK_ERR_RET(!*out, LOGMEM(NULL), LY_EMEM);
(*out)->type = LY_OUT_FILE;
(*out)->method.f = f;
return LY_SUCCESS;
}
LIBYANG_API_DEF FILE *
ly_out_file(struct ly_out *out, FILE *f)
{
FILE *prev_f;
LY_CHECK_ARG_RET(NULL, out, out->type == LY_OUT_FILE, NULL);
prev_f = out->method.f;
if (f) {
out->method.f = f;
}
return prev_f;
}
LIBYANG_API_DEF LY_ERR
ly_out_new_memory(char **strp, size_t size, struct ly_out **out)
{
LY_CHECK_ARG_RET(NULL, out, strp, LY_EINVAL);
*out = calloc(1, sizeof **out);
LY_CHECK_ERR_RET(!*out, LOGMEM(NULL), LY_EMEM);
(*out)->type = LY_OUT_MEMORY;
(*out)->method.mem.buf = strp;
if (!size) {
/* buffer is supposed to be allocated */
*strp = NULL;
} else if (*strp) {
/* there is already buffer to use */
(*out)->method.mem.size = size;
}
return LY_SUCCESS;
}
char *
ly_out_memory(struct ly_out *out, char **strp, size_t size)
{
char *data;
LY_CHECK_ARG_RET(NULL, out, out->type == LY_OUT_MEMORY, NULL);
data = *out->method.mem.buf;
if (strp) {
out->method.mem.buf = strp;
out->method.mem.len = out->method.mem.size = 0;
out->printed = 0;
if (!size) {
/* buffer is supposed to be allocated */
*strp = NULL;
} else if (*strp) {
/* there is already buffer to use */
out->method.mem.size = size;
}
}
return data;
}
LIBYANG_API_DEF LY_ERR
ly_out_reset(struct ly_out *out)
{
LY_CHECK_ARG_RET(NULL, out, LY_EINVAL);
switch (out->type) {
case LY_OUT_ERROR:
LOGINT(NULL);
return LY_EINT;
case LY_OUT_FD:
if ((lseek(out->method.fd, 0, SEEK_SET) == -1) && (errno != ESPIPE)) {
LOGERR(NULL, LY_ESYS, "Seeking output file descriptor failed (%s).", strerror(errno));
return LY_ESYS;
}
if ((errno != ESPIPE) && (ftruncate(out->method.fd, 0) == -1)) {
LOGERR(NULL, LY_ESYS, "Truncating output file failed (%s).", strerror(errno));
return LY_ESYS;
}
break;
case LY_OUT_FDSTREAM:
case LY_OUT_FILE:
case LY_OUT_FILEPATH:
if ((fseek(out->method.f, 0, SEEK_SET) == -1) && (errno != ESPIPE)) {
LOGERR(NULL, LY_ESYS, "Seeking output file stream failed (%s).", strerror(errno));
return LY_ESYS;
}
if ((errno != ESPIPE) && (ftruncate(fileno(out->method.f), 0) == -1)) {
LOGERR(NULL, LY_ESYS, "Truncating output file failed (%s).", strerror(errno));
return LY_ESYS;
}
break;
case LY_OUT_MEMORY:
if (out->method.mem.buf && *out->method.mem.buf) {
memset(*out->method.mem.buf, 0, out->method.mem.len);
}
out->printed = 0;
out->method.mem.len = 0;
break;
case LY_OUT_CALLBACK:
/* nothing to do (not seekable) */
break;
}
return LY_SUCCESS;
}
LIBYANG_API_DEF LY_ERR
ly_out_new_filepath(const char *filepath, struct ly_out **out)
{
LY_CHECK_ARG_RET(NULL, out, filepath, LY_EINVAL);
*out = calloc(1, sizeof **out);
LY_CHECK_ERR_RET(!*out, LOGMEM(NULL), LY_EMEM);
(*out)->type = LY_OUT_FILEPATH;
(*out)->method.fpath.f = fopen(filepath, "wb");
if (!(*out)->method.fpath.f) {
LOGERR(NULL, LY_ESYS, "Failed to open file \"%s\" (%s).", filepath, strerror(errno));
free(*out);
*out = NULL;
return LY_ESYS;
}
(*out)->method.fpath.filepath = strdup(filepath);
return LY_SUCCESS;
}
LIBYANG_API_DEF const char *
ly_out_filepath(struct ly_out *out, const char *filepath)
{
FILE *f;
LY_CHECK_ARG_RET(NULL, out, out->type == LY_OUT_FILEPATH, filepath ? NULL : ((void *)-1));
if (!filepath) {
return out->method.fpath.filepath;
}
/* replace filepath */
f = out->method.fpath.f;
out->method.fpath.f = fopen(filepath, "wb");
if (!out->method.fpath.f) {
LOGERR(NULL, LY_ESYS, "Failed to open file \"%s\" (%s).", filepath, strerror(errno));
out->method.fpath.f = f;
return (void *)-1;
}
fclose(f);
free(out->method.fpath.filepath);
out->method.fpath.filepath = strdup(filepath);
return NULL;
}
LIBYANG_API_DEF void
ly_out_free(struct ly_out *out, void (*clb_arg_destructor)(void *arg), ly_bool destroy)
{
if (!out) {
return;
}
switch (out->type) {
case LY_OUT_CALLBACK:
if (clb_arg_destructor) {
clb_arg_destructor(out->method.clb.arg);
}
break;
case LY_OUT_FDSTREAM:
fclose(out->method.fdstream.f);
if (destroy) {
close(out->method.fdstream.fd);
}
break;
case LY_OUT_FD:
if (destroy) {
close(out->method.fd);
}
break;
case LY_OUT_FILE:
if (destroy) {
fclose(out->method.f);
}
break;
case LY_OUT_MEMORY:
if (destroy) {
free(*out->method.mem.buf);
}
break;
case LY_OUT_FILEPATH:
free(out->method.fpath.filepath);
fclose(out->method.fpath.f);
break;
case LY_OUT_ERROR:
LOGINT(NULL);
}
free(out->buffered);
free(out);
}
static LY_ERR
ly_vprint_(struct ly_out *out, const char *format, va_list ap)
{
LY_ERR ret;
int written = 0;
char *msg = NULL;
switch (out->type) {
case LY_OUT_FD:
written = vdprintf(out->method.fd, format, ap);
break;
case LY_OUT_FDSTREAM:
case LY_OUT_FILEPATH:
case LY_OUT_FILE:
written = vfprintf(out->method.f, format, ap);
break;
case LY_OUT_MEMORY:
if ((written = vasprintf(&msg, format, ap)) < 0) {
break;
}
if (out->method.mem.len + written + 1 > out->method.mem.size) {
*out->method.mem.buf = ly_realloc(*out->method.mem.buf, out->method.mem.len + written + 1);
if (!*out->method.mem.buf) {
out->method.mem.len = 0;
out->method.mem.size = 0;
free(msg);
LOGMEM(NULL);
return LY_EMEM;
}
out->method.mem.size = out->method.mem.len + written + 1;
}
if (written) {
memcpy(&(*out->method.mem.buf)[out->method.mem.len], msg, written);
}
out->method.mem.len += written;
(*out->method.mem.buf)[out->method.mem.len] = '\0';
free(msg);
break;
case LY_OUT_CALLBACK:
if ((written = vasprintf(&msg, format, ap)) < 0) {
break;
}
written = out->method.clb.func(out->method.clb.arg, msg, written);
free(msg);
break;
case LY_OUT_ERROR:
LOGINT(NULL);
return LY_EINT;
}
if (written < 0) {
LOGERR(NULL, LY_ESYS, "%s: writing data failed (%s).", __func__, strerror(errno));
written = 0;
ret = LY_ESYS;
} else {
if (out->type == LY_OUT_FDSTREAM) {
/* move the original file descriptor to the end of the output file */
lseek(out->method.fdstream.fd, 0, SEEK_END);
}
ret = LY_SUCCESS;
}
out->printed += written;
out->func_printed += written;
return ret;
}
LY_ERR
ly_print_(struct ly_out *out, const char *format, ...)
{
LY_ERR ret;
va_list ap;
va_start(ap, format);
ret = ly_vprint_(out, format, ap);
va_end(ap);
return ret;
}
LIBYANG_API_DEF LY_ERR
ly_print(struct ly_out *out, const char *format, ...)
{
LY_ERR ret;
va_list ap;
out->func_printed = 0;
va_start(ap, format);
ret = ly_vprint_(out, format, ap);
va_end(ap);
return ret;
}
LIBYANG_API_DEF void
ly_print_flush(struct ly_out *out)
{
switch (out->type) {
case LY_OUT_FDSTREAM:
/* move the original file descriptor to the end of the output file */
lseek(out->method.fdstream.fd, 0, SEEK_END);
fflush(out->method.fdstream.f);
break;
case LY_OUT_FILEPATH:
case LY_OUT_FILE:
fflush(out->method.f);
break;
case LY_OUT_FD:
fsync(out->method.fd);
break;
case LY_OUT_MEMORY:
case LY_OUT_CALLBACK:
/* nothing to do */
break;
case LY_OUT_ERROR:
LOGINT(NULL);
}
free(out->buffered);
out->buf_size = out->buf_len = 0;
}
LY_ERR
ly_write_(struct ly_out *out, const char *buf, size_t len)
{
LY_ERR ret = LY_SUCCESS;
size_t written = 0, new_mem_size;
if (out->hole_count) {
/* we are buffering data after a hole */
if (out->buf_len + len > out->buf_size) {
out->buffered = ly_realloc(out->buffered, out->buf_len + len);
if (!out->buffered) {
out->buf_len = 0;
out->buf_size = 0;
LOGMEM(NULL);
return LY_EMEM;
}
out->buf_size = out->buf_len + len;
}
if (len) {
memcpy(&out->buffered[out->buf_len], buf, len);
}
out->buf_len += len;
out->printed += len;
out->func_printed += len;
return LY_SUCCESS;
}
repeat:
switch (out->type) {
case LY_OUT_MEMORY:
new_mem_size = out->method.mem.len + len + 1;
if (new_mem_size > out->method.mem.size) {
new_mem_size = REALLOC_CHUNK(new_mem_size);
*out->method.mem.buf = ly_realloc(*out->method.mem.buf, new_mem_size);
if (!*out->method.mem.buf) {
out->method.mem.len = 0;
out->method.mem.size = 0;
LOGMEM(NULL);
return LY_EMEM;
}
out->method.mem.size = new_mem_size;
}
if (len) {
memcpy(&(*out->method.mem.buf)[out->method.mem.len], buf, len);
}
out->method.mem.len += len;
(*out->method.mem.buf)[out->method.mem.len] = '\0';
written = len;
break;
case LY_OUT_FD: {
ssize_t r;
r = write(out->method.fd, buf, len);
if (r < 0) {
ret = LY_ESYS;
} else {
written = (size_t)r;
}
break;
}
case LY_OUT_FDSTREAM:
case LY_OUT_FILEPATH:
case LY_OUT_FILE:
written = fwrite(buf, sizeof *buf, len, out->method.f);
if (written != len) {
ret = LY_ESYS;
}
break;
case LY_OUT_CALLBACK: {
ssize_t r;
r = out->method.clb.func(out->method.clb.arg, buf, len);
if (r < 0) {
ret = LY_ESYS;
} else {
written = (size_t)r;
}
break;
}
case LY_OUT_ERROR:
LOGINT(NULL);
return LY_EINT;
}
if (ret) {
if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
ret = LY_SUCCESS;
goto repeat;
}
LOGERR(NULL, LY_ESYS, "%s: writing data failed (%s).", __func__, strerror(errno));
written = 0;
} else if (written != len) {
LOGERR(NULL, LY_ESYS, "%s: writing data failed (unable to write %" PRIu32 " from %" PRIu32 " data).", __func__,
(uint32_t)(len - written), (uint32_t)len);
ret = LY_ESYS;
} else {
if (out->type == LY_OUT_FDSTREAM) {
/* move the original file descriptor to the end of the output file */
lseek(out->method.fdstream.fd, 0, SEEK_END);
}
ret = LY_SUCCESS;
}
out->printed += written;
out->func_printed += written;
return ret;
}
LIBYANG_API_DEF LY_ERR
ly_write(struct ly_out *out, const char *buf, size_t len)
{
out->func_printed = 0;
return ly_write_(out, buf, len);
}
LIBYANG_API_DEF size_t
ly_out_printed(const struct ly_out *out)
{
return out->func_printed;
}
LY_ERR
ly_write_skip(struct ly_out *out, size_t count, size_t *position)
{
switch (out->type) {
case LY_OUT_MEMORY:
if (out->method.mem.len + count > out->method.mem.size) {
*out->method.mem.buf = ly_realloc(*out->method.mem.buf, out->method.mem.len + count);
if (!(*out->method.mem.buf)) {
out->method.mem.len = 0;
out->method.mem.size = 0;
LOGMEM(NULL);
return LY_EMEM;
}
out->method.mem.size = out->method.mem.len + count;
}
/* save the current position */
*position = out->method.mem.len;
/* skip the memory */
out->method.mem.len += count;
break;
case LY_OUT_FD:
case LY_OUT_FDSTREAM:
case LY_OUT_FILEPATH:
case LY_OUT_FILE:
case LY_OUT_CALLBACK:
/* buffer the hole */
if (out->buf_len + count > out->buf_size) {
out->buffered = ly_realloc(out->buffered, out->buf_len + count);
if (!out->buffered) {
out->buf_len = 0;
out->buf_size = 0;
LOGMEM(NULL);
return LY_EMEM;
}
out->buf_size = out->buf_len + count;
}
/* save the current position */
*position = out->buf_len;
/* skip the memory */
out->buf_len += count;
/* increase hole counter */
++out->hole_count;
break;
case LY_OUT_ERROR:
LOGINT(NULL);
return LY_EINT;
}
/* update printed bytes counter despite we actually printed just a hole */
out->printed += count;
out->func_printed += count;
return LY_SUCCESS;
}
LY_ERR
ly_write_skipped(struct ly_out *out, size_t position, const char *buf, size_t count)
{
LY_ERR ret = LY_SUCCESS;
assert(count);
switch (out->type) {
case LY_OUT_MEMORY:
/* write */
memcpy(&(*out->method.mem.buf)[position], buf, count);
break;
case LY_OUT_FD:
case LY_OUT_FDSTREAM:
case LY_OUT_FILEPATH:
case LY_OUT_FILE:
case LY_OUT_CALLBACK:
if (out->buf_len < position + count) {
LOGMEM(NULL);
return LY_EMEM;
}
/* write into the hole */
memcpy(&out->buffered[position], buf, count);
/* decrease hole counter */
--out->hole_count;
if (!out->hole_count) {
/* all holes filled, we can write the buffer,
* printed bytes counter is updated by ly_write_() */
ret = ly_write_(out, out->buffered, out->buf_len);
out->buf_len = 0;
}
break;
case LY_OUT_ERROR:
LOGINT(NULL);
return LY_EINT;
}
if (out->type == LY_OUT_FILEPATH) {
/* move the original file descriptor to the end of the output file */
lseek(out->method.fdstream.fd, 0, SEEK_END);
}
return ret;
}

307
src/out.h Normal file
View file

@ -0,0 +1,307 @@
/**
* @file out.h
* @author Radek Krejci <rkrejci@cesnet.cz>
* @brief libyang output structures and functions
*
* Copyright (c) 2015-2020 CESNET, z.s.p.o.
*
* This source code is licensed under BSD 3-Clause License (the "License").
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*/
#ifndef LY_OUT_H_
#define LY_OUT_H_
#include <stdio.h>
#include <sys/types.h>
#ifdef _MSC_VER
# define ssize_t SSIZE_T
#endif
#include "log.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @page howtoOutput Output Processing
*
* libyang provides a mechanism to generalize work with the outputs (and [inputs](@ref howtoInput)) of
* the different types. The ::ly_out handler can be created providing necessary information connected with the specific
* output type and then used throughout the printers functions. The API allows to combine output from libyang (data or schema)
* printers and output directly provided by the caller (via ::ly_print() or ::ly_write()).
*
* Using a generic output handler avoids need to have a set of functions for each printer functionality and results in simpler API.
*
* The API allows to alter the target of the data behind the handler by another target (of the same type). Also resetting
* a seekable output is possible with ::ly_out_reset() to re-write the output.
*
* @note
* This mechanism was introduced in libyang 2.0. To simplify transition from libyang 1.0 to version 2.0 and also for
* some simple use case where using the output handler would be an overkill, there are some basic printer functions
* that do not require output handler. But remember, that functionality of these function can be limited in particular cases
* in contrast to the functions using output handlers.
*
* Functions List
* --------------
* - ::ly_out_new_clb()
* - ::ly_out_new_fd()
* - ::ly_out_new_file()
* - ::ly_out_new_filepath()
* - ::ly_out_new_memory()
*
* - ::ly_out_clb()
* - ::ly_out_clb_arg()
* - ::ly_out_fd()
* - ::ly_out_file()
* - ::ly_out_filepath()
* - ::ly_out_memory()
*
* - ::ly_out_type()
* - ::ly_out_printed()
*
* - ::ly_out_reset()
* - ::ly_out_free()
*
* - ::ly_print()
* - ::ly_print_flush()
* - ::ly_write()
*
* libyang Printers List
* --------------------
* - @subpage howtoSchemaPrinters
* - @subpage howtoDataPrinters
*/
/**
* @struct ly_out
* @brief Printer output structure specifying where the data are printed.
*/
struct ly_out;
/**
* @brief Common value for data as well as schema printers to avoid formatting indentations and new lines
*/
#define LY_PRINT_SHRINK 0x02
/**
* @brief Types of the printer's output
*/
typedef enum LY_OUT_TYPE {
LY_OUT_ERROR = -1, /**< error value to indicate failure of the functions returning LY_OUT_TYPE */
LY_OUT_FD, /**< file descriptor printer */
LY_OUT_FDSTREAM, /**< internal replacement for LY_OUT_FD in case vdprintf() is not available */
LY_OUT_FILE, /**< FILE stream printer */
LY_OUT_FILEPATH, /**< filepath printer */
LY_OUT_MEMORY, /**< memory printer */
LY_OUT_CALLBACK /**< callback printer */
} LY_OUT_TYPE;
/**
* @brief Get output type of the printer handler.
*
* @param[in] out Printer handler.
* @return Type of the printer's output.
*/
LIBYANG_API_DECL LY_OUT_TYPE ly_out_type(const struct ly_out *out);
/**
* @brief Reset the output medium to write from its beginning, so the following printer function will rewrite the current data
* instead of appending.
*
* Note that in case the underlying output is not seekable (stream referring a pipe/FIFO/socket or the callback output type),
* nothing actually happens despite the function succeeds. Also note that the medium is not returned to the state it was when
* the handler was created. For example, file is seeked into the offset zero and truncated, the content from the time it was opened with
* ::ly_out_new_file() is not restored.
*
* @param[in] out Printer handler.
* @return LY_SUCCESS in case of success
* @return LY_ESYS in case of failure
*/
LIBYANG_API_DECL LY_ERR ly_out_reset(struct ly_out *out);
/**
* @brief Generic write callback for data printed by libyang.
*
* @param[in] user_data Optional caller-specific argument.
* @param[in] buf Data to write.
* @param[in] count Number of bytes to write.
* @return Number of printed bytes.
* @return Negative value in case of error.
*/
typedef ssize_t (*ly_write_clb)(void *user_data, const void *buf, size_t count);
/**
* @brief Create printer handler using callback printer function.
*
* @param[in] writeclb Pointer to the printer callback function writing the data (see write(2)).
* @param[in] user_data Optional caller-specific argument to be passed to the @p writeclb callback.
* @param[out] out Created printer handler supposed to be passed to different ly*_print() functions.
* @return LY_SUCCESS in case of success
* @return LY_EMEM in case allocating the @p out handler fails.
*/
LIBYANG_API_DECL LY_ERR ly_out_new_clb(ly_write_clb writeclb, void *user_data, struct ly_out **out);
/**
* @brief Get or reset callback function associated with a callback printer handler.
*
* @param[in] out Printer handler.
* @param[in] writeclb Optional argument providing a new printer callback function for the handler. If NULL, only the current
* printer callback is returned.
* @return Previous printer callback.
*/
LIBYANG_API_DECL ly_write_clb ly_out_clb(struct ly_out *out, ly_write_clb writeclb);
/**
* @brief Get or reset callback function's argument associated with a callback printer handler.
*
* @param[in] out Printer handler.
* @param[in] arg caller-specific argument to be passed to the callback function associated with the printer handler.
* If NULL, only the current file descriptor value is returned.
* @return The previous callback argument.
*/
LIBYANG_API_DECL void *ly_out_clb_arg(struct ly_out *out, void *arg);
/**
* @brief Create printer handler using file descriptor.
*
* @param[in] fd File descriptor to use.
* @param[out] out Created printer handler supposed to be passed to different ly*_print() functions.
* @return LY_SUCCESS in case of success
* @return LY_ERR value in case of failure.
*/
LIBYANG_API_DECL LY_ERR ly_out_new_fd(int fd, struct ly_out **out);
/**
* @brief Get or reset file descriptor printer handler.
*
* @param[in] out Printer handler.
* @param[in] fd Optional value of a new file descriptor for the handler. If -1, only the current file descriptor value is returned.
* @return Previous value of the file descriptor. Note that caller is responsible for closing the returned file descriptor in case of setting new descriptor @p fd.
* @return -1 in case of error when setting up the new file descriptor.
*/
LIBYANG_API_DECL int ly_out_fd(struct ly_out *out, int fd);
/**
* @brief Create printer handler using file stream.
*
* @param[in] f File stream to use.
* @param[out] out Created printer handler supposed to be passed to different ly*_print() functions.
* @return LY_SUCCESS in case of success
* @return LY_ERR value in case of failure.
*/
LIBYANG_API_DECL LY_ERR ly_out_new_file(FILE *f, struct ly_out **out);
/**
* @brief Get or reset file stream printer handler.
*
* @param[in] out Printer handler.
* @param[in] f Optional new file stream for the handler. If NULL, only the current file stream is returned.
* @return Previous file stream of the handler. Note that caller is responsible for closing the returned stream in case of setting new stream @p f.
*/
LIBYANG_API_DECL FILE *ly_out_file(struct ly_out *out, FILE *f);
/**
* @brief Create printer handler using memory to dump data.
*
* @param[in] strp Pointer to store the resulting data. If it points to a pointer to an allocated buffer and
* @p size of the buffer is set, the buffer is used (and extended if needed) to store the printed data.
* @param[in] size Size of the buffer provided via @p strp. In case it is 0, the buffer for the printed data
* is newly allocated even if @p strp points to a pointer to an existing buffer.
* @param[out] out Created printer handler supposed to be passed to different ly*_print() functions.
* @return LY_SUCCESS in case of success
* @return LY_ERR value in case of failure.
*/
LIBYANG_API_DECL LY_ERR ly_out_new_memory(char **strp, size_t size, struct ly_out **out);
/**
* @brief Get or change memory where the data are dumped.
*
* @param[in] out Printer handler.
* @param[in] strp Optional new string pointer to store the resulting data, same rules as in ::ly_out_new_memory() are applied.
* @param[in] size Size of the buffer provided via @p strp. In case it is 0, the buffer for the printed data
* is newly allocated even if @p strp points to a pointer to an existing buffer. In case the @p strp is NULL, this
* parameter is ignored.
* @return Previous dumped data. Note that the caller is responsible to free the data in case of changing string pointer @p strp.
*/
LIBYANG_API_DECL char *ly_out_memory(struct ly_out *out, char **strp, size_t size);
/**
* @brief Create printer handler file of the given filename.
*
* @param[in] filepath Path of the file where to write data.
* @param[out] out Created printer handler supposed to be passed to different ly*_print() functions.
* @return NULL in case of error.
* @return Created printer handler supposed to be passed to different ly*_print_*() functions.
*/
LIBYANG_API_DECL LY_ERR ly_out_new_filepath(const char *filepath, struct ly_out **out);
/**
* @brief Get or change the filepath of the file where the printer prints the data.
*
* Note that in case of changing the filepath, the current file is closed and a new one is
* created/opened instead of renaming the previous file. Also note that the previous filepath
* string is returned only in case of not changing it's value.
*
* @param[in] out Printer handler.
* @param[in] filepath Optional new filepath for the handler. If and only if NULL, the current filepath string is returned.
* @return Previous filepath string in case the @p filepath argument is NULL.
* @return NULL if changing filepath succeeds and ((void *)-1) otherwise.
*/
LIBYANG_API_DECL const char *ly_out_filepath(struct ly_out *out, const char *filepath);
/**
* @brief Generic printer of the given format string into the specified output.
*
* Alternatively, ::ly_write() can be used.
*
* @param[in] out Output specification.
* @param[in] format Format string to be printed.
* @return LY_ERR value, get number of the printed bytes using ::ly_out_printed.
*/
LIBYANG_API_DECL LY_ERR ly_print(struct ly_out *out, const char *format, ...);
/**
* @brief Flush the output from any internal buffers and clean any auxiliary data.
* @param[in] out Output specification.
*/
LIBYANG_API_DECL void ly_print_flush(struct ly_out *out);
/**
* @brief Generic printer of the given string buffer into the specified output.
*
* Alternatively, ::ly_print() can be used.
*
* @param[in] out Output specification.
* @param[in] buf Memory buffer with the data to print.
* @param[in] len Length of the data to print in the @p buf.
* @return LY_ERR value, get number of the printed bytes using ::ly_out_printed.
*/
LIBYANG_API_DECL LY_ERR ly_write(struct ly_out *out, const char *buf, size_t len);
/**
* @brief Get the number of printed bytes by the last function.
*
* @param[in] out Out structure used.
* @return Number of printed bytes.
*/
LIBYANG_API_DECL size_t ly_out_printed(const struct ly_out *out);
/**
* @brief Free the printer handler.
* @param[in] out Printer handler to free.
* @param[in] clb_arg_destructor Freeing function for printer callback (LY_OUT_CALLBACK) argument.
* @param[in] destroy Flag to free allocated buffer (for LY_OUT_MEMORY) or to
* close stream/file descriptor (for LY_OUT_FD, LY_OUT_FDSTREAM and LY_OUT_FILE)
*/
LIBYANG_API_DECL void ly_out_free(struct ly_out *out, void (*clb_arg_destructor)(void *arg), ly_bool destroy);
#ifdef __cplusplus
}
#endif
#endif /* LY_OUT_H_ */

110
src/out_internal.h Normal file
View file

@ -0,0 +1,110 @@
/**
* @file out_internal.h
* @author Radek Krejci <rkrejci@cesnet.cz>
* @brief Internal structures and functions for libyang
*
* Copyright (c) 2015-2020 CESNET, z.s.p.o.
*
* This source code is licensed under BSD 3-Clause License (the "License").
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*/
#ifndef LY_OUT_INTERNAL_H_
#define LY_OUT_INTERNAL_H_
#include "out.h"
struct lyd_node;
/**
* @brief Printer output structure specifying where the data are printed.
*/
struct ly_out {
LY_OUT_TYPE type; /**< type of the output to select the output method */
union {
int fd; /**< file descriptor for LY_OUT_FD type */
FILE *f; /**< file structure for LY_OUT_FILE, LY_OUT_FDSTREAM and LY_OUT_FILEPATH types */
struct {
FILE *f; /**< file stream from the original file descriptor, variable is mapped to the LY_OUT_FILE's f */
int fd; /**< original file descriptor, which was not used directly because of missing vdprintf() */
} fdstream; /**< structure for LY_OUT_FDSTREAM type, which is LY_OUT_FD when vdprintf() is missing */
struct {
FILE *f; /**< file structure for LY_OUT_FILEPATH, variable is mapped to the LY_OUT_FILE's f */
char *filepath; /**< stored original filepath */
} fpath; /**< filepath structure for LY_OUT_FILEPATH */
struct {
char **buf; /**< storage for the pointer to the memory buffer to store the output */
size_t len; /**< number of used bytes in the buffer */
size_t size; /**< allocated size of the buffer */
} mem; /**< memory buffer information for LY_OUT_MEMORY type */
struct {
ssize_t (*func)(void *arg, const void *buf, size_t count); /**< callback function */
void *arg; /**< optional argument for the callback function */
} clb; /**< printer callback for LY_OUT_CALLBACK type */
} method; /**< type-specific information about the output */
/* LYB only */
char *buffered; /**< additional buffer for holes */
size_t buf_len; /**< number of used bytes in the additional buffer for holes */
size_t buf_size; /**< allocated size of the buffer for holes */
size_t hole_count; /**< hole counter */
size_t printed; /**< Total number of printed bytes */
size_t func_printed; /**< Number of bytes printed by the last function */
};
/**
* @brief Generic printer of the given format string into the specified output.
*
* Does not reset printed bytes. Adds to printed bytes.
*
* @param[in] out Output specification.
* @param[in] format Format string to be printed.
* @return LY_ERR value.
*/
LY_ERR ly_print_(struct ly_out *out, const char *format, ...);
/**
* @brief Generic printer of the given string buffer into the specified output.
*
* Does not reset printed bytes. Adds to printed bytes.
*
* @param[in] out Output specification.
* @param[in] buf Memory buffer with the data to print.
* @param[in] len Length of the data to print in the @p buf.
* @return LY_ERR value.
*/
LY_ERR ly_write_(struct ly_out *out, const char *buf, size_t len);
/**
* @brief Create a hole in the output data that will be filled later.
*
* Adds printed bytes.
*
* @param[in] out Output specification.
* @param[in] len Length of the created hole.
* @param[out] position Position of the hole, value must be later provided to the ::ly_write_skipped() call.
* @return LY_ERR value.
*/
LY_ERR ly_write_skip(struct ly_out *out, size_t len, size_t *position);
/**
* @brief Write data into the hole at given position.
*
* Does not change printed bytes.
*
* @param[in] out Output specification.
* @param[in] position Position of the hole to fill, the value was provided by ::ly_write_skip().
* @param[in] buf Memory buffer with the data to print.
* @param[in] len Length of the data to print in the @p buf. Not that the length must correspond
* to the len value specified in the corresponding ::ly_write_skip() call.
* @return LY_ERR value.
*/
LY_ERR ly_write_skipped(struct ly_out *out, size_t position, const char *buf, size_t len);
#endif /* LY_OUT_INTERNAL_H_ */

Some files were not shown because too many files have changed in this diff Show more