1
0
Fork 0

Merging upstream version 3.12.2.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-05-02 04:14:45 +02:00
parent 6375ddbe5b
commit 580fa3f55c
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
66 changed files with 4041 additions and 2142 deletions

View file

@ -25,7 +25,7 @@ jobs:
options: "-DENABLE_TESTS=ON",
packager: "sudo apt-get",
# no expect because stdout seems to be redirected
packages: "libcmocka-dev shunit2",
packages: "libcmocka-dev libxxhash-dev shunit2",
snaps: "",
build-cmd: "make"
}
@ -36,7 +36,7 @@ jobs:
cc: "clang",
options: "-DENABLE_TESTS=ON",
packager: "sudo apt-get",
packages: "libcmocka-dev shunit2",
packages: "libcmocka-dev libxxhash-dev shunit2",
snaps: "",
build-cmd: "make"
}
@ -47,7 +47,7 @@ jobs:
cc: "gcc",
options: "",
packager: "sudo apt-get",
packages: "libcmocka-dev valgrind shunit2",
packages: "libcmocka-dev libxxhash-dev valgrind shunit2",
snaps: "",
build-cmd: "make"
}
@ -59,7 +59,7 @@ jobs:
options: "",
packager: "sudo apt-get",
# no valgrind because it does not support DWARF5 yet generated by clang 14
packages: "libcmocka-dev shunit2",
packages: "libcmocka-dev libxxhash-dev shunit2",
snaps: "",
build-cmd: "make"
}
@ -70,7 +70,7 @@ jobs:
cc: "clang",
options: "-DENABLE_TESTS=ON -DPATH_EXPECT=",
packager: "brew",
packages: "cmocka shunit2 tcl-tk",
packages: "cmocka xxhash shunit2 tcl-tk",
snaps: "",
build-cmd: "make"
}
@ -81,7 +81,7 @@ jobs:
cc: "clang",
options: "-DCMAKE_C_FLAGS=-fsanitize=address,undefined -DENABLE_TESTS=ON -DENABLE_VALGRIND_TESTS=OFF",
packager: "sudo apt-get",
packages: "libcmocka-dev",
packages: "libcmocka-dev libxxhash-dev",
snaps: "",
build-cmd: "make"
}
@ -92,7 +92,7 @@ jobs:
cc: "gcc",
options: "",
packager: "sudo apt-get",
packages: "libcmocka-dev abi-dumper abi-compliance-checker",
packages: "libcmocka-dev libxxhash-dev abi-dumper abi-compliance-checker",
snaps: "core universal-ctags",
build-cmd: "make abi-check"
}
@ -103,7 +103,7 @@ jobs:
cc: "gcc",
options: "",
packager: "sudo apt-get",
packages: "cmake debhelper libcmocka-dev python3-pip",
packages: "cmake debhelper libcmocka-dev libxxhash-dev python3-pip",
snaps: "",
build-cmd: ""
}
@ -132,7 +132,7 @@ jobs:
cd uncrustify
mkdir build
cd build
CC=${{ matrix.config.cc }} cmake ..
CC=${{ matrix.config.cc }} cmake -DCMAKE_POLICY_VERSION_MINIMUM=3.5 ..
make
sudo make install
if: ${{ matrix.config.name == 'Debug, gcc' }}
@ -209,8 +209,13 @@ jobs:
id: cpu-cores
uses: SimenB/github-actions-cpu-cores@v1
- name: pin CMake to the latest 3.x series
uses: jwlawson/actions-setup-cmake@09fd9b0fb3b239b4b68d9256cd65adf8d6b91da0
with:
cmake-version: '3.31.6'
- name: Install Windows dependencies
run: vcpkg install --triplet=${{ matrix.triplet }} pcre2 pthreads dirent dlfcn-win32 cmocka getopt
run: vcpkg install --triplet=${{ matrix.triplet }} pcre2 pthreads dirent dlfcn-win32 cmocka getopt xxhash
- name: Configure
shell: bash

View file

@ -17,7 +17,7 @@ jobs:
fuzz-seconds: 300
dry-run: false
- name: Upload Crash
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@main
if: failure() && steps.build.outcome == 'success'
with:
name: artifacts

View file

@ -34,7 +34,7 @@ jobs:
cc: "gcc",
options: "-DENABLE_COVERAGE=ON",
packager: "sudo apt-get",
packages: "libcmocka-dev lcov",
packages: "libcmocka-dev libxxhash-dev lcov",
snaps: "",
make-prepend: "",
make-target: ""

View file

@ -59,14 +59,14 @@ set (CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
# set version of the project
set(LIBYANG_MAJOR_VERSION 3)
set(LIBYANG_MINOR_VERSION 7)
set(LIBYANG_MICRO_VERSION 8)
set(LIBYANG_MINOR_VERSION 12)
set(LIBYANG_MICRO_VERSION 2)
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 6)
set(LIBYANG_MICRO_SOVERSION 10)
set(LIBYANG_MINOR_SOVERSION 9)
set(LIBYANG_MICRO_SOVERSION 1)
set(LIBYANG_SOVERSION_FULL ${LIBYANG_MAJOR_SOVERSION}.${LIBYANG_MINOR_SOVERSION}.${LIBYANG_MICRO_SOVERSION})
set(LIBYANG_SOVERSION ${LIBYANG_MAJOR_SOVERSION})
@ -411,6 +411,17 @@ find_package(PCRE2 10.21 REQUIRED)
include_directories(${PCRE2_INCLUDE_DIRS})
target_link_libraries(yang ${PCRE2_LIBRARIES})
# XXHash include and library
find_package(XXHash)
if(XXHASH_FOUND)
add_definitions(-DLY_XXHASH_SUPPORT)
include_directories(${XXHASH_INCLUDE_DIR})
target_link_libraries(yang ${XXHASH_LIBRARY})
message(STATUS "Hash algorithm: xxhash")
else()
message(STATUS "Hash algorithm: internal Jenkin's one-at-a-time")
endif()
# generated header list
foreach(h IN LISTS gen_headers)
list(APPEND g_headers ${PROJECT_BINARY_DIR}/libyang/${h})

View file

@ -0,0 +1,38 @@
# Try to find XXHash
# Once done this will define
#
# Read-Only variables:
# XXHASH_FOUND - system has XXHash
# XXHASH_INCLUDE_DIR - the XXHash include directory
# XXHASH_LIBRARY - Link these to use XXHash
find_path(XXHASH_INCLUDE_DIR
NAMES
xxhash.h
PATHS
/usr/include
/usr/local/include
/opt/local/include
/sw/include
${CMAKE_INCLUDE_PATH}
${CMAKE_INSTALL_PREFIX}/include
)
find_library(XXHASH_LIBRARY
NAMES
xxhash
libxxhash
PATHS
PATHS
/usr/lib
/usr/lib64
/usr/local/lib
/usr/local/lib64
/opt/local/lib
/sw/lib
${CMAKE_LIBRARY_PATH}
${CMAKE_INSTALL_PREFIX}/lib
)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(XXHash FOUND_VAR XXHASH_FOUND REQUIRED_VARS XXHASH_INCLUDE_DIR XXHASH_LIBRARY)

View file

@ -61,6 +61,7 @@ the `distro` directory.
#### Optional
* xxhash (for faster hashing)
* doxygen (for generating documentation)
* cmocka >= 1.0.1 (for [tests](#Tests))
* valgrind (for enhanced testing)

View file

@ -1,485 +0,0 @@
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
};

565
models/yang@2025-01-29.h Normal file
View file

@ -0,0 +1,565 @@
char yang_2025_01_29_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, 0x35, 0x2d, 0x30, 0x31, 0x2d,
0x32, 0x39, 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, 0x20, 0x6f, 0x66, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x64,
0x61, 0x74, 0x61, 0x2e, 0x22, 0x3b, 0x0a, 0x20, 0x20, 0x7d, 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, 0x74, 0x79,
0x70, 0x65, 0x64, 0x65, 0x66, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61,
0x74, 0x61, 0x2d, 0x63, 0x68, 0x61, 0x6e, 0x67, 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, 0x52, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e,
0x74, 0x73, 0x20, 0x61, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74,
0x61, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x76,
0x61, 0x6c, 0x75, 0x65, 0x20, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x20,
0x61, 0x6e, 0x64, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x69, 0x73, 0x74, 0x73,
0x20, 0x6f, 0x66, 0x20, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x6e,
0x61, 0x6d, 0x65, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6e,
0x61, 0x6d, 0x65, 0x2c, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x74, 0x68, 0x65,
0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68,
0x65, 0x20, 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x27, 0x3c, 0x6d, 0x6f, 0x64,
0x75, 0x6c, 0x65, 0x2d, 0x6e, 0x61, 0x6d, 0x65, 0x3e, 0x3a, 0x3c, 0x61,
0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x6e, 0x61,
0x6d, 0x65, 0x3e, 0x3d, 0x3c, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3e, 0x27,
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, 0x0a, 0x20,
0x20, 0x6d, 0x64, 0x3a, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69,
0x6f, 0x6e, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x2d, 0x63, 0x72, 0x65, 0x61,
0x74, 0x65, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x74, 0x79, 0x70,
0x65, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2d, 0x63,
0x68, 0x61, 0x6e, 0x67, 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, 0x72, 0x65, 0x61, 0x74, 0x65,
0x64, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x20, 0x69,
0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x77, 0x69, 0x74, 0x68,
0x20, 0x69, 0x74, 0x73, 0x20, 0x6e, 0x65, 0x77, 0x20, 0x76, 0x61, 0x6c,
0x75, 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, 0x6d, 0x65, 0x74, 0x61, 0x2d, 0x64, 0x65, 0x6c, 0x65,
0x74, 0x65, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x74, 0x79, 0x70,
0x65, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2d, 0x63,
0x68, 0x61, 0x6e, 0x67, 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, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65,
0x64, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x20, 0x69,
0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x77, 0x69, 0x74, 0x68,
0x20, 0x69, 0x74, 0x73, 0x20, 0x6f, 0x6c, 0x64, 0x20, 0x76, 0x61, 0x6c,
0x75, 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, 0x6d, 0x65, 0x74, 0x61, 0x2d, 0x72, 0x65, 0x70, 0x6c,
0x61, 0x63, 0x65, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x74, 0x79,
0x70, 0x65, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2d,
0x63, 0x68, 0x61, 0x6e, 0x67, 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, 0x68, 0x61, 0x6e, 0x67,
0x65, 0x64, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x20,
0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x77, 0x69, 0x74,
0x68, 0x20, 0x69, 0x74, 0x73, 0x20, 0x6e, 0x65, 0x77, 0x20, 0x76, 0x61,
0x6c, 0x75, 0x65, 0x2e, 0x20, 0x54, 0x68, 0x65, 0x20, 0x6f, 0x6c, 0x64,
0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x69, 0x73, 0x20, 0x73, 0x74,
0x6f, 0x72, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x27, 0x6d, 0x65, 0x74,
0x61, 0x2d, 0x6f, 0x72, 0x69, 0x67, 0x27, 0x20, 0x6d, 0x65, 0x74, 0x61,
0x64, 0x61, 0x74, 0x61, 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, 0x6d, 0x65, 0x74, 0x61, 0x2d, 0x6f, 0x72,
0x69, 0x67, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x74, 0x79, 0x70,
0x65, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2d, 0x63,
0x68, 0x61, 0x6e, 0x67, 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, 0x68, 0x61, 0x6e, 0x67, 0x65,
0x64, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x20, 0x69,
0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x77, 0x69, 0x74, 0x68,
0x20, 0x69, 0x74, 0x73, 0x20, 0x6f, 0x6c, 0x64, 0x20, 0x76, 0x61, 0x6c,
0x75, 0x65, 0x2e, 0x20, 0x54, 0x68, 0x65, 0x20, 0x6e, 0x65, 0x77, 0x20,
0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x69, 0x73, 0x20, 0x73, 0x74, 0x6f,
0x72, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x27, 0x6d, 0x65, 0x74, 0x61,
0x2d, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x27, 0x20, 0x6d, 0x65,
0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x22, 0x3b, 0x0a, 0x20, 0x20,
0x7d, 0x0a, 0x7d, 0x0a, 0x00
};

View file

@ -21,6 +21,11 @@ module yang {
of various metadata defined in RFC 6020 and RFC 7950. There are
additional metadata used in libyang diff data format.";
revision 2025-01-29 {
description
"Added metadata for diff of metadata.";
}
revision 2022-06-16 {
description
"Added typedef for key metadata type.";
@ -59,6 +64,13 @@ module yang {
"The key predicates of the full instance-identifier built-in type.";
}
typedef metadata-change {
type string;
description
"Represents a metadata instance value change and consists of module name,
annotation name, and the value in the form '<module-name>:<annotation-name>=<value>'.";
}
md:annotation insert {
type enumeration {
enum first;
@ -192,4 +204,28 @@ module yang {
"Its meaning is the same as the \"position\" attribute but identifies
the original list instance rather than the new one.";
}
md:annotation meta-create {
type metadata-change;
description
"Created metadata instance with its new value.";
}
md:annotation meta-delete {
type metadata-change;
description
"Deleted metadata instance with its old value.";
}
md:annotation meta-replace {
type metadata-change;
description
"Changed metadata instance with its new value. The old value is stored in 'meta-orig' metadata.";
}
md:annotation meta-orig {
type metadata-change;
description
"Changed metadata instance with its old value. The new value is stored in 'meta-replace' metadata.";
}
}

View file

@ -55,7 +55,7 @@
#include "../models/ietf-yang-schema-mount@2019-01-14.h"
#include "../models/ietf-yang-structure-ext@2020-06-17.h"
#include "../models/ietf-yang-types@2013-07-15.h"
#include "../models/yang@2022-06-16.h"
#include "../models/yang@2025-01-29.h"
#define IETF_YANG_LIB_REV "2019-01-04"
static struct internal_modules_s {
@ -66,7 +66,7 @@ static struct internal_modules_s {
LYS_INFORMAT format;
} internal_modules[] = {
{"ietf-yang-metadata", "2016-08-05", (const char *)ietf_yang_metadata_2016_08_05_yang, 0, LYS_IN_YANG},
{"yang", "2022-06-16", (const char *)yang_2022_06_16_yang, 1, LYS_IN_YANG},
{"yang", "2025-01-29", (const char *)yang_2025_01_29_yang, 1, LYS_IN_YANG},
{"ietf-inet-types", "2013-07-15", (const char *)ietf_inet_types_2013_07_15_yang, 0, LYS_IN_YANG},
{"ietf-yang-types", "2013-07-15", (const char *)ietf_yang_types_2013_07_15_yang, 0, LYS_IN_YANG},
{"ietf-yang-schema-mount", "2019-01-14", (const char *)ietf_yang_schema_mount_2019_01_14_yang, 1, LYS_IN_YANG},
@ -272,9 +272,9 @@ ly_ctx_ht_err_equal_cb(void *val1_p, void *val2_p, ly_bool UNUSED(mod), void *UN
static ly_bool
ly_ctx_ht_leafref_links_equal_cb(void *val1_p, void *val2_p, ly_bool UNUSED(mod), void *UNUSED(cb_data))
{
struct lyd_leafref_links_rec *rec1 = val1_p, *rec2 = val2_p;
struct lyd_leafref_links_rec **rec1 = val1_p, **rec2 = val2_p;
return rec1->node == rec2->node;
return (*rec1)->node == (*rec2)->node;
}
/**
@ -285,9 +285,10 @@ ly_ctx_ht_leafref_links_equal_cb(void *val1_p, void *val2_p, ly_bool UNUSED(mod)
static void
ly_ctx_ht_leafref_links_rec_free(void *val_p)
{
struct lyd_leafref_links_rec *rec = val_p;
struct lyd_leafref_links_rec **rec = val_p;
lyd_free_leafref_links_rec(rec);
lyd_free_leafref_links_rec(*rec);
free(*rec);
}
LIBYANG_API_DEF LY_ERR
@ -316,7 +317,12 @@ ly_ctx_new(const char *search_dir, uint16_t options, struct ly_ctx **new_ctx)
LY_CHECK_ERR_GOTO(lyplg_init(builtin_plugins_only), LOGINT(NULL); rc = LY_EINT, cleanup);
if (options & LY_CTX_LEAFREF_LINKING) {
ctx->leafref_links_ht = lyht_new(1, sizeof(struct lyd_leafref_links_rec), ly_ctx_ht_leafref_links_equal_cb, NULL, 1);
/**
* storing the pointer instead of record itself is needed to avoid invalid memory reads. Hash table can reallocate
* its memory completely during various manipulation function (e.g. remove, insert). In case of using pointers, the
* pointer can be reallocated safely, while record itself remains untouched and can be accessed/modified freely
* */
ctx->leafref_links_ht = lyht_new(1, sizeof(struct lyd_leafref_links_rec *), ly_ctx_ht_leafref_links_equal_cb, NULL, 1);
LY_CHECK_ERR_GOTO(!ctx->leafref_links_ht, rc = LY_EMEM, cleanup);
}
@ -367,7 +373,7 @@ ly_ctx_new(const char *search_dir, uint16_t options, struct ly_ctx **new_ctx)
/* load internal modules */
for (i = 0; i < ((options & LY_CTX_NO_YANGLIBRARY) ? (LY_INTERNAL_MODS_COUNT - 2) : LY_INTERNAL_MODS_COUNT); i++) {
ly_in_memory(in, internal_modules[i].data);
LY_CHECK_GOTO(rc = lys_parse_in(ctx, in, internal_modules[i].format, NULL, NULL, &unres.creating, &module), cleanup);
LY_CHECK_GOTO(rc = lys_parse_in(ctx, in, internal_modules[i].format, NULL, &unres.creating, &module), cleanup);
if (internal_modules[i].implemented || (ctx->flags & LY_CTX_ALL_IMPLEMENTED)) {
imp_f = (ctx->flags & LY_CTX_ENABLE_IMP_FEATURES) ? all_f : NULL;
LY_CHECK_GOTO(rc = lys_implement(module, imp_f, &unres), cleanup);
@ -654,7 +660,7 @@ ly_ctx_set_options(struct ly_ctx *ctx, uint16_t option)
}
if (!(ctx->flags & LY_CTX_LEAFREF_LINKING) && (option & LY_CTX_LEAFREF_LINKING)) {
ctx->leafref_links_ht = lyht_new(1, sizeof(struct lyd_leafref_links_rec), ly_ctx_ht_leafref_links_equal_cb, NULL, 1);
ctx->leafref_links_ht = lyht_new(1, sizeof(struct lyd_leafref_links_rec *), ly_ctx_ht_leafref_links_equal_cb, NULL, 1);
LY_CHECK_ERR_RET(!ctx->leafref_links_ht, LOGARG(ctx, option), LY_EMEM);
}

1198
src/diff.c

File diff suppressed because it is too large Load diff

View file

@ -3,7 +3,7 @@
* @author Michal Vasko <mvasko@cesnet.cz>
* @brief internal diff header
*
* Copyright (c) 2020 CESNET, z.s.p.o.
* Copyright (c) 2020 - 2025 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.
@ -53,10 +53,11 @@ enum lyd_diff_op {
* @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.
* @param[out] diff_node Optional created diff node.
* @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);
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, struct lyd_node **diff_node);
#endif /* LY_DIFF_H_ */

View file

@ -4,7 +4,7 @@
* @author Michal Vasko <mvasko@cesnet.cz>
* @brief libyang generic hash table implementation
*
* Copyright (c) 2015 - 2023 CESNET, z.s.p.o.
* Copyright (c) 2015 - 2025 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.
@ -26,9 +26,20 @@
#include "log.h"
#include "ly_common.h"
#ifdef LY_XXHASH_SUPPORT
# include <xxhash.h>
#endif
LIBYANG_API_DEF uint32_t
lyht_hash_multi(uint32_t hash, const char *key_part, size_t len)
{
#ifdef LY_XXHASH_SUPPORT
if (key_part && len) {
return XXH3_64bits_withSeed(key_part, len, hash);
}
return XXH3_64bits_withSeed(NULL, 0, hash);
#else
uint32_t i;
if (key_part && len) {
@ -44,15 +55,20 @@ lyht_hash_multi(uint32_t hash, const char *key_part, size_t len)
}
return hash;
#endif
}
LIBYANG_API_DEF uint32_t
lyht_hash(const char *key, size_t len)
{
#ifdef LY_XXHASH_SUPPORT
return XXH3_64bits(key, len);
#else
uint32_t hash;
hash = lyht_hash_multi(0, key, len);
return lyht_hash_multi(hash, NULL, len);
#endif
}
static LY_ERR

View file

@ -54,6 +54,8 @@ LIBYANG_API_DECL uint32_t lyht_hash_multi(uint32_t hash, const char *key_part, s
*
* Spooky hash is faster, but it works only for little endian architectures.
*
* Uses XXH3_64bits internally if xxhash is available. See https://xxhash.com
*
* @param[in] key Key to hash.
* @param[in] len Length of @p key.
* @return Hash of the key.

View file

@ -579,6 +579,38 @@ log_stderr_path_line(const char *data_path, const char *schema_path, uint64_t li
fprintf(stderr, par ? ")\n" : "\n");
}
/**
* @brief Learn whether a log is a no-operation or must be produced, based on current ly_log_opts.
*
* @param[in] level Message log level to compare to enabled logging level.
* @param[out] will_log Optionally learn whether the log will be printed.
* @param[out] will_store Optionally learn whether the log will be stored.
* @return 1 if the log is a no-operation, 0 otherwise.
*/
static ly_bool
log_is_noop(LY_LOG_LEVEL level, ly_bool *will_log, ly_bool *will_store)
{
ly_bool 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 (will_log) {
*will_log = lolog;
}
if (will_store) {
*will_store = lostore;
}
return (level > ATOMIC_LOAD_RELAXED(ly_ll)) || (!lolog && !lostore);
}
/**
* @brief Log a message.
*
@ -601,16 +633,7 @@ log_vprintf(const struct ly_ctx *ctx, LY_LOG_LEVEL level, LY_ERR err, LY_VECODE
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)) {
if (log_is_noop(level, &lolog, &lostore)) {
/* do not print or store the message */
goto cleanup;
}
@ -858,6 +881,10 @@ ly_vlog(const struct ly_ctx *ctx, const char *apptag, LY_VECODE code, const char
char *data_path = NULL, *schema_path = NULL;
uint64_t line = 0;
if (log_is_noop(LY_LLERR, NULL, NULL)) {
return;
}
if (ctx) {
ly_vlog_build_path_line(ctx, &data_path, &schema_path, &line);
}
@ -887,9 +914,10 @@ ly_ext_log(const struct ly_ctx *ctx, const char *plugin_name, LY_LOG_LEVEL level
{
char *plugin_msg;
if (ATOMIC_LOAD_RELAXED(ly_ll) < level) {
if (log_is_noop(level, NULL, NULL)) {
return;
}
if (asprintf(&plugin_msg, "Ext plugin \"%s\": %s", plugin_name, format) == -1) {
LOGMEM(ctx);
return;
@ -987,6 +1015,10 @@ _ly_err_print(const struct ly_ctx *ctx, const struct ly_err_item *eitem, const c
LY_CHECK_ARG_RET(ctx, eitem, );
if (log_is_noop(eitem->level, NULL, NULL)) {
return;
}
if (eitem->data_path) {
data_path = strdup(eitem->data_path);
}

View file

@ -154,7 +154,7 @@ const struct lyd_node *ly_log_location_dnode(uint32_t idx);
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).
* @brief Update location schema/data nodes for logger. If both NULL, root data node is added.
*
* @param[in] SCNODE Compiled schema node.
* @param[in] DNODE Data node.
@ -232,12 +232,12 @@ void ly_log_dbg(uint32_t group, const char *format, ...);
#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__)
#define LY_CHECK_CTX_EQUAL_RET2(FUNC, CTX1, CTX2, RETVAL) if ((CTX1) && (CTX2) && ((CTX1) != (CTX2))) \
{LOGERR(CTX1, LY_EINVAL, "Different contexts mixed in a \"%s\" function call.", FUNC); return RETVAL;}
#define LY_CHECK_CTX_EQUAL_RET3(FUNC, CTX1, CTX2, CTX3, RETVAL) LY_CHECK_CTX_EQUAL_RET2(FUNC, CTX1, CTX2, RETVAL); \
LY_CHECK_CTX_EQUAL_RET2(FUNC, CTX2, CTX3, RETVAL); LY_CHECK_CTX_EQUAL_RET2(FUNC, CTX1, CTX3, RETVAL)
#define LY_CHECK_CTX_EQUAL_RET(FUNC, CTX, ...) GETMACRO3(__VA_ARGS__, LY_CHECK_CTX_EQUAL_RET3, LY_CHECK_CTX_EQUAL_RET2, \
DUMMY) (FUNC, CTX, __VA_ARGS__)
/* count sequence size for LY_VCODE_INCHILDSTMT validation error code */
int LY_VCODE_INSTREXP_len(const char *str);

View file

@ -179,7 +179,10 @@ struct ly_in;
#define LYD_PARSE_JSON_NULL 0x4000000 /**< Allow using JSON empty value 'null' within JSON input, such nodes are
silently skipped and treated as non-existent. By default, such values
are invalid. */
#define LYD_PARSE_JSON_STRING_DATATYPES 0x8000000 /**< By default, JSON data values are expected to be in the correct
format according to RFC 7951 based on their type. Using this
option the validation can be softened to accept boolean and
number type values enclosed in quotes. */
#define LYD_PARSE_OPTS_MASK 0xFFFF0000 /**< Mask for all the LYD_PARSE_ options. */
/** @} dataparseroptions */

View file

@ -340,7 +340,7 @@ cleanup:
/**
* @brief Get the hint for the data type parsers according to the current JSON parser context.
*
* @param[in] jsonctx JSON parser context. The context is supposed to be on a value.
* @param[in] lydctx JSON data parser context.
* @param[in,out] status Pointer to the current context status,
* in some circumstances the function manipulates with the context so the status is updated.
* @param[out] type_hint_p Pointer to the variable to store the result.
@ -348,8 +348,10 @@ cleanup:
* @return LY_EINVAL in case of invalid context status not referring to a value.
*/
static LY_ERR
lydjson_value_type_hint(struct lyjson_ctx *jsonctx, enum LYJSON_PARSER_STATUS *status_p, uint32_t *type_hint_p)
lydjson_value_type_hint(struct lyd_json_ctx *lydctx, enum LYJSON_PARSER_STATUS *status_p, uint32_t *type_hint_p)
{
struct lyjson_ctx *jsonctx = lydctx->jsonctx;
*type_hint_p = 0;
if (*status_p == LYJSON_ARRAY) {
@ -383,6 +385,10 @@ lydjson_value_type_hint(struct lyjson_ctx *jsonctx, enum LYJSON_PARSER_STATUS *s
return LY_EINVAL;
}
if (lydctx->parse_opts & LYD_PARSE_JSON_STRING_DATATYPES) {
*type_hint_p |= LYD_VALHINT_STRING_DATATYPES;
}
return LY_SUCCESS;
}
@ -391,15 +397,16 @@ lydjson_value_type_hint(struct lyjson_ctx *jsonctx, enum LYJSON_PARSER_STATUS *s
*
* Checks for all the list's keys. Function does not revert the context state.
*
* @param[in] jsonctx JSON parser context.
* @param[in] lydctx JSON data parser context.
* @param[in] list List schema node corresponding to the input data object.
* @return LY_SUCCESS in case the data are ok for the @p list
* @return LY_ENOT in case the input data are not sufficient to fully parse the list instance.
*/
static LY_ERR
lydjson_check_list(struct lyjson_ctx *jsonctx, const struct lysc_node *list)
lydjson_check_list(struct lyd_json_ctx *lydctx, const struct lysc_node *list)
{
LY_ERR rc = LY_SUCCESS;
struct lyjson_ctx *jsonctx = lydctx->jsonctx;
enum LYJSON_PARSER_STATUS status = lyjson_ctx_status(jsonctx);
struct ly_set key_set = {0};
const struct lysc_node *snode;
@ -451,7 +458,7 @@ lydjson_check_list(struct lyjson_ctx *jsonctx, const struct lysc_node *list)
goto cleanup;
}
rc = lydjson_value_type_hint(jsonctx, &status, &hints);
rc = lydjson_value_type_hint(lydctx, &status, &hints);
LY_CHECK_GOTO(rc, cleanup);
rc = ly_value_validate(NULL, snode, jsonctx->value, jsonctx->value_len, LY_VALUE_JSON, NULL, hints);
LY_CHECK_GOTO(rc, cleanup);
@ -521,7 +528,7 @@ lydjson_data_check_opaq(struct lyd_json_ctx *lydctx, const struct lysc_node *sno
case LYS_LEAFLIST:
case LYS_LEAF:
/* value may not be valid in which case we parse it as an opaque node */
if ((ret = lydjson_value_type_hint(jsonctx, &status, type_hint_p))) {
if ((ret = lydjson_value_type_hint(lydctx, &status, type_hint_p))) {
break;
}
@ -533,14 +540,14 @@ lydjson_data_check_opaq(struct lyd_json_ctx *lydctx, const struct lysc_node *sno
break;
case LYS_LIST:
/* lists may not have all its keys */
if (lydjson_check_list(jsonctx, snode)) {
if (lydjson_check_list(lydctx, snode)) {
/* invalid list, parse as opaque if it misses/has invalid some keys */
ret = LY_ENOT;
}
break;
}
} else if (snode->nodetype & LYD_NODE_TERM) {
ret = lydjson_value_type_hint(jsonctx, &status, type_hint_p);
ret = lydjson_value_type_hint(lydctx, &status, type_hint_p);
}
/* restore parser */
@ -852,7 +859,7 @@ next_entry:
LY_CHECK_GOTO(rc = lyjson_ctx_next(lydctx->jsonctx, &status), cleanup);
/* get value hints */
LY_CHECK_GOTO(rc = lydjson_value_type_hint(lydctx->jsonctx, &status, &val_hints), cleanup);
LY_CHECK_GOTO(rc = lydjson_value_type_hint(lydctx, &status, &val_hints), cleanup);
if (node->schema) {
/* create metadata */
@ -981,7 +988,7 @@ lydjson_create_opaq(struct lyd_json_ctx *lydctx, const char *name, size_t name_l
dynamic = lydctx->jsonctx->dynamic;
lydctx->jsonctx->dynamic = 0;
LY_CHECK_RET(lydjson_value_type_hint(lydctx->jsonctx, status_inner_p, &type_hint));
LY_CHECK_RET(lydjson_value_type_hint(lydctx, status_inner_p, &type_hint));
}
/* get the module name */

View file

@ -4,7 +4,7 @@
* @author Michal Vasko <mvasko@cesnet.cz>
* @brief XML data parser for libyang
*
* Copyright (c) 2019 - 2022 CESNET, z.s.p.o.
* Copyright (c) 2019 - 2025 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.
@ -1392,396 +1392,10 @@ cleanup:
return rc;
}
/**
* @brief Parse an XML element as an opaque node subtree.
*
* @param[in] xmlctx XML parser context.
* @param[in] parent Parent to append nodes to.
* @return LY_ERR value.
*/
static LY_ERR
lydxml_opaq_r(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
{
LY_ERR rc = LY_SUCCESS;
const struct lyxml_ns *ns;
struct lyd_attr *attr = NULL;
struct lyd_node *node = NULL;
struct lyd_node_opaq *opaq;
const char *name, *prefix, *value = NULL;
size_t name_len, prefix_len, value_len;
ly_bool ws_only, dynamic = 0;
assert(xmlctx->status == LYXML_ELEMENT);
name = xmlctx->name;
name_len = xmlctx->name_len;
prefix = xmlctx->prefix;
prefix_len = xmlctx->prefix_len;
ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
if (!ns) {
lydxml_log_namespace_err(xmlctx, prefix, prefix_len, NULL, 0);
return LY_EVALID;
}
LY_CHECK_RET(lyxml_ctx_next(xmlctx));
/* create attributes */
if (xmlctx->status == LYXML_ATTRIBUTE) {
LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
}
/* remember the value */
assert(xmlctx->status == LYXML_ELEM_CONTENT);
value = xmlctx->value;
value_len = xmlctx->value_len;
ws_only = xmlctx->ws_only;
dynamic = xmlctx->dynamic;
if (dynamic) {
xmlctx->dynamic = 0;
}
/* create the node without value */
rc = lyd_create_opaq(xmlctx->ctx, name, name_len, prefix, prefix_len, ns->uri, strlen(ns->uri), NULL, 0, NULL,
LY_VALUE_XML, NULL, 0, &node);
LY_CHECK_GOTO(rc, cleanup);
/* assign atributes */
((struct lyd_node_opaq *)node)->attr = attr;
attr = NULL;
/* parser next element */
LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
/* parse all the descendants */
while (xmlctx->status == LYXML_ELEMENT) {
rc = lydxml_opaq_r(xmlctx, node);
LY_CHECK_GOTO(rc, cleanup);
}
/* insert */
lyd_insert_node(parent, NULL, node, LYD_INSERT_NODE_LAST);
/* update the value */
opaq = (struct lyd_node_opaq *)node;
if (opaq->child) {
if (!ws_only) {
LOGVAL(xmlctx->ctx, LYVE_SYNTAX_XML, "Mixed XML content node \"%s\" found, not supported.", LYD_NAME(node));
rc = LY_EVALID;
goto cleanup;
}
} else if (value_len) {
lydict_remove(xmlctx->ctx, opaq->value);
if (dynamic) {
LY_CHECK_GOTO(rc = lydict_insert_zc(xmlctx->ctx, (char *)value, &opaq->value), cleanup);
dynamic = 0;
} else {
LY_CHECK_GOTO(rc = lydict_insert(xmlctx->ctx, value, value_len, &opaq->value), cleanup);
}
}
cleanup:
lyd_free_attr_siblings(xmlctx->ctx, attr);
if (dynamic) {
free((char *)value);
}
if (rc) {
lyd_free_tree(node);
}
return rc;
}
/**
* @brief Parse all expected non-data XML elements of the error-info element in NETCONF rpc-reply message.
*
* @param[in] xmlctx XML parser context.
* @param[in] parent Parent to append nodes to.
* @return LY_ERR value.
*/
static LY_ERR
lydxml_env_netconf_rpc_reply_error_info(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
{
LY_ERR r;
struct lyd_node *child, *iter;
ly_bool no_dup;
/* there must be some child */
if (xmlctx->status == LYXML_ELEM_CLOSE) {
LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"error-info\".");
return LY_EVALID;
}
while (xmlctx->status == LYXML_ELEMENT) {
child = NULL;
/*
* session-id
*/
r = lydxml_envelope(xmlctx, "session-id", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
if (r == LY_SUCCESS) {
no_dup = 1;
goto check_child;
} else if (r != LY_ENOT) {
goto error;
}
/*
* bad-attribute
*/
r = lydxml_envelope(xmlctx, "bad-attribute", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
if (r == LY_SUCCESS) {
no_dup = 1;
goto check_child;
} else if (r != LY_ENOT) {
goto error;
}
/*
* bad-element
*/
r = lydxml_envelope(xmlctx, "bad-element", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
if (r == LY_SUCCESS) {
no_dup = 1;
goto check_child;
} else if (r != LY_ENOT) {
goto error;
}
/*
* bad-namespace
*/
r = lydxml_envelope(xmlctx, "bad-namespace", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
if (r == LY_SUCCESS) {
no_dup = 1;
goto check_child;
} else if (r != LY_ENOT) {
goto error;
}
if (r == LY_ENOT) {
assert(xmlctx->status == LYXML_ELEMENT);
/* custom elements, parse all the siblings */
while (xmlctx->status == LYXML_ELEMENT) {
LY_CHECK_GOTO(r = lydxml_opaq_r(xmlctx, parent), error);
LY_CHECK_GOTO(r = lyxml_ctx_next(xmlctx), error);
}
continue;
}
check_child:
/* check for duplicates */
if (no_dup) {
LY_LIST_FOR(lyd_child(parent), iter) {
if ((((struct lyd_node_opaq *)iter)->name.name == ((struct lyd_node_opaq *)child)->name.name) &&
(((struct lyd_node_opaq *)iter)->name.module_ns == ((struct lyd_node_opaq *)child)->name.module_ns)) {
LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Duplicate element \"%s\" in \"error-info\".",
((struct lyd_node_opaq *)child)->name.name);
r = LY_EVALID;
goto error;
}
}
}
/* finish child parsing */
if (xmlctx->status != LYXML_ELEM_CLOSE) {
assert(xmlctx->status == LYXML_ELEMENT);
LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"error-info\".",
(int)xmlctx->name_len, xmlctx->name);
r = LY_EVALID;
goto error;
}
LY_CHECK_GOTO(r = lyxml_ctx_next(xmlctx), error);
/* insert */
lyd_insert_node(parent, NULL, child, LYD_INSERT_NODE_LAST);
}
return LY_SUCCESS;
error:
lyd_free_tree(child);
return r;
}
/**
* @brief Parse all expected non-data XML elements of the rpc-error element in NETCONF rpc-reply message.
*
* @param[in] xmlctx XML parser context.
* @param[in] parent Parent to append nodes to.
* @return LY_ERR value.
*/
static LY_ERR
lydxml_env_netconf_rpc_reply_error(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
{
LY_ERR r;
struct lyd_node *child, *iter;
const char *val;
ly_bool no_dup;
/* there must be some child */
if (xmlctx->status == LYXML_ELEM_CLOSE) {
LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"rpc-error\".");
return LY_EVALID;
}
while (xmlctx->status == LYXML_ELEMENT) {
child = NULL;
/*
* error-type
*/
r = lydxml_envelope(xmlctx, "error-type", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
if (r == LY_SUCCESS) {
val = ((struct lyd_node_opaq *)child)->value;
if (strcmp(val, "transport") && strcmp(val, "rpc") && strcmp(val, "protocol") && strcmp(val, "application")) {
LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
((struct lyd_node_opaq *)child)->name.name);
r = LY_EVALID;
goto error;
}
no_dup = 1;
goto check_child;
} else if (r != LY_ENOT) {
goto error;
}
/*
* error-tag
*/
r = lydxml_envelope(xmlctx, "error-tag", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
if (r == LY_SUCCESS) {
val = ((struct lyd_node_opaq *)child)->value;
if (strcmp(val, "in-use") && strcmp(val, "invalid-value") && strcmp(val, "too-big") &&
strcmp(val, "missing-attribute") && strcmp(val, "bad-attribute") &&
strcmp(val, "unknown-attribute") && strcmp(val, "missing-element") && strcmp(val, "bad-element") &&
strcmp(val, "unknown-element") && strcmp(val, "unknown-namespace") && strcmp(val, "access-denied") &&
strcmp(val, "lock-denied") && strcmp(val, "resource-denied") && strcmp(val, "rollback-failed") &&
strcmp(val, "data-exists") && strcmp(val, "data-missing") && strcmp(val, "operation-not-supported") &&
strcmp(val, "operation-failed") && strcmp(val, "malformed-message")) {
LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
((struct lyd_node_opaq *)child)->name.name);
r = LY_EVALID;
goto error;
}
no_dup = 1;
goto check_child;
} else if (r != LY_ENOT) {
goto error;
}
/*
* error-severity
*/
r = lydxml_envelope(xmlctx, "error-severity", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
if (r == LY_SUCCESS) {
val = ((struct lyd_node_opaq *)child)->value;
if (strcmp(val, "error") && strcmp(val, "warning")) {
LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
((struct lyd_node_opaq *)child)->name.name);
r = LY_EVALID;
goto error;
}
no_dup = 1;
goto check_child;
} else if (r != LY_ENOT) {
goto error;
}
/*
* error-app-tag
*/
r = lydxml_envelope(xmlctx, "error-app-tag", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
if (r == LY_SUCCESS) {
no_dup = 1;
goto check_child;
} else if (r != LY_ENOT) {
goto error;
}
/*
* error-path
*/
r = lydxml_envelope(xmlctx, "error-path", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
if (r == LY_SUCCESS) {
no_dup = 1;
goto check_child;
} else if (r != LY_ENOT) {
goto error;
}
/*
* error-message
*/
r = lydxml_envelope(xmlctx, "error-message", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
if (r == LY_SUCCESS) {
no_dup = 1;
goto check_child;
} else if (r != LY_ENOT) {
goto error;
}
/* error-info */
r = lydxml_envelope(xmlctx, "error-info", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
if (r == LY_SUCCESS) {
/* parse all the descendants */
LY_CHECK_GOTO(r = lydxml_env_netconf_rpc_reply_error_info(xmlctx, child), error);
no_dup = 0;
goto check_child;
} else if (r != LY_ENOT) {
goto error;
}
if (r == LY_ENOT) {
assert(xmlctx->status == LYXML_ELEMENT);
LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"rpc-error\".",
(int)xmlctx->name_len, xmlctx->name);
r = LY_EVALID;
goto error;
}
check_child:
/* check for duplicates */
if (no_dup) {
LY_LIST_FOR(lyd_child(parent), iter) {
if ((((struct lyd_node_opaq *)iter)->name.name == ((struct lyd_node_opaq *)child)->name.name) &&
(((struct lyd_node_opaq *)iter)->name.module_ns == ((struct lyd_node_opaq *)child)->name.module_ns)) {
LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Duplicate element \"%s\" in \"rpc-error\".",
((struct lyd_node_opaq *)child)->name.name);
r = LY_EVALID;
goto error;
}
}
}
/* finish child parsing */
if (xmlctx->status != LYXML_ELEM_CLOSE) {
assert(xmlctx->status == LYXML_ELEMENT);
LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"rpc-error\".",
(int)xmlctx->name_len, xmlctx->name);
r = LY_EVALID;
goto error;
}
LY_CHECK_GOTO(r = lyxml_ctx_next(xmlctx), error);
/* insert */
lyd_insert_node(parent, NULL, child, LYD_INSERT_NODE_LAST);
}
return LY_SUCCESS;
error:
lyd_free_tree(child);
return r;
}
/**
* @brief Parse all expected non-data XML elements of a NETCONF rpc-reply message.
*
* @param[in] xmlctx XML parser context.
* @param[in] lydctx XML YANG data parser context.
* @param[out] evnp Parsed envelope(s) (opaque node).
* @param[out] int_opts Internal options for parsing the rest of YANG data.
* @param[out] close_elem Number of parsed opened elements that need to be closed.
@ -1789,14 +1403,19 @@ error:
* @return LY_ERR value on error.
*/
static LY_ERR
lydxml_env_netconf_reply(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
lydxml_env_netconf_reply(struct lyd_xml_ctx *lydctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
{
LY_ERR rc = LY_SUCCESS, r;
struct lyxml_ctx *xmlctx = lydctx->xmlctx;
struct lyd_node *child = NULL;
const char *parsed_elem = NULL;
assert(envp && !*envp);
/* not all nodes are represented as internal schema nodes and there may even be custom additional nodes */
lydctx->parse_opts &= ~LYD_PARSE_STRICT;
lydctx->parse_opts |= LYD_PARSE_OPAQ;
/* parse "rpc-reply" */
r = lydxml_envelope(xmlctx, "rpc-reply", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, envp);
LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
@ -1833,24 +1452,8 @@ lydxml_env_netconf_reply(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint3
}
/* try to parse all "rpc-error" elements */
while (xmlctx->status == LYXML_ELEMENT) {
r = lydxml_envelope(xmlctx, "rpc-error", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
if (r == LY_ENOT) {
break;
} else if (r) {
rc = r;
goto cleanup;
}
/* insert */
lyd_insert_node(*envp, NULL, child, LYD_INSERT_NODE_LAST);
/* parse all children of "rpc-error" */
LY_CHECK_GOTO(rc = lydxml_env_netconf_rpc_reply_error(xmlctx, child), cleanup);
/* finish child parsing */
assert(xmlctx->status == LYXML_ELEM_CLOSE);
LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
while ((xmlctx->status == LYXML_ELEMENT) && !ly_strncmp("rpc-error", xmlctx->name, xmlctx->name_len)) {
LY_CHECK_GOTO(rc = lydxml_subtree_r(lydctx, *envp, lyd_node_child_p(*envp), NULL), cleanup);
parsed_elem = "rpc-error";
}
@ -1929,7 +1532,7 @@ lyd_parse_xml_netconf(const struct ly_ctx *ctx, const struct lysc_ext_instance *
break;
case LYD_TYPE_REPLY_NETCONF:
assert(parent);
rc = lydxml_env_netconf_reply(lydctx->xmlctx, envp, &int_opts, &close_elem);
rc = lydxml_env_netconf_reply(lydctx, envp, &int_opts, &close_elem);
if (rc == LY_ENOT) {
LOGVAL(ctx, LYVE_DATA, "Missing NETCONF <rpc-reply> envelope or in incorrect namespace.");
}

View file

@ -100,7 +100,7 @@ struct lys_glob_unres;
goto ERR_LABEL; \
} \
if (KW == LY_STMT_SYNTAX_RIGHT_BRACE) { \
if (EXTS && (RET = ly_set_add(&(CTX)->main_ctx->ext_inst, (EXTS), 1, NULL))) { \
if (EXTS && (RET = ly_set_add(&(CTX)->ext_inst, (EXTS), 1, NULL))) { \
goto ERR_LABEL; \
} \
__loop_end = 1; \
@ -417,13 +417,11 @@ read_qstring(struct lysp_yang_ctx *ctx, enum yang_arg arg, char **word_p, char *
break;
case '\r':
/* newline may be escaped */
if ((ctx->in->current[1] != '\n') && strncmp(&ctx->in->current[1], "\\n", 2)) {
LOGVAL_PARSER(ctx, LY_VCODE_INCHAR, ctx->in->current[0]);
return LY_EVALID;
}
if ((ctx->in->current[1] == '\n') || !strncmp(&ctx->in->current[1], "\\n", 2)) {
/* skip this character, do not store it */
++ctx->in->current;
} /* else just store '\n' instead */
/* skip this character, do not store it */
++ctx->in->current;
/* fallthrough */
case '\n':
if (block_indent) {
@ -437,9 +435,20 @@ read_qstring(struct lysp_yang_ctx *ctx, enum yang_arg arg, char **word_p, char *
current_indent = 0;
}
c = NULL;
if (ctx->in->current[0] != '\n') {
/* storing '\r' as '\n' */
c = ctx->in->current;
ctx->in->current = "\n";
}
/* check and store character */
LY_CHECK_RET(buf_store_char(ctx, arg, word_p, word_len, word_b, buf_len, need_buf, &prefix));
if (c) {
ctx->in->current = c + 1;
}
/* reset context indentation counter for possible string after this one */
ctx->indent = 0;
trailing_ws = 0;
@ -2833,8 +2842,7 @@ parse_typedef(struct lysp_yang_ctx *ctx, struct lysp_node *parent, struct lysp_t
/* store data for collision check */
if (parent) {
assert(ctx->main_ctx);
LY_CHECK_RET(ly_set_add(&ctx->main_ctx->tpdfs_nodes, parent, 0, NULL));
LY_CHECK_RET(ly_set_add(&ctx->tpdfs_nodes, parent, 0, NULL));
}
cleanup:
@ -3175,8 +3183,7 @@ parse_grouping(struct lysp_yang_ctx *ctx, struct lysp_node *parent, struct lysp_
/* store data for collision check */
if (parent) {
assert(ctx->main_ctx);
LY_CHECK_RET(ly_set_add(&ctx->main_ctx->grps_nodes, parent, 0, NULL));
LY_CHECK_RET(ly_set_add(&ctx->grps_nodes, parent, 0, NULL));
}
cleanup:

View file

@ -646,7 +646,7 @@ yin_unres_exts_add(struct lysp_yin_ctx *ctx, struct lysp_ext_instance *exts)
return LY_SUCCESS;
}
return ly_set_add(&ctx->main_ctx->ext_inst, exts, 1, NULL);
return ly_set_add(&ctx->ext_inst, exts, 1, NULL);
}
/**
@ -1713,8 +1713,7 @@ yin_parse_typedef(struct lysp_yin_ctx *ctx, struct tree_node_meta *typedef_meta)
/* store data for collision check */
if (typedef_meta->parent) {
assert(ctx->main_ctx);
LY_CHECK_RET(ly_set_add(&ctx->main_ctx->tpdfs_nodes, typedef_meta->parent, 0, NULL));
LY_CHECK_RET(ly_set_add(&ctx->tpdfs_nodes, typedef_meta->parent, 0, NULL));
}
return LY_SUCCESS;
@ -2472,8 +2471,7 @@ yin_parse_grouping(struct lysp_yin_ctx *ctx, struct tree_node_meta *gr_meta)
/* store data for collision check */
if (!ret && grp->parent) {
assert(ctx->main_ctx);
LY_CHECK_RET(ly_set_add(&ctx->main_ctx->grps_nodes, grp->parent, 0, NULL));
LY_CHECK_RET(ly_set_add(&ctx->grps_nodes, grp->parent, 0, NULL));
}
return ret;

View file

@ -3,7 +3,7 @@
* @author Michal Vasko <mvasko@cesnet.cz>
* @brief Path functions
*
* Copyright (c) 2020 - 2023 CESNET, z.s.p.o.
* Copyright (c) 2020 - 2025 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.
@ -339,6 +339,17 @@ ly_path_parse(const struct ly_ctx *ctx, const struct lysc_node *ctx_node, const
LOG_LOCSET(ctx_node, NULL);
}
if (!path_len) {
path_len = strlen(str_path);
}
/* check if path begins with '/' if expected to and fail early if not */
if ((begin == LY_PATH_BEGIN_ABSOLUTE) && (str_path[0] != '/')) {
LOGVAL(ctx, LYVE_XPATH, "XPath \"%.*s\" was expected to be absolute.", (int)path_len, str_path);
ret = LY_EVALID;
goto error;
}
/* parse as a generic XPath expression, reparse is performed manually */
LY_CHECK_GOTO(ret = lyxp_expr_parse(ctx, str_path, path_len, 0, &exp), error);
tok_idx = 0;
@ -499,7 +510,7 @@ error:
* @brief Parse NameTest and get the corresponding schema node.
*
* @param[in] ctx libyang context.
* @param[in] cur_node Optional current (original context) node.
* @param[in] cur_node Current (original context) node.
* @param[in] cur_mod Current module of the path (where the path is "instantiated"). Needed for ::LY_VALUE_SCHEMA
* and ::LY_VALUE_SCHEMA_RESOLVED.
* @param[in] prev_ctx_node Previous context node.
@ -519,7 +530,7 @@ ly_path_compile_snode(const struct ly_ctx *ctx, const struct lysc_node *cur_node
void *prefix_data, const struct lysc_ext_instance *top_ext, uint32_t getnext_opts, const struct lysc_node **snode,
struct lysc_ext_instance **ext)
{
LY_ERR ret;
LY_ERR rc = LY_SUCCESS, r;
const struct lys_module *mod = NULL;
struct lysc_ext_instance *e = NULL;
const char *pref, *name;
@ -551,39 +562,37 @@ ly_path_compile_snode(const struct ly_ctx *ctx, const struct lysc_node *cur_node
/* find node module */
if (pref) {
if (cur_node) {
LOG_LOCSET(cur_node, NULL);
}
mod = ly_resolve_prefix(prev_ctx_node ? prev_ctx_node->module->ctx : ctx, pref, len, format, prefix_data);
if ((!mod || !mod->implemented) && prev_ctx_node) {
/* check for nested ext data */
ret = ly_nested_ext_schema(NULL, prev_ctx_node, pref, len, format, prefix_data, name, name_len, snode, &e);
if (!ret) {
goto success;
} else if (ret != LY_ENOT) {
goto error;
r = ly_nested_ext_schema(NULL, prev_ctx_node, pref, len, format, prefix_data, name, name_len, snode, &e);
if (!r) {
goto cleanup;
} else if (r != LY_ENOT) {
rc = r;
goto cleanup;
}
}
if (!mod) {
LOGVAL(ctx, LYVE_XPATH, "No module connected with the prefix \"%.*s\" found (prefix format %s).",
(int)len, pref, ly_format2str(format));
ret = LY_EVALID;
goto error;
LOGVAL_PATH(ctx, cur_node, prev_ctx_node, LYVE_XPATH,
"No module connected with the prefix \"%.*s\" found (prefix format %s).", (int)len, pref,
ly_format2str(format));
rc = LY_EVALID;
goto cleanup;
} else if (!mod->implemented) {
LOGVAL(ctx, LYVE_XPATH, "Not implemented module \"%s\" in path.", mod->name);
ret = LY_EVALID;
goto error;
LOGVAL_PATH(ctx, cur_node, prev_ctx_node, LYVE_XPATH, "Not implemented module \"%s\" in path.", mod->name);
rc = LY_EVALID;
goto cleanup;
}
LOG_LOCBACK(cur_node ? 1 : 0, 0);
} else {
switch (format) {
case LY_VALUE_SCHEMA:
case LY_VALUE_SCHEMA_RESOLVED:
if (!cur_mod) {
LOGINT_RET(ctx);
LOGINT(ctx);
rc = LY_EINT;
goto cleanup;
}
/* use current module */
mod = cur_mod;
@ -591,7 +600,9 @@ ly_path_compile_snode(const struct ly_ctx *ctx, const struct lysc_node *cur_node
case LY_VALUE_JSON:
case LY_VALUE_LYB:
if (!prev_ctx_node) {
LOGINT_RET(ctx);
LOGINT(ctx);
rc = LY_EINT;
goto cleanup;
}
/* inherit module of the previous node */
mod = prev_ctx_node->module;
@ -600,7 +611,9 @@ ly_path_compile_snode(const struct ly_ctx *ctx, const struct lysc_node *cur_node
case LY_VALUE_XML:
case LY_VALUE_STR_NS:
/* not really defined or accepted */
LOGINT_RET(ctx);
LOGINT(ctx);
rc = LY_EINT;
goto cleanup;
}
}
@ -610,24 +623,21 @@ ly_path_compile_snode(const struct ly_ctx *ctx, const struct lysc_node *cur_node
} else {
*snode = lys_find_child(prev_ctx_node, mod, name, name_len, 0, getnext_opts);
if (!(*snode) && prev_ctx_node) {
ret = ly_nested_ext_schema(NULL, prev_ctx_node, pref, len, format, prefix_data, name, name_len, snode, &e);
LY_CHECK_RET(ret && (ret != LY_ENOT), ret);
r = ly_nested_ext_schema(NULL, prev_ctx_node, pref, len, format, prefix_data, name, name_len, snode, &e);
LY_CHECK_ERR_GOTO(r && (r != LY_ENOT), rc = r, cleanup);
}
}
if (!(*snode)) {
LOGVAL(ctx, LYVE_XPATH, "Not found node \"%.*s\" in path.", (int)name_len, name);
return LY_ENOTFOUND;
LOGVAL_PATH(ctx, cur_node, prev_ctx_node, LYVE_XPATH, "Not found node \"%.*s\" in path.", (int)name_len, name);
rc = LY_ENOTFOUND;
goto cleanup;
}
success:
if (ext) {
cleanup:
if (!rc && ext) {
*ext = e;
}
return LY_SUCCESS;
error:
LOG_LOCBACK(cur_node ? 1 : 0, 0);
return ret;
return rc;
}
LY_ERR
@ -635,7 +645,7 @@ ly_path_compile_predicate(const struct ly_ctx *ctx, const struct lysc_node *cur_
const struct lysc_node *ctx_node, const struct lyxp_expr *expr, uint32_t *tok_idx, LY_VALUE_FORMAT format,
void *prefix_data, struct ly_path_predicate **predicates)
{
LY_ERR ret = LY_SUCCESS;
LY_ERR rc = LY_SUCCESS;
struct ly_path_predicate *p;
const struct lysc_node *key;
const char *val;
@ -643,10 +653,6 @@ ly_path_compile_predicate(const struct ly_ctx *ctx, const struct lysc_node *cur_
assert(ctx && ctx_node);
if (cur_node) {
LOG_LOCSET(cur_node, NULL);
}
*predicates = NULL;
if (lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1)) {
@ -656,31 +662,32 @@ ly_path_compile_predicate(const struct ly_ctx *ctx, const struct lysc_node *cur_
if (expr->tokens[*tok_idx] == LYXP_TOKEN_NAMETEST) {
if (ctx_node->nodetype != LYS_LIST) {
LOGVAL(ctx, LYVE_XPATH, "List predicate defined for %s \"%s\" in path.",
LOGVAL_PATH(ctx, cur_node, ctx_node, LYVE_XPATH, "List predicate defined for %s \"%s\" in path.",
lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
ret = LY_EVALID;
rc = LY_EVALID;
goto cleanup;
} else if (ctx_node->flags & LYS_KEYLESS) {
LOGVAL(ctx, LYVE_XPATH, "List predicate defined for keyless %s \"%s\" in path.",
LOGVAL_PATH(ctx, cur_node, ctx_node, LYVE_XPATH, "List predicate defined for keyless %s \"%s\" in path.",
lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
ret = LY_EVALID;
rc = LY_EVALID;
goto cleanup;
}
do {
/* NameTest, find the key */
LY_CHECK_RET(ly_path_compile_snode(ctx, cur_node, cur_mod, ctx_node, expr, *tok_idx, format, prefix_data,
NULL, 0, &key, NULL));
rc = ly_path_compile_snode(ctx, cur_node, cur_mod, ctx_node, expr, *tok_idx, format, prefix_data, NULL, 0,
&key, NULL);
LY_CHECK_GOTO(rc, cleanup);
if ((key->nodetype != LYS_LEAF) || !(key->flags & LYS_KEY)) {
LOGVAL(ctx, LYVE_XPATH, "Key expected instead of %s \"%s\" in path.", lys_nodetype2str(key->nodetype),
key->name);
ret = LY_EVALID;
LOGVAL_PATH(ctx, cur_node, ctx_node, LYVE_XPATH, "Key expected instead of %s \"%s\" in path.",
lys_nodetype2str(key->nodetype), key->name);
rc = LY_EVALID;
goto cleanup;
}
++(*tok_idx);
/* new predicate */
LY_ARRAY_NEW_GOTO(ctx, *predicates, p, ret, cleanup);
LY_ARRAY_NEW_GOTO(ctx, *predicates, p, rc, cleanup);
p->key = key;
/* '=' */
@ -691,7 +698,7 @@ ly_path_compile_predicate(const struct ly_ctx *ctx, const struct lysc_node *cur_
if (expr->tokens[*tok_idx] == LYXP_TOKEN_VARREF) {
/* store the variable name */
p->variable = strndup(expr->expr + expr->tok_pos[*tok_idx], expr->tok_len[*tok_idx]);
LY_CHECK_ERR_GOTO(!p->variable, LOGMEM(ctx); ret = LY_EMEM, cleanup);
LY_CHECK_ERR_GOTO(!p->variable, LOGMEM(ctx); rc = LY_EMEM, cleanup);
p->type = LY_PATH_PREDTYPE_LIST_VAR;
++(*tok_idx);
@ -708,10 +715,10 @@ ly_path_compile_predicate(const struct ly_ctx *ctx, const struct lysc_node *cur_
/* store the value */
LOG_LOCSET(key, NULL);
ret = lyd_value_store(ctx_node->module->ctx, &p->value, ((struct lysc_node_leaf *)key)->type, val, val_len, 0, 0,
rc = lyd_value_store(ctx_node->module->ctx, &p->value, ((struct lysc_node_leaf *)key)->type, val, val_len, 0, 0,
NULL, format, prefix_data, LYD_HINT_DATA, key, NULL);
LOG_LOCBACK(1, 0);
LY_CHECK_ERR_GOTO(ret, p->value.realtype = NULL, cleanup);
LY_CHECK_ERR_GOTO(rc, p->value.realtype = NULL, cleanup);
/* "allocate" the type to avoid problems when freeing the value after the type was freed */
LY_ATOMIC_INC_BARRIER(((struct lysc_type *)p->value.realtype)->refcount);
@ -734,23 +741,23 @@ ly_path_compile_predicate(const struct ly_ctx *ctx, const struct lysc_node *cur_
}
if (LY_ARRAY_COUNT(*predicates) != key_count) {
/* names (keys) are unique - it was checked when parsing */
LOGVAL(ctx, LYVE_XPATH, "Predicate missing for a key of %s \"%s\" in path.",
LOGVAL_PATH(ctx, cur_node, ctx_node, LYVE_XPATH, "Predicate missing for a key of %s \"%s\" in path.",
lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
ret = LY_EVALID;
rc = LY_EVALID;
goto cleanup;
}
} else if (expr->tokens[*tok_idx] == LYXP_TOKEN_DOT) {
if (ctx_node->nodetype != LYS_LEAFLIST) {
LOGVAL(ctx, LYVE_XPATH, "Leaf-list predicate defined for %s \"%s\" in path.",
LOGVAL_PATH(ctx, cur_node, ctx_node, LYVE_XPATH, "Leaf-list predicate defined for %s \"%s\" in path.",
lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
ret = LY_EVALID;
rc = LY_EVALID;
goto cleanup;
}
++(*tok_idx);
/* new predicate */
LY_ARRAY_NEW_GOTO(ctx, *predicates, p, ret, cleanup);
LY_ARRAY_NEW_GOTO(ctx, *predicates, p, rc, cleanup);
p->type = LY_PATH_PREDTYPE_LEAFLIST;
/* '=' */
@ -769,11 +776,9 @@ ly_path_compile_predicate(const struct ly_ctx *ctx, const struct lysc_node *cur_
}
/* store the value */
LOG_LOCSET(ctx_node, NULL);
ret = lyd_value_store(ctx_node->module->ctx, &p->value, ((struct lysc_node_leaflist *)ctx_node)->type, val, val_len, 0, 0,
rc = lyd_value_store(ctx_node->module->ctx, &p->value, ((struct lysc_node_leaflist *)ctx_node)->type, val, val_len, 0, 0,
NULL, format, prefix_data, LYD_HINT_DATA, ctx_node, NULL);
LOG_LOCBACK(1, 0);
LY_CHECK_ERR_GOTO(ret, p->value.realtype = NULL, cleanup);
LY_CHECK_ERR_GOTO(rc, p->value.realtype = NULL, cleanup);
++(*tok_idx);
/* "allocate" the type to avoid problems when freeing the value after the type was freed */
@ -785,19 +790,19 @@ ly_path_compile_predicate(const struct ly_ctx *ctx, const struct lysc_node *cur_
} else {
assert(expr->tokens[*tok_idx] == LYXP_TOKEN_NUMBER);
if (!(ctx_node->nodetype & (LYS_LEAFLIST | LYS_LIST))) {
ret = LY_EVALID;
LOGVAL(ctx, LYVE_XPATH, "Positional predicate defined for %s \"%s\" in path.",
LOGVAL_PATH(ctx, cur_node, ctx_node, LYVE_XPATH, "Positional predicate defined for %s \"%s\" in path.",
lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
rc = LY_EVALID;
goto cleanup;
} else if (ctx_node->flags & LYS_CONFIG_W) {
ret = LY_EVALID;
LOGVAL(ctx, LYVE_XPATH, "Positional predicate defined for configuration %s \"%s\" in path.",
LOGVAL_PATH(ctx, cur_node, ctx_node, LYVE_XPATH, "Positional predicate defined for configuration %s \"%s\" in path.",
lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
rc = LY_EVALID;
goto cleanup;
}
/* new predicate */
LY_ARRAY_NEW_GOTO(ctx, *predicates, p, ret, cleanup);
LY_ARRAY_NEW_GOTO(ctx, *predicates, p, rc, cleanup);
p->type = LY_PATH_PREDTYPE_POSITION;
/* syntax was already checked */
@ -810,12 +815,11 @@ ly_path_compile_predicate(const struct ly_ctx *ctx, const struct lysc_node *cur_
}
cleanup:
LOG_LOCBACK(cur_node ? 1 : 0, 0);
if (ret) {
if (rc) {
ly_path_predicates_free(ctx_node->module->ctx, *predicates);
*predicates = NULL;
}
return ret;
return rc;
}
/**
@ -833,7 +837,7 @@ static LY_ERR
ly_path_compile_predicate_leafref(const struct lysc_node *ctx_node, const struct lysc_node *cur_node,
const struct lyxp_expr *expr, uint32_t *tok_idx, LY_VALUE_FORMAT format, void *prefix_data)
{
LY_ERR ret = LY_SUCCESS;
LY_ERR rc = LY_SUCCESS;
const struct lysc_node *key, *node, *node2;
struct ly_ctx *ctx = cur_node->module->ctx;
@ -843,26 +847,26 @@ ly_path_compile_predicate_leafref(const struct lysc_node *ctx_node, const struct
}
if (ctx_node->nodetype != LYS_LIST) {
LOGVAL(ctx, LYVE_XPATH, "List predicate defined for %s \"%s\" in path.",
LOGVAL_PATH(ctx, cur_node, ctx_node, LYVE_XPATH, "List predicate defined for %s \"%s\" in path.",
lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
ret = LY_EVALID;
rc = LY_EVALID;
goto cleanup;
} else if (ctx_node->flags & LYS_KEYLESS) {
LOGVAL(ctx, LYVE_XPATH, "List predicate defined for keyless %s \"%s\" in path.",
LOGVAL_PATH(ctx, cur_node, ctx_node, LYVE_XPATH, "List predicate defined for keyless %s \"%s\" in path.",
lys_nodetype2str(ctx_node->nodetype), ctx_node->name);
ret = LY_EVALID;
rc = LY_EVALID;
goto cleanup;
}
do {
/* NameTest, find the key */
ret = ly_path_compile_snode(ctx, cur_node, cur_node->module, ctx_node, expr, *tok_idx, format, prefix_data,
rc = ly_path_compile_snode(ctx, cur_node, cur_node->module, ctx_node, expr, *tok_idx, format, prefix_data,
NULL, 0, &key, NULL);
LY_CHECK_GOTO(ret, cleanup);
LY_CHECK_GOTO(rc, cleanup);
if ((key->nodetype != LYS_LEAF) || !(key->flags & LYS_KEY)) {
LOGVAL(ctx, LYVE_XPATH, "Key expected instead of %s \"%s\" in path.",
LOGVAL_PATH(ctx, cur_node, ctx_node, LYVE_XPATH, "Key expected instead of %s \"%s\" in path.",
lys_nodetype2str(key->nodetype), key->name);
ret = LY_EVALID;
rc = LY_EVALID;
goto cleanup;
}
++(*tok_idx);
@ -896,8 +900,8 @@ ly_path_compile_predicate_leafref(const struct lysc_node *ctx_node, const struct
/* go to parent */
if (!node) {
LOGVAL(ctx, LYVE_XPATH, "Too many parent references in path.");
ret = LY_EVALID;
LOGVAL_PATH(ctx, cur_node, ctx_node, LYVE_XPATH, "Too many parent references in path.");
rc = LY_EVALID;
goto cleanup;
}
node = lysc_data_parent(node);
@ -914,17 +918,18 @@ ly_path_compile_predicate_leafref(const struct lysc_node *ctx_node, const struct
/* NameTest */
assert(expr->tokens[*tok_idx] == LYXP_TOKEN_NAMETEST);
LY_CHECK_RET(ly_path_compile_snode(ctx, cur_node, cur_node->module, node, expr, *tok_idx, format,
prefix_data, NULL, 0, &node2, NULL));
rc = ly_path_compile_snode(ctx, cur_node, cur_node->module, node, expr, *tok_idx, format, prefix_data, NULL,
0, &node2, NULL);
LY_CHECK_GOTO(rc, cleanup);
node = node2;
++(*tok_idx);
} while ((*tok_idx + 1 < expr->used) && (expr->tokens[*tok_idx + 1] == LYXP_TOKEN_NAMETEST));
/* check the last target node */
if (node->nodetype != LYS_LEAF) {
LOGVAL(ctx, LYVE_XPATH, "Leaf expected instead of %s \"%s\" in leafref predicate in path.",
LOGVAL_PATH(ctx, cur_node, ctx_node, LYVE_XPATH, "Leaf expected instead of %s \"%s\" in leafref predicate in path.",
lys_nodetype2str(node->nodetype), node->name);
ret = LY_EVALID;
rc = LY_EVALID;
goto cleanup;
}
@ -939,7 +944,7 @@ ly_path_compile_predicate_leafref(const struct lysc_node *ctx_node, const struct
} while (!lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1));
cleanup:
return (ret == LY_ENOTFOUND) ? LY_EVALID : ret;
return (rc == LY_ENOTFOUND) ? LY_EVALID : rc;
}
/**
@ -1022,6 +1027,7 @@ cleanup:
* @brief Compile deref XPath function into ly_path structure.
*
* @param[in] ctx libyang context.
* @param[in] cur_node Current (original context) node.
* @param[in] ctx_node Optional context node, mandatory of @p lref.
* @param[in] top_ext Extension instance containing the definition of the data being created. It is used to find
* the top-level node inside the extension instance instead of a module. Note that this is the case not only if
@ -1037,7 +1043,7 @@ cleanup:
* @return LY_ERR value.
*/
static LY_ERR
ly_path_compile_deref(const struct ly_ctx *ctx, const struct lysc_node *ctx_node,
ly_path_compile_deref(const struct ly_ctx *ctx, const struct lysc_node *cur_node, const struct lysc_node *ctx_node,
const struct lysc_ext_instance *top_ext, const struct lyxp_expr *expr, uint16_t oper, uint16_t target,
LY_VALUE_FORMAT format, void *prefix_data, uint32_t *tok_idx, struct ly_path **path)
{
@ -1081,13 +1087,14 @@ ly_path_compile_deref(const struct ly_ctx *ctx, const struct lysc_node *ctx_node
&path2), cleanup);
node2 = path2[LY_ARRAY_COUNT(path2) - 1].node;
if ((node2->nodetype != LYS_LEAF) && (node2->nodetype != LYS_LEAFLIST)) {
LOGVAL(ctx, LYVE_XPATH, "The deref function target node \"%s\" is not leaf nor leaflist", node2->name);
LOGVAL_PATH(ctx, cur_node, node2, LYVE_XPATH, "Deref function target node \"%s\" is not leaf nor leaflist.",
node2->name);
ret = LY_EVALID;
goto cleanup;
}
deref_leaf_node = (const struct lysc_node_leaf *)node2;
if (deref_leaf_node->type->basetype != LY_TYPE_LEAFREF) {
LOGVAL(ctx, LYVE_XPATH, "The deref function target node \"%s\" is not leafref", node2->name);
LOGVAL_PATH(ctx, cur_node, node2, LYVE_XPATH, "Deref function target node \"%s\" is not leafref.", node2->name);
ret = LY_EVALID;
goto cleanup;
}
@ -1160,9 +1167,9 @@ _ly_path_compile(const struct ly_ctx *ctx, const struct lys_module *cur_mod, con
const struct lysc_ext_instance *top_ext, const struct lyxp_expr *expr, ly_bool lref, uint16_t oper, uint16_t target,
ly_bool limit_access_tree, LY_VALUE_FORMAT format, void *prefix_data, struct ly_path **path)
{
LY_ERR ret = LY_SUCCESS;
LY_ERR rc = LY_SUCCESS;
uint32_t tok_idx = 0, getnext_opts;
const struct lysc_node *node2, *cur_node, *op;
const struct lysc_node *node2, *cur_node, *op, *prev_ctx_node = NULL;
struct ly_path *p = NULL;
struct lysc_ext_instance *ext = NULL;
@ -1182,9 +1189,6 @@ _ly_path_compile(const struct ly_ctx *ctx, const struct lys_module *cur_mod, con
/* remember original context node */
cur_node = ctx_node;
if (cur_node) {
LOG_LOCSET(cur_node, NULL);
}
if (oper == LY_PATH_OPER_OUTPUT) {
getnext_opts = LYS_GETNEXT_OUTPUT;
@ -1195,7 +1199,7 @@ _ly_path_compile(const struct ly_ctx *ctx, const struct lys_module *cur_mod, con
if (lref && (ly_ctx_get_options(ctx) & LY_CTX_LEAFREF_EXTENDED) &&
(expr->tokens[tok_idx] == LYXP_TOKEN_FUNCNAME)) {
/* deref function */
ret = ly_path_compile_deref(ctx, ctx_node, top_ext, expr, oper, target, format, prefix_data, &tok_idx, path);
rc = ly_path_compile_deref(ctx, cur_node, ctx_node, top_ext, expr, oper, target, format, prefix_data, &tok_idx, path);
goto cleanup;
} else if (expr->tokens[tok_idx] == LYXP_TOKEN_OPER_PATH) {
/* absolute path */
@ -1206,19 +1210,20 @@ _ly_path_compile(const struct ly_ctx *ctx, const struct lys_module *cur_mod, con
/* relative path */
if (!ctx_node) {
LOGVAL(ctx, LYVE_XPATH, "No initial schema parent for a relative path.");
ret = LY_EVALID;
rc = LY_EVALID;
goto cleanup;
}
/* go up the parents for leafref */
while (lref && (expr->tokens[tok_idx] == LYXP_TOKEN_DDOT)) {
if (!ctx_node) {
LOGVAL(ctx, LYVE_XPATH, "Too many parent references in path.");
ret = LY_EVALID;
LOGVAL_PATH(ctx, cur_node, prev_ctx_node, LYVE_XPATH, "Too many parent references in path.");
rc = LY_EVALID;
goto cleanup;
}
/* get parent */
prev_ctx_node = ctx_node;
ctx_node = lysc_data_parent(ctx_node);
++tok_idx;
@ -1231,63 +1236,66 @@ _ly_path_compile(const struct ly_ctx *ctx, const struct lys_module *cur_mod, con
do {
/* check last compiled inner node, whether it is uniquely identified (even key-less list) */
if (p && !lref && (target == LY_PATH_TARGET_SINGLE) && (p->node->nodetype == LYS_LIST) && !p->predicates) {
LOGVAL(ctx, LYVE_XPATH, "Predicate missing for %s \"%s\" in path.",
LOGVAL_PATH(ctx, cur_node, prev_ctx_node, LYVE_XPATH, "Predicate missing for %s \"%s\" in path.",
lys_nodetype2str(p->node->nodetype), p->node->name);
ret = LY_EVALID;
rc = LY_EVALID;
goto cleanup;
}
/* NameTest */
LY_CHECK_ERR_GOTO(lyxp_check_token(ctx, expr, tok_idx, LYXP_TOKEN_NAMETEST), ret = LY_EVALID, cleanup);
LY_CHECK_ERR_GOTO(lyxp_check_token(ctx, expr, tok_idx, LYXP_TOKEN_NAMETEST), rc = LY_EVALID, cleanup);
/* get schema node */
LY_CHECK_GOTO(ret = ly_path_compile_snode(ctx, cur_node, cur_mod, ctx_node, expr, tok_idx, format, prefix_data,
LY_CHECK_GOTO(rc = ly_path_compile_snode(ctx, cur_node, cur_mod, ctx_node, expr, tok_idx, format, prefix_data,
top_ext, getnext_opts, &node2, &ext), cleanup);
++tok_idx;
if ((op && (node2->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) && (node2 != op))) {
LOGVAL(ctx, LYVE_XPATH, "Not found node \"%s\" in path.", node2->name);
ret = LY_EVALID;
LOGVAL_PATH(ctx, cur_node, prev_ctx_node, LYVE_XPATH, "Not found node \"%s\" in path.", node2->name);
rc = LY_EVALID;
goto cleanup;
}
/* next node */
prev_ctx_node = ctx_node;
ctx_node = node2;
/* new path segment */
LY_ARRAY_NEW_GOTO(ctx, *path, p, ret, cleanup);
LY_ARRAY_NEW_GOTO(ctx, *path, p, rc, cleanup);
p->node = ctx_node;
p->ext = ext;
/* compile any predicates */
if (lref) {
ret = ly_path_compile_predicate_leafref(ctx_node, cur_node, expr, &tok_idx, format, prefix_data);
rc = ly_path_compile_predicate_leafref(ctx_node, cur_node, expr, &tok_idx, format, prefix_data);
} else {
ret = ly_path_compile_predicate(ctx, cur_node, cur_mod, ctx_node, expr, &tok_idx, format, prefix_data,
rc = ly_path_compile_predicate(ctx, cur_node, cur_mod, ctx_node, expr, &tok_idx, format, prefix_data,
&p->predicates);
}
LY_CHECK_GOTO(ret, cleanup);
LY_CHECK_GOTO(rc, cleanup);
} while (!lyxp_next_token(NULL, expr, &tok_idx, LYXP_TOKEN_OPER_PATH));
/* check leftover tokens */
if (tok_idx < expr->used) {
LOGVAL(ctx, LY_VCODE_XP_INTOK, lyxp_token2str(expr->tokens[tok_idx]), &expr->expr[expr->tok_pos[tok_idx]]);
ret = LY_EVALID;
LOGVAL_PATH(ctx, cur_node, ctx_node, LY_VCODE_XP_INTOK, lyxp_token2str(expr->tokens[tok_idx]),
&expr->expr[expr->tok_pos[tok_idx]]);
rc = LY_EVALID;
goto cleanup;
}
/* check last compiled node */
if (!lref && (target == LY_PATH_TARGET_SINGLE) && (p->node->nodetype & (LYS_LIST | LYS_LEAFLIST)) && !p->predicates) {
LOGVAL(ctx, LYVE_XPATH, "Predicate missing for %s \"%s\" in path.",
LOGVAL_PATH(ctx, cur_node, ctx_node, LYVE_XPATH, "Predicate missing for %s \"%s\" in path.",
lys_nodetype2str(p->node->nodetype), p->node->name);
ret = LY_EVALID;
rc = LY_EVALID;
goto cleanup;
}
cleanup:
if (ret) {
if (rc) {
ly_path_free(*path);
*path = NULL;
}
LOG_LOCBACK(cur_node ? 1 : 0, 0);
return (ret == LY_ENOTFOUND) ? LY_EVALID : ret;
return (rc == LY_ENOTFOUND) ? LY_EVALID : rc;
}
LY_ERR
@ -1304,6 +1312,8 @@ ly_path_compile_leafref(const struct ly_ctx *ctx, const struct lysc_node *ctx_no
const struct lyxp_expr *expr, uint16_t oper, uint16_t target, LY_VALUE_FORMAT format, void *prefix_data,
struct ly_path **path)
{
assert(ctx_node);
return _ly_path_compile(ctx, ctx_node->module, ctx_node, top_ext, expr, 1, oper, target, 1, format, prefix_data, path);
}

View file

@ -3,7 +3,7 @@
* @author Michal Vasko <mvasko@cesnet.cz>
* @brief Path structure and manipulation routines.
*
* Copyright (c) 2020 - 2023 CESNET, z.s.p.o.
* Copyright (c) 2020 - 2025 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.
@ -28,6 +28,25 @@ struct lysc_ext_instance;
struct lysc_node;
struct lyxp_expr;
/**
* @brief Similar to LOGVAL, but also logs path of CUR_SCNODE and if not set, CTX_SCNODE, in this order.
*
* @param[in] CTX Context to use.
* @param[in] CUR_SCNODE Current (original context) node.
* @param[in] CTX_SCNODE Context node.
*/
#define LOGVAL_PATH(CTX, CUR_SCNODE, CTX_SCNODE, ...) \
if ((CUR_SCNODE) || (CTX_SCNODE)) { \
LOG_LOCSET((CUR_SCNODE) ? (CUR_SCNODE) : (CTX_SCNODE), NULL); \
} \
ly_vlog(CTX, NULL, __VA_ARGS__); \
if ((CUR_SCNODE) || (CTX_SCNODE)) { \
LOG_LOCBACK(1, 0); \
}
/**
* @brief Common types of predicates.
*/
enum ly_path_pred_type {
LY_PATH_PREDTYPE_POSITION, /**< position predicate - [2] */
LY_PATH_PREDTYPE_LIST, /**< keys predicate - [key1='val1'][key2='val2']... */
@ -99,7 +118,7 @@ struct ly_path {
* @param[in] ctx libyang context.
* @param[in] ctx_node Optional context node, used for logging.
* @param[in] str_path Path to parse.
* @param[in] path_len Length of @p str_path.
* @param[in] path_len Length of @p str_path, may be 0 if @p str_path is 0-terminated.
* @param[in] lref Whether leafref is being parsed or not.
* @param[in] begin Begin option (@ref path_begin_options).
* @param[in] prefix Prefix option (@ref path_prefix_options).
@ -116,7 +135,7 @@ LY_ERR ly_path_parse(const struct ly_ctx *ctx, const struct lysc_node *ctx_node,
* @param[in] ctx libyang context.
* @param[in] cur_node Optional current (original context) node, used for logging.
* @param[in] str_path Path to parse.
* @param[in] path_len Length of @p str_path.
* @param[in] path_len Length of @p str_path, may be 0 if @p str_path is 0-terminated.
* @param[in] prefix Prefix option (@ref path_prefix_options).
* @param[in] pred Predicate option (@ref path_pred_options).
* @param[out] expr Parsed path.

View file

@ -318,7 +318,8 @@ structure_aug_parse(struct lysp_ctx *pctx, struct lysp_ext_instance *ext)
/* augment-structure must define some data-def-stmt */
LY_LIST_FOR(ext->child, stmt) {
if (stmt->kw & LY_STMT_DATA_NODE_MASK) {
if (stmt->kw & (LY_STMT_CONTAINER | LY_STMT_LEAF | LY_STMT_LEAF_LIST | LY_STMT_LIST | LY_STMT_CHOICE |
LY_STMT_ANYDATA | LY_STMT_ANYXML | LY_STMT_USES)) {
break;
}
}

View file

@ -685,7 +685,8 @@ lyplg_type_check_hints(uint32_t hints, const char *value, size_t value_len, LY_D
case LY_TYPE_INT32:
LY_CHECK_ARG_RET(NULL, base, LY_EINVAL);
if (!(hints & (LYD_VALHINT_DECNUM | LYD_VALHINT_OCTNUM | LYD_VALHINT_HEXNUM))) {
if (!(hints & (LYD_VALHINT_DECNUM | LYD_VALHINT_OCTNUM | LYD_VALHINT_HEXNUM)) &&
!(hints & LYD_VALHINT_STRING_DATATYPES)) {
return ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL, "Invalid non-number-encoded %s value \"%.*s\".",
lys_datatype2str(type), (int)value_len, value);
}
@ -695,7 +696,8 @@ lyplg_type_check_hints(uint32_t hints, const char *value, size_t value_len, LY_D
case LY_TYPE_INT64:
LY_CHECK_ARG_RET(NULL, base, LY_EINVAL);
if (!(hints & LYD_VALHINT_NUM64)) {
if (!(hints & LYD_VALHINT_NUM64) &&
!(hints & LYD_VALHINT_STRING_DATATYPES)) {
return ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL, "Invalid non-num64-encoded %s value \"%.*s\".",
lys_datatype2str(type), (int)value_len, value);
}
@ -714,7 +716,8 @@ lyplg_type_check_hints(uint32_t hints, const char *value, size_t value_len, LY_D
}
break;
case LY_TYPE_BOOL:
if (!(hints & LYD_VALHINT_BOOLEAN)) {
if (!(hints & LYD_VALHINT_BOOLEAN) &&
!(hints & LYD_VALHINT_STRING_DATATYPES)) {
return ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL, "Invalid non-boolean-encoded %s value \"%.*s\".",
lys_datatype2str(type), (int)value_len, value);
}

View file

@ -150,6 +150,48 @@ lyb_parse_union(const void *lyb_data, size_t lyb_data_len, uint32_t *type_idx, c
}
}
/**
* @brief For leafref failures, ensure the appropriate error is propagated, not a type validation failure.
*
* RFC7950 Section 15.5 defines the appropriate error app tag of "require-instance".
*
* @param[in,out] err Error record to be updated.
* @param[in] type Leafref type used to extract target path.
* @param[in] value Value attempted to be stored.
* @param[in] value_len Length of @p value.
* @return LY_ERR value. Only possible errors are LY_SUCCESS and LY_EMEM.
*/
static LY_ERR
union_update_lref_err(struct ly_err_item *err, const struct lysc_type *type, const void *value, size_t value_len)
{
const struct lysc_type_leafref *lref;
char *valstr = NULL;
int r;
if (!err || (type->basetype != LY_TYPE_LEAFREF)) {
/* nothing to do */
return LY_SUCCESS;
}
lref = (const struct lysc_type_leafref *)type;
/* update error-app-tag */
free(err->apptag);
err->apptag = strdup("instance-required");
LY_CHECK_ERR_RET(!err->apptag, LOGMEM(NULL), LY_EMEM);
valstr = strndup((const char *)value, value_len);
LY_CHECK_ERR_RET(!valstr, LOGMEM(NULL), LY_EMEM);
/* update error-message */
free(err->msg);
r = asprintf(&err->msg, LY_ERRMSG_NOLREF_VAL, valstr, lyxp_get_expr(lref->path));
free(valstr);
LY_CHECK_ERR_RET(r == -1, LOGMEM(NULL), LY_EMEM);
return LY_SUCCESS;
}
/**
* @brief Store (and validate) subvalue as a specific type.
*
@ -187,10 +229,13 @@ union_store_type(const struct ly_ctx *ctx, struct lysc_type_union *type_u, uint3
/* value of another type, first store the value properly and then use its JSON value for parsing */
rc = type_u->types[ti]->plugin->store(ctx, type_u->types[ti], value, value_len, LYPLG_TYPE_STORE_ONLY,
subvalue->format, subvalue->prefix_data, subvalue->hints, subvalue->ctx_node, &subvalue->value, unres, err);
if ((rc != LY_SUCCESS) && (rc != LY_EINCOMPLETE)) {
if (rc && (rc != LY_EINCOMPLETE)) {
/* clear any leftover/freed garbage */
memset(&subvalue->value, 0, sizeof subvalue->value);
return rc;
/* if this is a leafref, lets make sure we propagate the appropriate error, and not a type validation failure */
union_update_lref_err(*err, type_u->types[ti], value, value_len);
goto cleanup;
}
assert(subvalue->value.realtype);
@ -219,16 +264,16 @@ union_store_type(const struct ly_ctx *ctx, struct lysc_type_union *type_u, uint3
if (options & LYPLG_TYPE_STORE_ONLY) {
opts |= LYPLG_TYPE_STORE_ONLY;
}
if (dynamic) {
opts |= LYPLG_TYPE_STORE_DYNAMIC;
}
rc = type->plugin->store(ctx, type, value, value_len, opts, format, prefix_data, subvalue->hints,
subvalue->ctx_node, &subvalue->value, unres, err);
if ((rc != LY_SUCCESS) && (rc != LY_EINCOMPLETE)) {
if (rc && (rc != LY_EINCOMPLETE)) {
/* clear any leftover/freed garbage */
memset(&subvalue->value, 0, sizeof subvalue->value);
return rc;
/* if this is a leafref, lets make sure we propagate the appropriate error, and not a type validation failure */
union_update_lref_err(*err, type, value, value_len);
goto cleanup;
}
if (validate && (rc == LY_EINCOMPLETE)) {
@ -237,9 +282,14 @@ union_store_type(const struct ly_ctx *ctx, struct lysc_type_union *type_u, uint3
if (rc) {
/* validate failed, we need to free the stored value */
type->plugin->free(ctx, &subvalue->value);
goto cleanup;
}
}
cleanup:
if (dynamic) {
free((void *)value);
}
return rc;
}
@ -267,8 +317,9 @@ union_find_type(const struct ly_ctx *ctx, struct lysc_type_union *type_u, struct
LY_ARRAY_COUNT_TYPE u;
struct ly_err_item **errs = NULL, *e;
uint32_t *prev_lo, temp_lo = 0;
char *msg = NULL;
char *msg = NULL, *err_app_tag = NULL;
int msg_len = 0;
ly_bool use_err_app_tag = 0;
*err = NULL;
@ -299,6 +350,8 @@ union_find_type(const struct ly_ctx *ctx, struct lysc_type_union *type_u, struct
}
if (msg_len == -1) {
LY_CHECK_ERR_GOTO(!errs, ret = LY_EMEM, cleanup);
/* for further actions in function msg_len is just 0 */
msg_len = 0;
}
for (u = 0; u < LY_ARRAY_COUNT(type_u->types); ++u) {
if (!errs[u]) {
@ -306,12 +359,27 @@ union_find_type(const struct ly_ctx *ctx, struct lysc_type_union *type_u, struct
continue;
}
/* use an app-tag if all the types set it or set none */
if (errs[u]->apptag) {
if (!err_app_tag) {
err_app_tag = strdup(errs[u]->apptag);
LY_CHECK_ERR_GOTO(!err_app_tag, ret = LY_EMEM, cleanup);
use_err_app_tag = 1;
} else if (strcmp(errs[u]->apptag, err_app_tag)) {
use_err_app_tag = 0;
}
}
msg = ly_realloc(msg, msg_len + 4 + strlen(type_u->types[u]->plugin->id) + 2 + strlen(errs[u]->msg) + 2);
LY_CHECK_ERR_GOTO(!msg, ret = LY_EMEM, cleanup);
msg_len += sprintf(msg + msg_len, " %s: %s\n", type_u->types[u]->plugin->id, errs[u]->msg);
}
ret = ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL, "%s", msg);
if (!use_err_app_tag) {
free(err_app_tag);
err_app_tag = NULL;
}
ret = ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, err_app_tag, "%s", msg);
} else if (type_idx) {
*type_idx = u;
}
@ -496,26 +564,33 @@ lyplg_type_compare_union(const struct ly_ctx *ctx, const struct lyd_value *val1,
LIBYANG_API_DEF int
lyplg_type_sort_union(const struct ly_ctx *ctx, const struct lyd_value *val1, const struct lyd_value *val2)
{
int rc = LY_SUCCESS;
int rc;
LY_ARRAY_COUNT_TYPE u;
struct lysc_type **types;
struct lysc_type **types, *type;
if (val1->subvalue->value.realtype == val2->subvalue->value.realtype) {
return val1->subvalue->value.realtype->plugin->sort(ctx, &val1->subvalue->value, &val2->subvalue->value);
}
/* compare according to the order of types */
rc = 0;
types = ((struct lysc_type_union *)val1->realtype)->types;
LY_ARRAY_FOR(types, u) {
if (types[u] == val1->subvalue->value.realtype) {
if (types[u]->basetype == LY_TYPE_LEAFREF) {
type = ((struct lysc_type_leafref *)types[u])->realtype;
} else {
type = types[u];
}
if (type == val1->subvalue->value.realtype) {
rc = 1;
break;
} else if (types[u] == val2->subvalue->value.realtype) {
} else if (type == val2->subvalue->value.realtype) {
rc = -1;
break;
}
}
assert(rc != 0);
assert(rc);
return rc;
}

View file

@ -590,7 +590,7 @@ struct trt_fp_read {
.module_name = tro_read_module_name, \
.node = troc_read_node, \
.if_sibling_exists = troc_read_if_sibling_exists, \
.if_parent_exists = tro_read_if_sibling_exists \
.if_parent_exists = tro_read_if_parent_exists \
}
/**
@ -601,7 +601,7 @@ struct trt_fp_read {
.module_name = tro_read_module_name, \
.node = trop_read_node, \
.if_sibling_exists = trop_read_if_sibling_exists, \
.if_parent_exists = tro_read_if_sibling_exists \
.if_parent_exists = tro_read_if_parent_exists \
}
/**********************************************************************
@ -781,6 +781,7 @@ typedef const char *(*trt_get_charptr_func)(const struct lysp_node *pn);
*/
struct tro_getters {
uint16_t (*nodetype)(const void *); /**< Get nodetype. */
uint16_t (*lysp_flags)(const void *); /**< Get flags from lysp_node. */
const void *(*next)(const void *); /**< Get sibling. */
const void *(*parent)(const void *); /**< Get parent. */
const void *(*child)(const void *); /**< Get child. */
@ -1947,6 +1948,16 @@ trop_nodetype(const void *node)
return ((const struct lysp_node *)node)->nodetype;
}
/**
* @brief Get lysp_node flags.
* @param[in] node is any lysp_node.
*/
static uint16_t
trop_flags(const void *node)
{
return ((const struct lysp_node *)node)->flags;
}
/**
* @brief Get sibling.
* @param[in] node is any lysp_node.
@ -2026,6 +2037,7 @@ trop_init_getters(void)
{
return (struct tro_getters) {
.nodetype = trop_nodetype,
.lysp_flags = trop_flags,
.next = trop_next,
.parent = trop_parent,
.child = trop_child,
@ -2046,6 +2058,23 @@ troc_nodetype(const void *node)
return ((const struct lysc_node *)node)->nodetype;
}
/**
* @brief Get lysp_node flags.
* @param[in] node is any lysc_node.
*/
static uint16_t
troc_lysp_flags(const void *node)
{
const struct lysc_node *cn;
cn = (const struct lysc_node *)node;
if (TRP_TREE_CTX_LYSP_NODE_PRESENT(cn)) {
return TRP_TREE_CTX_GET_LYSP_NODE(cn)->flags;
} else {
return 0;
}
}
/**
* @brief Get sibling.
* @param[in] node is any lysc_node.
@ -2125,6 +2154,7 @@ troc_init_getters(void)
{
return (struct tro_getters) {
.nodetype = troc_nodetype,
.lysp_flags = troc_lysp_flags,
.next = troc_next,
.parent = troc_parent,
.child = troc_child,
@ -2272,6 +2302,8 @@ tro_next_sibling(const void *node, const struct trt_tree_ctx *tc)
plugin_ctx = tc->plugin_ctx;
if (sibl && tro_set_node_overr(tc->lysc_tree, sibl, 1, &plugin_ctx) && plugin_ctx.filtered) {
return tro_next_sibling(sibl, tc);
} else if (sibl && (get.lysp_flags(node) & LYS_INTERNAL)) {
return tro_next_sibling(sibl, tc);
}
return sibl;
@ -2328,6 +2360,8 @@ tro_next_child(const void *node, const struct trt_tree_ctx *tc)
plugin_ctx = tc->plugin_ctx;
if (child && tro_set_node_overr(tc->lysc_tree, child, 1, &plugin_ctx) && plugin_ctx.filtered) {
return tro_next_sibling(child, tc);
} else if (child && (get.lysp_flags(node) & LYS_INTERNAL)) {
return tro_next_sibling(child, tc);
}
return child;
@ -2605,7 +2639,7 @@ tro_read_module_name(const struct trt_tree_ctx *tc)
}
static ly_bool
tro_read_if_sibling_exists(const struct trt_tree_ctx *tc)
tro_read_if_parent_exists(const struct trt_tree_ctx *tc)
{
const void *parent;
@ -3118,7 +3152,11 @@ trop_modi_first_sibling(struct trt_parent_cache ca, struct trt_tree_ctx *tc)
default:
assert(0);
}
node = trop_read_node(ca, tc);
if (tc->pn && (trop_flags(tc->pn) & LYS_INTERNAL)) {
node = trop_modi_next_sibling(ca, tc);
} else {
node = trop_read_node(ca, tc);
}
}
if (tc->plugin_ctx.filtered) {
@ -3440,7 +3478,11 @@ troc_modi_first_sibling(struct trt_parent_cache ca, struct trt_tree_ctx *tc)
default:
assert(0);
}
node = troc_read_node(ca, tc);
if (tc->cn && (troc_lysp_flags(tc->cn) & LYS_INTERNAL)) {
node = troc_modi_next_sibling(ca, tc);
} else {
node = troc_read_node(ca, tc);
}
}
if (tc->plugin_ctx.filtered) {

View file

@ -463,6 +463,7 @@ no_content:
pctx->options = prev_opts;
break;
case LYD_ANYDATA_STRING:
case LYD_ANYDATA_JSON:
/* escape XML-sensitive characters */
if (!any->value.str[0]) {
goto no_content;
@ -478,9 +479,8 @@ no_content:
}
ly_print_(pctx->out, ">%s", any->value.str);
break;
case LYD_ANYDATA_JSON:
case LYD_ANYDATA_LYB:
/* JSON and LYB format is not supported */
/* LYB format is not supported */
LOGWRN(pctx->ctx, "Unable to print anydata content (type %d) as XML.", any->value_type);
goto no_content;
}

View file

@ -2269,6 +2269,10 @@ yang_print_parsed_body(struct lys_ypr_ctx *pctx, const struct lysp_module *modp)
YPR_EXTRA_LINE(modp->groupings, pctx);
LY_LIST_FOR(modp->data, data) {
if (data->flags & LYS_INTERNAL) {
continue;
}
YPR_EXTRA_LINE_PRINT(pctx);
yprp_node(pctx, data);
}

View file

@ -1367,6 +1367,10 @@ yin_print_parsed_body(struct lys_ypr_ctx *pctx, const struct lysp_module *modp)
}
LY_LIST_FOR(modp->data, data) {
if (data->flags & LYS_INTERNAL) {
continue;
}
yprp_node(pctx, data);
}

View file

@ -937,6 +937,7 @@ lys_compile_unres_dflt(struct lysc_ctx *ctx, struct lysc_node *node, struct lysc
{
LY_ERR ret;
uint32_t options;
struct lyd_value *val;
struct ly_err_item *err = NULL;
options = (ctx->ctx->flags & LY_CTX_REF_IMPLEMENTED) ? LYPLG_TYPE_STORE_IMPLEMENT : 0;
@ -963,11 +964,16 @@ lys_compile_unres_dflt(struct lysc_ctx *ctx, struct lysc_node *node, struct lysc
}
LY_ATOMIC_INC_BARRIER(((struct lysc_type *)storage->realtype)->refcount);
if (storage->realtype->basetype == LY_TYPE_INST) {
if (storage->realtype->basetype == LY_TYPE_UNION) {
val = &storage->subvalue->value;
} else {
val = storage;
}
if (val->realtype->basetype == LY_TYPE_INST) {
/* ly_path includes references to other nodes, in case they are in foreign modules, the context would
* need to be freed in specific order to avoid accessing freed memory, so just avoid storing it */
ly_path_free(storage->target);
storage->target = NULL;
ly_path_free(val->target);
val->target = NULL;
}
return LY_SUCCESS;
}
@ -1537,11 +1543,13 @@ lys_compile_depset_r(struct ly_ctx *ctx, struct ly_set *dep_set, struct lys_glob
LY_CHECK_GOTO(ret = lys_compile(mod, &unres->ds_unres), cleanup);
}
resolve_unres:
/* resolve dep set unres */
ret = lys_compile_unres_depset(ctx, unres);
lys_compile_unres_depset_erase(ctx, unres);
if (ret == LY_ERECOMPILE) {
/* new module is implemented, discard current dep set unres and recompile the whole dep set */
lys_compile_unres_depset_erase(ctx, unres);
/* new module is implemented referencing previously compiled modules, recompile the whole dep set */
return lys_compile_depset_r(ctx, dep_set, unres);
} else if (ret) {
/* error */
@ -1551,6 +1559,13 @@ lys_compile_depset_r(struct ly_ctx *ctx, struct ly_set *dep_set, struct lys_glob
/* success, unset the flags of all the modules in the dep set */
for (i = 0; i < dep_set->count; ++i) {
mod = dep_set->objs[i];
if (mod->to_compile && !mod->compiled) {
/* new module is implemented but does not require recompilation of the whole dep set */
LY_CHECK_GOTO(ret = lys_compile(mod, &unres->ds_unres), cleanup);
goto resolve_unres;
}
mod->to_compile = 0;
}

View file

@ -365,12 +365,12 @@ lysc_range_dup(struct lysc_ctx *ctx, const struct lysc_range *orig, struct ly_se
dup = calloc(1, sizeof *dup);
LY_CHECK_ERR_RET(!dup, LOGMEM(ctx->ctx), NULL);
if (orig->parts) {
LY_ARRAY_CREATE_GOTO(ctx->ctx, dup->parts, LY_ARRAY_COUNT(orig->parts), ret, cleanup);
LY_ARRAY_CREATE_GOTO(ctx->ctx, dup->parts, LY_ARRAY_COUNT(orig->parts), ret, error);
(*((LY_ARRAY_COUNT_TYPE *)(dup->parts) - 1)) = LY_ARRAY_COUNT(orig->parts);
memcpy(dup->parts, orig->parts, LY_ARRAY_COUNT(dup->parts) * sizeof *dup->parts);
}
DUP_STRING_GOTO(ctx->ctx, orig->eapptag, dup->eapptag, ret, cleanup);
DUP_STRING_GOTO(ctx->ctx, orig->emsg, dup->emsg, ret, cleanup);
DUP_STRING_GOTO(ctx->ctx, orig->eapptag, dup->eapptag, ret, error);
DUP_STRING_GOTO(ctx->ctx, orig->emsg, dup->emsg, ret, error);
/* collect all range extensions */
if (tpdf_chain->count > tpdf_chain_last) {
@ -381,15 +381,17 @@ lysc_range_dup(struct lysc_ctx *ctx, const struct lysc_range *orig, struct ly_se
if (!tpdf_item->tpdf->type.range) {
continue;
}
COMPILE_EXTS_GOTO(ctx, tpdf_item->tpdf->type.range->exts, dup->exts, dup, ret, cleanup);
COMPILE_EXTS_GOTO(ctx, tpdf_item->tpdf->type.range->exts, dup->exts, dup, ret, error);
} while (i > tpdf_chain_last);
}
return dup;
cleanup:
free(dup);
(void) ret; /* set but not used due to the return type */
error:
if (dup) {
lysc_range_free(&ctx->free_ctx, dup);
free(dup);
}
return NULL;
}
@ -1518,7 +1520,7 @@ lys_compile_type_enums(struct lysc_ctx *ctx, const struct lysp_type_enum *enums_
}
}
/* save highest value for auto assing */
/* save highest value for auto assign */
if (highest_value < cur_val) {
highest_value = cur_val;
}
@ -1553,7 +1555,7 @@ lys_compile_type_enums(struct lysc_ctx *ctx, const struct lysp_type_enum *enums_
}
}
/* save highest position for auto assing */
/* save highest position for auto assign */
if (highest_position < cur_pos) {
highest_position = cur_pos;
}
@ -1583,7 +1585,17 @@ lys_compile_type_enums(struct lysc_ctx *ctx, const struct lysp_type_enum *enums_
DUP_STRING_GOTO(ctx->ctx, enums_p[u].name, e->name, ret, done);
DUP_STRING_GOTO(ctx->ctx, enums_p[u].dsc, e->dsc, ret, done);
DUP_STRING_GOTO(ctx->ctx, enums_p[u].ref, e->ref, ret, done);
e->flags = (enums_p[u].flags & LYS_FLAGS_COMPILED_MASK) | (basetype == LY_TYPE_ENUM ? LYS_IS_ENUM : 0);
/* copy flags except for status */
e->flags = (enums_p[u].flags & LYS_FLAGS_COMPILED_MASK) & ~LYS_STATUS_MASK;
/* compile status */
LY_CHECK_RET(lys_compile_status(ctx, enums_p[u].flags, 0, 0, NULL, (basetype == LY_TYPE_ENUM) ? "enum" : "bit",
&e->flags));
/* enum/bit flag */
e->flags |= (basetype == LY_TYPE_ENUM) ? LYS_IS_ENUM : 0;
if (basetype == LY_TYPE_ENUM) {
e->value = cur_val;
} else {
@ -4127,49 +4139,82 @@ cleanup:
return rc;
}
/**
* @brief Generate path of a grouping for logging.
*
* @param[in] ctx Compile context.
* @param[in] node Grouping node.
* @param[out] path Generated path.
* @return Length of the generated @p path;
* @return -1 on error.
*/
static int
lys_compile_grouping_pathlog(struct lysc_ctx *ctx, struct lysp_node *node, char **path)
{
struct lysp_node *iter;
int len = 0;
int len = 0, r;
char *s, *id;
*path = NULL;
for (iter = node; iter && len >= 0; iter = iter->parent) {
char *s = *path;
char *id;
for (iter = node; iter && (len >= 0); iter = iter->parent) {
s = *path;
/* next node segment */
switch (iter->nodetype) {
case LYS_USES:
LY_CHECK_RET(asprintf(&id, "{uses='%s'}", iter->name) == -1, -1);
r = asprintf(&id, "{uses='%s'}", iter->name);
break;
case LYS_GROUPING:
LY_CHECK_RET(asprintf(&id, "{grouping='%s'}", iter->name) == -1, -1);
r = asprintf(&id, "{grouping='%s'}", iter->name);
break;
case LYS_AUGMENT:
LY_CHECK_RET(asprintf(&id, "{augment='%s'}", iter->name) == -1, -1);
r = asprintf(&id, "{augment='%s'}", iter->name);
break;
default:
id = strdup(iter->name);
r = id ? 1 : -1;
break;
}
if (r == -1) {
len = -1;
goto cleanup;
}
/* append the segment to the path */
if (!iter->parent) {
/* print prefix */
len = asprintf(path, "/%s:%s%s", ctx->cur_mod->name, id, s ? s : "");
r = asprintf(path, "/%s:%s%s", ctx->cur_mod->name, id, s ? s : "");
} else {
/* prefix is the same as in parent */
len = asprintf(path, "/%s%s", id, s ? s : "");
r = asprintf(path, "/%s%s", id, s ? s : "");
}
free(s);
free(id);
if (r == -1) {
len = -1;
goto cleanup;
}
/* remember the length of the full path */
len = r;
}
if (!len) {
/* root node path */
*path = strdup("/");
if (!*path) {
len = -1;
goto cleanup;
}
len = 1;
}
cleanup:
if (len < 0) {
free(*path);
*path = NULL;
} else if (len == 0) {
*path = strdup("/");
len = 1;
}
return len;
}

View file

@ -222,10 +222,14 @@ LIBYANG_API_DEF LY_ERR
lyd_parse_data(const struct ly_ctx *ctx, struct lyd_node *parent, struct ly_in *in, LYD_FORMAT format,
uint32_t parse_options, uint32_t validate_options, struct lyd_node **tree)
{
LY_CHECK_ARG_RET(ctx, ctx, in, parent || tree, LY_EINVAL);
LY_CHECK_ARG_RET(ctx, ctx || parent, in, parent || tree, LY_EINVAL);
LY_CHECK_ARG_RET(ctx, !(parse_options & ~LYD_PARSE_OPTS_MASK), LY_EINVAL);
LY_CHECK_ARG_RET(ctx, !(validate_options & ~LYD_VALIDATE_OPTS_MASK), LY_EINVAL);
if (!ctx) {
ctx = LYD_CTX(parent);
}
return lyd_parse(ctx, NULL, parent, tree, in, format, parse_options, validate_options, NULL);
}
@ -1035,7 +1039,7 @@ LIBYANG_API_DEF LY_ERR
lyd_insert_child(struct lyd_node *parent, struct lyd_node *node)
{
LY_CHECK_ARG_RET(NULL, parent, node, !parent->schema || (parent->schema->nodetype & LYD_NODE_INNER), LY_EINVAL);
LY_CHECK_CTX_EQUAL_RET(LYD_CTX(parent), LYD_CTX(node), LY_EINVAL);
LY_CHECK_CTX_EQUAL_RET(__func__, LYD_CTX(parent), LYD_CTX(node), LY_EINVAL);
LY_CHECK_RET(lyd_insert_check_schema(parent->schema, NULL, node->schema));
@ -1101,7 +1105,7 @@ LIBYANG_API_DEF LY_ERR
lyd_insert_before(struct lyd_node *sibling, struct lyd_node *node)
{
LY_CHECK_ARG_RET(NULL, sibling, node, sibling != node, LY_EINVAL);
LY_CHECK_CTX_EQUAL_RET(LYD_CTX(sibling), LYD_CTX(node), LY_EINVAL);
LY_CHECK_CTX_EQUAL_RET(__func__, LYD_CTX(sibling), LYD_CTX(node), LY_EINVAL);
LY_CHECK_RET(lyd_insert_check_schema(NULL, sibling->schema, node->schema));
@ -1125,7 +1129,7 @@ LIBYANG_API_DEF LY_ERR
lyd_insert_after(struct lyd_node *sibling, struct lyd_node *node)
{
LY_CHECK_ARG_RET(NULL, sibling, node, sibling != node, LY_EINVAL);
LY_CHECK_CTX_EQUAL_RET(LYD_CTX(sibling), LYD_CTX(node), LY_EINVAL);
LY_CHECK_CTX_EQUAL_RET(__func__, LYD_CTX(sibling), LYD_CTX(node), LY_EINVAL);
LY_CHECK_RET(lyd_insert_check_schema(NULL, sibling->schema, node->schema));
@ -2002,6 +2006,121 @@ lyd_find_schema_ctx(const struct lysc_node *schema, const struct ly_ctx *trg_ctx
return LY_SUCCESS;
}
/**
* @brief Return the top-level context of a subtree of node. Handles extension data nodes.
*
* @param[in] node Node to use.
* @return
*/
static const struct ly_ctx *
lyd_dup_get_top_ctx(const struct lyd_node *node)
{
const struct lyd_node *par;
par = node;
while (par && !(par->flags & LYD_EXT)) {
par = lyd_parent(par);
}
if (par && lyd_parent(par)) {
/* context of the first non-extension parent */
return LYD_CTX(lyd_parent(par));
}
/* context of the node, all the parents have it */
return LYD_CTX(node);
}
/**
* @brief Find (update) the target context for the next node, if needed.
*
* @param[in] orig_node First extension data node being processed from the original tree.
* @param[in] dup_parent Duplicated parent of @p orig_node, set if @p dup_sparent is NULL.
* @param[in] dup_sparent Schema node of the duplicated parent of @p orig_node, set if @p dup_parent is NULL.
* @param[in,out] trg_ctx Target context, may be updated.
* @return LY_ERR value.
*/
static LY_ERR
lyd_find_ext_ctx(const struct lyd_node *orig_node, const struct lyd_node *dup_parent,
const struct lysc_node *dup_sparent, const struct ly_ctx **trg_ctx)
{
LY_ERR r;
const struct lysc_node *snode;
char *path;
assert(orig_node && (orig_node->flags & LYD_EXT) && *trg_ctx);
if (!lyd_parent(orig_node)) {
/* treat as a non-extension node */
return LY_SUCCESS;
}
assert(dup_parent || dup_sparent);
if (LYD_CTX(lyd_parent(orig_node)) == *trg_ctx) {
/* same contexts, just extension data */
*trg_ctx = LYD_CTX(orig_node);
return LY_SUCCESS;
}
/* find the extension context to use from the target context */
r = ly_nested_ext_schema(dup_parent, dup_sparent, orig_node->schema->module->name, strlen(orig_node->schema->module->name),
LY_VALUE_JSON, NULL, LYD_NAME(orig_node), strlen(LYD_NAME(orig_node)), &snode, NULL);
if (r == LY_ENOT) {
path = lyd_path(orig_node, LYD_PATH_STD, NULL, 0);
LOGERR(*trg_ctx, LY_ENOTFOUND, "Schema node of an extension node \"%s\" not found in the target context.", path);
free(path);
return LY_ENOTFOUND;
} else if (r) {
return r;
}
/* update the context */
*trg_ctx = snode->module->ctx;
return LY_SUCCESS;
}
/**
* @brief Find (update) the target context for the specific nested node, if needed.
*
* @param[in] orig_node Nested data node being processed from the original tree.
* @param[in,out] trg_ctx Target context, may be updated.
* @return LY_ERR value.
*/
static LY_ERR
lyd_find_ext_ctx_nested(const struct lyd_node *orig_node, const struct ly_ctx **trg_ctx)
{
const struct lyd_node *parent;
const struct lysc_node *sparent;
char *path;
if (lyd_dup_get_top_ctx(orig_node) == *trg_ctx) {
/* it is the same context, use the same one for extension data nodes as well (if node is nested in such data) */
*trg_ctx = LYD_CTX(orig_node);
} else {
/* not the same context, need to find the right one */
parent = orig_node;
while (parent && !(parent->flags & LYD_EXT)) {
parent = lyd_parent(parent);
}
if (parent && lyd_parent(parent)) {
/* find the parent schema node in the target context */
path = lysc_path(lyd_parent(parent)->schema, LYSC_PATH_DATA, NULL, 0);
sparent = lys_find_path(*trg_ctx, NULL, path, 0);
if (!sparent) {
LOGERR(*trg_ctx, LY_ENOTFOUND, "Node \"%s\" was not found in the target context.", path);
free(path);
return LY_ENOTFOUND;
}
free(path);
LY_CHECK_RET(lyd_find_ext_ctx(parent, NULL, sparent, trg_ctx));
}
}
return LY_SUCCESS;
}
/**
* @brief Duplicate a single node and connect it into @p parent (if present) or last of @p first siblings.
*
@ -2020,7 +2139,7 @@ static LY_ERR
lyd_dup_r(const struct lyd_node *node, const struct ly_ctx *trg_ctx, struct lyd_node *parent, uint32_t insert_order,
struct lyd_node **first, uint32_t options, struct lyd_node **dup_p)
{
LY_ERR ret;
LY_ERR rc = LY_SUCCESS;
struct lyd_node *dup = NULL;
struct lyd_meta *meta;
struct lyd_attr *attr;
@ -2036,8 +2155,10 @@ lyd_dup_r(const struct lyd_node *node, const struct ly_ctx *trg_ctx, struct lyd_
return LY_SUCCESS;
}
/* we need to use the same context */
trg_ctx = LYD_CTX(node);
if (parent) {
/* update the context */
LY_CHECK_GOTO(rc = lyd_find_ext_ctx(node, parent, NULL, &trg_ctx), cleanup);
} /* else called from lyd_dup_get_local_parent() and the context is correct */
}
if (!node->schema) {
@ -2062,11 +2183,11 @@ lyd_dup_r(const struct lyd_node *node, const struct ly_ctx *trg_ctx, struct lyd_
break;
default:
LOGINT(trg_ctx);
ret = LY_EINT;
goto error;
rc = LY_EINT;
goto cleanup;
}
}
LY_CHECK_ERR_GOTO(!dup, LOGMEM(trg_ctx); ret = LY_EMEM, error);
LY_CHECK_ERR_GOTO(!dup, LOGMEM(trg_ctx); rc = LY_EMEM, cleanup);
if (options & LYD_DUP_WITH_FLAGS) {
dup->flags = node->flags;
@ -2076,15 +2197,17 @@ lyd_dup_r(const struct lyd_node *node, const struct ly_ctx *trg_ctx, struct lyd_
if (options & LYD_DUP_WITH_PRIV) {
dup->priv = node->priv;
}
/* find schema node */
if (trg_ctx == LYD_CTX(node)) {
dup->schema = node->schema;
} else {
ret = lyd_find_schema_ctx(node->schema, trg_ctx, parent, 1, &dup->schema);
if (ret) {
rc = lyd_find_schema_ctx(node->schema, trg_ctx, parent, 1, &dup->schema);
if (rc) {
/* has no schema but is not an opaque node */
free(dup);
dup = NULL;
goto error;
goto cleanup;
}
}
dup->prev = dup;
@ -2093,11 +2216,11 @@ lyd_dup_r(const struct lyd_node *node, const struct ly_ctx *trg_ctx, struct lyd_
if (!(options & LYD_DUP_NO_META)) {
if (!node->schema) {
LY_LIST_FOR(((struct lyd_node_opaq *)node)->attr, attr) {
LY_CHECK_GOTO(ret = lyd_dup_attr_single(attr, dup, NULL), error);
LY_CHECK_GOTO(rc = lyd_dup_attr_single(attr, dup, NULL), cleanup);
}
} else {
LY_LIST_FOR(node->meta, meta) {
LY_CHECK_GOTO(ret = lyd_dup_meta_single_to_ctx(trg_ctx, meta, dup, NULL), error);
LY_CHECK_GOTO(rc = lyd_dup_meta_single_to_ctx(trg_ctx, meta, dup, NULL), cleanup);
}
}
}
@ -2111,18 +2234,18 @@ lyd_dup_r(const struct lyd_node *node, const struct ly_ctx *trg_ctx, struct lyd_
if (options & LYD_DUP_RECURSIVE) {
/* duplicate all the children */
LY_LIST_FOR(orig->child, child) {
LY_CHECK_GOTO(ret = lyd_dup_r(child, trg_ctx, dup, LYD_INSERT_NODE_LAST, NULL, options, NULL), error);
LY_CHECK_GOTO(rc = lyd_dup_r(child, trg_ctx, dup, LYD_INSERT_NODE_LAST, NULL, options, NULL), cleanup);
}
}
LY_CHECK_GOTO(ret = lydict_insert(trg_ctx, orig->name.name, 0, &opaq->name.name), error);
LY_CHECK_GOTO(ret = lydict_insert(trg_ctx, orig->name.prefix, 0, &opaq->name.prefix), error);
LY_CHECK_GOTO(ret = lydict_insert(trg_ctx, orig->name.module_ns, 0, &opaq->name.module_ns), error);
LY_CHECK_GOTO(ret = lydict_insert(trg_ctx, orig->value, 0, &opaq->value), error);
LY_CHECK_GOTO(rc = lydict_insert(trg_ctx, orig->name.name, 0, &opaq->name.name), cleanup);
LY_CHECK_GOTO(rc = lydict_insert(trg_ctx, orig->name.prefix, 0, &opaq->name.prefix), cleanup);
LY_CHECK_GOTO(rc = lydict_insert(trg_ctx, orig->name.module_ns, 0, &opaq->name.module_ns), cleanup);
LY_CHECK_GOTO(rc = lydict_insert(trg_ctx, orig->value, 0, &opaq->value), cleanup);
opaq->hints = orig->hints;
opaq->format = orig->format;
if (orig->val_prefix_data) {
ret = ly_dup_prefix_data(trg_ctx, opaq->format, orig->val_prefix_data, &opaq->val_prefix_data);
LY_CHECK_GOTO(ret, error);
rc = ly_dup_prefix_data(trg_ctx, opaq->format, orig->val_prefix_data, &opaq->val_prefix_data);
LY_CHECK_GOTO(rc, cleanup);
}
} else if (dup->schema->nodetype & LYD_NODE_TERM) {
struct lyd_node_term *term = (struct lyd_node_term *)dup;
@ -2130,15 +2253,15 @@ lyd_dup_r(const struct lyd_node *node, const struct ly_ctx *trg_ctx, struct lyd_
term->hash = orig->hash;
if (trg_ctx == LYD_CTX(node)) {
ret = orig->value.realtype->plugin->duplicate(trg_ctx, &orig->value, &term->value);
LY_CHECK_ERR_GOTO(ret, LOGERR(trg_ctx, ret, "Value duplication failed."), error);
rc = orig->value.realtype->plugin->duplicate(trg_ctx, &orig->value, &term->value);
LY_CHECK_ERR_GOTO(rc, LOGERR(trg_ctx, rc, "Value duplication failed."), cleanup);
} else {
/* store canonical value in the target context */
val_can = lyd_get_value(node);
type = ((struct lysc_node_leaf *)term->schema)->type;
ret = lyd_value_store(trg_ctx, &term->value, type, val_can, strlen(val_can), 1, 1, NULL, LY_VALUE_CANON, NULL,
rc = lyd_value_store(trg_ctx, &term->value, type, val_can, strlen(val_can), 1, 1, NULL, LY_VALUE_CANON, NULL,
LYD_HINT_DATA, term->schema, NULL);
LY_CHECK_GOTO(ret, error);
LY_CHECK_GOTO(rc, cleanup);
}
} else if (dup->schema->nodetype & LYD_NODE_INNER) {
struct lyd_node_inner *orig = (struct lyd_node_inner *)node;
@ -2147,44 +2270,44 @@ lyd_dup_r(const struct lyd_node *node, const struct ly_ctx *trg_ctx, struct lyd_
if (options & LYD_DUP_RECURSIVE) {
/* create a hash table with the size of the previous hash table (duplicate) */
if (orig->children_ht) {
((struct lyd_node_inner *)dup)->children_ht = lyht_new(orig->children_ht->size, sizeof(struct lyd_node *), lyd_hash_table_val_equal, NULL, 1);
((struct lyd_node_inner *)dup)->children_ht = lyht_new(orig->children_ht->size,
sizeof(struct lyd_node *), lyd_hash_table_val_equal, NULL, 1);
}
/* duplicate all the children */
LY_LIST_FOR(orig->child, child) {
LY_CHECK_GOTO(ret = lyd_dup_r(child, trg_ctx, dup, LYD_INSERT_NODE_LAST, NULL, options, NULL), error);
LY_CHECK_GOTO(rc = lyd_dup_r(child, trg_ctx, dup, LYD_INSERT_NODE_LAST, NULL, options, NULL), cleanup);
}
} else if ((dup->schema->nodetype == LYS_LIST) && !(dup->schema->flags & LYS_KEYLESS)) {
/* always duplicate keys of a list */
for (child = orig->child; child && lysc_is_key(child->schema); child = child->next) {
LY_CHECK_GOTO(ret = lyd_dup_r(child, trg_ctx, dup, LYD_INSERT_NODE_LAST, NULL, options, NULL), error);
LY_CHECK_GOTO(rc = lyd_dup_r(child, trg_ctx, dup, LYD_INSERT_NODE_LAST, NULL, options, NULL), cleanup);
}
}
lyd_hash(dup);
} else if (dup->schema->nodetype & LYD_NODE_ANY) {
dup->hash = node->hash;
any = (struct lyd_node_any *)node;
LY_CHECK_GOTO(ret = lyd_any_copy_value(dup, &any->value, any->value_type), error);
LY_CHECK_GOTO(rc = lyd_any_copy_value(dup, &any->value, any->value_type), cleanup);
}
/* insert */
lyd_insert_node(parent, first, dup, insert_order);
if (dup_p) {
cleanup:
if (rc) {
lyd_free_tree(dup);
} else if (dup_p) {
*dup_p = dup;
}
return LY_SUCCESS;
error:
lyd_free_tree(dup);
return ret;
return rc;
}
/**
* @brief Get a parent node to connect duplicated subtree to.
*
* @param[in] node Node (subtree) to duplicate.
* @param[in] trg_ctx Target context for duplicated nodes.
* @param[in,out] trg_ctx Target context for duplicated nodes, may be updated for @p node.
* @param[in] parent Initial parent to connect to.
* @param[in] options Bitmask of options flags, see @ref dupoptions.
* @param[out] dup_parent First duplicated parent node, if any.
@ -2192,24 +2315,30 @@ error:
* @return LY_ERR value.
*/
static LY_ERR
lyd_dup_get_local_parent(const struct lyd_node *node, const struct ly_ctx *trg_ctx, struct lyd_node *parent,
lyd_dup_get_local_parent(const struct lyd_node *node, const struct ly_ctx **trg_ctx, struct lyd_node *parent,
uint32_t options, struct lyd_node **dup_parent, struct lyd_node **local_parent)
{
const struct lyd_node *orig_parent;
const struct ly_ctx *ctx, *top_ctx;
struct lyd_node *iter = NULL;
ly_bool repeat = 1, ext_parent = 0;
ly_bool repeat = 1;
assert(node && *trg_ctx);
*dup_parent = NULL;
*local_parent = NULL;
if (node->flags & LYD_EXT) {
ext_parent = 1;
if (!lyd_parent(node)) {
/* no parents */
return LY_SUCCESS;
}
/* adjust the context for node parent correctly */
top_ctx = *trg_ctx;
LY_CHECK_RET(lyd_find_ext_ctx_nested(lyd_parent(node), trg_ctx));
ctx = *trg_ctx;
for (orig_parent = lyd_parent(node); repeat && orig_parent; orig_parent = lyd_parent(orig_parent)) {
if (ext_parent) {
/* use the standard context */
trg_ctx = LYD_CTX(orig_parent);
}
if (parent && (LYD_CTX(parent) == LYD_CTX(orig_parent)) && (parent->schema == orig_parent->schema)) {
/* stop creating parents, connect what we have into the provided parent */
iter = parent;
@ -2221,7 +2350,7 @@ lyd_dup_get_local_parent(const struct lyd_node *node, const struct ly_ctx *trg_c
repeat = 0;
} else {
iter = NULL;
LY_CHECK_RET(lyd_dup_r(orig_parent, trg_ctx, NULL, LYD_INSERT_NODE_DEFAULT, &iter, options, &iter));
LY_CHECK_RET(lyd_dup_r(orig_parent, ctx, NULL, LYD_INSERT_NODE_DEFAULT, &iter, options, &iter));
/* insert into the previous duplicated parent */
if (*dup_parent) {
@ -2238,13 +2367,14 @@ lyd_dup_get_local_parent(const struct lyd_node *node, const struct ly_ctx *trg_c
}
if (orig_parent->flags & LYD_EXT) {
ext_parent = 1;
/* parents of the nested extension data, use the original context */
ctx = top_ctx;
}
}
if (repeat && parent) {
/* given parent and created parents chain actually do not interconnect */
LOGERR(trg_ctx, LY_EINVAL, "None of the duplicated node \"%s\" schema parents match the provided parent \"%s\".",
LOGERR(*trg_ctx, LY_EINVAL, "None of the duplicated node \"%s\" schema parents match the provided parent \"%s\".",
LYD_NAME(node), LYD_NAME(parent));
return LY_EINVAL;
}
@ -2272,11 +2402,13 @@ lyd_dup(const struct lyd_node *node, const struct ly_ctx *trg_ctx, struct lyd_no
assert(node && trg_ctx);
/* create/find parents, adjusts the context as well */
if (options & LYD_DUP_WITH_PARENTS) {
LY_CHECK_GOTO(rc = lyd_dup_get_local_parent(node, trg_ctx, parent, options & (LYD_DUP_WITH_FLAGS | LYD_DUP_NO_META),
LY_CHECK_GOTO(rc = lyd_dup_get_local_parent(node, &trg_ctx, parent, options & (LYD_DUP_WITH_FLAGS | LYD_DUP_NO_META),
&top, &local_parent), error);
} else {
local_parent = parent;
LY_CHECK_GOTO(rc = lyd_find_ext_ctx_nested(node, &trg_ctx), error);
}
LY_LIST_FOR(node, orig) {
@ -2340,42 +2472,16 @@ error:
return rc;
}
/**
* @brief Check the context of node and parent when duplicating nodes.
*
* @param[in] node Node to duplicate.
* @param[in] parent Parent of the duplicated node(s).
* @return LY_ERR value.
*/
static LY_ERR
lyd_dup_ctx_check(const struct lyd_node *node, const struct lyd_node_inner *parent)
{
const struct lyd_node *iter;
if (!node || !parent) {
return LY_SUCCESS;
}
if ((LYD_CTX(node) != LYD_CTX(parent))) {
/* try to find top-level ext data parent */
for (iter = node; iter && !(iter->flags & LYD_EXT); iter = lyd_parent(iter)) {}
if (!iter || !lyd_parent(iter) || (LYD_CTX(lyd_parent(iter)) != LYD_CTX(parent))) {
LOGERR(LYD_CTX(node), LY_EINVAL, "Different contexts used in node duplication.");
return LY_EINVAL;
}
}
return LY_SUCCESS;
}
LIBYANG_API_DEF LY_ERR
lyd_dup_single(const struct lyd_node *node, struct lyd_node_inner *parent, uint32_t options, struct lyd_node **dup)
{
LY_CHECK_ARG_RET(NULL, node, LY_EINVAL);
LY_CHECK_RET(lyd_dup_ctx_check(node, parent));
if (parent && (lyd_dup_get_top_ctx(node) != lyd_dup_get_top_ctx(&parent->node))) {
LOGERR(LYD_CTX(node), LY_EINVAL, "Different \"node\" and \"parent\" contexts used in node duplication.");
return LY_EINVAL;
}
return lyd_dup(node, LYD_CTX(node), (struct lyd_node *)parent, options, 1, dup);
return lyd_dup(node, lyd_dup_get_top_ctx(node), (struct lyd_node *)parent, options, 1, dup);
}
LIBYANG_API_DEF LY_ERR
@ -2383,6 +2489,10 @@ lyd_dup_single_to_ctx(const struct lyd_node *node, const struct ly_ctx *trg_ctx,
uint32_t options, struct lyd_node **dup)
{
LY_CHECK_ARG_RET(trg_ctx, node, trg_ctx, LY_EINVAL);
if (parent && (trg_ctx != lyd_dup_get_top_ctx(&parent->node))) {
LOGERR(LYD_CTX(node), LY_EINVAL, "Different \"trg_ctx\" and \"parent\" contexts used in node duplication.");
return LY_EINVAL;
}
return lyd_dup(node, trg_ctx, (struct lyd_node *)parent, options, 1, dup);
}
@ -2391,9 +2501,12 @@ LIBYANG_API_DEF LY_ERR
lyd_dup_siblings(const struct lyd_node *node, struct lyd_node_inner *parent, uint32_t options, struct lyd_node **dup)
{
LY_CHECK_ARG_RET(NULL, node, LY_EINVAL);
LY_CHECK_RET(lyd_dup_ctx_check(node, parent));
if (parent && (lyd_dup_get_top_ctx(node) != lyd_dup_get_top_ctx(&parent->node))) {
LOGERR(LYD_CTX(node), LY_EINVAL, "Different \"node\" and \"parent\" contexts used in node duplication.");
return LY_EINVAL;
}
return lyd_dup(node, LYD_CTX(node), (struct lyd_node *)parent, options, 0, dup);
return lyd_dup(node, lyd_dup_get_top_ctx(node), (struct lyd_node *)parent, options, 0, dup);
}
LIBYANG_API_DEF LY_ERR
@ -2401,6 +2514,10 @@ lyd_dup_siblings_to_ctx(const struct lyd_node *node, const struct ly_ctx *trg_ct
uint32_t options, struct lyd_node **dup)
{
LY_CHECK_ARG_RET(trg_ctx, node, trg_ctx, LY_EINVAL);
if (parent && (trg_ctx != lyd_dup_get_top_ctx(&parent->node))) {
LOGERR(LYD_CTX(node), LY_EINVAL, "Different \"trg_ctx\" and \"parent\" contexts used in node duplication.");
return LY_EINVAL;
}
return lyd_dup(node, trg_ctx, (struct lyd_node *)parent, options, 0, dup);
}
@ -2635,8 +2752,8 @@ lyd_merge(struct lyd_node **target, const struct lyd_node *source, const struct
struct lyds_pool lyds = {0};
LY_CHECK_ARG_RET(NULL, target, LY_EINVAL);
LY_CHECK_CTX_EQUAL_RET(*target ? LYD_CTX(*target) : NULL, source ? LYD_CTX(source) : NULL, mod ? mod->ctx : NULL,
LY_EINVAL);
LY_CHECK_CTX_EQUAL_RET(__func__, *target ? LYD_CTX(*target) : NULL, source ? LYD_CTX(source) : NULL,
mod ? mod->ctx : NULL, LY_EINVAL);
if (!source) {
/* nothing to merge */
@ -2993,7 +3110,7 @@ lyd_find_meta(const struct lyd_meta *first, const struct lys_module *module, con
size_t pref_len, name_len;
LY_CHECK_ARG_RET(NULL, module || strchr(name, ':'), name, NULL);
LY_CHECK_CTX_EQUAL_RET(first ? first->annotation->module->ctx : NULL, module ? module->ctx : NULL, NULL);
LY_CHECK_CTX_EQUAL_RET(__func__, first ? first->annotation->module->ctx : NULL, module ? module->ctx : NULL, NULL);
if (!first) {
return NULL;
@ -3188,7 +3305,7 @@ lyd_find_sibling_dup_inst_set(const struct lyd_node *siblings, const struct lyd_
uint32_t comp_opts;
LY_CHECK_ARG_RET(NULL, target, set, LY_EINVAL);
LY_CHECK_CTX_EQUAL_RET(siblings ? LYD_CTX(siblings) : NULL, LYD_CTX(target), LY_EINVAL);
LY_CHECK_CTX_EQUAL_RET(__func__, siblings ? LYD_CTX(siblings) : NULL, LYD_CTX(target), LY_EINVAL);
LY_CHECK_RET(ly_set_new(set));
@ -3262,6 +3379,11 @@ lyd_find_sibling_opaq_next(const struct lyd_node *first, const char *name, struc
LY_CHECK_ARG_RET(NULL, name, LY_EINVAL);
if (first && first->schema) {
/* find the actual first node */
while (first->prev->next) {
first = first->prev;
}
first = first->prev;
if (first->schema) {
/* no opaque nodes */
@ -3573,8 +3695,8 @@ lyd_find_path(const struct lyd_node *ctx_node, const char *path, ly_bool output,
LY_CHECK_ARG_RET(NULL, ctx_node, ctx_node->schema, path, LY_EINVAL);
/* parse the path */
ret = ly_path_parse(LYD_CTX(ctx_node), ctx_node->schema, path, strlen(path), 0, LY_PATH_BEGIN_EITHER,
LY_PATH_PREFIX_FIRST, LY_PATH_PRED_SIMPLE, &expr);
ret = ly_path_parse(LYD_CTX(ctx_node), ctx_node->schema, path, 0, 0, LY_PATH_BEGIN_EITHER, LY_PATH_PREFIX_FIRST,
LY_PATH_PRED_SIMPLE, &expr);
LY_CHECK_GOTO(ret, cleanup);
/* compile the path */
@ -3617,8 +3739,11 @@ LY_ERR
lyd_get_or_create_leafref_links_record(const struct lyd_node_term *node, struct lyd_leafref_links_rec **record, ly_bool create)
{
struct ly_ht *ht;
LY_ERR ret = LY_SUCCESS;
uint32_t hash;
struct lyd_leafref_links_rec rec = {0};
struct lyd_leafref_links_rec *rec_p = &rec;
struct lyd_leafref_links_rec **rec_p2;
assert(node);
assert(record);
@ -3633,15 +3758,23 @@ lyd_get_or_create_leafref_links_record(const struct lyd_node_term *node, struct
ht = LYD_CTX(node)->leafref_links_ht;
hash = lyht_hash((const char *)&node, sizeof node);
if (lyht_find(ht, &rec, hash, (void **)record) == LY_ENOTFOUND) {
if (lyht_find(ht, &rec_p, hash, (void **)&rec_p2) == LY_ENOTFOUND) {
if (create) {
LY_CHECK_RET(lyht_insert_no_check(ht, &rec, hash, (void **)record));
rec_p = calloc(1, sizeof rec);
rec_p->node = node;
LY_CHECK_ERR_RET(!rec_p, LOGMEM(LYD_CTX(node)), LY_EMEM);
ret = lyht_insert_no_check(ht, &rec_p, hash, (void **)&rec_p2);
LY_CHECK_ERR_GOTO(ret, free(rec_p), cleanup);
} else {
return LY_ENOTFOUND;
}
}
return LY_SUCCESS;
cleanup:
if (!ret) {
*record = *rec_p2;
}
return ret;
}
LIBYANG_API_DEF LY_ERR

View file

@ -4,7 +4,7 @@
* @author Michal Vasko <mvasko@cesnet.cz>
* @brief libyang representation of YANG data trees.
*
* Copyright (c) 2015 - 2024 CESNET, z.s.p.o.
* Copyright (c) 2015 - 2025 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.
@ -556,15 +556,16 @@ typedef enum {
* @brief List of possible value types stored in ::lyd_node_any.
*/
typedef enum {
LYD_ANYDATA_DATATREE, /**< Value is a pointer to ::lyd_node structure (first sibling). When provided as input parameter, the pointer
is directly connected into the anydata node without duplication, caller is supposed to not manipulate
with the data after a successful call (including calling ::lyd_free_all() on the provided data) */
LYD_ANYDATA_STRING, /**< Value is a generic string without any knowledge about its format (e.g. anyxml value in JSON encoded
as string). XML sensitive characters (such as & or \>) are automatically escaped when the anydata
is printed in XML format. */
LYD_ANYDATA_XML, /**< Value is a string containing the serialized XML data. */
LYD_ANYDATA_JSON, /**< Value is a string containing the data modeled by YANG and encoded as I-JSON. */
LYD_ANYDATA_LYB /**< Value is a memory chunk with the serialized data tree in LYB format. */
LYD_ANYDATA_DATATREE, /**< Value is a pointer to ::lyd_node structure (first sibling). When provided as input
parameter, the pointer is directly connected into the anydata node without duplication,
caller is supposed to not manipulate with the data after a successful call (including
calling ::lyd_free_all() on the provided data) */
LYD_ANYDATA_STRING, /**< Value is a generic string without any knowledge about its format (e.g. anyxml value in
JSON encoded as string). XML sensitive characters (such as & or \>) are automatically
escaped when the anydata is printed in XML format. */
LYD_ANYDATA_XML, /**< Value is a string containing the serialized XML data. */
LYD_ANYDATA_JSON, /**< Value is a string containing the data modeled by YANG and encoded as I-JSON. */
LYD_ANYDATA_LYB /**< Value is a memory chunk with the serialized data tree in LYB format. */
} LYD_ANYDATA_VALUETYPE;
/** @} */
@ -944,6 +945,7 @@ struct lyd_node_any {
#define LYD_VALHINT_NUM64 0x0010 /**< value is allowed to be an int64 or uint64 */
#define LYD_VALHINT_BOOLEAN 0x0020 /**< value is allowed to be a boolean */
#define LYD_VALHINT_EMPTY 0x0040 /**< value is allowed to be empty */
#define LYD_VALHINT_STRING_DATATYPES 0x0080 /**< boolean and numeric fields are allowed to be quoted */
/**
* @} lydvalhints
*/
@ -1554,8 +1556,8 @@ LIBYANG_API_DECL LY_ERR lyd_new_attr2(struct lyd_node *parent, const char *modul
* and @p value is set, the predicate is preferred.
*
* For key-less lists, positional predicates must be used (indices starting from 1). For non-configuration leaf-lists
* either positional predicate can be used or leaf-list predicate, when an instance is always created at the end.
* If no predicate is used for these nodes, they are always created.
* (or lists) either positional predicate can be used or leaf-list (or key) predicate, when an instance is always
* created at the end. If no predicate is used for these nodes, they are always created.
*
* @param[in] parent Data parent to add to/modify, can be NULL. Note that in case a first top-level sibling is used,
* it may no longer be first if @p path is absolute and starts with a non-existing top-level node inserted
@ -1591,7 +1593,7 @@ LIBYANG_API_DECL LY_ERR lyd_new_path(struct lyd_node *parent, const struct ly_ct
* @param[in] value_type Anyxml/anydata node @p value type.
* @param[in] options Bitmask of options, see @ref newvaloptions.
* @param[out] new_parent Optional first parent node created. If only one node was created, equals to @p new_node.
* @param[out] new_node Optional last node created.
* @param[out] new_node Optional target node of @p path (the last created node, the list instance in case of a list).
* @return LY_SUCCESS on success.
* @return LY_EEXIST if the final node to create exists (unless ::LYD_NEW_PATH_UPDATE is used).
* @return LY_EINVAL on invalid arguments including invalid @p path.
@ -2005,7 +2007,8 @@ LIBYANG_API_DECL LY_ERR lyd_dup_single(const struct lyd_node *node, struct lyd_n
* @brief Create a copy of the specified data tree @p node. Schema references are assigned from @p trg_ctx.
*
* @param[in] node Data tree node to be duplicated.
* @param[in] trg_ctx Target context for duplicated nodes.
* @param[in] trg_ctx Target context for duplicated nodes. In case of mixed contexts in @p node subtree or parents
* (schema mount data), this is the context of top-level nodes.
* @param[in] parent Optional parent node where to connect the duplicated node(s). If set in combination with
* ::LYD_DUP_WITH_PARENTS, the missing parents' chain is duplicated and connected with @p parent.
* @param[in] options Bitmask of options flags, see @ref dupoptions.
@ -2035,7 +2038,8 @@ LIBYANG_API_DECL LY_ERR lyd_dup_siblings(const struct lyd_node *node, struct lyd
* from @p trg_ctx.
*
* @param[in] node Data tree node to be duplicated.
* @param[in] trg_ctx Target context for duplicated nodes.
* @param[in] trg_ctx Target context for duplicated nodes. In case of mixed contexts in @p node subtree or parents
* (schema mount data), this is the context of top-level nodes.
* @param[in] parent Optional parent node where to connect the duplicated node(s). If set in combination with
* ::LYD_DUP_WITH_PARENTS, the missing parents' chain is duplicated and connected with @p parent.
* @param[in] options Bitmask of options flags, see @ref dupoptions.
@ -2158,12 +2162,18 @@ LIBYANG_API_DECL LY_ERR lyd_merge_module(struct lyd_node **target, const struct
*
* Default behavior:
* - any default nodes are treated as non-existent and ignored.
* - nodes with 'none' operation can appear only in case a leaf node has not changed its value and only its
* default flag.
* - metadata differences are not included in the diff.
* @{
*/
#define LYD_DIFF_DEFAULTS 0x01 /**< Default nodes in the trees are not ignored but treated similarly to explicit
nodes. Also, leaves and leaf-lists are added into diff even in case only their
default flag (state) was changed. */
#define LYD_DIFF_META 0x02 /**< All metadata are compared and the full difference reported in the diff always in
the form of 'yang:meta-<operation>' metadata. Also, equal nodes with only changes
in their metadata will be present in the diff with the 'none' operation. */
/** @} diffoptions */
@ -2661,7 +2671,7 @@ LIBYANG_API_DECL int ly_time_tz_offset_at(time_t time);
/**
* @brief Convert date-and-time from string to UNIX timestamp and fractions of a second.
*
* @param[in] value Valid string date-and-time value.
* @param[in] value Valid string date-and-time value, the string may continue after the value (be longer).
* @param[out] time UNIX timestamp.
* @param[out] fractions_s Optional fractions of a second, set to NULL if none.
* @return LY_ERR value.
@ -2681,7 +2691,7 @@ LIBYANG_API_DECL LY_ERR ly_time_time2str(time_t time, const char *fractions_s, c
/**
* @brief Convert date-and-time from string to timespec.
*
* @param[in] value Valid string date-and-time value.
* @param[in] value Valid string date-and-time value, the string may continue after the value (be longer).
* @param[out] ts Timespec.
* @return LY_ERR value.
*/

View file

@ -516,6 +516,7 @@ lyd_value_store(const struct ly_ctx *ctx, struct lyd_value *val, const struct ly
if (!value) {
value = "";
value_len = 0;
}
if (incomplete) {
*incomplete = 0;
@ -1626,9 +1627,6 @@ ly_time_tz_offset_at(time_t time)
struct tm tm_local, tm_utc;
int result = 0;
/* init timezone */
tzset();
/* get local and UTC time */
localtime_r(&time, &tm_local);
gmtime_r(&time, &tm_utc);
@ -1670,7 +1668,7 @@ ly_time_str2time(const char *value, time_t *time, char **fractions_s)
int64_t shift, shift_m;
time_t t;
LY_CHECK_ARG_RET(NULL, value, strlen(value) > 17, time, LY_EINVAL);
LY_CHECK_ARG_RET(NULL, value, strnlen(value, 18) > 17, time, LY_EINVAL);
tm.tm_year = atoi(&value[0]) - 1900;
tm.tm_mon = atoi(&value[5]) - 1;
@ -1776,9 +1774,6 @@ ly_time_time2str(time_t time, const char *fractions_s, char **str)
LY_CHECK_ARG_RET(NULL, str, LY_EINVAL);
/* init timezone */
tzset();
/* convert */
if (!localtime_r(&time, &tm)) {
return LY_ESYS;

View file

@ -191,7 +191,8 @@ lyd_free_leafref_nodes(const struct lyd_node_term *node)
/* free entry itself from hash table */
ht = LYD_CTX(node)->leafref_links_ht;
hash = lyht_hash((const char *)&node, sizeof node);
lyht_remove(ht, rec, hash);
lyht_remove(ht, &rec, hash);
free(rec);
}
/**

View file

@ -505,7 +505,7 @@ lyd_new_inner(struct lyd_node *parent, const struct lys_module *module, const ch
const struct ly_ctx *ctx = parent ? LYD_CTX(parent) : (module ? module->ctx : NULL);
LY_CHECK_ARG_RET(ctx, parent || module, parent || node, name, LY_EINVAL);
LY_CHECK_CTX_EQUAL_RET(parent ? LYD_CTX(parent) : NULL, module ? module->ctx : NULL, LY_EINVAL);
LY_CHECK_CTX_EQUAL_RET(__func__, parent ? LYD_CTX(parent) : NULL, module ? module->ctx : NULL, LY_EINVAL);
if (!module) {
module = parent->schema->module;
@ -621,7 +621,7 @@ lyd_new_list(struct lyd_node *parent, const struct lys_module *module, const cha
va_list ap;
LY_CHECK_ARG_RET(ctx, parent || module, parent || node, name, LY_EINVAL);
LY_CHECK_CTX_EQUAL_RET(parent ? LYD_CTX(parent) : NULL, module ? module->ctx : NULL, LY_EINVAL);
LY_CHECK_CTX_EQUAL_RET(__func__, parent ? LYD_CTX(parent) : NULL, module ? module->ctx : NULL, LY_EINVAL);
LY_CHECK_RET(lyd_new_val_get_format(options, &format));
LY_CHECK_ARG_RET(ctx, !(store_only && (format == LY_VALUE_CANON || format == LY_VALUE_LYB)), LY_EINVAL);
@ -726,7 +726,7 @@ lyd_new_list2(struct lyd_node *parent, const struct lys_module *module, const ch
uint32_t getnext_opts = (options & LYD_NEW_VAL_OUTPUT) ? LYS_GETNEXT_OUTPUT : 0;
LY_CHECK_ARG_RET(ctx, parent || module, parent || node, name, LY_EINVAL);
LY_CHECK_CTX_EQUAL_RET(parent ? LYD_CTX(parent) : NULL, module ? module->ctx : NULL, LY_EINVAL);
LY_CHECK_CTX_EQUAL_RET(__func__, parent ? LYD_CTX(parent) : NULL, module ? module->ctx : NULL, LY_EINVAL);
if (!module) {
module = parent->schema->module;
@ -781,7 +781,7 @@ lyd_new_list3(struct lyd_node *parent, const struct lys_module *module, const ch
LY_CHECK_RET(lyd_new_val_get_format(options, &format));
LY_CHECK_ARG_RET(ctx, parent || module, parent || node, name, (format != LY_VALUE_LYB) || value_lengths, LY_EINVAL);
LY_CHECK_CTX_EQUAL_RET(parent ? LYD_CTX(parent) : NULL, module ? module->ctx : NULL, LY_EINVAL);
LY_CHECK_CTX_EQUAL_RET(__func__, parent ? LYD_CTX(parent) : NULL, module ? module->ctx : NULL, LY_EINVAL);
LY_CHECK_ARG_RET(ctx, !(store_only && (format == LY_VALUE_CANON || format == LY_VALUE_LYB)), LY_EINVAL);
/* create the list node */
@ -845,7 +845,7 @@ _lyd_new_term(struct lyd_node *parent, const struct lys_module *module, const ch
LY_VALUE_FORMAT format;
LY_CHECK_ARG_RET(ctx, parent || module, parent || node, name, LY_EINVAL);
LY_CHECK_CTX_EQUAL_RET(parent ? LYD_CTX(parent) : NULL, module ? module->ctx : NULL, LY_EINVAL);
LY_CHECK_CTX_EQUAL_RET(__func__, parent ? LYD_CTX(parent) : NULL, module ? module->ctx : NULL, LY_EINVAL);
LY_CHECK_RET(lyd_new_val_get_format(options, &format));
LY_CHECK_ARG_RET(ctx, !(store_only && (format == LY_VALUE_CANON || format == LY_VALUE_LYB)), LY_EINVAL);
@ -941,7 +941,7 @@ lyd_new_any(struct lyd_node *parent, const struct lys_module *module, const char
LY_CHECK_ARG_RET(ctx, parent || module, parent || node, name,
(value_type == LYD_ANYDATA_DATATREE) || (value_type == LYD_ANYDATA_STRING) || value, LY_EINVAL);
LY_CHECK_CTX_EQUAL_RET(parent ? LYD_CTX(parent) : NULL, module ? module->ctx : NULL, LY_EINVAL);
LY_CHECK_CTX_EQUAL_RET(__func__, parent ? LYD_CTX(parent) : NULL, module ? module->ctx : NULL, LY_EINVAL);
if (!module) {
module = parent->schema->module;
@ -1007,7 +1007,7 @@ lyd_new_meta(const struct ly_ctx *ctx, struct lyd_node *parent, const struct lys
ly_bool store_only = options & LYD_NEW_VAL_STORE_ONLY;
LY_CHECK_ARG_RET(ctx, ctx || parent, name, module || strchr(name, ':'), parent || meta, LY_EINVAL);
LY_CHECK_CTX_EQUAL_RET(ctx, parent ? LYD_CTX(parent) : NULL, module ? module->ctx : NULL, LY_EINVAL);
LY_CHECK_CTX_EQUAL_RET(__func__, ctx, parent ? LYD_CTX(parent) : NULL, module ? module->ctx : NULL, LY_EINVAL);
if (!ctx) {
ctx = module ? module->ctx : LYD_CTX(parent);
}
@ -1050,7 +1050,7 @@ lyd_new_meta2(const struct ly_ctx *ctx, struct lyd_node *parent, uint32_t option
ly_bool store_only = options & LYD_NEW_VAL_STORE_ONLY;
LY_CHECK_ARG_RET(NULL, ctx, attr, parent || meta, LY_EINVAL);
LY_CHECK_CTX_EQUAL_RET(ctx, parent ? LYD_CTX(parent) : NULL, LY_EINVAL);
LY_CHECK_CTX_EQUAL_RET(__func__, ctx, parent ? LYD_CTX(parent) : NULL, LY_EINVAL);
if (parent && !parent->schema) {
LOGERR(ctx, LY_EINVAL, "Cannot add metadata to an opaque node \"%s\".",
@ -1092,7 +1092,7 @@ lyd_new_opaq(struct lyd_node *parent, const struct ly_ctx *ctx, const char *name
uint32_t hints = 0;
LY_CHECK_ARG_RET(ctx, parent || ctx, parent || node, name, module_name, !prefix || !strcmp(prefix, module_name), LY_EINVAL);
LY_CHECK_CTX_EQUAL_RET(ctx, parent ? LYD_CTX(parent) : NULL, LY_EINVAL);
LY_CHECK_CTX_EQUAL_RET(__func__, ctx, parent ? LYD_CTX(parent) : NULL, LY_EINVAL);
if (!ctx) {
ctx = LYD_CTX(parent);
@ -1122,7 +1122,7 @@ lyd_new_opaq2(struct lyd_node *parent, const struct ly_ctx *ctx, const char *nam
struct lyd_node *ret = NULL;
LY_CHECK_ARG_RET(ctx, parent || ctx, parent || node, name, module_ns, LY_EINVAL);
LY_CHECK_CTX_EQUAL_RET(ctx, parent ? LYD_CTX(parent) : NULL, LY_EINVAL);
LY_CHECK_CTX_EQUAL_RET(__func__, ctx, parent ? LYD_CTX(parent) : NULL, LY_EINVAL);
if (!ctx) {
ctx = LYD_CTX(parent);
@ -1479,13 +1479,14 @@ cleanup:
* @param[in] value_len Length of @p value.
* @param[in] value_type Type of @p value for anydata/anyxml node.
* @param[in] format Format of @p value.
* @param[in] any_use_value Whether to spend @p value when updating an anydata/anyxml node or not.
* @param[out] new_parent Set to @p node if the value was updated, otherwise set to NULL.
* @param[out] new_node Set to @p node if the value was updated, otherwise set to NULL.
* @return LY_ERR value.
*/
static LY_ERR
lyd_new_path_update(struct lyd_node *node, const void *value, size_t value_len, LYD_ANYDATA_VALUETYPE value_type,
LY_VALUE_FORMAT format, struct lyd_node **new_parent, struct lyd_node **new_node)
LY_VALUE_FORMAT format, ly_bool any_use_value, struct lyd_node **new_parent, struct lyd_node **new_node)
{
LY_ERR ret = LY_SUCCESS;
struct lyd_node *new_any;
@ -1525,12 +1526,14 @@ lyd_new_path_update(struct lyd_node *node, const void *value, size_t value_len,
case LYS_ANYDATA:
case LYS_ANYXML:
/* create a new any node */
LY_CHECK_RET(lyd_create_any(node->schema, value, value_type, 0, &new_any));
LY_CHECK_RET(lyd_create_any(node->schema, value, value_type, any_use_value, &new_any));
/* compare with the existing one */
if (lyd_compare_single(node, new_any, 0)) {
/* not equal, switch values (so that we can use generic node free) */
((struct lyd_node_any *)new_any)->value = ((struct lyd_node_any *)node)->value;
value = ((struct lyd_node_any *)new_any)->value.str;
value_type = ((struct lyd_node_any *)new_any)->value_type;
((struct lyd_node_any *)new_any)->value.str = ((struct lyd_node_any *)node)->value.str;
((struct lyd_node_any *)new_any)->value_type = ((struct lyd_node_any *)node)->value_type;
((struct lyd_node_any *)node)->value.str = value;
((struct lyd_node_any *)node)->value_type = value_type;
@ -1679,7 +1682,7 @@ lyd_new_path_(struct lyd_node *parent, const struct ly_ctx *ctx, const struct ly
LY_CHECK_GOTO(ret = lyd_new_val_get_format(options, &format), cleanup);
/* parse path */
LY_CHECK_GOTO(ret = ly_path_parse(ctx, NULL, path, strlen(path), 0, LY_PATH_BEGIN_EITHER, LY_PATH_PREFIX_FIRST,
LY_CHECK_GOTO(ret = ly_path_parse(ctx, NULL, path, 0, 0, LY_PATH_BEGIN_EITHER, LY_PATH_PREFIX_FIRST,
LY_PATH_PRED_SIMPLE, &exp), cleanup);
/* compile path */
@ -1708,7 +1711,7 @@ lyd_new_path_(struct lyd_node *parent, const struct ly_ctx *ctx, const struct ly
}
/* update the existing node */
ret = lyd_new_path_update(node, value, value_len, value_type, format, &nparent, &nnode);
ret = lyd_new_path_update(node, value, value_len, value_type, format, any_use_value, &nparent, &nnode);
goto cleanup;
} /* else we were not searching for the whole path */
} else if (r == LY_EINCOMPLETE) {
@ -1811,7 +1814,8 @@ lyd_new_path_(struct lyd_node *parent, const struct ly_ctx *ctx, const struct ly
if (val) {
LY_CHECK_GOTO(ret = lyd_create_term2(schema, val, &node), cleanup);
} else {
LY_CHECK_GOTO(ret = lyd_create_term(schema, value, value_len, 0, store_only, NULL, format, NULL, LYD_HINT_DATA, NULL, &node), cleanup);
LY_CHECK_GOTO(ret = lyd_create_term(schema, value, value_len, 0, store_only, NULL, format, NULL,
LYD_HINT_DATA, NULL, &node), cleanup);
}
break;
case LYS_LEAF:
@ -1836,15 +1840,16 @@ lyd_new_path_(struct lyd_node *parent, const struct ly_ctx *ctx, const struct ly
if (value && (format == LY_VALUE_JSON) && !ly_strncmp("[null]", value, value_len)) {
hints |= LYD_VALHINT_EMPTY;
}
LY_CHECK_GOTO(ret = lyd_create_opaq(ctx, schema->name, strlen(schema->name), NULL, 0,
schema->module->name, strlen(schema->module->name), value, value_len, NULL, format, NULL, hints, &node),
cleanup);
ret = lyd_create_opaq(ctx, schema->name, strlen(schema->name), NULL, 0, schema->module->name,
strlen(schema->module->name), value, value_len, NULL, format, NULL, hints, &node);
LY_CHECK_GOTO(ret, cleanup);
break;
}
}
/* create a leaf instance */
LY_CHECK_GOTO(ret = lyd_create_term(schema, value, value_len, 0, store_only, NULL, format, NULL, LYD_HINT_DATA, NULL, &node), cleanup);
LY_CHECK_GOTO(ret = lyd_create_term(schema, value, value_len, 0, store_only, NULL, format, NULL,
LYD_HINT_DATA, NULL, &node), cleanup);
break;
case LYS_ANYDATA:
case LYS_ANYXML:
@ -1903,7 +1908,7 @@ lyd_new_path(struct lyd_node *parent, const struct ly_ctx *ctx, const char *path
{
LY_CHECK_ARG_RET(ctx, parent || ctx, path, (path[0] == '/') || parent,
!(options & LYD_NEW_VAL_BIN) || !(options & LYD_NEW_VAL_CANON), LY_EINVAL);
LY_CHECK_CTX_EQUAL_RET(parent ? LYD_CTX(parent) : NULL, ctx, LY_EINVAL);
LY_CHECK_CTX_EQUAL_RET(__func__, parent ? LYD_CTX(parent) : NULL, ctx, LY_EINVAL);
return lyd_new_path_(parent, ctx, NULL, path, value, 0, LYD_ANYDATA_STRING, options, node, NULL);
}
@ -1915,7 +1920,7 @@ lyd_new_path2(struct lyd_node *parent, const struct ly_ctx *ctx, const char *pat
{
LY_CHECK_ARG_RET(ctx, parent || ctx, path, (path[0] == '/') || parent,
!(options & LYD_NEW_VAL_BIN) || !(options & LYD_NEW_VAL_CANON), LY_EINVAL);
LY_CHECK_CTX_EQUAL_RET(parent ? LYD_CTX(parent) : NULL, ctx, LY_EINVAL);
LY_CHECK_CTX_EQUAL_RET(__func__, parent ? LYD_CTX(parent) : NULL, ctx, LY_EINVAL);
return lyd_new_path_(parent, ctx, NULL, path, value, value_len, value_type, options, new_parent, new_node);
}
@ -1928,7 +1933,7 @@ lyd_new_ext_path(struct lyd_node *parent, const struct lysc_ext_instance *ext, c
LY_CHECK_ARG_RET(ctx, ext, path, (path[0] == '/') || parent,
!(options & LYD_NEW_VAL_BIN) || !(options & LYD_NEW_VAL_CANON), LY_EINVAL);
LY_CHECK_CTX_EQUAL_RET(parent ? LYD_CTX(parent) : NULL, ctx, LY_EINVAL);
LY_CHECK_CTX_EQUAL_RET(__func__, parent ? LYD_CTX(parent) : NULL, ctx, LY_EINVAL);
return lyd_new_path_(parent, ctx, ext, path, value, 0, LYD_ANYDATA_STRING, options, node, NULL);
}
@ -2150,7 +2155,7 @@ lyd_new_implicit_all(struct lyd_node **tree, const struct ly_ctx *ctx, uint32_t
LY_ERR rc = LY_SUCCESS;
LY_CHECK_ARG_RET(ctx, tree, *tree || ctx, LY_EINVAL);
LY_CHECK_CTX_EQUAL_RET(*tree ? LYD_CTX(*tree) : NULL, ctx, LY_EINVAL);
LY_CHECK_CTX_EQUAL_RET(__func__, *tree ? LYD_CTX(*tree) : NULL, ctx, LY_EINVAL);
if (diff) {
*diff = NULL;
}
@ -2191,7 +2196,7 @@ lyd_new_implicit_module(struct lyd_node **tree, const struct lys_module *module,
struct ly_ht *getnext_ht = NULL;
LY_CHECK_ARG_RET(NULL, tree, module, LY_EINVAL);
LY_CHECK_CTX_EQUAL_RET(*tree ? LYD_CTX(*tree) : NULL, module ? module->ctx : NULL, LY_EINVAL);
LY_CHECK_CTX_EQUAL_RET(__func__, *tree ? LYD_CTX(*tree) : NULL, module ? module->ctx : NULL, LY_EINVAL);
if (diff) {
*diff = NULL;
}

View file

@ -148,7 +148,7 @@ void *ly_realloc(void *ptr, size_t size);
} \
p__ = (char *)((LY_ARRAY_COUNT_TYPE*)(p__) + 1); \
memcpy(&(ARRAY), &p__, sizeof p__); \
if (ARRAY) { \
if ((ARRAY) && (SIZE > 0)) { \
memset(&(ARRAY)[*((LY_ARRAY_COUNT_TYPE*)(p__) - 1)], 0, (SIZE) * sizeof *(ARRAY)); \
} \
}

View file

@ -1,9 +1,10 @@
/**
* @file tree_schema.c
* @author Radek Krejci <rkrejci@cesnet.cz>
* @author Michal Vasko <mvasko@cesnet.cz>
* @brief Schema tree implementation
*
* Copyright (c) 2015 - 2018 CESNET, z.s.p.o.
* Copyright (c) 2015 - 2025 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.
@ -410,7 +411,7 @@ lys_find_child(const struct lysc_node *parent, const struct lys_module *module,
const struct lysc_node *node = NULL;
LY_CHECK_ARG_RET(NULL, module, name, NULL);
LY_CHECK_CTX_EQUAL_RET(parent ? parent->module->ctx : NULL, module->ctx, NULL);
LY_CHECK_CTX_EQUAL_RET(__func__, parent ? parent->module->ctx : NULL, module->ctx, NULL);
if (!nodetype) {
nodetype = LYS_NODETYPE_MASK;
}
@ -447,7 +448,7 @@ lys_find_xpath_atoms(const struct ly_ctx *ctx, const struct lysc_node *ctx_node,
uint32_t i;
LY_CHECK_ARG_RET(NULL, ctx || ctx_node, xpath, set, LY_EINVAL);
LY_CHECK_CTX_EQUAL_RET(ctx, ctx_node ? ctx_node->module->ctx : NULL, LY_EINVAL);
LY_CHECK_CTX_EQUAL_RET(__func__, ctx, ctx_node ? ctx_node->module->ctx : NULL, LY_EINVAL);
if (!(options & LYXP_SCNODE_ALL)) {
options |= LYXP_SCNODE;
}
@ -494,7 +495,7 @@ lys_find_expr_atoms(const struct lysc_node *ctx_node, const struct lys_module *c
uint32_t i;
LY_CHECK_ARG_RET(NULL, cur_mod, expr, prefixes, set, LY_EINVAL);
LY_CHECK_CTX_EQUAL_RET(ctx_node ? ctx_node->module->ctx : NULL, cur_mod->ctx, LY_EINVAL);
LY_CHECK_CTX_EQUAL_RET(__func__, ctx_node ? ctx_node->module->ctx : NULL, cur_mod->ctx, LY_EINVAL);
if (!(options & LYXP_SCNODE_ALL)) {
options = LYXP_SCNODE;
}
@ -542,9 +543,9 @@ lys_find_xpath(const struct ly_ctx *ctx, const struct lysc_node *ctx_node, const
uint32_t i;
LY_CHECK_ARG_RET(NULL, ctx || ctx_node, xpath, set, LY_EINVAL);
LY_CHECK_CTX_EQUAL_RET(ctx, ctx_node ? ctx_node->module->ctx : NULL, LY_EINVAL);
LY_CHECK_CTX_EQUAL_RET(__func__, ctx, ctx_node ? ctx_node->module->ctx : NULL, LY_EINVAL);
if (!(options & LYXP_SCNODE_ALL)) {
options = LYXP_SCNODE;
options |= LYXP_SCNODE;
}
if (!ctx) {
ctx = ctx_node->module->ctx;
@ -624,14 +625,14 @@ lys_find_path_atoms(const struct ly_ctx *ctx, const struct lysc_node *ctx_node,
struct ly_path *p = NULL;
LY_CHECK_ARG_RET(ctx, ctx || ctx_node, path, set, LY_EINVAL);
LY_CHECK_CTX_EQUAL_RET(ctx, ctx_node ? ctx_node->module->ctx : NULL, LY_EINVAL);
LY_CHECK_CTX_EQUAL_RET(__func__, ctx, ctx_node ? ctx_node->module->ctx : NULL, LY_EINVAL);
if (!ctx) {
ctx = ctx_node->module->ctx;
}
/* parse */
ret = ly_path_parse(ctx, ctx_node, path, strlen(path), 0, LY_PATH_BEGIN_EITHER, LY_PATH_PREFIX_FIRST,
ret = ly_path_parse(ctx, ctx_node, path, 0, 0, LY_PATH_BEGIN_EITHER, LY_PATH_PREFIX_FIRST,
LY_PATH_PRED_SIMPLE, &expr);
LY_CHECK_GOTO(ret, cleanup);
@ -658,15 +659,15 @@ lys_find_path(const struct ly_ctx *ctx, const struct lysc_node *ctx_node, const
LY_ERR ret;
uint8_t oper;
LY_CHECK_ARG_RET(ctx, ctx || ctx_node, NULL);
LY_CHECK_CTX_EQUAL_RET(ctx, ctx_node ? ctx_node->module->ctx : NULL, NULL);
LY_CHECK_ARG_RET(ctx, ctx || ctx_node, path, NULL);
LY_CHECK_CTX_EQUAL_RET(__func__, ctx, ctx_node ? ctx_node->module->ctx : NULL, NULL);
if (!ctx) {
ctx = ctx_node->module->ctx;
}
/* parse */
ret = ly_path_parse(ctx, ctx_node, path, strlen(path), 0, LY_PATH_BEGIN_EITHER, LY_PATH_PREFIX_FIRST,
ret = ly_path_parse(ctx, ctx_node, path, 0, 0, LY_PATH_BEGIN_EITHER, LY_PATH_PREFIX_FIRST,
LY_PATH_PRED_SIMPLE, &expr);
LY_CHECK_GOTO(ret, cleanup);
@ -787,6 +788,7 @@ lysc_path_until(const struct lysc_node *node, const struct lysc_node *parent, LY
if (buffer) {
strcpy(buffer, "/");
} else {
free(path);
path = strdup("/");
}
}
@ -1420,35 +1422,147 @@ next_iter:
return LY_SUCCESS;
}
/**
* @brief Generate a warning if the filename does not match the expected module name and version.
*
* @param[in] ctx Context for logging
* @param[in] name Expected module name
* @param[in] revision Expected module revision, or NULL if not to be checked
* @param[in] filename File path to be checked
*/
static void
ly_check_module_filename(const struct ly_ctx *ctx, const char *name, const char *revision, const char *filename)
{
const char *basename, *rev, *dot;
size_t len;
/* check that name and revision match filename */
basename = strrchr(filename, '/');
#ifdef _WIN32
const char *backslash = strrchr(filename, '\\');
if (!basename || (basename && backslash && (backslash > basename))) {
basename = backslash;
}
#endif
if (!basename) {
basename = filename;
} else {
basename++; /* leading slash */
}
rev = strchr(basename, '@');
dot = strrchr(basename, '.');
/* name */
len = strlen(name);
if (strncmp(basename, name, len) ||
((rev && (rev != &basename[len])) || (!rev && (dot != &basename[len])))) {
LOGWRN(ctx, "File name \"%s\" does not match module name \"%s\".", basename, name);
}
if (rev) {
len = dot - ++rev;
if (!revision || (len != LY_REV_SIZE - 1) || strncmp(revision, rev, len)) {
LOGWRN(ctx, "File name \"%s\" does not match module revision \"%s\".", basename,
revision ? revision : "none");
}
}
}
/**
* @brief Check created (sub)module that it matches the expected module.
*
* @param[in] ctx Context to use.
* @param[in] mod Parsed module.
* @param[in] submod Parsed submodule.
* @param[in] mod_data Expected module data.
* @return LY_SUCCESS on success;
* @return LY_EEXIST if the same module already exists;
* @return LY_ERR on error.
*/
static LY_ERR
lysp_load_module_data_check(const struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_submodule *submod,
const struct lysp_load_module_data *mod_data)
{
const char *name;
uint8_t latest_revision;
struct lysp_revision *revs;
name = mod ? mod->mod->name : submod->name;
revs = mod ? mod->revs : submod->revs;
latest_revision = mod ? mod->mod->latest_revision : submod->latest_revision;
if (mod_data->name) {
/* check name of the parsed model */
if (strcmp(mod_data->name, name)) {
LOGERR(ctx, LY_EINVAL, "Unexpected module \"%s\" parsed instead of \"%s\".", name, mod_data->name);
return LY_EINVAL;
}
}
if (mod_data->revision) {
/* check revision of the parsed model */
if (!revs || strcmp(mod_data->revision, revs[0].date)) {
LOGERR(ctx, LY_EINVAL, "Module \"%s\" parsed with the wrong revision (\"%s\" instead \"%s\").", name,
revs ? revs[0].date : "none", mod_data->revision);
return LY_EINVAL;
}
} else if (!latest_revision) {
/* do not log, we just need to drop the schema and use the latest revision from the context */
return LY_EEXIST;
}
if (submod) {
assert(mod_data->submoduleof);
/* check that the submodule belongs-to our module */
if (strcmp(mod_data->submoduleof, submod->mod->name)) {
LOGVAL(ctx, LYVE_REFERENCE, "Included \"%s\" submodule from \"%s\" belongs-to a different module \"%s\".",
submod->name, mod_data->submoduleof, submod->mod->name);
return LY_EVALID;
}
/* check circular dependency */
if (submod->parsing) {
LOGVAL(ctx, LYVE_REFERENCE, "A circular dependency (include) for module \"%s\".", submod->name);
return LY_EVALID;
}
}
if (mod_data->path) {
ly_check_module_filename(ctx, name, revs ? revs[0].date : NULL, mod_data->path);
}
return LY_SUCCESS;
}
LY_ERR
lys_parse_submodule(struct ly_ctx *ctx, struct ly_in *in, LYS_INFORMAT format, struct lysp_ctx *main_ctx,
LY_ERR (*custom_check)(const struct ly_ctx *, struct lysp_module *, struct lysp_submodule *, void *),
void *check_data, struct ly_set *new_mods, struct lysp_submodule **submodule)
const struct lysp_load_module_data *mod_data, struct ly_set *new_mods, struct lysp_submodule **submodule)
{
LY_ERR ret;
LY_ERR rc = LY_SUCCESS, r;
struct lysp_submodule *submod = NULL, *latest_sp;
struct lysp_yang_ctx *yangctx = NULL;
struct lysp_yin_ctx *yinctx = NULL;
struct lysp_ctx *pctx;
struct lysp_ctx *pctx = NULL;
struct lysf_ctx fctx = {.ctx = ctx};
const char *submod_name;
LY_CHECK_ARG_RET(ctx, ctx, in, LY_EINVAL);
switch (format) {
case LYS_IN_YIN:
ret = yin_parse_submodule(&yinctx, ctx, main_ctx, in, &submod);
rc = yin_parse_submodule(&yinctx, ctx, main_ctx, in, &submod);
pctx = (struct lysp_ctx *)yinctx;
break;
case LYS_IN_YANG:
ret = yang_parse_submodule(&yangctx, ctx, main_ctx, in, &submod);
rc = yang_parse_submodule(&yangctx, ctx, main_ctx, in, &submod);
pctx = (struct lysp_ctx *)yangctx;
break;
default:
LOGERR(ctx, LY_EINVAL, "Invalid schema input format.");
ret = LY_EINVAL;
rc = LY_EINVAL;
break;
}
LY_CHECK_GOTO(ret, error);
LY_CHECK_GOTO(rc, cleanup);
assert(submod);
/* make sure that the newest revision is at position 0 */
@ -1475,8 +1589,21 @@ lys_parse_submodule(struct ly_ctx *ctx, struct ly_in *in, LYS_INFORMAT format, s
submod->latest_revision = 1;
}
if (custom_check) {
LY_CHECK_GOTO(ret = custom_check(ctx, NULL, submod, check_data), error);
if (mod_data) {
/* check the parsed submodule it is as expected */
r = lysp_load_module_data_check(ctx, NULL, submod, mod_data);
if (r == LY_EEXIST) {
/* not an error, the submodule already exists so free this one */
ly_set_erase(&pctx->tpdfs_nodes, NULL);
ly_set_erase(&pctx->grps_nodes, NULL);
ly_set_erase(&pctx->ext_inst, NULL);
lysp_module_free(&fctx, (struct lysp_module *)submod);
submod = NULL;
goto cleanup;
} else if (r) {
rc = r;
goto cleanup;
}
}
if (latest_sp) {
@ -1486,29 +1613,47 @@ lys_parse_submodule(struct ly_ctx *ctx, struct ly_in *in, LYS_INFORMAT format, s
lys_parser_fill_filepath(ctx, in, &submod->filepath);
/* resolve imports and includes */
LY_CHECK_GOTO(ret = lysp_resolve_import_include(pctx, (struct lysp_module *)submod, new_mods), error);
LY_CHECK_GOTO(rc = lysp_resolve_import_include(pctx, (struct lysp_module *)submod, new_mods), cleanup);
cleanup:
if (rc) {
if (submod && submod->name) {
submod_name = submod->name;
} else if (mod_data) {
submod_name = mod_data->name;
} else {
submod_name = NULL;
}
if (submod_name) {
LOGERR(ctx, rc, "Parsing submodule \"%s\" failed.", submod_name);
} else {
LOGERR(ctx, rc, "Parsing submodule failed.");
}
if (pctx) {
ly_set_erase(&pctx->tpdfs_nodes, NULL);
ly_set_erase(&pctx->grps_nodes, NULL);
ly_set_erase(&pctx->ext_inst, NULL);
}
lysp_module_free(&fctx, (struct lysp_module *)submod);
} else if (submod) {
*submodule = submod;
/* merge submod unres into main_ctx unres */
ly_set_merge(&pctx->main_ctx->tpdfs_nodes, &pctx->tpdfs_nodes, 1, NULL);
ly_set_erase(&pctx->tpdfs_nodes, NULL);
ly_set_merge(&pctx->main_ctx->grps_nodes, &pctx->grps_nodes, 1, NULL);
ly_set_erase(&pctx->grps_nodes, NULL);
ly_set_merge(&pctx->main_ctx->ext_inst, &pctx->ext_inst, 1, NULL);
ly_set_erase(&pctx->ext_inst, NULL);
}
if (format == LYS_IN_YANG) {
lysp_yang_ctx_free(yangctx);
} else {
lysp_yin_ctx_free(yinctx);
}
*submodule = submod;
return LY_SUCCESS;
error:
if (!submod || !submod->name) {
LOGERR(ctx, ret, "Parsing submodule failed.");
} else {
LOGERR(ctx, ret, "Parsing submodule \"%s\" failed.", submod->name);
}
lysp_module_free(&fctx, (struct lysp_module *)submod);
if (format == LYS_IN_YANG) {
lysp_yang_ctx_free(yangctx);
} else {
lysp_yin_ctx_free(yinctx);
}
return ret;
return rc;
}
/**
@ -1524,6 +1669,9 @@ lysp_add_internal_ietf_netconf(struct lysp_ctx *pctx, struct lysp_module *mod)
{
struct lysp_ext_instance *extp, *prev_exts = mod->exts;
struct lysp_stmt *stmt;
struct lysp_node_leaf *leaf;
struct lysp_node_container *cont;
struct lysp_type_enum *enm;
struct lysp_import *imp;
uint32_t idx;
@ -1677,6 +1825,107 @@ lysp_add_internal_ietf_netconf(struct lysp_ctx *pctx, struct lysp_module *mod)
pctx->ext_inst.objs[idx] = mod->exts;
}
/*
* 4) rpc-error
*/
LY_LIST_NEW_RET(mod->mod->ctx, &mod->data, cont, next, LY_EMEM);
cont->nodetype = LYS_CONTAINER;
LY_CHECK_RET(lydict_insert(mod->mod->ctx, "rpc-error", 0, &cont->name));
LY_CHECK_RET(lydict_insert(mod->mod->ctx, "presence", 0, &cont->presence));
cont->flags = LYS_INTERNAL;
LY_LIST_NEW_RET(mod->mod->ctx, &cont->child, leaf, next, LY_EMEM);
leaf->nodetype = LYS_LEAF;
LY_CHECK_RET(lydict_insert(mod->mod->ctx, "error-type", 0, &leaf->name));
leaf->flags = LYS_INTERNAL;
LY_CHECK_RET(lydict_insert(mod->mod->ctx, "enumeration", 0, &leaf->type.name));
leaf->type.pmod = mod;
leaf->type.flags = LYS_SET_ENUM;
LY_ARRAY_NEW_RET(mod->mod->ctx, leaf->type.enums, enm, LY_EMEM);
LY_CHECK_RET(lydict_insert(mod->mod->ctx, "transport", 0, &enm->name));
LY_ARRAY_NEW_RET(mod->mod->ctx, leaf->type.enums, enm, LY_EMEM);
LY_CHECK_RET(lydict_insert(mod->mod->ctx, "rpc", 0, &enm->name));
LY_ARRAY_NEW_RET(mod->mod->ctx, leaf->type.enums, enm, LY_EMEM);
LY_CHECK_RET(lydict_insert(mod->mod->ctx, "protocol", 0, &enm->name));
LY_ARRAY_NEW_RET(mod->mod->ctx, leaf->type.enums, enm, LY_EMEM);
LY_CHECK_RET(lydict_insert(mod->mod->ctx, "application", 0, &enm->name));
LY_LIST_NEW_RET(mod->mod->ctx, &cont->child, leaf, next, LY_EMEM);
leaf->nodetype = LYS_LEAF;
LY_CHECK_RET(lydict_insert(mod->mod->ctx, "error-tag", 0, &leaf->name));
leaf->flags = LYS_INTERNAL;
LY_CHECK_RET(lydict_insert(mod->mod->ctx, "enumeration", 0, &leaf->type.name));
leaf->type.pmod = mod;
leaf->type.flags = LYS_SET_ENUM;
LY_ARRAY_NEW_RET(mod->mod->ctx, leaf->type.enums, enm, LY_EMEM);
LY_CHECK_RET(lydict_insert(mod->mod->ctx, "in-use", 0, &enm->name));
LY_ARRAY_NEW_RET(mod->mod->ctx, leaf->type.enums, enm, LY_EMEM);
LY_CHECK_RET(lydict_insert(mod->mod->ctx, "invalid-value", 0, &enm->name));
LY_ARRAY_NEW_RET(mod->mod->ctx, leaf->type.enums, enm, LY_EMEM);
LY_CHECK_RET(lydict_insert(mod->mod->ctx, "too-big", 0, &enm->name));
LY_ARRAY_NEW_RET(mod->mod->ctx, leaf->type.enums, enm, LY_EMEM);
LY_CHECK_RET(lydict_insert(mod->mod->ctx, "missing-attribute", 0, &enm->name));
LY_ARRAY_NEW_RET(mod->mod->ctx, leaf->type.enums, enm, LY_EMEM);
LY_CHECK_RET(lydict_insert(mod->mod->ctx, "bad-attribute", 0, &enm->name));
LY_ARRAY_NEW_RET(mod->mod->ctx, leaf->type.enums, enm, LY_EMEM);
LY_CHECK_RET(lydict_insert(mod->mod->ctx, "unknown-attribute", 0, &enm->name));
LY_ARRAY_NEW_RET(mod->mod->ctx, leaf->type.enums, enm, LY_EMEM);
LY_CHECK_RET(lydict_insert(mod->mod->ctx, "missing-element", 0, &enm->name));
LY_ARRAY_NEW_RET(mod->mod->ctx, leaf->type.enums, enm, LY_EMEM);
LY_CHECK_RET(lydict_insert(mod->mod->ctx, "bad-element", 0, &enm->name));
LY_ARRAY_NEW_RET(mod->mod->ctx, leaf->type.enums, enm, LY_EMEM);
LY_CHECK_RET(lydict_insert(mod->mod->ctx, "unknown-element", 0, &enm->name));
LY_ARRAY_NEW_RET(mod->mod->ctx, leaf->type.enums, enm, LY_EMEM);
LY_CHECK_RET(lydict_insert(mod->mod->ctx, "unknown-namespace", 0, &enm->name));
LY_ARRAY_NEW_RET(mod->mod->ctx, leaf->type.enums, enm, LY_EMEM);
LY_CHECK_RET(lydict_insert(mod->mod->ctx, "access-denied", 0, &enm->name));
LY_ARRAY_NEW_RET(mod->mod->ctx, leaf->type.enums, enm, LY_EMEM);
LY_CHECK_RET(lydict_insert(mod->mod->ctx, "lock-denied", 0, &enm->name));
LY_ARRAY_NEW_RET(mod->mod->ctx, leaf->type.enums, enm, LY_EMEM);
LY_CHECK_RET(lydict_insert(mod->mod->ctx, "resource-denied", 0, &enm->name));
LY_ARRAY_NEW_RET(mod->mod->ctx, leaf->type.enums, enm, LY_EMEM);
LY_CHECK_RET(lydict_insert(mod->mod->ctx, "rollback-failed", 0, &enm->name));
LY_ARRAY_NEW_RET(mod->mod->ctx, leaf->type.enums, enm, LY_EMEM);
LY_CHECK_RET(lydict_insert(mod->mod->ctx, "data-exists", 0, &enm->name));
LY_ARRAY_NEW_RET(mod->mod->ctx, leaf->type.enums, enm, LY_EMEM);
LY_CHECK_RET(lydict_insert(mod->mod->ctx, "data-missing", 0, &enm->name));
LY_ARRAY_NEW_RET(mod->mod->ctx, leaf->type.enums, enm, LY_EMEM);
LY_CHECK_RET(lydict_insert(mod->mod->ctx, "operation-not-supported", 0, &enm->name));
LY_ARRAY_NEW_RET(mod->mod->ctx, leaf->type.enums, enm, LY_EMEM);
LY_CHECK_RET(lydict_insert(mod->mod->ctx, "operation-failed", 0, &enm->name));
LY_ARRAY_NEW_RET(mod->mod->ctx, leaf->type.enums, enm, LY_EMEM);
LY_CHECK_RET(lydict_insert(mod->mod->ctx, "partial-operation", 0, &enm->name));
LY_ARRAY_NEW_RET(mod->mod->ctx, leaf->type.enums, enm, LY_EMEM);
LY_CHECK_RET(lydict_insert(mod->mod->ctx, "malformed-message", 0, &enm->name));
LY_LIST_NEW_RET(mod->mod->ctx, &cont->child, leaf, next, LY_EMEM);
leaf->nodetype = LYS_LEAF;
LY_CHECK_RET(lydict_insert(mod->mod->ctx, "error-severity", 0, &leaf->name));
leaf->flags = LYS_INTERNAL;
LY_CHECK_RET(lydict_insert(mod->mod->ctx, "enumeration", 0, &leaf->type.name));
leaf->type.pmod = mod;
leaf->type.flags = LYS_SET_ENUM;
LY_ARRAY_NEW_RET(mod->mod->ctx, leaf->type.enums, enm, LY_EMEM);
LY_CHECK_RET(lydict_insert(mod->mod->ctx, "error", 0, &enm->name));
LY_ARRAY_NEW_RET(mod->mod->ctx, leaf->type.enums, enm, LY_EMEM);
LY_CHECK_RET(lydict_insert(mod->mod->ctx, "warning", 0, &enm->name));
LY_LIST_NEW_RET(mod->mod->ctx, &cont->child, leaf, next, LY_EMEM);
leaf->nodetype = LYS_LEAF;
LY_CHECK_RET(lydict_insert(mod->mod->ctx, "error-app-tag", 0, &leaf->name));
leaf->flags = LYS_INTERNAL;
LY_CHECK_RET(lydict_insert(mod->mod->ctx, "string", 0, &leaf->type.name));
leaf->type.pmod = mod;
LY_LIST_NEW_RET(mod->mod->ctx, &cont->child, leaf, next, LY_EMEM);
leaf->nodetype = LYS_LEAF;
LY_CHECK_RET(lydict_insert(mod->mod->ctx, "error-path", 0, &leaf->name));
leaf->flags = LYS_INTERNAL;
LY_CHECK_RET(lydict_insert(mod->mod->ctx, "yang_:xpath1.0", 0, &leaf->type.name));
leaf->type.pmod = mod;
/* the rest are opaque nodes, error-message (because of 'xml:lang' attribute) and error-info (because can be any nodes) */
/* create new imports for the used prefixes */
LY_ARRAY_NEW_RET(mod->mod->ctx, mod->imports, imp, LY_EMEM);
LY_CHECK_RET(lydict_insert(mod->mod->ctx, "ietf-yang-metadata", 0, &imp->name));
@ -1810,17 +2059,16 @@ lysp_add_internal_yang(struct lysp_ctx *pctx, struct lysp_module *mod)
}
LY_ERR
lys_parse_in(struct ly_ctx *ctx, struct ly_in *in, LYS_INFORMAT format,
LY_ERR (*custom_check)(const struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_submodule *submod, void *data),
void *check_data, struct ly_set *new_mods, struct lys_module **module)
lys_parse_in(struct ly_ctx *ctx, struct ly_in *in, LYS_INFORMAT format, const struct lysp_load_module_data *mod_data,
struct ly_set *new_mods, struct lys_module **module)
{
LY_ERR rc = LY_SUCCESS, r;
struct lys_module *mod = NULL, *latest, *mod_dup = NULL;
LY_ERR ret;
struct lysp_yang_ctx *yangctx = NULL;
struct lysp_yin_ctx *yinctx = NULL;
struct lysp_ctx *pctx = NULL;
struct lysf_ctx fctx = {.ctx = ctx};
ly_bool module_created = 0;
ly_bool mod_created = 0, mod_exists = 0;
assert(ctx && in && new_mods);
@ -1835,24 +2083,24 @@ lys_parse_in(struct ly_ctx *ctx, struct ly_in *in, LYS_INFORMAT format,
/* parse */
switch (format) {
case LYS_IN_YIN:
ret = yin_parse_module(&yinctx, in, mod);
rc = yin_parse_module(&yinctx, in, mod);
pctx = (struct lysp_ctx *)yinctx;
break;
case LYS_IN_YANG:
ret = yang_parse_module(&yangctx, in, mod);
rc = yang_parse_module(&yangctx, in, mod);
pctx = (struct lysp_ctx *)yangctx;
break;
default:
LOGERR(ctx, LY_EINVAL, "Invalid schema input format.");
ret = LY_EINVAL;
rc = LY_EINVAL;
break;
}
LY_CHECK_GOTO(ret, cleanup);
LY_CHECK_GOTO(rc, cleanup);
/* make sure that the newest revision is at position 0 */
lysp_sort_revisions(mod->parsed->revs);
if (mod->parsed->revs) {
LY_CHECK_GOTO(ret = lydict_insert(ctx, mod->parsed->revs[0].date, 0, &mod->revision), cleanup);
LY_CHECK_GOTO(rc = lydict_insert(ctx, mod->parsed->revs[0].date, 0, &mod->revision), cleanup);
}
/* decide the latest revision */
@ -1876,8 +2124,16 @@ lys_parse_in(struct ly_ctx *ctx, struct ly_in *in, LYS_INFORMAT format,
mod->latest_revision = LYS_MOD_LATEST_REV;
}
if (custom_check) {
LY_CHECK_GOTO(ret = custom_check(ctx, mod->parsed, NULL, check_data), cleanup);
if (mod_data) {
/* check the parsed module it is as expected */
r = lysp_load_module_data_check(ctx, mod->parsed, NULL, mod_data);
if (r == LY_EEXIST) {
mod_exists = 1;
goto cleanup;
} else if (r) {
rc = r;
goto cleanup;
}
}
/* check whether it is not already in the context in the same revision */
@ -1894,7 +2150,7 @@ lys_parse_in(struct ly_ctx *ctx, struct ly_in *in, LYS_INFORMAT format,
if (mod_dup && (mod_dup->revision == mod->revision)) {
LOGERR(ctx, LY_EINVAL, "Two different modules (\"%s\" and \"%s\") have the same namespace \"%s\".",
mod_dup->name, mod->name, mod->ns);
ret = LY_EINVAL;
rc = LY_EINVAL;
goto cleanup;
}
@ -1909,7 +2165,7 @@ lys_parse_in(struct ly_ctx *ctx, struct ly_in *in, LYS_INFORMAT format,
break;
case LY_IN_ERROR:
LOGINT(ctx);
ret = LY_EINT;
rc = LY_EINT;
goto cleanup;
}
lys_parser_fill_filepath(ctx, in, &mod->filepath);
@ -1920,53 +2176,51 @@ lys_parse_in(struct ly_ctx *ctx, struct ly_in *in, LYS_INFORMAT format,
/* add internal data in case specific modules were parsed */
if (!strcmp(mod->name, "ietf-netconf")) {
LY_CHECK_GOTO(ret = lysp_add_internal_ietf_netconf(pctx, mod->parsed), cleanup);
LY_CHECK_GOTO(rc = lysp_add_internal_ietf_netconf(pctx, mod->parsed), cleanup);
} else if (!strcmp(mod->name, "ietf-netconf-with-defaults")) {
LY_CHECK_GOTO(ret = lysp_add_internal_ietf_netconf_with_defaults(pctx, mod->parsed), cleanup);
LY_CHECK_GOTO(rc = lysp_add_internal_ietf_netconf_with_defaults(pctx, mod->parsed), cleanup);
} else if (!strcmp(mod->name, "yang")) {
LY_CHECK_GOTO(ret = lysp_add_internal_yang(pctx, mod->parsed), cleanup);
LY_CHECK_GOTO(rc = lysp_add_internal_yang(pctx, mod->parsed), cleanup);
}
/* add the module into newly created module set, will also be freed from there on any error */
LY_CHECK_GOTO(ret = ly_set_add(new_mods, mod, 1, NULL), cleanup);
module_created = 1;
LY_CHECK_GOTO(rc = ly_set_add(new_mods, mod, 1, NULL), cleanup);
mod_created = 1;
/* add into context */
ret = ly_set_add(&ctx->list, mod, 1, NULL);
LY_CHECK_GOTO(ret, cleanup);
rc = ly_set_add(&ctx->list, mod, 1, NULL);
LY_CHECK_GOTO(rc, cleanup);
ctx->change_count++;
/* resolve includes and all imports */
LY_CHECK_GOTO(ret = lysp_resolve_import_include(pctx, mod->parsed, new_mods), cleanup);
LY_CHECK_GOTO(rc = lysp_resolve_import_include(pctx, mod->parsed, new_mods), cleanup);
/* resolve extension instance plugin records */
LY_CHECK_GOTO(ret = lysp_resolve_ext_instance_records(pctx), cleanup);
LY_CHECK_GOTO(rc = lysp_resolve_ext_instance_records(pctx), cleanup);
/* check name collisions */
LY_CHECK_GOTO(ret = lysp_check_dup_typedefs(pctx, mod->parsed), cleanup);
LY_CHECK_GOTO(ret = lysp_check_dup_groupings(pctx, mod->parsed), cleanup);
LY_CHECK_GOTO(ret = lysp_check_dup_features(pctx, mod->parsed), cleanup);
LY_CHECK_GOTO(ret = lysp_check_dup_identities(pctx, mod->parsed), cleanup);
LY_CHECK_GOTO(rc = lysp_check_dup_typedefs(pctx, mod->parsed), cleanup);
LY_CHECK_GOTO(rc = lysp_check_dup_groupings(pctx, mod->parsed), cleanup);
LY_CHECK_GOTO(rc = lysp_check_dup_features(pctx, mod->parsed), cleanup);
LY_CHECK_GOTO(rc = lysp_check_dup_identities(pctx, mod->parsed), cleanup);
/* compile features */
LY_CHECK_GOTO(ret = lys_compile_feature_iffeatures(mod->parsed), cleanup);
LY_CHECK_GOTO(rc = lys_compile_feature_iffeatures(mod->parsed), cleanup);
/* compile identities */
LY_CHECK_GOTO(ret = lys_compile_identities(mod), cleanup);
LY_CHECK_GOTO(rc = lys_compile_identities(mod), cleanup);
cleanup:
if (ret && (ret != LY_EEXIST)) {
if (mod && mod->name) {
/* there are cases when path is not available for parsing error, so this additional
* message tries to add information about the module where the error occurred */
const struct ly_err_item *e = ly_err_last(ctx);
if (rc && mod && mod->name) {
/* there are cases when path is not available for parsing error, so this additional
* message tries to add information about the module where the error occurred */
const struct ly_err_item *e = ly_err_last(ctx);
if (e && (!e->schema_path || e->line)) {
LOGERR(ctx, LY_EOTHER, "Parsing module \"%s\" failed.", mod->name);
}
if (e && (!e->schema_path || e->line)) {
LOGERR(ctx, LY_EOTHER, "Parsing module \"%s\" failed.", mod->name);
}
}
if (!module_created) {
if (!mod_created) {
fctx.mod = mod;
lys_module_free(&fctx, mod, 0);
lysf_ctx_erase(&fctx);
@ -1980,10 +2234,10 @@ cleanup:
lysp_yin_ctx_free(yinctx);
}
if (!ret && module) {
if (!rc && !mod_exists && module) {
*module = mod;
}
return ret;
return rc;
}
static LYS_INFORMAT
@ -2027,7 +2281,7 @@ lys_parse(struct ly_ctx *ctx, struct ly_in *in, LYS_INFORMAT format, const char
in->func_start = in->current;
/* parse */
ret = lys_parse_in(ctx, in, format, NULL, NULL, &ctx->unres.creating, &mod);
ret = lys_parse_in(ctx, in, format, NULL, &ctx->unres.creating, &mod);
LY_CHECK_GOTO(ret, cleanup);
/* implement */

View file

@ -4,7 +4,7 @@
* @author Michal Vasko <mvasko@cesnet.cz>
* @brief libyang representation of YANG schema trees.
*
* Copyright (c) 2015 - 2022 CESNET, z.s.p.o.
* Copyright (c) 2015 - 2025 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.
@ -1908,13 +1908,39 @@ LIBYANG_API_DECL struct lysc_must *lysc_node_musts(const struct lysc_node *node)
LIBYANG_API_DECL struct lysc_when **lysc_node_when(const struct lysc_node *node);
/**
* @brief Get the target node of a leafref node.
* @brief Get the target node of a leafref node. Function ::lysc_node_lref_targets() should be used instead
* to get all the leafref targets even for a union node.
*
* @param[in] node Leafref node.
* @return Leafref target, NULL on any error.
*/
LIBYANG_API_DECL const struct lysc_node *lysc_node_lref_target(const struct lysc_node *node);
/**
* @brief Get the target node(s) of a leafref node or union node with leafrefs.
*
* @param[in] node Term node to use.
* @param[out] set Set with all the leafref targets, may be empty if the node is a different type or the targets
* are not found.
* @return LY_SUCCESS on success.
* @return LY_ERR value on error.
*/
LIBYANG_API_DECL LY_ERR lysc_node_lref_targets(const struct lysc_node *node, struct ly_set **set);
/**
* @brief Get all the leafref (or union with leafrefs) nodes that target a specific node.
*
* @param[in] ctx Context to use, may not be set if @p node is.
* @param[in] node Leafref target node to use for matching. If not set, all the leafref nodes are just collected.
* @param[in] match_ancestors If set, @p node is considered a match not only when a leafref targets it directly but
* even when an ancestor (parent) node of @p node is a target of the leafref.
* @param[out] set Set of matching leafref nodes.
* @return LY_SUCCESS on success.
* @return LY_ERR value on error.
*/
LIBYANG_API_DECL LY_ERR lysc_node_lref_backlinks(const struct ly_ctx *ctx, const struct lysc_node *node,
ly_bool match_ancestors, struct ly_set **set);
/**
* @brief Callback to be called for every schema node in a DFS traversal.
*

View file

@ -686,64 +686,6 @@ cleanup:
return ret;
}
struct lysp_load_module_check_data {
const char *name;
const char *revision;
const char *path;
const char *submoduleof;
};
static LY_ERR
lysp_load_module_check(const struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_submodule *submod, void *data)
{
struct lysp_load_module_check_data *info = data;
const char *name;
uint8_t latest_revision;
struct lysp_revision *revs;
name = mod ? mod->mod->name : submod->name;
revs = mod ? mod->revs : submod->revs;
latest_revision = mod ? mod->mod->latest_revision : submod->latest_revision;
if (info->name) {
/* check name of the parsed model */
if (strcmp(info->name, name)) {
LOGERR(ctx, LY_EINVAL, "Unexpected module \"%s\" parsed instead of \"%s\").", name, info->name);
return LY_EINVAL;
}
}
if (info->revision) {
/* check revision of the parsed model */
if (!revs || strcmp(info->revision, revs[0].date)) {
LOGERR(ctx, LY_EINVAL, "Module \"%s\" parsed with the wrong revision (\"%s\" instead \"%s\").", name,
revs ? revs[0].date : "none", info->revision);
return LY_EINVAL;
}
} else if (!latest_revision) {
/* do not log, we just need to drop the schema and use the latest revision from the context */
return LY_EEXIST;
}
if (submod) {
assert(info->submoduleof);
/* check that the submodule belongs-to our module */
if (strcmp(info->submoduleof, submod->mod->name)) {
LOGVAL(ctx, LYVE_REFERENCE, "Included \"%s\" submodule from \"%s\" belongs-to a different module \"%s\".",
submod->name, info->submoduleof, submod->mod->name);
return LY_EVALID;
}
/* check circular dependency */
if (submod->parsing) {
LOGVAL(ctx, LYVE_REFERENCE, "A circular dependency (include) for module \"%s\".", submod->name);
return LY_EVALID;
}
}
if (info->path) {
ly_check_module_filename(ctx, name, revs ? revs[0].date : NULL, info->path);
}
return LY_SUCCESS;
}
/**
* @brief Parse a (sub)module from a local file and add into the context.
*
@ -771,7 +713,7 @@ lys_parse_localfile(struct ly_ctx *ctx, const char *name, const char *revision,
LYS_INFORMAT format = 0;
void *mod = NULL;
LY_ERR ret = LY_SUCCESS;
struct lysp_load_module_check_data check_data = {0};
struct lysp_load_module_data mod_data = {0};
LY_CHECK_RET(lys_search_localfile(ly_ctx_get_searchdirs(ctx), !(ctx->flags & LY_CTX_DISABLE_SEARCHDIR_CWD), name,
revision, &filepath, &format));
@ -779,8 +721,9 @@ lys_parse_localfile(struct ly_ctx *ctx, const char *name, const char *revision,
if (required) {
LOGERR(ctx, LY_ENOTFOUND, "Data model \"%s%s%s\" not found in local searchdirs.", name, revision ? "@" : "",
revision ? revision : "");
ret = LY_ENOTFOUND;
}
return LY_ENOTFOUND;
goto cleanup;
}
LOGVRB("Loading schema from \"%s\" file.", filepath);
@ -788,15 +731,14 @@ lys_parse_localfile(struct ly_ctx *ctx, const char *name, const char *revision,
/* get the (sub)module */
LY_CHECK_ERR_GOTO(ret = ly_in_new_filepath(filepath, 0, &in),
LOGERR(ctx, ret, "Unable to create input handler for filepath %s.", filepath), cleanup);
check_data.name = name;
check_data.revision = revision;
check_data.path = filepath;
check_data.submoduleof = main_name;
mod_data.name = name;
mod_data.revision = revision;
mod_data.path = filepath;
mod_data.submoduleof = main_name;
if (main_ctx) {
ret = lys_parse_submodule(ctx, in, format, main_ctx, lysp_load_module_check, &check_data, new_mods,
(struct lysp_submodule **)&mod);
ret = lys_parse_submodule(ctx, in, format, main_ctx, &mod_data, new_mods, (struct lysp_submodule **)&mod);
} else {
ret = lys_parse_in(ctx, in, format, lysp_load_module_check, &check_data, new_mods, (struct lys_module **)&mod);
ret = lys_parse_in(ctx, in, format, &mod_data, new_mods, (struct lys_module **)&mod);
}
ly_in_free(in, 1);
@ -804,8 +746,6 @@ lys_parse_localfile(struct ly_ctx *ctx, const char *name, const char *revision,
*result = mod;
/* success */
cleanup:
free(filepath);
return ret;
@ -827,11 +767,12 @@ static LY_ERR
lys_parse_load_from_clb_or_file(struct ly_ctx *ctx, const char *name, const char *revision,
struct lys_module *mod_latest, struct ly_set *new_mods, struct lys_module **mod)
{
LY_ERR r;
const char *module_data = NULL;
LYS_INFORMAT format = LYS_IN_UNKNOWN;
void (*module_data_free)(void *module_data, void *user_data) = NULL;
struct lysp_load_module_check_data check_data = {0};
struct lysp_load_module_data mod_data = {0};
struct ly_in *in;
*mod = NULL;
@ -848,13 +789,14 @@ search_clb:
if (ctx->imp_clb && (!mod_latest || !(mod_latest->latest_revision & LYS_MOD_LATEST_IMPCLB))) {
if (!ctx->imp_clb(name, revision, NULL, NULL, ctx->imp_clb_data, &format, &module_data, &module_data_free)) {
LY_CHECK_RET(ly_in_new_memory(module_data, &in));
check_data.name = name;
check_data.revision = revision;
lys_parse_in(ctx, in, format, lysp_load_module_check, &check_data, new_mods, mod);
mod_data.name = name;
mod_data.revision = revision;
r = lys_parse_in(ctx, in, format, &mod_data, new_mods, mod);
ly_in_free(in, 0);
if (module_data_free) {
module_data_free((void *)module_data, ctx->imp_clb_data);
}
LY_CHECK_RET(r);
}
}
if (*mod && !revision) {
@ -868,7 +810,7 @@ search_file:
/* check we can use searchdirs and that we should */
if (!(ctx->flags & LY_CTX_DISABLE_SEARCHDIRS) &&
(!mod_latest || !(mod_latest->latest_revision & LYS_MOD_LATEST_SEARCHDIRS))) {
lys_parse_localfile(ctx, name, revision, NULL, NULL, mod_latest ? 0 : 1, new_mods, (void **)mod);
LY_CHECK_RET(lys_parse_localfile(ctx, name, revision, NULL, NULL, mod_latest ? 0 : 1, new_mods, (void **)mod));
}
if (*mod && !revision) {
/* we got the latest revision module in the searchdirs */
@ -878,6 +820,11 @@ search_file:
}
}
if (!*mod && !mod_latest) {
LOGVAL(ctx, LYVE_REFERENCE, "Loading \"%s\" module failed, not found.", name);
return LY_ENOTFOUND;
}
return LY_SUCCESS;
}
@ -972,10 +919,6 @@ lys_parse_load(struct ly_ctx *ctx, const char *name, const char *revision, struc
if (!*mod) {
/* No suitable module in the context, try to load it. */
LY_CHECK_RET(lys_parse_load_from_clb_or_file(ctx, name, revision, mod_latest, new_mods, mod));
if (!*mod && !mod_latest) {
LOGVAL(ctx, LYVE_REFERENCE, "Loading \"%s\" module failed.", name);
return LY_EVALID;
}
/* Update the latest_revision flag - here we have selected the latest available schema,
* consider that even the callback provides correct latest revision.
@ -1171,22 +1114,29 @@ lysp_inject_submodule(struct lysp_ctx *pctx, struct lysp_include *inc)
LY_ERR
lysp_load_submodules(struct lysp_ctx *pctx, struct lysp_module *pmod, struct ly_set *new_mods)
{
LY_ARRAY_COUNT_TYPE u;
LY_ERR r;
struct ly_ctx *ctx = PARSER_CTX(pctx);
struct lysp_submodule *submod;
struct lysp_include *inc;
LY_ARRAY_COUNT_TYPE u;
ly_bool submod_included;
LY_ARRAY_FOR(pmod->includes, u) {
LY_ERR ret = LY_SUCCESS, r;
struct lysp_submodule *submod = NULL;
struct lysp_include *inc = &pmod->includes[u];
inc = &pmod->includes[u];
if (inc->submodule) {
continue;
}
submod = NULL;
submod_included = 1;
if (pmod->is_submod) {
/* try to find the submodule in the main module or its submodules */
ret = lysp_main_pmod_get_submodule(pctx, inc);
LY_CHECK_RET(ret != LY_ENOT, ret);
r = lysp_main_pmod_get_submodule(pctx, inc);
if (r == LY_ENOT) {
submod_included = 0;
} else if (r) {
return r;
}
}
/* try to use currently parsed submodule */
@ -1201,27 +1151,25 @@ search_clb:
LYS_INFORMAT format = LYS_IN_UNKNOWN;
void (*submodule_data_free)(void *module_data, void *user_data) = NULL;
struct lysp_load_module_check_data check_data = {0};
struct lysp_load_module_data mod_data = {0};
struct ly_in *in;
if (ctx->imp_clb(PARSER_CUR_PMOD(pctx)->mod->name, NULL, inc->name,
inc->rev[0] ? inc->rev : NULL, ctx->imp_clb_data,
&format, &submodule_data, &submodule_data_free) == LY_SUCCESS) {
if (ctx->imp_clb(PARSER_CUR_PMOD(pctx)->mod->name, NULL, inc->name, inc->rev[0] ? inc->rev : NULL,
ctx->imp_clb_data, &format, &submodule_data, &submodule_data_free) == LY_SUCCESS) {
LY_CHECK_RET(ly_in_new_memory(submodule_data, &in));
check_data.name = inc->name;
check_data.revision = inc->rev[0] ? inc->rev : NULL;
check_data.submoduleof = PARSER_CUR_PMOD(pctx)->mod->name;
lys_parse_submodule(ctx, in, format, pctx->main_ctx, lysp_load_module_check, &check_data, new_mods,
&submod);
/* update inc pointer - parsing another (YANG 1.0) submodule can cause injecting
* submodule's include into main module, where it is missing */
inc = &pmod->includes[u];
mod_data.name = inc->name;
mod_data.revision = inc->rev[0] ? inc->rev : NULL;
mod_data.submoduleof = PARSER_CUR_PMOD(pctx)->mod->name;
r = lys_parse_submodule(ctx, in, format, pctx->main_ctx, &mod_data, new_mods, &submod);
ly_in_free(in, 0);
if (submodule_data_free) {
submodule_data_free((void *)submodule_data, ctx->imp_clb_data);
}
LY_CHECK_RET(r);
/* update inc pointer - parsing another (YANG 1.0) submodule can cause injecting
* submodule's include into main module, where it is missing */
inc = &pmod->includes[u];
}
}
if (!submod && !(ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
@ -1250,7 +1198,7 @@ search_file:
}
inc->submodule = submod;
if (ret == LY_ENOT) {
if (!submod_included) {
/* the submodule include is not present in YANG 1.0 main module - add it there */
LY_CHECK_RET(lysp_inject_submodule(pctx, &pmod->includes[u]));
}
@ -1380,6 +1328,10 @@ lys_datatype2str(LY_DATA_TYPE basetype)
LIBYANG_API_DEF const struct lysp_tpdf *
lysp_node_typedefs(const struct lysp_node *node)
{
if (!node) {
return NULL;
}
switch (node->nodetype) {
case LYS_CONTAINER:
return ((struct lysp_node_container *)node)->typedefs;
@ -1403,6 +1355,10 @@ lysp_node_typedefs(const struct lysp_node *node)
LIBYANG_API_DEF const struct lysp_node_grp *
lysp_node_groupings(const struct lysp_node *node)
{
if (!node) {
return NULL;
}
switch (node->nodetype) {
case LYS_CONTAINER:
return ((struct lysp_node_container *)node)->groupings;
@ -1447,6 +1403,10 @@ lysp_node_actions(const struct lysp_node *node)
{
struct lysp_node_action **actions;
if (!node) {
return NULL;
}
actions = lysp_node_actions_p((struct lysp_node *)node);
if (actions) {
return *actions;
@ -1478,6 +1438,10 @@ lysp_node_notifs(const struct lysp_node *node)
{
struct lysp_node_notif **notifs;
if (!node) {
return NULL;
}
notifs = lysp_node_notifs_p((struct lysp_node *)node);
if (notifs) {
return *notifs;
@ -1621,6 +1585,7 @@ struct lysc_node_action **
lysc_node_actions_p(struct lysc_node *node)
{
assert(node);
switch (node->nodetype) {
case LYS_CONTAINER:
return &((struct lysc_node_container *)node)->actions;
@ -1636,6 +1601,10 @@ lysc_node_actions(const struct lysc_node *node)
{
struct lysc_node_action **actions;
if (!node) {
return NULL;
}
actions = lysc_node_actions_p((struct lysc_node *)node);
if (actions) {
return *actions;
@ -1648,6 +1617,7 @@ struct lysc_node_notif **
lysc_node_notifs_p(struct lysc_node *node)
{
assert(node);
switch (node->nodetype) {
case LYS_CONTAINER:
return &((struct lysc_node_container *)node)->notifs;
@ -1663,6 +1633,10 @@ lysc_node_notifs(const struct lysc_node *node)
{
struct lysc_node_notif **notifs;
if (!node) {
return NULL;
}
notifs = lysc_node_notifs_p((struct lysc_node *)node);
if (notifs) {
return *notifs;
@ -1750,6 +1724,10 @@ lysc_node_musts(const struct lysc_node *node)
{
struct lysc_must **must_p;
if (!node) {
return NULL;
}
must_p = lysc_node_musts_p(node);
if (must_p) {
return *must_p;
@ -1796,6 +1774,10 @@ lysc_node_when(const struct lysc_node *node)
{
struct lysc_when ***when_p;
if (!node) {
return NULL;
}
when_p = lysc_node_when_p(node);
if (when_p) {
return *when_p;
@ -1804,21 +1786,24 @@ lysc_node_when(const struct lysc_node *node)
}
}
LIBYANG_API_DEF const struct lysc_node *
lysc_node_lref_target(const struct lysc_node *node)
/**
* @brief Get the target node of a leafref.
*
* @param[in] node Context node for the leafref.
* @param[in] type Leafref type to resolve.
* @return Target schema node;
* @return NULL if the tearget is not found.
*/
static const struct lysc_node *
lysc_type_lref_target(const struct lysc_node *node, const struct lysc_type *type)
{
struct lysc_type_leafref *lref;
struct ly_path *p;
const struct lysc_node *target;
if (!node || !(node->nodetype & LYD_NODE_TERM)) {
return NULL;
}
assert(type->basetype == LY_TYPE_LEAFREF);
lref = (struct lysc_type_leafref *)((struct lysc_node_leaf *)node)->type;
if (lref->basetype != LY_TYPE_LEAFREF) {
return NULL;
}
lref = (struct lysc_type_leafref *)type;
/* compile the path */
if (ly_path_compile_leafref(node->module->ctx, node, NULL, lref->path,
@ -1834,6 +1819,164 @@ lysc_node_lref_target(const struct lysc_node *node)
return target;
}
LIBYANG_API_DEF const struct lysc_node *
lysc_node_lref_target(const struct lysc_node *node)
{
if (!node || !(node->nodetype & LYD_NODE_TERM) || (((struct lysc_node_leaf *)node)->type->basetype != LY_TYPE_LEAFREF)) {
return NULL;
}
return lysc_type_lref_target(node, ((struct lysc_node_leaf *)node)->type);
}
LIBYANG_API_DEF LY_ERR
lysc_node_lref_targets(const struct lysc_node *node, struct ly_set **set)
{
LY_ERR rc = LY_SUCCESS;
struct lysc_type *type;
struct lysc_type_union *type_un;
const struct lysc_node *target;
LY_ARRAY_COUNT_TYPE u;
LY_CHECK_ARG_RET(NULL, node, (node->nodetype & LYD_NODE_TERM), LY_EINVAL);
/* allocate return set */
LY_CHECK_RET(ly_set_new(set));
type = ((struct lysc_node_leaf *)node)->type;
if (type->basetype == LY_TYPE_UNION) {
/* union with possible leafrefs */
type_un = (struct lysc_type_union *)type;
LY_ARRAY_FOR(type_un->types, u) {
if (type_un->types[u]->basetype != LY_TYPE_LEAFREF) {
continue;
}
target = lysc_type_lref_target(node, type_un->types[u]);
if (target) {
LY_CHECK_GOTO(rc = ly_set_add(*set, target, 1, NULL), cleanup);
}
}
} else if (type->basetype == LY_TYPE_LEAFREF) {
/* leafref */
target = lysc_type_lref_target(node, type);
if (target) {
LY_CHECK_GOTO(rc = ly_set_add(*set, target, 1, NULL), cleanup);
}
}
cleanup:
if (rc) {
ly_set_free(*set, NULL);
*set = NULL;
}
return rc;
}
struct lysc_node_lref_backlings_arg {
const struct lysc_node *node;
ly_bool match_ancestors;
struct ly_set *set;
};
static LY_ERR
lysc_node_lref_backlinks_clb(struct lysc_node *node, void *data, ly_bool *dfs_continue)
{
LY_ERR rc = LY_SUCCESS;
struct lysc_node_lref_backlings_arg *arg = data;
struct ly_set *set = NULL;
const struct lysc_node *par;
uint32_t i;
(void)dfs_continue;
if (!(node->nodetype & LYD_NODE_TERM)) {
/* skip */
goto cleanup;
}
/* get all the leafref targets */
LY_CHECK_GOTO(rc = lysc_node_lref_targets(node, &set), cleanup);
/* ignore node if has no leafref targets */
if (!set->count) {
goto cleanup;
}
/* if just collecting leafrefs, we are done */
if (!arg->node) {
rc = ly_set_add(arg->set, node, 1, NULL);
goto cleanup;
}
/* check that the node (or the ancestor of) is the target of this leafref */
for (i = 0; i < set->count; ++i) {
for (par = set->snodes[i]; par; par = par->parent) {
if (par == arg->node) {
/* match */
break;
}
if (!arg->match_ancestors) {
/* not a match */
par = NULL;
break;
}
}
if (par) {
/* add into the set, matches */
LY_CHECK_GOTO(rc = ly_set_add(arg->set, node, 1, NULL), cleanup);
break;
}
}
cleanup:
ly_set_free(set, NULL);
return rc;
}
LIBYANG_API_DEF LY_ERR
lysc_node_lref_backlinks(const struct ly_ctx *ctx, const struct lysc_node *node, ly_bool match_ancestors,
struct ly_set **set)
{
LY_ERR rc = LY_SUCCESS;
struct lysc_node_lref_backlings_arg arg = {0};
uint32_t idx = 0;
const struct lys_module *mod;
LY_CHECK_ARG_RET(NULL, ctx || node, set, LY_EINVAL);
if (!ctx) {
ctx = node->module->ctx;
}
/* allocate return set */
LY_CHECK_RET(ly_set_new(set));
/* prepare the arg */
arg.node = node;
arg.match_ancestors = match_ancestors;
arg.set = *set;
/* iterate across all loaded modules */
while ((mod = ly_ctx_get_module_iter(ctx, &idx))) {
if (!mod->compiled) {
continue;
}
LY_CHECK_GOTO(rc = lysc_module_dfs_full(mod, lysc_node_lref_backlinks_clb, &arg), cleanup);
}
cleanup:
if (rc) {
ly_set_free(*set, NULL);
*set = NULL;
}
return rc;
}
enum ly_stmt
lysp_match_kw(struct ly_in *in, uint64_t *indent)
{
@ -2619,41 +2762,3 @@ lys_stmt_flags(enum ly_stmt stmt)
return 0;
}
void
ly_check_module_filename(const struct ly_ctx *ctx, const char *name, const char *revision, const char *filename)
{
const char *basename, *rev, *dot;
size_t len;
/* check that name and revision match filename */
basename = strrchr(filename, '/');
#ifdef _WIN32
const char *backslash = strrchr(filename, '\\');
if (!basename || (basename && backslash && (backslash > basename))) {
basename = backslash;
}
#endif
if (!basename) {
basename = filename;
} else {
basename++; /* leading slash */
}
rev = strchr(basename, '@');
dot = strrchr(basename, '.');
/* name */
len = strlen(name);
if (strncmp(basename, name, len) ||
((rev && (rev != &basename[len])) || (!rev && (dot != &basename[len])))) {
LOGWRN(ctx, "File name \"%s\" does not match module name \"%s\".", basename, name);
}
if (rev) {
len = dot - ++rev;
if (!revision || (len != LY_REV_SIZE - 1) || strncmp(revision, rev, len)) {
LOGWRN(ctx, "File name \"%s\" does not match module revision \"%s\".", basename,
revision ? revision : "none");
}
}
}

View file

@ -825,14 +825,7 @@ lysc_ident_free(struct lysf_ctx *ctx, struct lysc_ident *ident)
FREE_ARRAY(ctx, ident->exts, lysc_ext_instance_free);
}
/**
* @brief Free the compiled range structure.
*
* @param[in] ctx Free context.
* @param[in,out] range Compiled range structure to be freed.
* Since the structure is typically part of the sized array, the structure itself is not freed.
*/
static void
void
lysc_range_free(struct lysf_ctx *ctx, struct lysc_range *range)
{
LY_ARRAY_FREE(range->parts);

View file

@ -134,6 +134,15 @@ void lysc_ext_instance_free(struct lysf_ctx *ctx, struct lysc_ext_instance *ext)
*/
void lysc_iffeature_free(struct lysf_ctx *ctx, struct lysc_iffeature *iff);
/**
* @brief Free the compiled range structure.
*
* @param[in] ctx Free context.
* @param[in,out] range Compiled range structure to be freed.
* Since the structure is typically part of the sized array, the structure itself is not freed.
*/
void lysc_range_free(struct lysf_ctx *ctx, struct lysc_range *range);
/**
* @brief Free a compiled pattern.
*

View file

@ -130,11 +130,12 @@ enum yang_arg {
struct lysp_ctx {
LYS_INFORMAT format; /**< parser format */
struct ly_set tpdfs_nodes; /**< Set of nodes that contain typedef(s). Invalid in case of
submodule, use ::lysp_ctx.main_ctx instead. */
struct ly_set grps_nodes; /**< Set of nodes that contain grouping(s). Invalid in case of
submodule, use ::lysp_ctx.main_ctx instead. */
struct ly_set ext_inst; /**< parsed extension instances to finish parsing */
struct ly_set tpdfs_nodes; /**< Set of nodes that contain typedef(s). Used only temporarily in case of
submodule, ::lysp_ctx.main_ctx used instead. */
struct ly_set grps_nodes; /**< Set of nodes that contain grouping(s). Used only temporarily in case of
submodule, ::lysp_ctx.main_ctx used instead. */
struct ly_set ext_inst; /**< Set of parsed extension instances to finish parsing. Used only temporarily
in case of submodule, ::lysp_ctx.main_ctx used instead. */
struct ly_set *parsed_mods; /**< (sub)modules being parsed, the last one is the current */
struct lysp_ctx *main_ctx; /**< This pointer must not be NULL. If this context deals with the submodule,
@ -528,8 +529,12 @@ void lys_unres_glob_revert(struct ly_ctx *ctx, struct lys_glob_unres *unres);
*/
void lys_unres_glob_erase(struct lys_glob_unres *unres);
typedef LY_ERR (*lys_custom_check)(const struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_submodule *submod,
void *check_data);
struct lysp_load_module_data {
const char *name; /**< expected module name */
const char *revision; /**< expected module revision */
const char *path; /**< module file name to check */
const char *submoduleof; /**< expected submodule main module */
};
/**
* @brief Parse a module and add it into the context.
@ -537,15 +542,14 @@ typedef LY_ERR (*lys_custom_check)(const struct ly_ctx *ctx, struct lysp_module
* @param[in] ctx libyang context where to process the data model.
* @param[in] in Input structure.
* @param[in] format Format of the input data (YANG or YIN).
* @param[in] custom_check Callback to check the parsed schema before it is accepted.
* @param[in] check_data Caller's data to pass to the custom_check callback.
* @param[in] mod_data Optional expected module data to check.
* @param[in,out] new_mods Set of all the new mods added to the context. Includes this module and all of its imports.
* @param[out] module Created module.
* @return LY_SUCCESS on success.
* @return LY_ERR on error, @p new_mods may be modified.
*/
LY_ERR lys_parse_in(struct ly_ctx *ctx, struct ly_in *in, LYS_INFORMAT format, lys_custom_check custom_check,
void *check_data, struct ly_set *new_mods, struct lys_module **module);
LY_ERR lys_parse_in(struct ly_ctx *ctx, struct ly_in *in, LYS_INFORMAT format,
const struct lysp_load_module_data *mod_data, struct ly_set *new_mods, struct lys_module **module);
/**
* @brief Parse submodule.
@ -556,14 +560,13 @@ LY_ERR lys_parse_in(struct ly_ctx *ctx, struct ly_in *in, LYS_INFORMAT format, l
* @param[in] in Input structure.
* @param[in] format Format of the input data (YANG or YIN).
* @param[in] main_ctx Parser context of the main module.
* @param[in] custom_check Callback to check the parsed schema before it is accepted.
* @param[in] check_data Caller's data to pass to the custom_check callback.
* @param[in] mod_data Optional expected module data to check.
* @param[in] new_mods Set of all the new mods added to the context. Includes this module and all of its imports.
* @param[out] submodule Parsed submodule.
* @return LY_ERR value.
*/
LY_ERR lys_parse_submodule(struct ly_ctx *ctx, struct ly_in *in, LYS_INFORMAT format, struct lysp_ctx *main_ctx,
lys_custom_check custom_check, void *check_data, struct ly_set *new_mods, struct lysp_submodule **submodule);
const struct lysp_load_module_data *mod_data, struct ly_set *new_mods, struct lysp_submodule **submodule);
/**
* @brief Fill filepath value if available in input handler @p in
@ -732,14 +735,4 @@ uint8_t lys_stmt_flags(enum ly_stmt stmt);
*/
LY_ERR lyplg_ext_get_storage_p(const struct lysc_ext_instance *ext, int stmt, void ***storage_pp);
/**
* @brief Warning if the filename does not match the expected module name and version
*
* @param[in] ctx Context for logging
* @param[in] name Expected module name
* @param[in] revision Expected module revision, or NULL if not to be checked
* @param[in] filename File path to be checked
*/
void ly_check_module_filename(const struct ly_ctx *ctx, const char *name, const char *revision, const char *filename);
#endif /* LY_TREE_SCHEMA_INTERNAL_H_ */

View file

@ -216,7 +216,7 @@ lyd_val_diff_add(const struct lyd_node *node, enum lyd_diff_op op, struct lyd_no
}
/* create new diff tree */
LY_CHECK_GOTO(ret = lyd_diff_add(node, op, NULL, NULL, key, value, position, NULL, NULL, &new_diff), cleanup);
LY_CHECK_GOTO(ret = lyd_diff_add(node, op, NULL, NULL, key, value, position, NULL, NULL, &new_diff, NULL), cleanup);
/* merge into existing diff */
ret = lyd_diff_merge_all(diff, new_diff, 0);
@ -336,7 +336,8 @@ lyd_validate_autodel_node_del(struct lyd_node **first, struct lyd_node *del, con
/* remove nested from node_when set */
LYD_TREE_DFS_BEGIN(del, iter) {
if ((del != iter) && ly_set_contains(node_when, iter, &idx)) {
ly_set_rm_index(node_when, idx, NULL);
assert(0 && "Please contact libyang support with the use-case that triggered this assert.");
// ly_set_rm_index(node_when, idx, NULL);
}
LYD_TREE_DFS_END(del, iter);
}
@ -345,7 +346,9 @@ lyd_validate_autodel_node_del(struct lyd_node **first, struct lyd_node *del, con
if (node_types && node_types->count) {
/* remove from node_types set */
LYD_TREE_DFS_BEGIN(del, iter) {
if (ly_set_contains(node_types, iter, &idx)) {
if ((iter->schema->nodetype & LYD_NODE_TERM) &&
((struct lysc_node_leaf *)iter->schema)->type->plugin->validate &&
ly_set_contains(node_types, iter, &idx)) {
ly_set_rm_index(node_types, idx, NULL);
}
LYD_TREE_DFS_END(del, iter);
@ -490,8 +493,14 @@ lyd_validate_unres(struct lyd_node **tree, const struct lys_module *mod, enum ly
/* there must have been some when conditions resolved */
} while (prev_count > node_when->count);
/* there could have been no cyclic when dependencies, checked during compilation */
assert(!node_when->count || ((rc == LY_EVALID) && (val_opts & LYD_VALIDATE_MULTI_ERROR)));
if (node_when->count) {
/* there could have been no cyclic when dependencies, checked during compilation */
assert((rc == LY_EVALID) && (val_opts & LYD_VALIDATE_MULTI_ERROR));
/* when condition was validated and it is not satisfied, error printed, if kept in the set the following
* unres (for the next module) can fail this assert */
ly_set_erase(node_when, NULL);
}
}
if (node_types && node_types->count) {
@ -1140,13 +1149,17 @@ static LY_ERR
lyd_validate_minmax(const struct lyd_node *first, const struct lyd_node *parent, const struct lysc_node *snode,
uint32_t min, uint32_t max, uint32_t val_opts)
{
LY_ERR rc = LY_SUCCESS;
uint32_t count = 0;
struct lyd_node *iter;
struct lyd_node *iter, *last_iter = NULL;
const struct lysc_when *disabled;
char *log_path;
int r;
assert(min || max);
LYD_LIST_FOR_INST(first, snode, iter) {
last_iter = iter;
++count;
if (min && (count == min)) {
@ -1182,32 +1195,52 @@ lyd_validate_minmax(const struct lyd_node *first, const struct lyd_node *parent,
max = 0;
}
if (min) {
if (val_opts & LYD_VALIDATE_OPERATIONAL) {
/* only a warning */
LOG_LOCSET(snode, NULL);
LOGWRN(snode->module->ctx, "Too few \"%s\" instances.", snode->name);
LOG_LOCBACK(1, 0);
if (min || max) {
/* set log path */
if (last_iter) {
/* standard data path */
LOG_LOCSET(NULL, last_iter);
} else {
LOG_LOCSET(snode, NULL);
LOGVAL_APPTAG(snode->module->ctx, "too-few-elements", LY_VCODE_NOMIN, snode->name);
LOG_LOCBACK(1, 0);
return LY_EVALID;
/* data path with last schema node name or only the schema node if !parent */
if (lyd_node_module(parent) != snode->module) {
r = asprintf(&log_path, "/%s:%s", snode->module->name, snode->name);
} else {
r = asprintf(&log_path, "/%s", snode->name);
}
if (r == -1) {
LOGMEM_RET(snode->module->ctx);
}
ly_log_location(NULL, parent, log_path, NULL);
free(log_path);
}
} else if (max) {
if (val_opts & LYD_VALIDATE_OPERATIONAL) {
/* only a warning */
LOG_LOCSET(NULL, iter);
LOGWRN(snode->module->ctx, "Too many \"%s\" instances.", snode->name);
if (min) {
if (val_opts & LYD_VALIDATE_OPERATIONAL) {
/* only a warning */
LOGWRN(snode->module->ctx, "Too few \"%s\" instances.", snode->name);
} else {
LOGVAL_APPTAG(snode->module->ctx, "too-few-elements", LY_VCODE_NOMIN, snode->name);
rc = LY_EVALID;
}
} else if (max) {
if (val_opts & LYD_VALIDATE_OPERATIONAL) {
/* only a warning */
LOGWRN(snode->module->ctx, "Too many \"%s\" instances.", snode->name);
} else {
LOGVAL_APPTAG(snode->module->ctx, "too-many-elements", LY_VCODE_NOMAX, snode->name);
rc = LY_EVALID;
}
}
/* revert log path */
if (last_iter) {
LOG_LOCBACK(0, 1);
} else {
LOG_LOCSET(NULL, iter);
LOGVAL_APPTAG(snode->module->ctx, "too-many-elements", LY_VCODE_NOMAX, snode->name);
LOG_LOCBACK(0, 1);
return LY_EVALID;
ly_log_location_revert(0, parent ? 1 : 0, 1, 0);
}
}
return LY_SUCCESS;
return rc;
}
/**
@ -1588,7 +1621,8 @@ lyd_validate_obsolete(const struct lyd_node *node)
snode = node->schema;
do {
if (snode->flags & LYS_STATUS_OBSLT) {
if (snode->flags & LYS_STATUS_OBSLT &&
(!(snode->nodetype & LYD_NODE_INNER) || lyd_child(node))) {
LOG_LOCSET(NULL, node);
LOGWRN(snode->module->ctx, "Obsolete schema node \"%s\" instantiated in data.", snode->name);
LOG_LOCBACK(0, 1);
@ -2126,7 +2160,7 @@ LIBYANG_API_DEF LY_ERR
lyd_validate_all(struct lyd_node **tree, const struct ly_ctx *ctx, uint32_t val_opts, struct lyd_node **diff)
{
LY_CHECK_ARG_RET(NULL, tree, *tree || ctx, LY_EINVAL);
LY_CHECK_CTX_EQUAL_RET(*tree ? LYD_CTX(*tree) : NULL, ctx, LY_EINVAL);
LY_CHECK_CTX_EQUAL_RET(__func__, *tree ? LYD_CTX(*tree) : NULL, ctx, LY_EINVAL);
if (!ctx) {
ctx = LYD_CTX(*tree);
}
@ -2141,7 +2175,7 @@ LIBYANG_API_DEF LY_ERR
lyd_validate_module(struct lyd_node **tree, const struct lys_module *module, uint32_t val_opts, struct lyd_node **diff)
{
LY_CHECK_ARG_RET(NULL, tree, module, !(val_opts & LYD_VALIDATE_PRESENT), LY_EINVAL);
LY_CHECK_CTX_EQUAL_RET(*tree ? LYD_CTX(*tree) : NULL, module->ctx, LY_EINVAL);
LY_CHECK_CTX_EQUAL_RET(__func__, *tree ? LYD_CTX(*tree) : NULL, module->ctx, LY_EINVAL);
if (diff) {
*diff = NULL;
}
@ -2159,7 +2193,7 @@ lyd_validate_module_final(struct lyd_node *tree, const struct lys_module *module
struct ly_ht *getnext_ht = NULL;
LY_CHECK_ARG_RET(NULL, module, !(val_opts & (LYD_VALIDATE_PRESENT | LYD_VALIDATE_NOT_FINAL)), LY_EINVAL);
LY_CHECK_CTX_EQUAL_RET(tree ? LYD_CTX(tree) : NULL, module->ctx, LY_EINVAL);
LY_CHECK_CTX_EQUAL_RET(__func__, tree ? LYD_CTX(tree) : NULL, module->ctx, LY_EINVAL);
/* module is unchanged but we need to get the first module data node */
mod = lyd_mod_next_module(tree, module, module->ctx, &i, &first);

View file

@ -3690,6 +3690,7 @@ xpath_bit_is_set(struct lyxp_set **args, uint32_t UNUSED(arg_count), struct lyxp
struct lyd_node_term *leaf;
struct lysc_node_leaf *sleaf;
struct lyd_value_bits *bits;
struct lyd_value *val;
LY_ERR rc = LY_SUCCESS;
LY_ARRAY_COUNT_TYPE u;
@ -3725,10 +3726,14 @@ xpath_bit_is_set(struct lyxp_set **args, uint32_t UNUSED(arg_count), struct lyxp
LY_CHECK_RET(rc);
set_fill_boolean(set, 0);
if (args[0]->used) {
if (args[0]->used && (args[0]->val.nodes[0].node->schema->nodetype & LYD_NODE_TERM)) {
leaf = (struct lyd_node_term *)args[0]->val.nodes[0].node;
if ((leaf->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) && (leaf->value.realtype->basetype == LY_TYPE_BITS)) {
LYD_VALUE_GET(&leaf->value, bits);
val = &leaf->value;
if (val->realtype->basetype == LY_TYPE_UNION) {
val = &val->subvalue->value;
}
if (val->realtype->basetype == LY_TYPE_BITS) {
LYD_VALUE_GET(val, bits);
LY_ARRAY_FOR(bits->items, u) {
if (!strcmp(bits->items[u]->name, args[1]->val.str)) {
set_fill_boolean(set, 1);
@ -4200,17 +4205,21 @@ xpath_derived_(struct lyxp_set **args, struct lyxp_set *set, uint32_t options, l
leaf = (struct lyd_node_term *)args[0]->val.nodes[i].node;
sleaf = (struct lysc_node_leaf *)leaf->schema;
val = &leaf->value;
if (!sleaf || !(sleaf->nodetype & LYD_NODE_TERM) || (leaf->value.realtype->basetype != LY_TYPE_IDENT)) {
if (!sleaf || !(sleaf->nodetype & LYD_NODE_TERM)) {
/* uninteresting */
continue;
}
} else {
meta = args[0]->val.meta[i].meta;
val = &meta->value;
if (val->realtype->basetype != LY_TYPE_IDENT) {
/* uninteresting */
continue;
}
}
if (val->realtype->basetype == LY_TYPE_UNION) {
val = &val->subvalue->value;
}
if (val->realtype->basetype != LY_TYPE_IDENT) {
/* uninteresting */
continue;
}
/* check the identity itself */
@ -4972,6 +4981,7 @@ xpath_re_match(struct lyxp_set **args, uint32_t UNUSED(arg_count), struct lyxp_s
LOG_LOCBACK(0, 1);
}
if (rc != LY_SUCCESS) {
free(*pattern);
LY_ARRAY_FREE(patterns);
return rc;
}
@ -6801,7 +6811,8 @@ moveto_scnode(struct lyxp_set *set, const struct lys_module *moveto_mod, const c
}
}
if (moveto_mod && ncname && ((axis == LYXP_AXIS_DESCENDANT) || (axis == LYXP_AXIS_CHILD)) &&
/* only consider extension nodes after no local ones were found */
if ((orig_used == set->used) && moveto_mod && ncname && ((axis == LYXP_AXIS_DESCENDANT) || (axis == LYXP_AXIS_CHILD)) &&
(set->val.scnodes[i].type == LYXP_NODE_ELEM) && !ly_nested_ext_schema(NULL, set->val.scnodes[i].scnode,
moveto_mod->name, strlen(moveto_mod->name), LY_VALUE_JSON, NULL, ncname, strlen(ncname), &iter, NULL)) {
/* there is a matching node from an extension, use it */
@ -8236,14 +8247,16 @@ moveto:
}
LY_CHECK_GOTO(rc, cleanup);
i = set->used;
do {
--i;
if (set->val.scnodes[i].in_ctx > LYXP_SET_SCNODE_ATOM_NODE) {
found = 1;
break;
}
} while (i);
if (set->used) {
i = set->used;
do {
--i;
if (set->val.scnodes[i].in_ctx > LYXP_SET_SCNODE_ATOM_NODE) {
found = 1;
break;
}
} while (i);
}
if (!found) {
/* generate message */
eval_name_test_scnode_no_match_msg(set, scparent, ncname, ncname_len, exp->expr, options);

View file

@ -30,6 +30,9 @@ function(ly_add_utest)
endif()
endif()
if (XXHASH_FOUND)
target_link_libraries(${TEST_NAME} ${XXHASH_LIBRARY})
endif()
add_test(NAME ${TEST_NAME} COMMAND ${TEST_NAME})
set_property(TEST ${TEST_NAME} APPEND PROPERTY ENVIRONMENT "MALLOC_CHECK_=3")

View file

@ -6,7 +6,11 @@ set(format_sources
add_executable(ly_perf ${CMAKE_CURRENT_SOURCE_DIR}/perf.c $<TARGET_OBJECTS:yangobj>)
set_target_properties(ly_perf PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/tests")
target_link_libraries(ly_perf ${CMAKE_THREAD_LIBS_INIT} ${PCRE2_LIBRARIES} ${CMAKE_DL_LIBS})
if (NOT WIN32)
if(XXHASH_FOUND)
target_link_libraries(ly_perf ${XXHASH_LIBRARY})
endif()
if(NOT WIN32)
target_link_libraries(ly_perf m)
endif()

View file

@ -1,7 +1,7 @@
add_test(NAME headers
COMMAND ${CMAKE_SOURCE_DIR}/compat/check_includes.sh ${CMAKE_SOURCE_DIR}/src/ ${CMAKE_SOURCE_DIR}/tools/lint/ ${CMAKE_SOURCE_DIR}/tools/re/)
if (${SOURCE_FORMAT_ENABLED})
if(${SOURCE_FORMAT_ENABLED})
add_test(NAME format WORKING_DIRECTORY ${CMAKE_BINARY_DIR} COMMAND cmake --build ${CMAKE_BINARY_DIR} --target format-check)
endif()
@ -9,4 +9,8 @@ endif()
add_executable(cpp_compat cpp_compat.c $<TARGET_OBJECTS:yangobj>)
target_include_directories(cpp_compat BEFORE PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(cpp_compat ${CMAKE_THREAD_LIBS_INIT} ${PCRE2_LIBRARIES} ${CMAKE_DL_LIBS} m)
if(XXHASH_FOUND)
target_link_libraries(cpp_compat ${XXHASH_LIBRARY})
endif()
target_compile_options(cpp_compat PUBLIC "-Werror=c++-compat")

View file

@ -276,10 +276,32 @@ test_options(void **state)
}
static LY_ERR
test_imp_clb(const char *UNUSED(mod_name), const char *UNUSED(mod_rev), const char *UNUSED(submod_name),
const char *UNUSED(sub_rev), void *user_data, LYS_INFORMAT *format,
const char **module_data, void (**free_module_data)(void *model_data, void *user_data))
test_imp_clb(const char *mod_name, const char *UNUSED(mod_rev), const char *submod_name, const char *UNUSED(sub_rev),
void *user_data, LYS_INFORMAT *format, const char **module_data, void (**free_module_data)(void *model_data,
void *user_data))
{
const char *name;
if (submod_name) {
if (strncmp(user_data, "submodule", 9)) {
return LY_ENOTFOUND;
}
name = ((char *)user_data) + 10;
if (strncmp(name, submod_name, strlen(submod_name)) || (name[strlen(submod_name)] != ' ')) {
return LY_ENOTFOUND;
}
} else {
if (strncmp(user_data, "module", 6)) {
return LY_ENOTFOUND;
}
name = ((char *)user_data) + 7;
if (strncmp(name, mod_name, strlen(mod_name)) || (name[strlen(mod_name)] != ' ')) {
return LY_ENOTFOUND;
}
}
*module_data = user_data;
*format = LYS_IN_YANG;
*free_module_data = NULL;
@ -305,7 +327,7 @@ test_models(void **state)
assert_int_equal(UTEST_LYCTX->change_count, ly_ctx_get_change_count(UTEST_LYCTX));
assert_int_equal(LY_SUCCESS, ly_in_new_memory("module x {namespace urn:x;prefix x;}", &in));
assert_int_equal(LY_EINVAL, lys_parse_in(UTEST_LYCTX, in, 4, NULL, NULL, &unres.creating, &mod1));
assert_int_equal(LY_EINVAL, lys_parse_in(UTEST_LYCTX, in, 4, NULL, &unres.creating, &mod1));
lys_unres_glob_erase(&unres);
ly_in_free(in, 0);
CHECK_LOG_CTX("Invalid schema input format.", NULL, 0);
@ -324,17 +346,17 @@ test_models(void **state)
/* name collision of module and submodule */
ly_ctx_set_module_imp_clb(UTEST_LYCTX, test_imp_clb, "submodule y {belongs-to a {prefix a;} revision 2018-10-30;}");
assert_int_equal(LY_SUCCESS, ly_in_new_memory("module y {namespace urn:y;prefix y;include y;}", &in));
assert_int_equal(LY_EVALID, lys_parse_in(UTEST_LYCTX, in, LYS_IN_YANG, NULL, NULL, &unres.creating, &mod1));
assert_int_equal(LY_EVALID, lys_parse_in(UTEST_LYCTX, in, LYS_IN_YANG, NULL, &unres.creating, &mod1));
lys_unres_glob_erase(&unres);
ly_in_free(in, 0);
CHECK_LOG_CTX("Parsing module \"y\" failed.", NULL, 0);
CHECK_LOG_CTX("Name collision between module and submodule of name \"y\".", NULL, 1);
assert_int_equal(LY_SUCCESS, ly_in_new_memory("module a {namespace urn:a;prefix a;include y;revision 2018-10-30; }", &in));
assert_int_equal(LY_SUCCESS, lys_parse_in(UTEST_LYCTX, in, LYS_IN_YANG, NULL, NULL, &unres.creating, &mod1));
assert_int_equal(LY_SUCCESS, lys_parse_in(UTEST_LYCTX, in, LYS_IN_YANG, NULL, &unres.creating, &mod1));
ly_in_free(in, 0);
assert_int_equal(LY_SUCCESS, ly_in_new_memory("module y {namespace urn:y;prefix y;}", &in));
assert_int_equal(LY_EVALID, lys_parse_in(UTEST_LYCTX, in, LYS_IN_YANG, NULL, NULL, &unres.creating, &mod1));
assert_int_equal(LY_EVALID, lys_parse_in(UTEST_LYCTX, in, LYS_IN_YANG, NULL, &unres.creating, &mod1));
lys_unres_glob_erase(&unres);
ly_in_free(in, 0);
CHECK_LOG_CTX("Parsing module \"y\" failed.", NULL, 0);
@ -342,19 +364,18 @@ test_models(void **state)
ly_ctx_set_module_imp_clb(UTEST_LYCTX, test_imp_clb, "submodule y {belongs-to b {prefix b;}}");
assert_int_equal(LY_SUCCESS, ly_in_new_memory("module b {namespace urn:b;prefix b;include y;}", &in));
assert_int_equal(LY_EVALID, lys_parse_in(UTEST_LYCTX, in, LYS_IN_YANG, NULL, NULL, &unres.creating, &mod1));
assert_int_equal(LY_EVALID, lys_parse_in(UTEST_LYCTX, in, LYS_IN_YANG, NULL, &unres.creating, &mod1));
lys_unres_glob_revert(UTEST_LYCTX, &unres);
lys_unres_glob_erase(&unres);
ly_in_free(in, 0);
CHECK_LOG_CTX("Parsing module \"b\" failed.", NULL, 0);
CHECK_LOG_CTX("Including \"y\" submodule into \"b\" failed.", NULL, 0);
CHECK_LOG_CTX("Parsing submodule failed.", NULL, 0);
CHECK_LOG_CTX("Parsing submodule \"y\" failed.", NULL, 0);
CHECK_LOG_CTX("Name collision between submodules of name \"y\".", NULL, 1);
/* selecting correct revision of the submodules */
ly_ctx_set_module_imp_clb(UTEST_LYCTX, test_imp_clb, "submodule y {belongs-to a {prefix a;} revision 2018-10-31;}");
assert_int_equal(LY_SUCCESS, ly_in_new_memory("module a {namespace urn:a;prefix a;include y; revision 2018-10-31;}", &in));
assert_int_equal(LY_SUCCESS, lys_parse_in(UTEST_LYCTX, in, LYS_IN_YANG, NULL, NULL, &unres.creating, &mod2));
assert_int_equal(LY_SUCCESS, lys_parse_in(UTEST_LYCTX, in, LYS_IN_YANG, NULL, &unres.creating, &mod2));
lys_unres_glob_erase(&unres);
ly_in_free(in, 0);
assert_string_equal("2018-10-31", mod2->parsed->includes[0].submodule->revs[0].date);
@ -490,17 +511,17 @@ test_get_models(void **state)
/* select module by revision */
assert_int_equal(LY_SUCCESS, lys_parse(UTEST_LYCTX, in1, LYS_IN_YANG, NULL, &mod));
/* invalid attempts - implementing module of the same name and inserting the same module */
assert_int_equal(LY_SUCCESS, lys_parse_in(UTEST_LYCTX, in2, LYS_IN_YANG, NULL, NULL, &unres.creating, &mod2));
assert_int_equal(LY_SUCCESS, lys_parse_in(UTEST_LYCTX, in2, LYS_IN_YANG, NULL, &unres.creating, &mod2));
assert_int_equal(LY_EDENIED, lys_implement(mod2, NULL, &unres));
CHECK_LOG_CTX("Module \"a@2018-10-24\" is already implemented in revision \"2018-10-23\".", NULL, 0);
lys_unres_glob_erase(&unres);
ly_in_reset(in1);
/* it is already there, fine */
assert_int_equal(LY_SUCCESS, lys_parse_in(UTEST_LYCTX, in1, LYS_IN_YANG, NULL, NULL, &unres.creating, NULL));
assert_int_equal(LY_SUCCESS, lys_parse_in(UTEST_LYCTX, in1, LYS_IN_YANG, NULL, &unres.creating, NULL));
/* insert the second module only as imported, not implemented */
lys_unres_glob_erase(&unres);
ly_in_reset(in2);
assert_int_equal(LY_SUCCESS, lys_parse_in(UTEST_LYCTX, in2, LYS_IN_YANG, NULL, NULL, &unres.creating, &mod2));
assert_int_equal(LY_SUCCESS, lys_parse_in(UTEST_LYCTX, in2, LYS_IN_YANG, NULL, &unres.creating, &mod2));
lys_unres_glob_erase(&unres);
assert_non_null(mod2);
assert_ptr_not_equal(mod, mod2);
@ -509,7 +530,7 @@ test_get_models(void **state)
mod2 = ly_ctx_get_module_latest_ns(UTEST_LYCTX, mod->ns);
assert_ptr_equal(mod, mod2);
/* work with module with no revision */
assert_int_equal(LY_SUCCESS, lys_parse_in(UTEST_LYCTX, in0, LYS_IN_YANG, NULL, NULL, &unres.creating, &mod));
assert_int_equal(LY_SUCCESS, lys_parse_in(UTEST_LYCTX, in0, LYS_IN_YANG, NULL, &unres.creating, &mod));
lys_unres_glob_erase(&unres);
assert_ptr_equal(mod, ly_ctx_get_module(UTEST_LYCTX, "a", NULL));
assert_ptr_not_equal(mod, ly_ctx_get_module_latest(UTEST_LYCTX, "a"));
@ -517,7 +538,7 @@ test_get_models(void **state)
str1 = "submodule b {belongs-to a {prefix a;}}";
ly_in_free(in1, 0);
assert_int_equal(LY_SUCCESS, ly_in_new_memory(str1, &in1));
assert_int_equal(LY_EINVAL, lys_parse_in(UTEST_LYCTX, in1, LYS_IN_YANG, NULL, NULL, &unres.creating, &mod));
assert_int_equal(LY_EINVAL, lys_parse_in(UTEST_LYCTX, in1, LYS_IN_YANG, NULL, &unres.creating, &mod));
CHECK_LOG_CTX("Input data contains submodule which cannot be parsed directly without its main module.", NULL, 0);
lys_unres_glob_erase(&unres);
@ -540,7 +561,7 @@ test_ylmem(void **state)
" <name>complete</name>\n"\
" <module>\n"\
" <name>yang</name>\n"\
" <revision>2022-06-16</revision>\n"\
" <revision>2025-01-29</revision>\n"\
" <namespace>urn:ietf:params:xml:ns:yang:1</namespace>\n"\
" </module>\n"\
" <module>\n"\
@ -587,7 +608,7 @@ test_ylmem(void **state)
" </module>\n"\
" <module>\n"\
" <name>yang</name>\n"\
" <revision>2022-06-16</revision>\n"\
" <revision>2025-01-29</revision>\n"\
" <namespace>urn:ietf:params:xml:ns:yang:1</namespace>\n"\
" <conformance-type>implement</conformance-type>\n"\
" </module>\n"\
@ -740,7 +761,7 @@ test_ylmem(void **state)
" <name>complete</name>\n"
" <module>\n"
" <name>yang</name>\n"
" <revision>2022-06-16</revision>\n"
" <revision>2025-01-29</revision>\n"
" <namespace>urn:ietf:params:xml:ns:yang:1</namespace>\n"
" </module>\n"
DATA_YANG_BASE_IMPORTS
@ -978,7 +999,7 @@ test_set_priv_parsed(void **state)
ly_ctx_destroy(UTEST_LYCTX);
const char *feats[] = {"f1", NULL};
assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, LY_CTX_SET_PRIV_PARSED, &UTEST_LYCTX));
assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, LY_CTX_DISABLE_SEARCHDIR_CWD | LY_CTX_SET_PRIV_PARSED, &UTEST_LYCTX));
assert_int_equal(LY_SUCCESS, ly_ctx_set_searchdir(UTEST_LYCTX, TESTS_DIR_MODULES_YANG));
assert_non_null(ly_ctx_load_module(UTEST_LYCTX, "ietf-restconf", "2017-01-26", NULL));
UTEST_ADD_MODULE(schema_a, LYS_IN_YANG, feats, NULL);
@ -1054,7 +1075,7 @@ test_explicit_compile(void **state)
ly_ctx_destroy(UTEST_LYCTX);
const char *feats[] = {"f1", NULL};
assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, LY_CTX_EXPLICIT_COMPILE, &UTEST_LYCTX));
assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, LY_CTX_DISABLE_SEARCHDIR_CWD | LY_CTX_EXPLICIT_COMPILE, &UTEST_LYCTX));
UTEST_ADD_MODULE(schema_a, LYS_IN_YANG, NULL, &mod);
UTEST_ADD_MODULE(schema_b, LYS_IN_YANG, NULL, NULL);
UTEST_ADD_MODULE(schema_c, LYS_IN_YANG, NULL, NULL);

View file

@ -23,11 +23,11 @@
#define CHECK_LYD_STRING(INPUT, TEXT) \
CHECK_LYD_STRING_PARAM(INPUT, TEXT, LYD_XML, LYD_PRINT_WITHSIBLINGS)
#define CHECK_PARSE_LYD_DIFF(INPUT_1, INPUT_2, OUT_DIFF) \
assert_int_equal(LY_SUCCESS, lyd_diff_siblings(INPUT_1, INPUT_2, 0, &OUT_DIFF));\
#define CHECK_PARSE_LYD_DIFF(INPUT_1, INPUT_2, OPTS, OUT_DIFF) \
assert_int_equal(LY_SUCCESS, lyd_diff_siblings(INPUT_1, INPUT_2, OPTS, &OUT_DIFF));\
assert_non_null(OUT_DIFF)
#define TEST_DIFF_3(XML1, XML2, XML3, DIFF1, DIFF2, MERGE) \
#define TEST_DIFF_3(XML1, XML2, XML3, OPTS, DIFF1, DIFF2, MERGE) \
{ \
struct lyd_node *data1;\
struct lyd_node *data2;\
@ -38,13 +38,13 @@
CHECK_PARSE_LYD(XML3, data3);\
/* diff1 */ \
struct lyd_node *diff1;\
CHECK_PARSE_LYD_DIFF(data1, data2, diff1); \
CHECK_PARSE_LYD_DIFF(data1, data2, OPTS, diff1); \
CHECK_LYD_STRING(diff1, DIFF1); \
assert_int_equal(lyd_diff_apply_all(&data1, diff1), LY_SUCCESS); \
CHECK_LYD(data1, data2); \
/* diff2 */ \
struct lyd_node *diff2;\
CHECK_PARSE_LYD_DIFF(data2, data3, diff2); \
CHECK_PARSE_LYD_DIFF(data2, data3, OPTS, diff2); \
CHECK_LYD_STRING(diff2, DIFF2); \
assert_int_equal(lyd_diff_apply_all(&data2, diff2), LY_SUCCESS);\
CHECK_LYD(data2, data3);\
@ -59,248 +59,104 @@
lyd_free_all(diff2);\
}
const char *schema1 =
"module defaults {\n"
" yang-version 1.1;\n"
" namespace \"urn:libyang:tests:defaults\";\n"
" prefix df;\n"
const char *schema =
"module defaults {"
"yang-version 1.1;"
"namespace \"urn:libyang:tests:defaults\";"
"prefix df;"
""
" feature unhide;\n"
"import ietf-yang-metadata {prefix md;}"
""
" typedef defint32 {\n"
" type int32;\n"
" default \"42\";\n"
" }\n"
"feature unhide;"
""
" leaf hiddenleaf {\n"
" if-feature \"unhide\";\n"
" type int32;\n"
" default \"42\";\n"
" }\n"
"md:annotation my-meta {type string;}"
"md:annotation my-meta2 {type string;}"
""
" container df {\n"
" leaf foo {\n"
" type defint32;\n"
" }\n"
"typedef defint32 {type int32; default \"42\";}"
""
" leaf hiddenleaf {\n"
" if-feature \"unhide\";\n"
" type int32;\n"
" default \"42\";\n"
" }\n"
""
" container bar {\n"
" presence \"\";\n"
" leaf hi {\n"
" type int32;\n"
" default \"42\";\n"
" }\n"
""
" leaf ho {\n"
" type int32;\n"
" mandatory true;\n"
" }\n"
" }\n"
""
" leaf-list llist {\n"
" type defint32;\n"
" ordered-by user;\n"
" }\n"
""
" list ul {\n"
" key \"l1\";\n"
" ordered-by user;\n"
" leaf l1 {\n"
" type string;\n"
" }\n"
""
" leaf l2 {\n"
" type int32;\n"
" }\n"
""
" container cont {\n"
" leaf l3 {\n"
" type string;\n"
" }\n"
" }\n"
" }\n"
""
" leaf-list dllist {\n"
" type uint8;\n"
" default \"1\";\n"
" default \"2\";\n"
" default \"3\";\n"
" }\n"
""
" list list {\n"
" key \"name\";\n"
" leaf name {\n"
" type string;\n"
" }\n"
""
" leaf value {\n"
" type int32;\n"
" default \"42\";\n"
" }\n"
" list list2 {\n"
" key \"name2\";\n"
" leaf name2 {\n"
" type string;\n"
" }\n"
" leaf value2 {\n"
" type int32;\n"
" }\n"
" }\n"
" }\n";
const char *schema2 =
" choice select {\n"
" default \"a\";\n"
" case a {\n"
" choice a {\n"
" leaf a1 {\n"
" type int32;\n"
" default \"42\";\n"
" }\n"
""
" leaf a2 {\n"
" type int32;\n"
" default \"24\";\n"
" }\n"
" }\n"
" }\n"
""
" leaf b {\n"
" type string;\n"
" }\n"
""
" container c {\n"
" presence \"\";\n"
" leaf x {\n"
" type int32;\n"
" default \"42\";\n"
" }\n"
" }\n"
" }\n"
""
" choice select2 {\n"
" default \"s2b\";\n"
" leaf s2a {\n"
" type int32;\n"
" default \"42\";\n"
" }\n"
""
" case s2b {\n"
" choice s2b {\n"
" default \"b1\";\n"
" case b1 {\n"
" leaf b1_1 {\n"
" type int32;\n"
" default \"42\";\n"
" }\n"
""
" leaf b1_2 {\n"
" type string;\n"
" }\n"
""
" leaf b1_status {\n"
" type int32;\n"
" default \"42\";\n"
" config false;\n"
" }\n"
" }\n"
""
" leaf b2 {\n"
" type int32;\n"
" default \"42\";\n"
" }\n"
" }\n"
" }\n"
" }\n"
" list kl {\n"
" config \"false\";\n"
" leaf l1 {\n"
" type string;\n"
" }\n"
""
" leaf l2 {\n"
" type int32;\n"
" }\n"
" }\n"
""
" leaf-list kll {\n"
" config \"false\";\n"
" type string;\n"
" }\n"
" }\n"
""
" container hidden {\n"
" leaf foo {\n"
" type int32;\n"
" default \"42\";\n"
" }\n"
""
" leaf baz {\n"
" type int32;\n"
" default \"42\";\n"
" }\n"
""
" leaf papa {\n"
" type int32;\n"
" default \"42\";\n"
" config false;\n"
" }\n"
" }\n"
""
" rpc rpc1 {\n"
" input {\n"
" leaf inleaf1 {\n"
" type string;\n"
" }\n"
""
" leaf inleaf2 {\n"
" type string;\n"
" default \"def1\";\n"
" }\n"
" }\n"
""
" output {\n"
" leaf outleaf1 {\n"
" type string;\n"
" default \"def2\";\n"
" }\n"
""
" leaf outleaf2 {\n"
" type string;\n"
" }\n"
" }\n"
" }\n"
""
" notification notif {\n"
" leaf ntfleaf1 {\n"
" type string;\n"
" default \"def3\";\n"
" }\n"
""
" leaf ntfleaf2 {\n"
" type string;\n"
" }\n"
" }\n"
"}\n";
"leaf hiddenleaf {if-feature \"unhide\"; type int32; default \"42\";}"
"container df {"
" leaf foo {type defint32; }"
" leaf hiddenleaf {if-feature \"unhide\"; type int32; default \"42\";}"
" container bar { presence \"\";"
" leaf hi {type int32; default \"42\";}"
" leaf ho {type int32; mandatory true;}"
" }"
" leaf-list llist {type defint32; ordered-by user;}"
" list ul {key \"l1\"; ordered-by user;"
" leaf l1 {type string;}"
" leaf l2 {type int32;}"
" container cont {"
" leaf l3 {type string;}"
" }"
" }"
" leaf-list dllist {type uint8; default \"1\"; default \"2\"; default \"3\";}"
" list list {key \"name\";"
" leaf name {type string;}"
" leaf value {type int32; default \"42\";}"
" list list2 {key \"name2\";"
" leaf name2 {type string;}"
" leaf value2 {type int32;}"
" }"
" }"
" choice select {default \"a\";"
" case a {"
" choice a {"
" leaf a1 {type int32; default \"42\";}"
" leaf a2 {type int32; default \"24\";}"
" }"
" }"
" leaf b {type string;}"
" container c {presence \"\";"
" leaf x {type int32; default \"42\";}"
" }"
" }"
" choice select2 {default \"s2b\";"
" leaf s2a {type int32; default \"42\";}"
" case s2b {"
" choice s2b {default \"b1\";"
" case b1 {"
" leaf b1_1 {type int32; default \"42\";}"
" leaf b1_2 {type string;}"
" leaf b1_status {type int32; default \"42\"; config false;}"
" }"
" leaf b2 {type int32; default \"42\";}"
" }"
" }"
" }"
" list kl {config \"false\";"
" leaf l1 {type string;}"
" leaf l2 {type int32;}"
" }"
" leaf-list kll {config \"false\"; type string;}"
"}"
"container hidden {"
" leaf foo {type int32; default \"42\";}"
" leaf baz {type int32; default \"42\";}"
" leaf papa {type int32; default \"42\"; config false;}"
"}"
"rpc rpc1 {"
" input {"
" leaf inleaf1 {type string;}"
" leaf inleaf2 {type string; default \"def1\";}"
" }"
" output {"
" leaf outleaf1 {type string; default \"def2\";}"
" leaf outleaf2 {type string;}"
" }"
"}"
"notification notif {"
" leaf ntfleaf1 {type string; default \"def3\";}"
" leaf ntfleaf2 {type string;}"
"}"
"}";
static int
setup(void **state)
{
char *schema;
UTEST_SETUP;
/* create one schema, longer than 4095 chars */
schema = malloc(strlen(schema1) + strlen(schema2) + 1);
strcpy(schema, schema1);
strcat(schema, schema2);
UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
free(schema);
return 0;
}
@ -384,7 +240,7 @@ test_empty1(void **state)
struct lyd_node *diff;
CHECK_PARSE_LYD_DIFF(model_1, model_2, diff);
CHECK_PARSE_LYD_DIFF(model_1, model_2, 0, diff);
CHECK_LYD_STRING(diff,
"<df xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"create\">\n"
" <foo>42</foo>\n"
@ -420,7 +276,7 @@ test_empty2(void **state)
struct lyd_node *diff;
CHECK_PARSE_LYD_DIFF(model_1, NULL, diff);
CHECK_PARSE_LYD_DIFF(model_1, NULL, 0, diff);
CHECK_LYD_STRING(diff,
"<df xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"delete\">\n"
" <foo>42</foo>\n"
@ -455,7 +311,7 @@ test_empty_nested(void **state)
struct lyd_node *diff1;
CHECK_PARSE_LYD_DIFF(NULL, lyd_child(model_1), diff1);
CHECK_PARSE_LYD_DIFF(NULL, lyd_child(model_1), 0, diff1);
CHECK_LYD_STRING(diff1,
"<df xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"none\">\n"
" <foo yang:operation=\"create\">42</foo>\n"
@ -463,7 +319,7 @@ test_empty_nested(void **state)
struct lyd_node *diff2;
CHECK_PARSE_LYD_DIFF(lyd_child(model_1), NULL, diff2);
CHECK_PARSE_LYD_DIFF(lyd_child(model_1), NULL, 0, diff2);
CHECK_LYD_STRING(diff2,
"<df xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"none\">\n"
" <foo yang:operation=\"delete\">42</foo>\n"
@ -565,7 +421,7 @@ test_leaf(void **state)
" <baz yang:operation=\"delete\">42</baz>\n"
"</hidden>\n";
TEST_DIFF_3(xml1, xml2, xml3, out_diff_1, out_diff_2, out_merge);
TEST_DIFF_3(xml1, xml2, xml3, 0, out_diff_1, out_diff_2, out_merge);
}
static void
@ -641,7 +497,7 @@ test_list(void **state)
" </list>\n"
"</df>\n";
TEST_DIFF_3(xml1, xml2, xml3, out_diff_1, out_diff_2, out_merge);
TEST_DIFF_3(xml1, xml2, xml3, 0, out_diff_1, out_diff_2, out_merge);
}
static void
@ -713,7 +569,7 @@ test_nested_list(void **state)
CHECK_PARSE_LYD(xml1, data1);
CHECK_PARSE_LYD(xml2, data2);
CHECK_PARSE_LYD_DIFF(data1, data2, diff);
CHECK_PARSE_LYD_DIFF(data1, data2, 0, diff);
CHECK_LYD_STRING(diff,
"<df xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"none\">\n"
@ -810,7 +666,7 @@ test_userord_llist(void **state)
" <llist yang:orig-default=\"false\" yang:orig-value=\"2\" yang:value=\"\" yang:operation=\"replace\">5</llist>\n"
"</df>\n";
TEST_DIFF_3(xml1, xml2, xml3, out_diff_1, out_diff_2, out_merge);
TEST_DIFF_3(xml1, xml2, xml3, 0, out_diff_1, out_diff_2, out_merge);
}
static void
@ -856,7 +712,7 @@ test_userord_llist2(void **state)
" <llist yang:orig-value=\"1\" yang:operation=\"delete\">2</llist>\n"
"</df>\n";
TEST_DIFF_3(xml1, xml2, xml3, out_diff_1, out_diff_2, out_merge);
TEST_DIFF_3(xml1, xml2, xml3, 0, out_diff_1, out_diff_2, out_merge);
}
static void
@ -899,7 +755,7 @@ test_userord_mix(void **state)
" <llist yang:value=\"1\" yang:operation=\"create\">4</llist>\n"
"</df>\n";
TEST_DIFF_3(xml1, xml2, xml3, out_diff_1, out_diff_2, out_merge);
TEST_DIFF_3(xml1, xml2, xml3, 0, out_diff_1, out_diff_2, out_merge);
}
static void
@ -985,7 +841,7 @@ test_userord_list(void **state)
" </ul>\n"
"</df>\n";
TEST_DIFF_3(xml1, xml2, xml3, out_diff_1, out_diff_2, out_merge);
TEST_DIFF_3(xml1, xml2, xml3, 0, out_diff_1, out_diff_2, out_merge);
}
static void
@ -1064,7 +920,7 @@ test_userord_list2(void **state)
" </ul>\n"
"</df>\n";
TEST_DIFF_3(xml1, xml2, xml3, out_diff_1, out_diff_2, out_merge);
TEST_DIFF_3(xml1, xml2, xml3, 0, out_diff_1, out_diff_2, out_merge);
}
static void
@ -1176,7 +1032,7 @@ test_userord_list3(void **state)
" </ul>\n"
"</df>\n";
TEST_DIFF_3(xml1, xml2, xml3, out_diff_1, out_diff_2, out_merge);
TEST_DIFF_3(xml1, xml2, xml3, 0, out_diff_1, out_diff_2, out_merge);
}
static void
@ -1302,7 +1158,7 @@ test_keyless_list(void **state)
" </kl>\n"
"</df>\n";
TEST_DIFF_3(xml1, xml2, xml3, out_diff_1, out_diff_2, out_merge);
TEST_DIFF_3(xml1, xml2, xml3, 0, out_diff_1, out_diff_2, out_merge);
}
static void
@ -1349,7 +1205,7 @@ test_state_llist(void **state)
" <kll yang:position=\"1\" yang:operation=\"create\">d</kll>\n"
"</df>\n";
TEST_DIFF_3(xml1, xml2, xml3, out_diff_1, out_diff_2, out_merge);
TEST_DIFF_3(xml1, xml2, xml3, 0, out_diff_1, out_diff_2, out_merge);
}
static void
@ -1435,6 +1291,89 @@ test_wd(void **state)
lyd_free_all(diff2);
}
static void
test_metadata(void **state)
{
(void) state;
const char *xml1 = "<df xmlns=\"urn:libyang:tests:defaults\" xmlns:df=\"urn:libyang:tests:defaults\">\n"
" <list df:my-meta=\"val1\">\n"
" <name>a</name>\n"
" <value df:my-meta2=\"val2\">1</value>\n"
" </list>\n"
" <list>\n"
" <name df:my-meta=\"val10\">b</name>\n"
" <value df:my-meta=\"repeated\" df:my-meta=\"repeated\">2</value>\n"
" </list>\n"
"</df>\n";
const char *xml2 = "<df xmlns=\"urn:libyang:tests:defaults\" xmlns:df=\"urn:libyang:tests:defaults\">\n"
" <list>\n"
" <name>b</name>\n"
" <value df:my-meta=\"repeated\">2</value>\n"
" </list>\n"
" <list>\n"
" <name df:my-meta2=\"val22\">c</name>\n"
" <value df:my-meta2=\"val23\">3</value>\n"
" </list>\n"
"</df>\n";
const char *xml3 = "<df xmlns=\"urn:libyang:tests:defaults\" xmlns:df=\"urn:libyang:tests:defaults\" df:my-meta=\"top\">\n"
" <list>\n"
" <name>b</name>\n"
" <value df:my-meta=\"repeated\" df:my-meta=\"new\">2</value>\n"
" </list>\n"
" <list>\n"
" <name df:my-meta=\"val22\">c</name>\n"
" <value df:my-meta2=\"val23\">3</value>\n"
" </list>\n"
"</df>\n";
const char *out_diff_1 =
"<df xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"none\">\n"
" <list yang:operation=\"delete\" yang:meta-delete=\"defaults:my-meta=val1\">\n"
" <name>a</name>\n"
" <value yang:meta-delete=\"defaults:my-meta2=val2\">1</value>\n"
" </list>\n"
" <list>\n"
" <name yang:meta-delete=\"defaults:my-meta=val10\">b</name>\n"
" <value yang:orig-default=\"false\" yang:meta-delete=\"defaults:my-meta=repeated\">2</value>\n"
" </list>\n"
" <list yang:operation=\"create\">\n"
" <name yang:meta-create=\"defaults:my-meta2=val22\">c</name>\n"
" <value yang:meta-create=\"defaults:my-meta2=val23\">3</value>\n"
" </list>\n"
"</df>\n";
const char *out_diff_2 =
"<df xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"none\" "
"yang:meta-create=\"defaults:my-meta=top\">\n"
" <list>\n"
" <name>b</name>\n"
" <value yang:orig-default=\"false\" yang:meta-create=\"defaults:my-meta=new\">2</value>\n"
" </list>\n"
" <list>\n"
" <name yang:meta-delete=\"defaults:my-meta2=val22\" yang:meta-create=\"defaults:my-meta=val22\">c</name>\n"
" <value yang:operation=\"none\">3</value>\n"
" </list>\n"
"</df>\n";
const char *out_merge =
"<df xmlns=\"urn:libyang:tests:defaults\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"none\" "
"yang:meta-create=\"defaults:my-meta=top\">\n"
" <list yang:operation=\"delete\" yang:meta-delete=\"defaults:my-meta=val1\">\n"
" <name>a</name>\n"
" <value yang:meta-delete=\"defaults:my-meta2=val2\">1</value>\n"
" </list>\n"
" <list>\n"
" <name yang:meta-delete=\"defaults:my-meta=val10\">b</name>\n"
" <value yang:orig-default=\"false\" yang:meta-delete=\"defaults:my-meta=repeated\" "
"yang:meta-create=\"defaults:my-meta=new\">2</value>\n"
" </list>\n"
" <list yang:operation=\"create\">\n"
" <name yang:meta-create=\"defaults:my-meta=val22\">c</name>\n"
" <value yang:meta-create=\"defaults:my-meta2=val23\">3</value>\n"
" </list>\n"
"</df>\n";
TEST_DIFF_3(xml1, xml2, xml3, LYD_DIFF_META, out_diff_1, out_diff_2, out_merge);
}
int
main(void)
{
@ -1457,6 +1396,7 @@ main(void)
UTEST(test_keyless_list, setup),
UTEST(test_state_llist, setup),
UTEST(test_wd, setup),
UTEST(test_metadata, setup),
};
return cmocka_run_group_tests(tests, NULL, NULL);

View file

@ -279,7 +279,7 @@ test_path(void **state)
lyd_free_tree(root);
/* try LYD_NEWOPT_OPAQ */
/* try LYD_NEW_PATH_OPAQ */
ret = lyd_new_path2(NULL, UTEST_LYCTX, "/a:l1", NULL, 0, 0, 0, NULL, NULL);
assert_int_equal(ret, LY_EINVAL);
CHECK_LOG_CTX("Predicate missing for list \"l1\" in path \"/a:l1\".", "/a:l1", 0);
@ -424,7 +424,6 @@ test_path(void **state)
ret = lyd_new_path2(NULL, UTEST_LYCTX, "/a:any", "<elem>val</elem>", 0, LYD_ANYDATA_XML, 0, &root, NULL);
assert_int_equal(ret, LY_SUCCESS);
assert_non_null(root);
lyd_print_mem(&str, root, LYD_XML, LYD_PRINT_WITHSIBLINGS);
assert_string_equal(str,
"<any xmlns=\"urn:tests:a\">\n"
@ -445,7 +444,6 @@ test_path(void **state)
ret = lyd_new_path2(NULL, UTEST_LYCTX, "/a:anyx", "<a/><b/><c/>", 0, LYD_ANYDATA_XML, 0, &root, NULL);
assert_int_equal(ret, LY_SUCCESS);
assert_non_null(root);
lyd_print_mem(&str, root, LYD_XML, LYD_PRINT_WITHSIBLINGS);
assert_string_equal(str,
"<anyx xmlns=\"urn:tests:a\">\n"
@ -466,10 +464,44 @@ test_path(void **state)
free(str);
lyd_free_siblings(root);
ret = lyd_new_path2(NULL, UTEST_LYCTX, "/a:anyx", "<a/><b/><c/>", 0, LYD_ANYDATA_XML, 0, &root, NULL);
assert_int_equal(ret, LY_SUCCESS);
assert_non_null(root);
ret = lyd_new_path2(root, NULL, "/a:anyx", "[10,11,12]", 0, LYD_ANYDATA_JSON, LYD_NEW_PATH_UPDATE, NULL, NULL);
assert_int_equal(ret, LY_SUCCESS);
lyd_print_mem(&str, root, LYD_XML, LYD_PRINT_WITHSIBLINGS);
assert_string_equal(str,
"<anyx xmlns=\"urn:tests:a\">[10,11,12]</anyx>\n");
free(str);
lyd_print_mem(&str, root, LYD_JSON, LYD_PRINT_WITHSIBLINGS);
assert_string_equal(str,
"{\n"
" \"a:anyx\": [10,11,12]\n"
"}\n");
free(str);
lyd_free_siblings(root);
ret = lyd_new_path2(NULL, UTEST_LYCTX, "/a:anyx", "<a/><b/><c/>", 0, LYD_ANYDATA_XML, 0, &root, NULL);
assert_int_equal(ret, LY_SUCCESS);
assert_non_null(root);
ret = lyd_new_path2(root, NULL, "/a:anyx", strdup("[10,11,12]"), 0, LYD_ANYDATA_JSON,
LYD_NEW_PATH_UPDATE | LYD_NEW_ANY_USE_VALUE, NULL, NULL);
assert_int_equal(ret, LY_SUCCESS);
lyd_print_mem(&str, root, LYD_XML, LYD_PRINT_WITHSIBLINGS);
assert_string_equal(str,
"<anyx xmlns=\"urn:tests:a\">[10,11,12]</anyx>\n");
free(str);
lyd_print_mem(&str, root, LYD_JSON, LYD_PRINT_WITHSIBLINGS);
assert_string_equal(str,
"{\n"
" \"a:anyx\": [10,11,12]\n"
"}\n");
free(str);
lyd_free_siblings(root);
ret = lyd_new_path2(NULL, UTEST_LYCTX, "/a:anyx", "{\"a\":[null],\"b\":[null],\"c\":[null]}", 0, LYD_ANYDATA_JSON, 0, &root, NULL);
assert_int_equal(ret, LY_SUCCESS);
assert_non_null(root);
lyd_print_mem(&str, root, LYD_XML, LYD_PRINT_WITHSIBLINGS);
assert_string_equal(str,
"<anyx xmlns=\"urn:tests:a\">\n"

View file

@ -168,6 +168,21 @@ test_leaf(void **state)
PARSER_CHECK_ERROR(data, 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID, "Invalid non-string-encoded string value \"\".", "/a:foo", 1);
CHECK_PARSE_LYD(data, LYD_PARSE_JSON_NULL, LYD_VALIDATE_PRESENT, tree);
assert_null(tree);
/* validate integer in quotes errors out by default */
data = "{\"a:foo3\":\"1234\"}";
PARSER_CHECK_ERROR(data, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, tree, LY_EVALID,
"Invalid non-number-encoded uint32 value \"1234\".", "/a:foo3", 1);
/* validate integers are parsed correctly */
data = "{\"a:foo3\":1234}";
CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree);
lyd_free_all(tree);
/* validate LYD_PARSE_JSON_STRING_DATATYPES parser flag allows integers in quotes */
data = "{\"a:foo3\":\"1234\"}";
CHECK_PARSE_LYD(data, LYD_PARSE_JSON_STRING_DATATYPES, LYD_VALIDATE_PRESENT, tree);
lyd_free_all(tree);
}
static void
@ -920,6 +935,25 @@ test_metadata(void **state)
CHECK_LOG_CTX("Invalid non-number-encoded int8 value \"value\".", "/a:c/x/@a:hint", 1);
}
static void
test_parent(void **state)
{
const char *data;
struct lyd_node *tree;
struct ly_in *in;
/* create the parent */
assert_int_equal(LY_SUCCESS, lyd_new_path(NULL, UTEST_LYCTX, "/a:l1[a='vala'][b='valb'][c='25']", NULL, 0, &tree));
/* parse nested data */
data = "{\"cont\":{\"e\":false}}";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(data, &in));
assert_int_equal(LY_SUCCESS, lyd_parse_data(NULL, tree, in, LYD_JSON, 0, LYD_VALIDATE_PRESENT, NULL));
ly_in_free(in, 0);
lyd_free_tree(tree);
}
int
main(void)
{
@ -939,6 +973,7 @@ main(void)
UTEST(test_restconf_notification, setup),
UTEST(test_restconf_reply, setup),
UTEST(test_metadata, setup),
UTEST(test_parent, setup),
};
return cmocka_run_group_tests(tests, NULL, NULL);

View file

@ -722,6 +722,8 @@ test_netconf_reply_or_notification(void **state)
struct ly_in *in;
struct lyd_node *action, *tree, *op, *op2;
assert_non_null((ly_ctx_load_module(UTEST_LYCTX, "ietf-netconf", "2011-06-01", NULL)));
/* parse the action */
data = "<c xmlns=\"urn:tests:a\">\n"
" <act>\n"
@ -817,6 +819,7 @@ test_netconf_reply_or_notification(void **state)
" <error-type>rpc</error-type>\n"
" <error-tag>missing-attribute</error-tag>\n"
" <error-severity>error</error-severity>\n"
" <error-path xmlns:a=\"urn:tests:a\">/a:c/a:x</error-path>\n"
" <error-info>\n"
" <bad-attribute>message-id</bad-attribute>\n"
" <bad-element>rpc</bad-element>\n"
@ -828,8 +831,6 @@ test_netconf_reply_or_notification(void **state)
ly_in_free(in, 0);
CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)tree, 1, 1, LY_VALUE_XML, "rpc-reply", 0, 0, 0, 0, "");
CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)lyd_child(tree), 0, 1, LY_VALUE_XML, "rpc-error", 0, 0, 0, 0, "");
CHECK_LYD_STRING(tree, LYD_PRINT_WITHSIBLINGS, data);
lyd_free_all(tree);

View file

@ -277,12 +277,12 @@ test_minmax(void **state)
CHECK_PARSE_LYD_PARAM("<l xmlns=\"urn:tests:c\">mate</l>"
"<d xmlns=\"urn:tests:c\"/>",
LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree);
CHECK_LOG_CTX_APPTAG("Too few \"l\" instances.", "/c:choic/b/l", 0, "too-few-elements");
CHECK_LOG_CTX_APPTAG("Too few \"l\" instances.", "/c:l[.='mate']", 0, "too-few-elements");
CHECK_PARSE_LYD_PARAM("<l xmlns=\"urn:tests:c\">val1</l>"
"<l xmlns=\"urn:tests:c\">val2</l>",
LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree);
CHECK_LOG_CTX_APPTAG("Too few \"l\" instances.", "/c:choic/b/l", 0, "too-few-elements");
CHECK_LOG_CTX_APPTAG("Too few \"l\" instances.", "/c:l[.='val2']", 0, "too-few-elements");
LYD_TREE_CREATE("<l xmlns=\"urn:tests:c\">val1</l>"
"<l xmlns=\"urn:tests:c\">val2</l>"
@ -1259,7 +1259,7 @@ test_multi_error(void **state)
CHECK_PARSE_LYD_PARAM(data, LYD_JSON, LYD_PARSE_ONLY, 0, LY_SUCCESS, tree);
assert_int_equal(LY_EVALID, lyd_validate_all(&tree, NULL, LYD_VALIDATE_PRESENT | LYD_VALIDATE_MULTI_ERROR, NULL));
lyd_free_tree(tree);
CHECK_LOG_CTX_APPTAG("Too few \"ll\" instances.", "/ii:cont/ll", 0, "too-few-elements");
CHECK_LOG_CTX_APPTAG("Too few \"ll\" instances.", "/ii:cont/ll[.='25']", 0, "too-few-elements");
CHECK_LOG_CTX_APPTAG("l leaf is not left", "/ii:cont/l3", 0, "not-left");
CHECK_LOG_CTX_APPTAG("Must condition \"../l = 'right'\" not satisfied.", "/ii:cont/l2", 0, "must-violation");
CHECK_LOG_CTX_APPTAG("Duplicate instance of \"l\".", "/ii:cont/l", 0, NULL);

View file

@ -20,32 +20,32 @@
void **glob_state;
const char *glob_schema =
"module sm {yang-version 1.1;namespace \"urn:sm\";prefix \"sm\";"
"import ietf-yang-schema-mount {prefix yangmnt;}"
"import ietf-interfaces {prefix if;}"
"container root {yangmnt:mount-point \"root\";}"
"container root2 {yangmnt:mount-point \"root\";}"
"container root3 {"
" list ls { key name; leaf name {type string;}"
" yangmnt:mount-point \"mnt-root\";"
" }"
"}"
"container root4 {config false; yangmnt:mount-point \"root\";}"
"leaf target{type string;}"
"augment /if:interfaces/if:interface {"
" leaf sm-name {type leafref {path \"/sm:target\";}}"
"}"
"}";
static int
setup(void **state)
{
const char *schema =
"module sm {yang-version 1.1;namespace \"urn:sm\";prefix \"sm\";"
"import ietf-yang-schema-mount {prefix yangmnt;}"
"import ietf-interfaces {prefix if;}"
"container root {yangmnt:mount-point \"root\";}"
"container root2 {yangmnt:mount-point \"root\";}"
"container root3 {"
" list ls { key name; leaf name {type string;}"
" yangmnt:mount-point \"mnt-root\";"
" }"
"}"
"container root4 {config false; yangmnt:mount-point \"root\";}"
"leaf target{type string;}"
"augment /if:interfaces/if:interface {"
" leaf sm-name {type leafref {path \"/sm:target\";}}"
"}"
"}";
UTEST_SETUP;
glob_state = state;
assert_int_equal(LY_SUCCESS, ly_ctx_set_searchdir(UTEST_LYCTX, TESTS_DIR_MODULES_YANG));
assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, schema, LYS_IN_YANG, NULL));
assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, glob_schema, LYS_IN_YANG, NULL));
assert_non_null(ly_ctx_load_module(UTEST_LYCTX, "iana-if-type", NULL, NULL));
return 0;
@ -1193,6 +1193,156 @@ test_parse_shared_parent_ref(void **state)
lyd_free_siblings(data);
}
static void
test_dup_shared(void **state)
{
struct ly_ctx *ctx2;
const char *ext_data, *xml;
struct ly_set *set;
struct lyd_node *data, *node, *dup;
uint32_t diff_opts;
ext_data = "<yang-library xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\" "
" xmlns:ds=\"urn:ietf:params:xml:ns:yang:ietf-datastores\">"
" <module-set>"
" <name>test-set</name>"
" <module>"
" <name>ietf-datastores</name>"
" <revision>2018-02-14</revision>"
" <namespace>urn:ietf:params:xml:ns:yang:ietf-datastores</namespace>"
" </module>"
" <module>"
" <name>ietf-yang-library</name>"
" <revision>2019-01-04</revision>"
" <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-library</namespace>"
" </module>"
" <module>"
" <name>ietf-yang-schema-mount</name>"
" <revision>2019-01-14</revision>"
" <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-schema-mount</namespace>"
" </module>"
" <module>"
" <name>ietf-interfaces</name>"
" <revision>2014-05-08</revision>"
" <namespace>urn:ietf:params:xml:ns:yang:ietf-interfaces</namespace>"
" </module>"
" <module>"
" <name>iana-if-type</name>"
" <revision>2014-05-08</revision>"
" <namespace>urn:ietf:params:xml:ns:yang:iana-if-type</namespace>"
" </module>"
" <import-only-module>"
" <name>ietf-yang-types</name>"
" <revision>2013-07-15</revision>"
" <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-types</namespace>"
" </import-only-module>"
" </module-set>"
" <schema>"
" <name>test-schema</name>"
" <module-set>test-set</module-set>"
" </schema>"
" <datastore>"
" <name>ds:running</name>"
" <schema>test-schema</schema>"
" </datastore>"
" <datastore>"
" <name>ds:operational</name>"
" <schema>test-schema</schema>"
" </datastore>"
" <content-id>1</content-id>"
"</yang-library>"
"<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\">"
" <module-set-id>1</module-set-id>"
"</modules-state>"
"<schema-mounts xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-schema-mount\">"
" <mount-point>"
" <module>sm</module>"
" <label>mnt-root</label>"
" <shared-schema/>"
" </mount-point>"
"</schema-mounts>";
xml =
"<root3 xmlns=\"urn:sm\">\n"
" <ls>\n"
" <name>ls1</name>\n"
" <interfaces xmlns=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\">\n"
" <interface>\n"
" <name>if1</name>\n"
" <type xmlns:ianaift=\"urn:ietf:params:xml:ns:yang:iana-if-type\">ianaift:ethernetCsmacd</type>\n"
" </interface>\n"
" </interfaces>\n"
" </ls>\n"
" <ls>\n"
" <name>ls2</name>\n"
" <interfaces-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\">\n"
" <interface>\n"
" <name>if2</name>\n"
" <type xmlns:ianaift=\"urn:ietf:params:xml:ns:yang:iana-if-type\">ianaift:ethernetCsmacd</type>\n"
" <oper-status>not-present</oper-status>\n"
" <statistics>\n"
" <discontinuity-time>2022-01-01T10:00:00-00:00</discontinuity-time>\n"
" </statistics>\n"
" </interface>\n"
" </interfaces-state>\n"
" </ls>\n"
"</root3>\n";
ly_ctx_set_ext_data_clb(UTEST_LYCTX, test_ext_data_clb, (void *)ext_data);
CHECK_PARSE_LYD_PARAM(xml, LYD_XML, LYD_PARSE_STRICT | LYD_PARSE_ONLY, 0, LY_SUCCESS, data);
diff_opts = LYD_DUP_NO_META | LYD_DUP_WITH_PARENTS | LYD_DUP_RECURSIVE | LYD_DUP_NO_LYDS;
/* dup to the same context */
assert_int_equal(LY_SUCCESS, lyd_find_xpath(data,
"/sm:root3/ls[name='ls1']/ietf-interfaces:interfaces/interface[name='if1']", &set));
assert_int_equal(1, set->count);
node = set->dnodes[0];
ly_set_free(set, NULL);
assert_int_equal(LY_SUCCESS, lyd_dup_single(node, NULL, diff_opts, &dup));
while (dup->parent) {
dup = lyd_parent(dup);
}
assert_int_equal(LY_SUCCESS, lyd_find_xpath(data,
"/sm:root3/ls[name='ls2']/ietf-interfaces:interfaces-state/interface[name='if2']", &set));
assert_int_equal(1, set->count);
node = set->dnodes[0];
ly_set_free(set, NULL);
assert_int_equal(LY_SUCCESS, lyd_dup_single_to_ctx(node, LYD_CTX(data), (struct lyd_node_inner *)dup, diff_opts, NULL));
lyd_free_siblings(dup);
/* dup to another context */
assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, LY_CTX_DISABLE_SEARCHDIR_CWD, &ctx2));
assert_int_equal(LY_SUCCESS, ly_ctx_set_searchdir(ctx2, TESTS_DIR_MODULES_YANG));
assert_int_equal(LY_SUCCESS, lys_parse_mem(ctx2, glob_schema, LYS_IN_YANG, NULL));
assert_non_null(ly_ctx_load_module(ctx2, "iana-if-type", NULL, NULL));
ly_ctx_set_ext_data_clb(ctx2, test_ext_data_clb, (void *)ext_data);
assert_int_equal(LY_SUCCESS, lyd_find_xpath(data,
"/sm:root3/ls[name='ls1']/ietf-interfaces:interfaces/interface[name='if1']", &set));
assert_int_equal(1, set->count);
node = set->dnodes[0];
ly_set_free(set, NULL);
assert_int_equal(LY_SUCCESS, lyd_dup_single_to_ctx(node, ctx2, NULL, diff_opts, &dup));
while (dup->parent) {
dup = lyd_parent(dup);
}
assert_int_equal(LY_SUCCESS, lyd_find_xpath(data,
"/sm:root3/ls[name='ls2']/ietf-interfaces:interfaces-state/interface[name='if2']", &set));
assert_int_equal(1, set->count);
node = set->dnodes[0];
ly_set_free(set, NULL);
assert_int_equal(LY_SUCCESS, lyd_dup_single_to_ctx(node, ctx2, (struct lyd_node_inner *)dup, diff_opts, NULL));
lyd_free_siblings(dup);
/* cleanup */
ly_ctx_destroy(ctx2);
lyd_free_siblings(data);
}
static void
test_parse_config(void **state)
{
@ -1648,6 +1798,7 @@ main(void)
UTEST(test_parse_inline, setup),
UTEST(test_parse_shared, setup),
UTEST(test_parse_shared_parent_ref, setup),
UTEST(test_dup_shared, setup),
UTEST(test_parse_config, setup),
UTEST(test_new, setup),
UTEST(test_lys_getnext, setup),

View file

@ -1051,7 +1051,7 @@ test_xml(void **state)
"</user>";
CHECK_PARSE_LYD_PARAM(data, LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree);
assert_null(tree);
CHECK_LOG_CTX("Too few \"user\" instances.", "/T2:user", 0);
CHECK_LOG_CTX("Too few \"user\" instances.", "/T2:user[uid='1']", 0);
data =
"<user xmlns=\"urn:tests:T2\">"
@ -1347,7 +1347,7 @@ test_json(void **state)
"]}";
CHECK_PARSE_LYD_PARAM(data, LYD_JSON, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree);
assert_null(tree);
CHECK_LOG_CTX("Too few \"user\" instances.", "/T2:user", 0);
CHECK_LOG_CTX("Too few \"user\" instances.", "/T2:user[uid='4']", 0);
data =
"{\"T2:user\": ["

View file

@ -1045,11 +1045,7 @@ test_includes(void **state)
ly_ctx_set_module_imp_clb(UTEST_LYCTX, module_clb, list);
mod = ly_ctx_load_module(UTEST_LYCTX, "main_b", NULL, NULL);
assert_null(mod);
CHECK_LOG_CTX("Loading \"main_b\" module failed.", NULL, 0);
CHECK_LOG_CTX("Data model \"main_b\" not found in local searchdirs.", NULL, 0);
CHECK_LOG_CTX("Parsing module \"main_b\" failed.", NULL, 0);
CHECK_LOG_CTX("Including \"sub_b_one\" submodule into \"main_b\" failed.", NULL, 0);
CHECK_LOG_CTX("Data model \"sub_b_one\" not found in local searchdirs.", NULL, 0);
CHECK_LOG_CTX("Parsing submodule \"sub_b_one\" failed.", NULL, 0);
CHECK_LOG_CTX("YANG 1.1 requires all submodules to be included from main module. But submodule \"sub_b_one\" includes "
"submodule \"sub_b_two\" which is not included by main module \"main_b\".", NULL, 0);
@ -1479,7 +1475,7 @@ test_extension_argument(void **state)
/* context reset */
ly_ctx_destroy(UTEST_LYCTX);
ly_ctx_new(NULL, 0, &UTEST_LYCTX);
ly_ctx_new(NULL, LY_CTX_DISABLE_SEARCHDIR_CWD, &UTEST_LYCTX);
/* from YIN */
ly_ctx_set_module_imp_clb(UTEST_LYCTX, test_imp_clb, (void *)mod_def_yin);
@ -1581,7 +1577,7 @@ test_extension_argument_element(void **state)
/* context reset */
ly_ctx_destroy(UTEST_LYCTX);
ly_ctx_new(NULL, 0, &UTEST_LYCTX);
ly_ctx_new(NULL, LY_CTX_DISABLE_SEARCHDIR_CWD, &UTEST_LYCTX);
/* from YIN */
ly_ctx_set_module_imp_clb(UTEST_LYCTX, test_imp_clb, (void *)mod_def_yin);
@ -1853,7 +1849,7 @@ test_ext_recursive(void **state)
/* context reset */
ly_ctx_destroy(UTEST_LYCTX);
ly_ctx_new(NULL, 0, &UTEST_LYCTX);
ly_ctx_new(NULL, LY_CTX_DISABLE_SEARCHDIR_CWD, &UTEST_LYCTX);
/* from YIN */
ly_ctx_set_module_imp_clb(UTEST_LYCTX, test_imp_clb, (void *)mod_imp_yin);
@ -1887,6 +1883,225 @@ test_lysc_path(void **state)
free(path);
}
/* TEST */
static ly_bool
compare_str_nodeset(struct ly_set *expected, struct ly_set *received)
{
ly_bool is_error = 0;
size_t r;
size_t e;
for (e = 0; expected && e < expected->count; e++) {
const char *epath = expected->objs[e];
ly_bool found = 0;
for (r = 0; received && (r < received->count); r++) {
const char *rpath = received->objs[r];
if (!strcmp(epath, rpath)) {
found = 1;
break;
}
}
if (!found) {
fprintf(stderr, "< %s\n", epath);
is_error = 1;
}
}
/* If the count was equal and there was no error, no need to scan again */
if (expected && received && (expected->count == received->count) && !is_error) {
return 1;
}
for (r = 0; received && (r < received->count); r++) {
ly_bool found = 0;
const char *rpath = received->objs[r];
for (e = 0; expected && (e < expected->count) && !found; e++) {
char *epath = expected->objs[e];
if (!strcmp(epath, rpath)) {
found = 1;
break;
}
}
if (!found) {
fprintf(stderr, "> %s\n", rpath);
}
}
return 0;
}
static struct ly_set *
strlist_to_pathset(const char **pathlist)
{
struct ly_set *set = NULL;
uint32_t i;
if (!pathlist || !pathlist[0]) {
return NULL;
}
ly_set_new(&set);
for (i = 0; pathlist[i]; i++) {
ly_set_add(set, pathlist[i], 0, NULL);
}
return set;
}
static struct ly_set *
lysc_nodeset_to_pathset(struct ly_set *nodeset)
{
struct ly_set *set = NULL;
uint32_t i;
if (!nodeset || !nodeset->count) {
return NULL;
}
ly_set_new(&set);
for (i = 0; i < nodeset->count; i++) {
char *path = lysc_path(nodeset->snodes[i], LYSC_PATH_DATA, NULL, 0);
ly_set_add(set, path, 0, NULL);
}
return set;
}
static void
test_lysc_backlinks(void **state)
{
const char *expect1[] = {
/* Built-ins, not sure how to exclude those when not limiting by
* path */
"/ietf-yang-library:yang-library/module-set/module/deviation",
"/ietf-yang-library:yang-library/schema/module-set",
"/ietf-yang-library:yang-library/datastore/schema",
"/ietf-yang-library:yang-library-update/content-id",
"/ietf-yang-library:yang-library-change/module-set-id",
/* Normal expected */
"/b:my_extref_list/my_extref",
"/a:refstr",
"/a:refnum",
"/b:my_extref_union",
NULL
};
const char *expect2[] = {
"/b:my_extref_list/my_extref",
"/a:refstr",
"/b:my_extref_union",
NULL
};
const char *expect3[] = {
"/b:my_extref_list/my_extref",
"/a:refstr",
"/a:refnum",
"/b:my_extref_union",
NULL
};
struct {
const char *match_path;
ly_bool match_ancestors;
const char **expected_paths;
} tests[] = {
{NULL, 0, expect1},
{"/a:my_list/my_leaf_string", 0, expect2},
{"/a:my_list", 1, expect3}
};
const char *str;
uint32_t i;
str = "module a {\n"
" namespace urn:a;\n"
" prefix a;\n"
" list my_list {\n"
" key my_leaf_string;\n"
" leaf my_leaf_string {\n"
" type string;\n"
" }\n"
" leaf my_leaf_number {\n"
" type uint32;\n"
" }\n"
" }\n"
" leaf refstr {\n"
" type leafref {\n"
" path \"../my_list/my_leaf_string\";\n"
" }\n"
" }\n"
" leaf refnum {\n"
" type leafref {\n"
" path \"../my_list/my_leaf_number\";\n"
" }\n"
" }\n"
"}\n";
assert_int_equal(lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, NULL), LY_SUCCESS);
CHECK_LOG_CTX(NULL, NULL, 0);
str = "module b {\n"
" namespace urn:b;\n"
" prefix b;\n"
" import a {\n"
" prefix a;\n"
" }\n"
" list my_extref_list {\n"
" key my_leaf_string;\n"
" leaf my_leaf_string {\n"
" type string;\n"
" }\n"
" leaf my_extref {\n"
" type leafref {\n"
" path \"/a:my_list/a:my_leaf_string\";\n"
" }\n"
" }\n"
" }\n"
" leaf my_extref_union {\n"
" type union {\n"
" type leafref {\n"
" path \"/a:my_list/a:my_leaf_string\";\n"
" }\n"
" type leafref {\n"
" path \"/a:my_list/a:my_leaf_number\";\n"
" }\n"
" type uint32;\n"
" }\n"
" }\n"
"}\n";
assert_int_equal(lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, NULL), LY_SUCCESS);
CHECK_LOG_CTX(NULL, NULL, 0);
for (i = 0; i < sizeof tests / sizeof *tests; i++) {
const struct lysc_node *node = NULL;
struct ly_set *set = NULL, *expected = NULL, *received = NULL;
if (tests[i].match_path) {
node = lys_find_path(UTEST_LYCTX, NULL, tests[i].match_path, 0);
assert_non_null(node);
}
assert_int_equal(LY_SUCCESS, lysc_node_lref_backlinks(UTEST_LYCTX, node, tests[i].match_ancestors, &set));
expected = strlist_to_pathset(tests[i].expected_paths);
received = lysc_nodeset_to_pathset(set);
assert_int_equal(1, compare_str_nodeset(expected, received));
ly_set_free(expected, NULL);
ly_set_free(received, free);
ly_set_free(set, NULL);
}
}
int
main(void)
{
@ -1909,6 +2124,7 @@ main(void)
UTEST(test_extension_compile),
UTEST(test_ext_recursive),
UTEST(test_lysc_path),
UTEST(test_lysc_backlinks),
};
return cmocka_run_group_tests(tests, NULL, NULL);

View file

@ -78,7 +78,7 @@ test_module(void **state)
str = "module test {namespace urn:test; prefix t;"
"feature f1;feature f2 {if-feature f1;}}";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
assert_int_equal(LY_SUCCESS, lys_parse_in(UTEST_LYCTX, in, LYS_IN_YANG, NULL, NULL, &unres.creating, &mod));
assert_int_equal(LY_SUCCESS, lys_parse_in(UTEST_LYCTX, in, LYS_IN_YANG, NULL, &unres.creating, &mod));
lys_unres_glob_erase(&unres);
ly_in_free(in, 0);
assert_int_equal(0, mod->implemented);
@ -104,7 +104,7 @@ test_module(void **state)
/* submodules cannot be compiled directly */
str = "submodule test {belongs-to xxx {prefix x;}}";
assert_int_equal(LY_SUCCESS, ly_in_new_memory(str, &in));
assert_int_equal(LY_EINVAL, lys_parse_in(UTEST_LYCTX, in, LYS_IN_YANG, NULL, NULL, &unres.creating, NULL));
assert_int_equal(LY_EINVAL, lys_parse_in(UTEST_LYCTX, in, LYS_IN_YANG, NULL, &unres.creating, NULL));
lys_unres_glob_erase(&unres);
ly_in_free(in, 0);
CHECK_LOG_CTX("Input data contains submodule which cannot be parsed directly without its main module.", NULL, 0);

View file

@ -886,18 +886,16 @@ test_module(void **state)
/* include */
ly_ctx_set_module_imp_clb(PARSER_CUR_PMOD(YCTX)->mod->ctx, test_imp_clb, "module xxx { namespace urn:xxx; prefix x;}");
in.current = "module" SCHEMA_BEGINNING "include xxx;}";
assert_int_equal(lys_parse_mem(PARSER_CUR_PMOD(YCTX)->mod->ctx, in.current, LYS_IN_YANG, NULL), LY_EVALID);
assert_int_equal(lys_parse_mem(PARSER_CUR_PMOD(YCTX)->mod->ctx, in.current, LYS_IN_YANG, NULL), LY_EINVAL);
CHECK_LOG_CTX("Parsing module \"name\" failed.", NULL, 0);
CHECK_LOG_CTX("Including \"xxx\" submodule into \"name\" failed.", NULL, 0);
CHECK_LOG_CTX("Data model \"xxx\" not found in local searchdirs.", NULL, 0);
CHECK_LOG_CTX("Parsing submodule failed.", NULL, 0);
CHECK_LOG_CTX("Parsing submodule \"xxx\" failed.", NULL, 0);
CHECK_LOG_CTX("Input data contains module in situation when a submodule is expected.", NULL, 0);
ly_ctx_set_module_imp_clb(PARSER_CUR_PMOD(YCTX)->mod->ctx, test_imp_clb, "submodule xxx {belongs-to wrong-name {prefix w;}}");
in.current = "module" SCHEMA_BEGINNING "include xxx;}";
assert_int_equal(lys_parse_mem(PARSER_CUR_PMOD(YCTX)->mod->ctx, in.current, LYS_IN_YANG, NULL), LY_EVALID);
CHECK_LOG_CTX("Parsing module \"name\" failed.", NULL, 0);
CHECK_LOG_CTX("Including \"xxx\" submodule into \"name\" failed.", NULL, 0);
CHECK_LOG_CTX("Parsing submodule \"xxx\" failed.", NULL, 0);
UTEST_LOG_CTX_CLEAN;
ly_ctx_set_module_imp_clb(PARSER_CUR_PMOD(YCTX)->mod->ctx, test_imp_clb, "submodule xxx {belongs-to name {prefix x;}}");

View file

@ -111,11 +111,11 @@ test_schema_yang(void **state)
CHECK_LYSC_NODE_LEAF(lysc_leaf, NULL, 0, 0x5, 1, "port", 0, 0, 0, NULL, 0, 0, NULL, NULL);
lysc_type = (struct lysc_type_bits *) lysc_leaf->type;
CHECK_LYSC_TYPE_BITS(lysc_type, 0, 5);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[0]), 0, NULL, 0, 0, "zero", NULL);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[1]), 1, NULL, 0, 0, "one", NULL);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[2]), 10, NULL, 0, 0, "ten", NULL);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[3]), 11, NULL, 0, 0, "eleven", NULL);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[4]), 4294967295, NULL, 0, 0, "last", NULL);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[0]), 0, NULL, 0, LYS_STATUS_CURR, "zero", NULL);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[1]), 1, NULL, 0, LYS_STATUS_CURR, "one", NULL);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[2]), 10, NULL, 0, LYS_STATUS_CURR, "ten", NULL);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[3]), 11, NULL, 0, LYS_STATUS_CURR, "eleven", NULL);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[4]), 4294967295, NULL, 0, LYS_STATUS_CURR, "last", NULL);
lysp_leaf = (void *)mod->parsed->data;
CHECK_LYSP_NODE_LEAF(lysp_leaf, NULL, 0, 0x0, 0, "port", 0, 0, NULL, 0, 0, NULL, NULL);
CHECK_LYSP_TYPE(&(lysp_leaf->type), 0, 5, 0, 0, 0, 0x02, 0, 0, "bits", 0, 0, 1, 0, 0, 0);
@ -128,10 +128,10 @@ test_schema_yang(void **state)
CHECK_LYSC_NODE_LEAF(lysc_leaf, NULL, 0, 0x5, 1, "port", 0, 0, 0, NULL, 0, 0, NULL, NULL);
lysc_type = (struct lysc_type_bits *) lysc_leaf->type;
CHECK_LYSC_TYPE_BITS(lysc_type, 0, 4);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[0]), 2, NULL, 0, 0, "_two", NULL);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[1]), 10, NULL, 0, 0, "_ten", NULL);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[2]), 11, NULL, 0, 0, "_ten-one", NULL);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[3]), 12, NULL, 0, 0, "ten_end...", NULL);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[0]), 2, NULL, 0, LYS_STATUS_CURR, "_two", NULL);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[1]), 10, NULL, 0, LYS_STATUS_CURR, "_ten", NULL);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[2]), 11, NULL, 0, LYS_STATUS_CURR, "_ten-one", NULL);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[3]), 12, NULL, 0, LYS_STATUS_CURR, "ten_end...", NULL);
lysp_leaf = (void *)mod->parsed->data;
CHECK_LYSP_NODE_LEAF(lysp_leaf, NULL, 0, 0x0, 0, "port", 0, 0, NULL, 0, 0, NULL, NULL);
CHECK_LYSP_TYPE(&(lysp_leaf->type), 0, 4, 0, 0, 0, 0x02, 0, 0, "bits", 0, 0, 1, 0, 0, 0);
@ -146,10 +146,10 @@ test_schema_yang(void **state)
CHECK_LYSC_NODE_LEAF(lysc_leaf, NULL, 0, 0x5, 1, "port", 0, 0, 0, NULL, 0, 0, NULL, NULL);
lysc_type = (struct lysc_type_bits *) lysc_leaf->type;
CHECK_LYSC_TYPE_BITS(lysc_type, 0, 4);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[0]), 2, NULL, 0, 0, "two", NULL);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[1]), 10, NULL, 0, 0, "ten", NULL);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[2]), 11, NULL, 0, 0, "eleven", NULL);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[3]), 12, NULL, 0, 0, "twelve", NULL);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[0]), 2, NULL, 0, LYS_STATUS_CURR, "two", NULL);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[1]), 10, NULL, 0, LYS_STATUS_CURR, "ten", NULL);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[2]), 11, NULL, 0, LYS_STATUS_CURR, "eleven", NULL);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[3]), 12, NULL, 0, LYS_STATUS_CURR, "twelve", NULL);
lysp_leaf = (void *)mod->parsed->data;
CHECK_LYSP_NODE_LEAF(lysp_leaf, NULL, 0, 0x0, 0, "port", 0, 0, NULL, 0, 0, NULL, NULL);
CHECK_LYSP_TYPE(&(lysp_leaf->type), 0, 0, 0, 0, 0, 0, 0, 0, "my_type", 0, 0, 1, 0, 0, 0);
@ -164,8 +164,8 @@ test_schema_yang(void **state)
CHECK_LYSC_NODE_LEAF(lysc_leaf, NULL, 0, 0x5, 1, "port", 0, 0, 0, NULL, 0, 0, NULL, NULL);
lysc_type = (struct lysc_type_bits *) lysc_leaf->type;
CHECK_LYSC_TYPE_BITS(lysc_type, 0, 2);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[0]), 2, NULL, 0, 0, "two", NULL);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[1]), 10, NULL, 0, 0, "ten", NULL);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[0]), 2, NULL, 0, LYS_STATUS_CURR, "two", NULL);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[1]), 10, NULL, 0, LYS_STATUS_CURR, "ten", NULL);
lysp_leaf = (void *)mod->parsed->data;
CHECK_LYSP_NODE_LEAF(lysp_leaf, NULL, 0, 0x0, 0, "port", 0, 0, NULL, 0, 0, NULL, NULL);
CHECK_LYSP_TYPE(&(lysp_leaf->type), 0, 2, 0, 0, 0, 0x02, 0, 0, "my_type", 0, 0, 1, 0, 0, 0);
@ -281,9 +281,9 @@ test_schema_yang(void **state)
CHECK_LYSC_NODE_LEAF(lysc_leaf, NULL, 0, 0x5, 1, "port", 0, 0, 0, NULL, 0, 0, NULL, NULL);
lysc_type = (struct lysc_type_bits *) lysc_leaf->type;
CHECK_LYSC_TYPE_BITS(lysc_type, 0, 3);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[0]), 0, NULL, 0, 0, "zero", NULL);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[1]), 1, NULL, 0, 0, "one", NULL);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[2]), 11, NULL, 0, 0, "eleven", NULL);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[0]), 0, NULL, 0, LYS_STATUS_CURR, "zero", NULL);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[1]), 1, NULL, 0, LYS_STATUS_CURR, "one", NULL);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[2]), 11, NULL, 0, LYS_STATUS_CURR, "eleven", NULL);
lysp_leaf = (void *)mod->parsed->data;
CHECK_LYSP_NODE_LEAF(lysp_leaf, NULL, 0, 0x0, 0, "port", 0, 0, NULL, 0, 0, NULL, NULL);
CHECK_LYSP_TYPE(&(lysp_leaf->type), 0, 4, 0, 0, 0, 0x02, 0, 0, "bits", 0, 0, 1, 0, 0, 0);
@ -300,10 +300,10 @@ test_schema_yang(void **state)
CHECK_LYSC_NODE_LEAF(lysc_leaf, NULL, 0, 0x5, 1, "port", 0, 0, 0, NULL, 0, 0, NULL, NULL);
lysc_type = (struct lysc_type_bits *) lysc_leaf->type;
CHECK_LYSC_TYPE_BITS(lysc_type, 0, 4);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[0]), 0, NULL, 0, 0, "zero", NULL);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[1]), 1, NULL, 0, 0, "one", NULL);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[2]), 10, NULL, 0, 0, "ten", NULL);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[3]), 11, NULL, 0, 0, "eleven", NULL);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[0]), 0, NULL, 0, LYS_STATUS_CURR, "zero", NULL);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[1]), 1, NULL, 0, LYS_STATUS_CURR, "one", NULL);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[2]), 10, NULL, 0, LYS_STATUS_CURR, "ten", NULL);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[3]), 11, NULL, 0, LYS_STATUS_CURR, "eleven", NULL);
lysp_leaf = (void *)mod->parsed->data;
CHECK_LYSP_NODE_LEAF(lysp_leaf, NULL, 0, 0x0, 0, "port", 0, 0, NULL, 0, 0, NULL, NULL);
CHECK_LYSP_TYPE(&(lysp_leaf->type), 0, 4, 0, 0, 0, 0x02, 0, 0, "bits", 0, 0, 1, 0, 0, 0);
@ -331,11 +331,11 @@ test_schema_yin(void **state)
CHECK_LYSC_NODE_LEAF(lysc_leaf, NULL, 0, 0x5, 1, "port", 0, 0, 0, NULL, 0, 0, NULL, NULL);
lysc_type = (struct lysc_type_bits *) lysc_leaf->type;
CHECK_LYSC_TYPE_BITS(lysc_type, 0, 5);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[0]), 0, NULL, 0, 0, "zero", NULL);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[1]), 1, NULL, 0, 0, "one", NULL);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[2]), 10, NULL, 0, 0, "ten", NULL);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[3]), 11, NULL, 0, 0, "eleven", NULL);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[4]), 4294967295, NULL, 0, 0, "last", NULL);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[0]), 0, NULL, 0, LYS_STATUS_CURR, "zero", NULL);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[1]), 1, NULL, 0, LYS_STATUS_CURR, "one", NULL);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[2]), 10, NULL, 0, LYS_STATUS_CURR, "ten", NULL);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[3]), 11, NULL, 0, LYS_STATUS_CURR, "eleven", NULL);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[4]), 4294967295, NULL, 0, LYS_STATUS_CURR, "last", NULL);
lysp_leaf = (void *)mod->parsed->data;
CHECK_LYSP_NODE_LEAF(lysp_leaf, NULL, 0, 0x0, 0, "port", 0, 0, NULL, 0, 0, NULL, NULL);
CHECK_LYSP_TYPE(&(lysp_leaf->type), 0, 5, 0, 0, 0, 0x02, 0, 0, "bits", 0, 0, 1, 0, 0, 0);
@ -351,10 +351,10 @@ test_schema_yin(void **state)
CHECK_LYSC_NODE_LEAF(lysc_leaf, NULL, 0, 0x5, 1, "port", 0, 0, 0, NULL, 0, 0, NULL, NULL);
lysc_type = (struct lysc_type_bits *) lysc_leaf->type;
CHECK_LYSC_TYPE_BITS(lysc_type, 0, 4);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[0]), 2, NULL, 0, 0, "_two", NULL);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[1]), 10, NULL, 0, 0, "_ten", NULL);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[2]), 11, NULL, 0, 0, "_ten-one", NULL);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[3]), 12, NULL, 0, 0, "ten_end...", NULL);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[0]), 2, NULL, 0, LYS_STATUS_CURR, "_two", NULL);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[1]), 10, NULL, 0, LYS_STATUS_CURR, "_ten", NULL);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[2]), 11, NULL, 0, LYS_STATUS_CURR, "_ten-one", NULL);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[3]), 12, NULL, 0, LYS_STATUS_CURR, "ten_end...", NULL);
lysp_leaf = (void *)mod->parsed->data;
CHECK_LYSP_NODE_LEAF(lysp_leaf, NULL, 0, 0x0, 0, "port", 0, 0, NULL, 0, 0, NULL, NULL);
CHECK_LYSP_TYPE(&(lysp_leaf->type), 0, 4, 0, 0, 0, 0x02, 0, 0, "bits", 0, 0, 1, 0, 0, 0);
@ -373,10 +373,10 @@ test_schema_yin(void **state)
CHECK_LYSC_NODE_LEAF(lysc_leaf, NULL, 0, 0x5, 1, "port", 0, 0, 0, NULL, 0, 0, NULL, NULL);
lysc_type = (struct lysc_type_bits *) lysc_leaf->type;
CHECK_LYSC_TYPE_BITS(lysc_type, 0, 4);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[0]), 2, NULL, 0, 0, "two", NULL);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[1]), 10, NULL, 0, 0, "ten", NULL);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[2]), 11, NULL, 0, 0, "eleven", NULL);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[3]), 12, NULL, 0, 0, "twelve", NULL);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[0]), 2, NULL, 0, LYS_STATUS_CURR, "two", NULL);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[1]), 10, NULL, 0, LYS_STATUS_CURR, "ten", NULL);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[2]), 11, NULL, 0, LYS_STATUS_CURR, "eleven", NULL);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[3]), 12, NULL, 0, LYS_STATUS_CURR, "twelve", NULL);
lysp_leaf = (void *)mod->parsed->data;
CHECK_LYSP_NODE_LEAF(lysp_leaf, NULL, 0, 0x0, 0, "port", 0, 0, NULL, 0, 0, NULL, NULL);
CHECK_LYSP_TYPE(&(lysp_leaf->type), 0, 0, 0, 0, 0, 0, 0, 0, "my_type", 0, 0, 1, 0, 0, 0);
@ -396,8 +396,8 @@ test_schema_yin(void **state)
CHECK_LYSC_NODE_LEAF(lysc_leaf, NULL, 0, 0x5, 1, "port", 0, 0, 0, NULL, 0, 0, NULL, NULL);
lysc_type = (struct lysc_type_bits *) lysc_leaf->type;
CHECK_LYSC_TYPE_BITS(lysc_type, 0, 2);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[0]), 2, NULL, 0, 0, "two", NULL);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[1]), 10, NULL, 0, 0, "ten", NULL);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[0]), 2, NULL, 0, LYS_STATUS_CURR, "two", NULL);
CHECK_LYSC_TYPE_BITENUM_ITEM(&(lysc_type->bits[1]), 10, NULL, 0, LYS_STATUS_CURR, "ten", NULL);
lysp_leaf = (void *)mod->parsed->data;
CHECK_LYSP_NODE_LEAF(lysp_leaf, NULL, 0, 0x0, 0, "port", 0, 0, NULL, 0, 0, NULL, NULL);
CHECK_LYSP_TYPE(&(lysp_leaf->type), 0, 2, 0, 0, 0, 0x02, 0, 0, "my_type", 0, 0, 1, 0, 0, 0);

View file

@ -200,7 +200,7 @@ test_data_xml(void **state)
TEST_ERROR_XML2("<cont xmlns=\"urn:tests:mod\"/>",
"defs", "xmlns:m=\"urn:tests:mod\"", "l1", "[1]", LY_EVALID);
CHECK_LOG_CTX("Invalid instance-identifier \"[1]\" value - syntax error: Unexpected XPath token \"[\" (\"[1]\"), expected \"Operator(Path)\".",
CHECK_LOG_CTX("Invalid instance-identifier \"[1]\" value - syntax error: XPath \"[1]\" was expected to be absolute.",
"/defs:l1", 1);
TEST_ERROR_XML2("<cont xmlns=\"urn:tests:mod\"><l2/></cont>",

View file

@ -294,7 +294,7 @@ test_xpath_invalid_schema(void **state)
"leaf r1 {type leafref {path \"deref(../l1)/../l2/t2\";}}");
UTEST_INVALID_MODULE(schema1, LYS_IN_YANG, NULL, LY_EVALID)
CHECK_LOG_CTX("The deref function target node \"l1\" is not leaf nor leaflist", "/xp_test:r1", 0);
CHECK_LOG_CTX("Deref function target node \"l1\" is not leaf nor leaflist.", "/xp_test:r1", 0);
schema2 = MODULE_CREATE_YANG("xp_test",
"list l1 {key t1;"
@ -307,7 +307,7 @@ test_xpath_invalid_schema(void **state)
"leaf r2 {type leafref {path \"deref(../r1)/../l2/t2\";}}");
UTEST_INVALID_MODULE(schema2, LYS_IN_YANG, NULL, LY_EVALID)
CHECK_LOG_CTX("The deref function target node \"r1\" is not leafref", "/xp_test:r2", 0);
CHECK_LOG_CTX("Deref function target node \"r1\" is not leafref.", "/xp_test:r2", 0);
}
int

View file

@ -105,8 +105,8 @@ test_data_xml(void **state)
TEST_ERROR_XML2("",
"defs", "", "un1", "123456789012345678901", LY_EVALID);
CHECK_LOG_CTX("Invalid union value \"123456789012345678901\" - no matching subtype found:\n"
" libyang 2 - leafref, version 1: Invalid type int8 value \"123456789012345678901\".\n"
" libyang 2 - leafref, version 1: Invalid type int64 value \"123456789012345678901\".\n"
" libyang 2 - leafref, version 1: Invalid leafref value \"123456789012345678901\" - no target instance \"/int8\" with the same value.\n"
" libyang 2 - leafref, version 1: Invalid leafref value \"123456789012345678901\" - no target instance \"/int64\" with the same value.\n"
" libyang 2 - identityref, version 1: Invalid identityref \"123456789012345678901\" value - identity not found in module \"defs\".\n"
" libyang 2 - instance-identifier, version 1: Invalid instance-identifier \"123456789012345678901\" value - syntax error.\n"
" libyang 2 - string, version 1: Unsatisfied length - string \"123456789012345678901\" length is not allowed.\n",
@ -295,7 +295,8 @@ test_validation(void **state)
assert_int_equal(LY_EVALID, lyd_validate_all(&tree, NULL, LYD_VALIDATE_PRESENT, NULL));
CHECK_LOG_CTX("Invalid LYB union value - no matching subtype found:\n"
" libyang 2 - leafref, version 1: Invalid leafref value \"one\" - no target instance \"../../a/name\" with the same value.\n"
" libyang 2 - leafref, version 1: Invalid type uint32 value \"one\".\n", "/lref:test/community[name='test']/view", 0);
" libyang 2 - leafref, version 1: Invalid leafref value \"one\" - no target instance \"../../b/name\" with the same value.\n",
"/lref:test/community[name='test']/view", 0);
lyd_free_all(tree);
}

View file

@ -161,7 +161,8 @@ struct utest_context {
}
/**
* @brief Compare two lyd_node structure. Macro print lyd_node structure into string and then compare string. Print function use these two parameters. LYD_PRINT_WITHSIBLINGS | LYD_PRINT_SHRINK;
* @brief Compare two lyd_node structure. Macro print lyd_node structure into string and then compare string.
*
* @param[in] NODE_1 pointer to lyd_node
* @param[in] NODE_2 pointer to lyd_node
*/
@ -169,8 +170,8 @@ struct utest_context {
{ \
char *str1; \
char *str2; \
assert_int_equal(LY_SUCCESS, lyd_print_mem(&str1, NODE_1, LYD_XML, LYD_PRINT_WITHSIBLINGS | LYD_PRINT_SHRINK)); \
assert_int_equal(LY_SUCCESS, lyd_print_mem(&str2, NODE_2, LYD_XML, LYD_PRINT_WITHSIBLINGS | LYD_PRINT_SHRINK)); \
assert_int_equal(LY_SUCCESS, lyd_print_mem(&str1, NODE_1, LYD_XML, LYD_PRINT_WITHSIBLINGS)); \
assert_int_equal(LY_SUCCESS, lyd_print_mem(&str2, NODE_2, LYD_XML, LYD_PRINT_WITHSIBLINGS)); \
assert_non_null(str1); \
assert_non_null(str2); \
assert_string_equal(str1, str2); \
@ -1315,7 +1316,7 @@ utest_setup(void **state)
*state = current_utest_context;
/* libyang context */
assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, 0, &current_utest_context->ctx));
assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, LY_CTX_DISABLE_SEARCHDIR_CWD, &current_utest_context->ctx));
/* backup timezone, if any */
cur_tz = getenv("TZ");
@ -1325,6 +1326,8 @@ utest_setup(void **state)
/* set CET */
setenv("TZ", "CET+02:00", 1);
/* call tzset explicitly, to update the tzname, timezone and daylight global variables */
tzset();
return 0;
}

View file

@ -29,6 +29,7 @@
#include "cmd.h"
#include "common.h"
#include "compat.h"
#include "out.h"
#include "tools/config.h"
#include "yl_opt.h"
@ -228,7 +229,8 @@ help(int shortout)
static void
libyang_verbclb(LY_LOG_LEVEL level, const char *msg, const char *data_path, const char *schema_path, uint64_t line)
{
char *levstr;
const char *levstr;
char *full_msg = NULL, *aux;
switch (level) {
case LY_LLERR:
@ -244,15 +246,34 @@ libyang_verbclb(LY_LOG_LEVEL level, const char *msg, const char *data_path, cons
levstr = "dbg :";
break;
}
if (data_path) {
fprintf(stderr, "libyang %s %s (%s)\n", levstr, msg, data_path);
} else if (schema_path) {
fprintf(stderr, "libyang %s %s (%s)\n", levstr, msg, schema_path);
} else if (line) {
fprintf(stderr, "libyang %s %s (line %" PRIu64 ")\n", levstr, msg, line);
} else {
fprintf(stderr, "libyang %s %s\n", levstr, msg);
if (asprintf(&full_msg, "libyang %s %s", levstr, msg) == -1) {
goto error;
}
if (data_path || schema_path) {
if (asprintf(&aux, "%s (%s)", full_msg, data_path ? data_path : schema_path) == -1) {
goto error;
}
free(full_msg);
full_msg = aux;
}
if (line) {
if (asprintf(&aux, "%s (line %" PRIu64 ")", full_msg, line) == -1) {
goto error;
}
free(full_msg);
full_msg = aux;
}
fprintf(stderr, "%s\n", full_msg);
free(full_msg);
return;
error:
free(full_msg);
fprintf(stderr, "libyang %s Memory allocation failed.\n", levstr);
}
static struct yl_schema_features *