summaryrefslogtreecommitdiff
path: root/core/src
diff options
context:
space:
mode:
authorruki <[email protected]>2017-08-14 11:27:19 +0800
committerruki <[email protected]>2017-08-14 11:29:30 +0800
commitdba45d143d8aff047da82cbe1a881056e6e4bc00 (patch)
tree7b80d5de264c17b538a7c9d0fbb234ded39ac683 /core/src
parent34706ba053dda9dd86902cacf42a6c1878c85234 (diff)
merge repo and require codes
Diffstat (limited to 'core/src')
-rw-r--r--core/src/demo/makefile6
-rw-r--r--core/src/demo/xmake.lua13
-rw-r--r--core/src/makefile2
-rw-r--r--core/src/sv/.gitignore149
-rw-r--r--core/src/sv/.travis.yml107
-rw-r--r--core/src/sv/CMakeLists.txt93
-rw-r--r--core/src/sv/INSTALL364
-rw-r--r--core/src/sv/LICENSE24
-rw-r--r--core/src/sv/Makefile.am105
-rw-r--r--core/src/sv/README.md330
-rw-r--r--core/src/sv/UNLICENSE24
-rw-r--r--core/src/sv/appveyor.yml40
-rwxr-xr-xcore/src/sv/autogen.sh13
-rw-r--r--core/src/sv/codecov.yml2
-rw-r--r--core/src/sv/configure.ac77
-rw-r--r--core/src/sv/include/semver.h228
-rw-r--r--core/src/sv/m4/mm-libtool-library-versions.m430
-rw-r--r--core/src/sv/makefile29
-rw-r--r--core/src/sv/scripts/libsv.pc.in30
-rw-r--r--core/src/sv/src/comp.c382
-rw-r--r--core/src/sv/src/comp.h38
-rw-r--r--core/src/sv/src/id.c141
-rw-r--r--core/src/sv/src/id.h42
-rw-r--r--core/src/sv/src/num.c75
-rw-r--r--core/src/sv/src/num.h36
-rw-r--r--core/src/sv/src/range.c135
-rw-r--r--core/src/sv/src/range.h38
-rw-r--r--core/src/sv/src/semvers.c108
-rw-r--r--core/src/sv/src/semvers.h35
-rw-r--r--core/src/sv/src/utils.c96
-rw-r--r--core/src/sv/src/utils.h35
-rw-r--r--core/src/sv/src/version.c175
-rw-r--r--core/src/sv/src/version.h43
-rw-r--r--core/src/sv/test/CMakeLists.txt27
-rw-r--r--core/src/sv/test/comp.c333
-rw-r--r--core/src/sv/test/match.c357
-rw-r--r--core/src/sv/test/range.c200
-rw-r--r--core/src/sv/test/semver.c106
-rw-r--r--core/src/sv/test/semvers.c115
-rw-r--r--core/src/sv/test/usage.c46
-rw-r--r--core/src/sv/test/utils.c102
-rw-r--r--core/src/sv/test/version.c236
-rw-r--r--core/src/sv/test/xmake.lua45
-rw-r--r--core/src/sv/xmake.lua31
-rw-r--r--core/src/xmake/hash/prefix.h36
-rw-r--r--core/src/xmake/hash/sha256.c110
-rw-r--r--core/src/xmake/hash/uuid.c (renamed from core/src/xmake/os/uuid.c)2
-rw-r--r--core/src/xmake/machine.c36
-rw-r--r--core/src/xmake/makefile11
-rw-r--r--core/src/xmake/os/sleep.c53
-rw-r--r--core/src/xmake/semver/parse.c65
-rw-r--r--core/src/xmake/semver/prefix.h37
-rw-r--r--core/src/xmake/semver/satisfies.c78
-rw-r--r--core/src/xmake/semver/select.c160
-rw-r--r--core/src/xmake/semver/semver.c91
-rw-r--r--core/src/xmake/xmake.lua2
56 files changed, 5308 insertions, 16 deletions
diff --git a/core/src/demo/makefile b/core/src/demo/makefile
index 3a474649f..084e525fe 100644
--- a/core/src/demo/makefile
+++ b/core/src/demo/makefile
@@ -15,9 +15,9 @@ demo_PKGS-$(TBOX) += tbox
demo_PKGS-$(BASE) += base
# others
-demo_LIBS += xmake$(DTYPE) luajit$(DTYPE)
-demo_INC_DIRS += ../ ../luajit/src
-demo_LIB_DIRS += ../xmake ../luajit
+demo_LIBS += xmake$(DTYPE) luajit$(DTYPE) sv$(DTYPE)
+demo_INC_DIRS += ../ ../luajit/src ../sv/include
+demo_LIB_DIRS += ../xmake ../luajit ../sv
demo_CXFLAGS += -D__tb_prefix__=\"xmake\"
# suffix
diff --git a/core/src/demo/xmake.lua b/core/src/demo/xmake.lua
index 40d089f7f..520241669 100644
--- a/core/src/demo/xmake.lua
+++ b/core/src/demo/xmake.lua
@@ -2,7 +2,7 @@
target("demo")
-- add deps
- add_deps("xmake")
+ add_deps("sv", "luajit", "xmake")
-- make as a binary
set_kind("binary")
@@ -19,10 +19,6 @@ target("demo")
-- add includes directory
add_includedirs("$(projectdir)", "$(projectdir)/src", "$(buildir)/luajit")
- -- add links and directory
- add_links("xmake", "luajit")
- add_linkdirs("$(buildir)")
-
-- link readline
if not is_plat("windows") then
add_links("readline")
@@ -33,9 +29,14 @@ target("demo")
-- add the common source files
add_files("**.c")
+
+ -- for macosx
+ if is_plat("macosx") then
+ add_ldflags("-all_load", "-pagezero_size 10000", "-image_base 100000000")
+ end
-- add the resource files (it will be enabled after publishing new version)
if is_plat("windows") then
add_files("*.rc")
end
-
+
diff --git a/core/src/makefile b/core/src/makefile
index 139d4ac64..6636d2ad6 100644
--- a/core/src/makefile
+++ b/core/src/makefile
@@ -3,7 +3,7 @@ include $(PRO_DIR)/prefix.mak
# projects
SUB_PROS += demo
-DEP_PROS += luajit xmake
+DEP_PROS += sv luajit xmake
# suffix
include $(PRO_DIR)/suffix.mak
diff --git a/core/src/sv/.gitignore b/core/src/sv/.gitignore
new file mode 100644
index 000000000..51272dc42
--- /dev/null
+++ b/core/src/sv/.gitignore
@@ -0,0 +1,149 @@
+# Created by .ignore support plugin (hsz.mobi)
+### Autotools template
+# http://www.gnu.org/software/automake
+
+Makefile.in
+/ar-lib
+/mdate-sh
+/py-compile
+/test-driver
+/ylwrap
+
+# http://www.gnu.org/software/autoconf
+
+/autom4te.cache
+/autoscan.log
+/autoscan-*.log
+/aclocal.m4
+/compile
+/config.guess
+/config.h.in
+/config.sub
+/configure
+/configure.scan
+/depcomp
+/install-sh
+/missing
+/stamp-h1
+
+# https://www.gnu.org/software/libtool/
+
+/ltmain.sh
+
+# http://www.gnu.org/software/texinfo
+
+/texinfo.tex
+### CMake template
+CMakeCache.txt
+CMakeFiles
+CMakeScripts
+Testing
+Makefile
+cmake_install.cmake
+install_manifest.txt
+compile_commands.json
+CTestTestfile.cmake
+### C template
+# Prerequisites
+*.d
+
+# Object files
+*.o
+*.ko
+*.obj
+*.elf
+
+# Linker output
+*.ilk
+*.map
+*.exp
+
+# Precompiled Headers
+*.gch
+*.pch
+
+# Libraries
+*.lib
+*.a
+*.la
+*.lo
+
+# Shared objects (inc. Windows DLLs)
+*.dll
+*.so
+*.so.*
+*.dylib
+
+# Executables
+*.exe
+*.out
+*.app
+*.i*86
+*.x86_64
+*.hex
+
+# Debug files
+*.dSYM/
+*.su
+*.idb
+*.pdb
+
+# Kernel Module Compile Results
+*.mod*
+*.cmd
+modules.order
+Module.symvers
+Mkfile.old
+dkms.conf
+### JetBrains template
+# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
+# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
+
+# User-specific stuff:
+.idea/**/workspace.xml
+.idea/**/tasks.xml
+.idea/dictionaries
+
+# Sensitive or high-churn files:
+.idea/**/dataSources/
+.idea/**/dataSources.ids
+.idea/**/dataSources.xml
+.idea/**/dataSources.local.xml
+.idea/**/sqlDataSources.xml
+.idea/**/dynamic.xml
+.idea/**/uiDesigner.xml
+
+# Gradle:
+.idea/**/gradle.xml
+.idea/**/libraries
+
+# Mongo Explorer plugin:
+.idea/**/mongoSettings.xml
+
+## File-based project format:
+*.iws
+
+## Plugin-specific files:
+
+# IntelliJ
+/out/
+
+# mpeltonen/sbt-idea plugin
+.idea_modules/
+
+# JIRA plugin
+atlassian-ide-plugin.xml
+
+# Crashlytics plugin (for Android Studio and IntelliJ)
+com_crashlytics_export_strings.xml
+crashlytics.properties
+crashlytics-build.properties
+fabric.properties
+
+# Clion
+.idea/
+cmake-build-debug/
+
+# xmake
+.xmake/
+build/
diff --git a/core/src/sv/.travis.yml b/core/src/sv/.travis.yml
new file mode 100644
index 000000000..505409db5
--- /dev/null
+++ b/core/src/sv/.travis.yml
@@ -0,0 +1,107 @@
+sudo: false
+language: c
+
+before_install:
+ - bash <(curl -s https://raw.githubusercontent.com/tboox/xmake/master/scripts/get.sh)
+
+install:
+ - xmake
+ - cd build
+ - cmake ..
+ - make all
+
+script:
+ - ctest --verbose
+ - cd .. && xmake check
+
+matrix:
+ include:
+ - os: linux
+ - os: linux
+ compiler: gcc-4.9
+ addons:
+ apt:
+ sources:
+ - ubuntu-toolchain-r-test
+ packages:
+ - gcc-4.9
+ - os: linux
+ compiler: gcc-5
+ addons:
+ apt:
+ sources:
+ - ubuntu-toolchain-r-test
+ packages:
+ - gcc-5
+ - os: linux
+ compiler: gcc-6
+ addons:
+ apt:
+ sources:
+ - ubuntu-toolchain-r-test
+ packages:
+ - gcc-6
+ - os: linux
+ compiler: clang-3.5
+ addons:
+ apt:
+ sources:
+ - ubuntu-toolchain-r-test
+ - llvm-toolchain-precise-3.5
+ packages:
+ - clang-3.5
+ - os: linux
+ compiler: clang-3.6
+ addons:
+ apt:
+ sources:
+ - ubuntu-toolchain-r-test
+ - llvm-toolchain-precise-3.6
+ packages:
+ - clang-3.6
+ - os: linux
+ compiler: clang-3.7
+ addons:
+ apt:
+ sources:
+ - ubuntu-toolchain-r-test
+ - llvm-toolchain-precise-3.7
+ packages:
+ - clang-3.7
+ - os: linux
+ compiler: clang-3.8
+ addons:
+ apt:
+ sources:
+ - ubuntu-toolchain-r-test
+ - llvm-toolchain-precise-3.8
+ packages:
+ - clang-3.8
+ - os: linux
+ compiler: clang-3.9
+ addons:
+ apt:
+ sources:
+ - ubuntu-toolchain-r-test
+ - llvm-toolchain-precise-3.9
+ packages:
+ - clang-3.9
+ - os: linux
+ dist: trusty
+ compiler: clang-4.0
+ addons:
+ apt:
+ sources:
+ - ubuntu-toolchain-r-test
+ - llvm-toolchain-trusty-4.0
+ packages:
+ - clang-4.0
+ - os: osx
+ osx_image: xcode6.4
+ compiler: clang
+ - os: osx
+ osx_image: xcode7.3
+ compiler: clang
+ - os: osx
+ osx_image: xcode8.3
+ compiler: clang
diff --git a/core/src/sv/CMakeLists.txt b/core/src/sv/CMakeLists.txt
new file mode 100644
index 000000000..9a08b2b1c
--- /dev/null
+++ b/core/src/sv/CMakeLists.txt
@@ -0,0 +1,93 @@
+cmake_minimum_required(VERSION 2.8.7 FATAL_ERROR)
+project(sv)
+
+option(SHARED "Build as shared library" OFF)
+option(COVERAGE "Turn on COVERAGE support" OFF)
+
+if (COVERAGE AND NOT MSVC)
+ set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} --coverage")
+endif()
+
+if(CMAKE_VERSION VERSION_LESS "3.1")
+ if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
+ set(CMAKE_C_FLAGS "-std=c99 ${CMAKE_C_FLAGS}")
+ endif()
+else()
+ set(CMAKE_C_STANDARD 99)
+endif()
+
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
+if(MSVC)
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W3")
+else()
+ if ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0 -g3 -DDEBUG")
+ else()
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3")
+ endif()
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wextra -Werror -fomit-frame-pointer")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-missing-field-initializers -Wno-unused-parameter -Wno-unused-function")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-unused-variable -Wno-unused-value -Wno-unused-result")
+endif()
+
+set(sv_INCLUDE_DIR ${CMAKE_CURRENT_LIST_DIR}/include)
+set(sv_SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/src)
+set(sv_TEST_DIR ${CMAKE_CURRENT_LIST_DIR}/test)
+
+file(GLOB sv_HEADERS ${sv_HEADERS} ${sv_INCLUDE_DIR}/*.h)
+file(GLOB sv_SOURCES ${sv_SOURCES} ${sv_SOURCE_DIR}/*.c)
+
+include_directories(${sv_INCLUDE_DIR})
+if(SHARED)
+ if(MSVC)
+ set(CMAKE_FLAGS
+ CMAKE_CXX_FLAGS
+ CMAKE_CXX_FLAGS_DEBUG
+ CMAKE_CXX_FLAGS_RELEASE
+ CMAKE_C_FLAGS
+ CMAKE_C_FLAGS_DEBUG
+ CMAKE_C_FLAGS_RELEASE
+ )
+ foreach(CMAKE_FLAG ${CMAKE_FLAGS})
+ string(REPLACE "/MD" "/MT" ${CMAKE_FLAG} "${${CMAKE_FLAG}}")
+ string(REPLACE "/MDd" "/MTd" ${CMAKE_FLAG} "${${CMAKE_FLAG}}")
+ endforeach()
+ endif()
+
+ add_library(${PROJECT_NAME} SHARED ${sv_SOURCES} ${sv_HEADERS})
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DSV_BUILD_DYNAMIC_LINK=1")
+else()
+ add_library(${PROJECT_NAME} STATIC ${sv_SOURCES} ${sv_HEADERS})
+endif()
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DSV_COMPILE=1")
+
+enable_testing()
+add_subdirectory(${sv_TEST_DIR})
+
+if(WIN32)
+ set(CPACK_GENERATOR "WIX")
+ set(CPACK_SOURCE_GENERATOR "ZIP")
+elseif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
+ set(CPACK_GENERATOR "PackageMake")
+else()
+ set(CPACK_GENERATOR "DEB;RPM")
+ set(CPACK_SOURCE_GENERATOR "TGZ")
+endif()
+
+set(CPACK_DEBIAN_PACKAGE_MAINTAINER "Lucas Abel")
+
+set(CPACK_PACKAGE_VERSION "1.0.0")
+set(CPACK_PACKAGE_VERSION_MAJOR "1")
+set(CPACK_PACKAGE_VERSION_MINOR "0")
+set(CPACK_PACKAGE_VERSION_PATCH "0")
+
+set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_SOURCE_DIR}/README.md")
+set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/UNLICENSE")
+set(CPACK_RESOURCE_FILE_README "${CMAKE_SOURCE_DIR}/README.md")
+set(CPACK_RESOURCE_FILE_WELCOME "${CMAKE_SOURCE_DIR}/README.md")
+
+set(CPACK_SOURCE_IGNORE_FILES "${CMAKE_SOURCE_DIR}/build/;${CMAKE_SOURCE_DIR}/.git/")
+
+set(CPACK_SYSTEM_NAME "")
+
+include(CPack)
diff --git a/core/src/sv/INSTALL b/core/src/sv/INSTALL
new file mode 100644
index 000000000..64c69372e
--- /dev/null
+++ b/core/src/sv/INSTALL
@@ -0,0 +1,364 @@
+Installation Instructions
+*************************
+
+Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005,
+2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+
+ Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved. This file is offered as-is,
+without warranty of any kind.
+
+Basic Installation
+==================
+
+ Briefly, the shell commands `./configure; make; make install' should
+configure, build, and install this package. The following
+more-detailed instructions are generic; see the `README' file for
+instructions specific to this package. Some packages provide this
+`INSTALL' file but do not implement all of the features documented
+below. The lack of an optional feature in a given package is not
+necessarily a bug. More recommendations for GNU packages can be found
+in *note Makefile Conventions: (standards)Makefile Conventions.
+
+ The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation. It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions. Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, and a
+file `config.log' containing compiler output (useful mainly for
+debugging `configure').
+
+ It can also use an optional file (typically called `config.cache'
+and enabled with `--cache-file=config.cache' or simply `-C') that saves
+the results of its tests to speed up reconfiguring. Caching is
+disabled by default to prevent problems with accidental use of stale
+cache files.
+
+ If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release. If you are using the cache, and at
+some point `config.cache' contains results you don't want to keep, you
+may remove or edit it.
+
+ The file `configure.ac' (or `configure.in') is used to create
+`configure' by a program called `autoconf'. You need `configure.ac' if
+you want to change it or regenerate `configure' using a newer version
+of `autoconf'.
+
+ The simplest way to compile this package is:
+
+ 1. `cd' to the directory containing the package's source code and type
+ `./configure' to configure the package for your system.
+
+ Running `configure' might take a while. While running, it prints
+ some messages telling which features it is checking for.
+
+ 2. Type `make' to compile the package.
+
+ 3. Optionally, type `make check' to run any self-tests that come with
+ the package, generally using the just-built uninstalled binaries.
+
+ 4. Type `make install' to install the programs and any data files and
+ documentation. When installing into a prefix owned by root, it is
+ recommended that the package be configured and built as a regular
+ user, and only the `make install' phase executed with root
+ privileges.
+
+ 5. Optionally, type `make installcheck' to repeat any self-tests, but
+ this time using the binaries in their final installed location.
+ This target does not install anything. Running this target as a
+ regular user, particularly if the prior `make install' required
+ root privileges, verifies that the installation completed
+ correctly.
+
+ 6. You can remove the program binaries and object files from the
+ source code directory by typing `make clean'. To also remove the
+ files that `configure' created (so you can compile the package for
+ a different kind of computer), type `make distclean'. There is
+ also a `make maintainer-clean' target, but that is intended mainly
+ for the package's developers. If you use it, you may have to get
+ all sorts of other programs in order to regenerate files that came
+ with the distribution.
+
+ 7. Often, you can also type `make uninstall' to remove the installed
+ files again. In practice, not all packages have tested that
+ uninstallation works correctly, even though it is required by the
+ GNU Coding Standards.
+
+ 8. Some packages, particularly those that use Automake, provide `make
+ distcheck', which can by used by developers to test that all other
+ targets like `make install' and `make uninstall' work correctly.
+ This target is generally not run by end users.
+
+Compilers and Options
+=====================
+
+ Some systems require unusual options for compilation or linking that
+the `configure' script does not know about. Run `./configure --help'
+for details on some of the pertinent environment variables.
+
+ You can give `configure' initial values for configuration parameters
+by setting variables in the command line or in the environment. Here
+is an example:
+
+ ./configure CC=c99 CFLAGS=-g LIBS=-lposix
+
+ *Note Defining Variables::, for more details.
+
+Compiling For Multiple Architectures
+====================================
+
+ You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory. To do this, you can use GNU `make'. `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script. `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'. This
+is known as a "VPATH" build.
+
+ With a non-GNU `make', it is safer to compile the package for one
+architecture at a time in the source code directory. After you have
+installed the package for one architecture, use `make distclean' before
+reconfiguring for another architecture.
+
+ On MacOS X 10.5 and later systems, you can create libraries and
+executables that work on multiple system types--known as "fat" or
+"universal" binaries--by specifying multiple `-arch' options to the
+compiler but only a single `-arch' option to the preprocessor. Like
+this:
+
+ ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
+ CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
+ CPP="gcc -E" CXXCPP="g++ -E"
+
+ This is not guaranteed to produce working output in all cases, you
+may have to build one architecture at a time and combine the results
+using the `lipo' tool if you have problems.
+
+Installation Names
+==================
+
+ By default, `make install' installs the package's commands under
+`/usr/local/bin', include files under `/usr/local/include', etc. You
+can specify an installation prefix other than `/usr/local' by giving
+`configure' the option `--prefix=PREFIX', where PREFIX must be an
+absolute file name.
+
+ You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If you
+pass the option `--exec-prefix=PREFIX' to `configure', the package uses
+PREFIX as the prefix for installing programs and libraries.
+Documentation and other data files still use the regular prefix.
+
+ In addition, if you use an unusual directory layout you can give
+options like `--bindir=DIR' to specify different values for particular
+kinds of files. Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them. In general, the
+default for these options is expressed in terms of `${prefix}', so that
+specifying just `--prefix' will affect all of the other directory
+specifications that were not explicitly provided.
+
+ The most portable way to affect installation locations is to pass the
+correct locations to `configure'; however, many packages provide one or
+both of the following shortcuts of passing variable assignments to the
+`make install' command line to change installation locations without
+having to reconfigure or recompile.
+
+ The first method involves providing an override variable for each
+affected directory. For example, `make install
+prefix=/alternate/directory' will choose an alternate location for all
+directory configuration variables that were expressed in terms of
+`${prefix}'. Any directories that were specified during `configure',
+but not in terms of `${prefix}', must each be overridden at install
+time for the entire installation to be relocated. The approach of
+makefile variable overrides for each directory variable is required by
+the GNU Coding Standards, and ideally causes no recompilation.
+However, some platforms have known limitations with the semantics of
+shared libraries that end up requiring recompilation when using this
+method, particularly noticeable in packages that use GNU Libtool.
+
+ The second method involves providing the `DESTDIR' variable. For
+example, `make install DESTDIR=/alternate/directory' will prepend
+`/alternate/directory' before all installation names. The approach of
+`DESTDIR' overrides is not required by the GNU Coding Standards, and
+does not work on platforms that have drive letters. On the other hand,
+it does better at avoiding recompilation issues, and works well even
+when some directory options were not specified in terms of `${prefix}'
+at `configure' time.
+
+Optional Features
+=================
+
+ If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+ Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System). The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+ For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+ Some packages offer the ability to configure how verbose the
+execution of `make' will be. For these packages, running `./configure
+--enable-silent-rules' sets the default to minimal output, which can be
+overridden with `make V=1'; while running `./configure
+--disable-silent-rules' sets the default to verbose, which can be
+overridden with `make V=0'.
+
+Particular systems
+==================
+
+ On HP-UX, the default C compiler is not ANSI C compatible. If GNU
+CC is not installed, it is recommended to use the following options in
+order to use an ANSI C compiler:
+
+ ./configure CC="cc -Ae -D_XOPEN_SOURCE=500"
+
+and if that doesn't work, install pre-built binaries of GCC for HP-UX.
+
+ On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot
+parse its `<wchar.h>' header file. The option `-nodtk' can be used as
+a workaround. If GNU CC is not installed, it is therefore recommended
+to try
+
+ ./configure CC="cc"
+
+and if that doesn't work, try
+
+ ./configure CC="cc -nodtk"
+
+ On Solaris, don't put `/usr/ucb' early in your `PATH'. This
+directory contains several dysfunctional programs; working variants of
+these programs are available in `/usr/bin'. So, if you need `/usr/ucb'
+in your `PATH', put it _after_ `/usr/bin'.
+
+ On Haiku, software installed for all users goes in `/boot/common',
+not `/usr/local'. It is recommended to use the following options:
+
+ ./configure --prefix=/boot/common
+
+Specifying the System Type
+==========================
+
+ There may be some features `configure' cannot figure out
+automatically, but needs to determine by the type of machine the package
+will run on. Usually, assuming the package is built to be run on the
+_same_ architectures, `configure' can figure that out, but if it prints
+a message saying it cannot guess the machine type, give it the
+`--build=TYPE' option. TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name which has the form:
+
+ CPU-COMPANY-SYSTEM
+
+where SYSTEM can have one of these forms:
+
+ OS
+ KERNEL-OS
+
+ See the file `config.sub' for the possible values of each field. If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the machine type.
+
+ If you are _building_ compiler tools for cross-compiling, you should
+use the option `--target=TYPE' to select the type of system they will
+produce code for.
+
+ If you want to _use_ a cross compiler, that generates code for a
+platform different from the build platform, you should specify the
+"host" platform (i.e., that on which the generated programs will
+eventually be run) with `--host=TYPE'.
+
+Sharing Defaults
+================
+
+ If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists. Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Defining Variables
+==================
+
+ Variables not defined in a site shell script can be set in the
+environment passed to `configure'. However, some packages may run
+configure again during the build, and the customized values of these
+variables may be lost. In order to avoid this problem, you should set
+them in the `configure' command line, using `VAR=value'. For example:
+
+ ./configure CC=/usr/local2/bin/gcc
+
+causes the specified `gcc' to be used as the C compiler (unless it is
+overridden in the site shell script).
+
+Unfortunately, this technique does not work for `CONFIG_SHELL' due to
+an Autoconf bug. Until the bug is fixed you can use this workaround:
+
+ CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash
+
+`configure' Invocation
+======================
+
+ `configure' recognizes the following options to control how it
+operates.
+
+`--help'
+`-h'
+ Print a summary of all of the options to `configure', and exit.
+
+`--help=short'
+`--help=recursive'
+ Print a summary of the options unique to this package's
+ `configure', and exit. The `short' variant lists options used
+ only in the top level, while the `recursive' variant lists options
+ also present in any nested packages.
+
+`--version'
+`-V'
+ Print the version of Autoconf used to generate the `configure'
+ script, and exit.
+
+`--cache-file=FILE'
+ Enable the cache: use and save the results of the tests in FILE,
+ traditionally `config.cache'. FILE defaults to `/dev/null' to
+ disable caching.
+
+`--config-cache'
+`-C'
+ Alias for `--cache-file=config.cache'.
+
+`--quiet'
+`--silent'
+`-q'
+ Do not print messages saying which checks are being made. To
+ suppress all normal output, redirect it to `/dev/null' (any error
+ messages will still be shown).
+
+`--srcdir=DIR'
+ Look for the package's source code in directory DIR. Usually
+ `configure' can determine that directory automatically.
+
+`--prefix=DIR'
+ Use DIR as the installation prefix. *note Installation Names::
+ for more details, including other options available for fine-tuning
+ the installation locations.
+
+`--no-create'
+`-n'
+ Run the configure checks, but stop before creating any output
+ files.
+
+`configure' also accepts some other, not widely useful, options. Run
+`configure --help' for more details.
diff --git a/core/src/sv/LICENSE b/core/src/sv/LICENSE
new file mode 100644
index 000000000..cf1ab25da
--- /dev/null
+++ b/core/src/sv/LICENSE
@@ -0,0 +1,24 @@
+This is free and unencumbered software released into the public domain.
+
+Anyone is free to copy, modify, publish, use, compile, sell, or
+distribute this software, either in source code form or as a compiled
+binary, for any purpose, commercial or non-commercial, and by any
+means.
+
+In jurisdictions that recognize copyright laws, the author or authors
+of this software dedicate any and all copyright interest in the
+software to the public domain. We make this dedication for the benefit
+of the public at large and to the detriment of our heirs and
+successors. We intend this dedication to be an overt act of
+relinquishment in perpetuity of all present and future rights to this
+software under copyright law.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+For more information, please refer to <http://unlicense.org>
diff --git a/core/src/sv/Makefile.am b/core/src/sv/Makefile.am
new file mode 100644
index 000000000..a53382d22
--- /dev/null
+++ b/core/src/sv/Makefile.am
@@ -0,0 +1,105 @@
+## Process this file with automake to produce Makefile.in
+
+ACLOCAL_AMFLAGS = -I m4
+AUTOMAKE_OPTIONS = foreign
+dist_doc_DATA = UNLICENSE README.md
+AM_CFLAGS = -I$(srcdir)/src -I$(srcdir)/include -Wall $(AX_CFLAGS)
+
+## --------------------------------------------------------------------
+
+EXTRA_DIST = scripts/libsv.pc.in
+pkgconfigdir = $(libdir)/pkgconfig
+nodist_pkgconfig_DATA = scripts/libsv.pc
+
+## --------------------------------------------------------------------
+
+# Commented out because at present there is no Texinfo documentation
+# included. It will come later. (Marco Maggi; May 17, 2017)
+#
+# AM_MAKEINFOFLAGS = --no-split
+# info_TEXINFOS = doc/semver.texi
+# doc_semver_TEXINFOS = doc/macros.texi
+
+#page
+#### libraries
+
+libsv_CURRENT = @libsv_VERSION_INTERFACE_CURRENT@
+libsv_REVISION = @libsv_VERSION_INTERFACE_REVISION@
+libsv_AGE = @libsv_VERSION_INTERFACE_AGE@
+
+include_HEADERS = include/semver.h
+
+lib_LTLIBRARIES = libsv.la
+libsv_la_LDFLAGS = -version-info $(libsv_CURRENT):$(libsv_REVISION):$(libsv_AGE)
+libsv_la_SOURCES = \
+ src/comp.c \
+ src/id.c \
+ src/num.c \
+ src/range.c \
+ src/semvers.c \
+ src/version.c \
+ src/utils.c
+
+#page
+#### test
+
+check_PROGRAMS = \
+ test/version \
+ test/comp \
+ test/match \
+ test/range \
+ test/semvers \
+ test/utils \
+ test/usage
+
+TESTS = $(check_PROGRAMS)
+
+libsv_test_cppflags = -I$(srcdir)/src -I$(srcdir)/include
+libsv_test_ldadd = libsv.la
+
+test_version_CPPFLAGS = $(libsv_test_cppflags)
+test_version_LDADD = $(libsv_test_ldadd)
+
+test_comp_CPPFLAGS = $(libsv_test_cppflags)
+test_comp_LDADD = $(libsv_test_ldadd)
+
+test_match_CPPFLAGS = $(libsv_test_cppflags)
+test_match_LDADD = $(libsv_test_ldadd)
+
+test_range_CPPFLAGS = $(libsv_test_cppflags)
+test_range_LDADD = $(libsv_test_ldadd)
+
+test_semvers_CPPFLAGS = $(libsv_test_cppflags)
+test_semvers_LDADD = $(libsv_test_ldadd)
+
+test_utils_CPPFLAGS = $(libsv_test_cppflags)
+test_utils_LDADD = $(libsv_test_ldadd)
+
+test_usage_CPPFLAGS = $(libsv_test_cppflags)
+test_usage_LDADD = $(libsv_test_ldadd)
+
+installcheck-local: $(TEST)
+ @for f in $(TEST); do $(builddir)/$$f; done
+
+#page
+#### Static analysis with Clang's Static Analyzer
+#
+# See the documentation for the command line tool at:
+#
+# <http://clang-analyzer.llvm.org/scan-build.html>
+#
+# To run the tool we must do:
+#
+# $ make clean
+# $ make clang-static-analysis
+#
+# The program "scan-build" works by overriding the CC and CXX
+# environment variables.
+#
+
+.PHONY: clang-static-analysis
+
+clang-static-analysis:
+ scan-build make
+
+### end of file
diff --git a/core/src/sv/README.md b/core/src/sv/README.md
new file mode 100644
index 000000000..e55d9718d
--- /dev/null
+++ b/core/src/sv/README.md
@@ -0,0 +1,330 @@
+# libsv
+libsv - Public domain semantic versioning in c
+
+[![Build Status](https://travis-ci.org/uael/sv.svg?branch=master)](https://travis-ci.org/uael/sv)
+[![Build status](https://ci.appveyor.com/api/projects/status/7li44f9agk0u4dxc?svg=true)](https://ci.appveyor.com/project/uael/sv)
+[![codecov](https://codecov.io/gh/uael/sv/branch/master/graph/badge.svg)](https://codecov.io/gh/uael/sv)
+[![Codacy Badge](https://api.codacy.com/project/badge/Grade/b21f7acd11a9437c8fe79b0600dc205e)](https://www.codacy.com/app/lucas.abel/sv?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=uael/sv&amp;utm_campaign=Badge_Grade)
+
+# Topics
+- [Introduction](#introduction)
+- [License](#license)
+- [Install](#install)
+ - [xmake](#xmake)
+ - [cmake](#cmake)
+ - [autotools](#autotools)
+- [Usage](#usage)
+- [Credits](#credits)
+- [Bugs, vulnerabilities and contributions](#bugs-vulnerabilities-and-contributions)
+- [Resources](#resources)
+- [Badges and static analysis](#badges-and-static-analysis)
+ - [Travis CI](#travis-ci)
+ - [Clang's Static Analyzer](#clangs-static-analyzer)
+
+## Introduction
+
+This is free and unencumbered software released into the public domain.
+This package installs a C language library implementing semantic versioning for the C language.
+
+## License
+
+See the [UNLICENSE](https://github.com/uael/sv/blob/master/UNLICENSE) file.
+
+## Install
+
+### xmake
+
+[Install xmake build system (A make-like build utility based on Lua)](http://xmake.io)
+
+```bash
+$ xmake
+$ xmake check
+$ xmake install
+```
+
+### cmake
+
+```bash
+$ mkdir build && cd build
+$ cmake ..
+$ make
+$ make test
+$ make install
+```
+
+### autotools
+
+To install from a proper release tarball, do this:
+```bash
+$ cd libsv-3.1
+$ mkdir build
+$ cd build
+$ ../configure
+$ make
+$ make check
+$ make install
+```
+to inspect the available configuration options:
+```bash
+$ ../configure --help
+```
+The Makefile is designed to allow parallel builds, so we can do:
+```bash
+$ make -j4 all && make -j4 check
+```
+which, on a 4-core CPU, should speed up building and checking significantly.
+The Makefile supports the DESTDIR environment variable to install files in a temporary location, example: to see what will happen:
+```bash
+$ make -n install DESTDIR=/tmp/libsv
+```
+to really do it:
+```bash
+$ make install DESTDIR=/tmp/libsv
+```
+After the installation it is possible to verify the installed library against the test suite with:
+```bash
+$ make installcheck
+```
+From a repository checkout or snapshot (the ones from the Github site): we must install the GNU Autotools (GNU Automake, GNU Autoconf, GNU Libtool), then we must first run the script "autogen.sh" from the top source directory, to generate the needed files:
+```bash
+$ cd libsv
+$ sh autogen.sh
+```
+notice that "autogen.sh" will run the programs "autoreconf" and "libtoolize"; the latter is selected through the environment variable "LIBTOOLIZE", whose value can be customised; for example to run "glibtoolize" rather than "libtoolize" we do:
+```bash
+$ LIBTOOLIZE=glibtoolize sh autogen.sh
+```
+After this the procedure is the same as the one for building from a proper release tarball, but we have to enable maintainer mode:
+```bash
+$ ../configure --enable-maintainer-mode [options]
+$ make
+$ make check
+$ make install
+```
+
+## Usage
+
+```c
+...
+semver_t semver = {0};
+
+semver(&semver, "v1.2.3-alpha.1");
+
+assert(1 == semver.major);
+assert(2 == semver.minor);
+assert(3 == semver.patch);
+assert(0 == memcmp("alpha", semver.prerelease.raw, sizeof("alpha")-1));
+assert(0 == memcmp("1", semver.prerelease.next->raw, sizeof("1")-1));
+assert(true == semver_rmatch(semver, "1.2.1 || >=1.2.3-alpha <1.2.5"));
+
+semver_dtor(&semver);
+...
+```
+
+### Versions
+
+A "version" is described by the `v2.0.0` specification found at
+<http://semver.org/>.
+
+A leading `"v"` character is stripped off and ignored.
+
+### Ranges
+
+A `version range` is a set of `comparators` which specify versions
+that satisfy the range.
+
+A `comparator` is composed of an `operator` and a `version`. The set
+of primitive `operators` is:
+
+* `<` Less than
+* `<=` Less than or equal to
+* `>` Greater than
+* `>=` Greater than or equal to
+* `=` Equal. If no operator is specified, then equality is assumed,
+ so this operator is optional, but MAY be included.
+
+For example, the comparator `>=1.2.7` would match the versions
+`1.2.7`, `1.2.8`, `2.5.3`, and `1.3.9`, but not the versions `1.2.6`
+or `1.1.0`.
+
+Comparators can be joined by whitespace to form a `comparator set`,
+which is satisfied by the **intersection** of all of the comparators
+it includes.
+
+A range is composed of one or more comparator sets, joined by `||`. A
+version matches a range if and only if every comparator in at least
+one of the `||`-separated comparator sets is satisfied by the version.
+
+For example, the range `>=1.2.7 <1.3.0` would match the versions
+`1.2.7`, `1.2.8`, and `1.2.99`, but not the versions `1.2.6`, `1.3.0`,
+or `1.1.0`.
+
+The range `1.2.7 || >=1.2.9 <2.0.0` would match the versions `1.2.7`,
+`1.2.9`, and `1.4.6`, but not the versions `1.2.8` or `2.0.0`.
+
+#### Prerelease Tags
+
+If a version has a prerelease tag (for example, `1.2.3-alpha.3`) then
+it will only be allowed to satisfy comparator sets if at least one
+comparator with the same `[major, minor, patch]` tuple also has a
+prerelease tag.
+
+For example, the range `>1.2.3-alpha.3` would be allowed to match the
+version `1.2.3-alpha.7`, but it would *not* be satisfied by
+`3.4.5-alpha.9`, even though `3.4.5-alpha.9` is technically "greater
+than" `1.2.3-alpha.3` according to the SemVer sort rules. The version
+range only accepts prerelease tags on the `1.2.3` version. The
+version `3.4.5` *would* satisfy the range, because it does not have a
+prerelease flag, and `3.4.5` is greater than `1.2.3-alpha.7`.
+
+The purpose for this behavior is twofold. First, prerelease versions
+frequently are updated very quickly, and contain many breaking changes
+that are (by the author's design) not yet fit for public consumption.
+Therefore, by default, they are excluded from range matching
+semantics.
+
+Second, a user who has opted into using a prerelease version has
+clearly indicated the intent to use *that specific* set of
+alpha/beta/rc versions. By including a prerelease tag in the range,
+the user is indicating that they are aware of the risk. However, it
+is still not appropriate to assume that they have opted into taking a
+similar risk on the *next* set of prerelease versions.
+
+#### Advanced Range Syntax
+
+Advanced range syntax desugars to primitive comparators in
+deterministic ways.
+
+Advanced ranges may be combined in the same way as primitive
+comparators using white space or `||`.
+
+##### Hyphen Ranges `X.Y.Z - A.B.C`
+
+Specifies an inclusive set.
+
+* `1.2.3 - 2.3.4` := `>=1.2.3 <=2.3.4`
+
+If a partial version is provided as the first version in the inclusive
+range, then the missing pieces are replaced with zeroes.
+
+* `1.2 - 2.3.4` := `>=1.2.0 <=2.3.4`
+
+If a partial version is provided as the second version in the
+inclusive range, then all versions that start with the supplied parts
+of the tuple are accepted, but nothing that would be greater than the
+provided tuple parts.
+
+* `1.2.3 - 2.3` := `>=1.2.3 <2.4.0`
+* `1.2.3 - 2` := `>=1.2.3 <3.0.0`
+
+##### X-Ranges `1.2.x` `1.X` `1.2.*` `*`
+
+Any of `X`, `x`, or `*` may be used to "stand in" for one of the
+numeric values in the `[major, minor, patch]` tuple.
+
+* `*` := `>=0.0.0` (Any version satisfies)
+* `1.x` := `>=1.0.0 <2.0.0` (Matching major version)
+* `1.2.x` := `>=1.2.0 <1.3.0` (Matching major and minor versions)
+
+A partial version range is treated as an X-Range, so the special
+character is in fact optional.
+
+* `""` (empty string) := `*` := `>=0.0.0`
+* `1` := `1.x.x` := `>=1.0.0 <2.0.0`
+* `1.2` := `1.2.x` := `>=1.2.0 <1.3.0`
+
+##### Tilde Ranges `~1.2.3` `~1.2` `~1`
+
+Allows patch-level changes if a minor version is specified on the
+comparator. Allows minor-level changes if not.
+
+* `~1.2.3` := `>=1.2.3 <1.(2+1).0` := `>=1.2.3 <1.3.0`
+* `~1.2` := `>=1.2.0 <1.(2+1).0` := `>=1.2.0 <1.3.0` (Same as `1.2.x`)
+* `~1` := `>=1.0.0 <(1+1).0.0` := `>=1.0.0 <2.0.0` (Same as `1.x`)
+* `~0.2.3` := `>=0.2.3 <0.(2+1).0` := `>=0.2.3 <0.3.0`
+* `~0.2` := `>=0.2.0 <0.(2+1).0` := `>=0.2.0 <0.3.0` (Same as `0.2.x`)
+* `~0` := `>=0.0.0 <(0+1).0.0` := `>=0.0.0 <1.0.0` (Same as `0.x`)
+* `~1.2.3-beta.2` := `>=1.2.3-beta.2 <1.3.0` Note that prereleases in
+ the `1.2.3` version will be allowed, if they are greater than or
+ equal to `beta.2`. So, `1.2.3-beta.4` would be allowed, but
+ `1.2.4-beta.2` would not, because it is a prerelease of a
+ different `[major, minor, patch]` tuple.
+
+#### Caret Ranges `^1.2.3` `^0.2.5` `^0.0.4`
+
+Allows changes that do not modify the left-most non-zero digit in the
+`[major, minor, patch]` tuple. In other words, this allows patch and
+minor updates for versions `1.0.0` and above, patch updates for
+versions `0.X >=0.1.0`, and *no* updates for versions `0.0.X`.
+
+Many authors treat a `0.x` version as if the `x` were the major
+"breaking-change" indicator.
+
+Caret ranges are ideal when an author may make breaking changes
+between `0.2.4` and `0.3.0` releases, which is a common practice.
+However, it presumes that there will *not* be breaking changes between
+`0.2.4` and `0.2.5`. It allows for changes that are presumed to be
+additive (but non-breaking), according to commonly observed practices.
+
+* `^1.2.3` := `>=1.2.3 <2.0.0`
+* `^0.2.3` := `>=0.2.3 <0.3.0`
+* `^0.0.3` := `>=0.0.3 <0.0.4`
+* `^1.2.3-beta.2` := `>=1.2.3-beta.2 <2.0.0` Note that prereleases in
+ the `1.2.3` version will be allowed, if they are greater than or
+ equal to `beta.2`. So, `1.2.3-beta.4` would be allowed, but
+ `1.2.4-beta.2` would not, because it is a prerelease of a
+ different `[major, minor, patch]` tuple.
+* `^0.0.3-beta` := `>=0.0.3-beta <0.0.4` Note that prereleases in the
+ `0.0.3` version *only* will be allowed, if they are greater than or
+ equal to `beta`. So, `0.0.3-pr.2` would be allowed.
+
+When parsing caret ranges, a missing `patch` value desugars to the
+number `0`, but will allow flexibility within that value, even if the
+major and minor versions are both `0`.
+
+* `^1.2.x` := `>=1.2.0 <2.0.0`
+* `^0.0.x` := `>=0.0.0 <0.1.0`
+* `^0.0` := `>=0.0.0 <0.1.0`
+
+A missing `minor` and `patch` values will desugar to zero, but also
+allow flexibility within those values, even if the major version is
+zero.
+
+* `^1.x` := `>=1.0.0 <2.0.0`
+* `^0.x` := `>=0.0.0 <1.0.0`
+
+## Credits
+
+The stuff was written by Lucas Abel <https://github.com/uael> and contributors
+- Marco Maggi <https://github.com/marcomaggi>
+
+## Bugs, vulnerabilities and contributions
+
+Bug and vulnerability reports are appreciated, all the vulnerability reports are public; register them using the Issue Tracker at the project's Github site. For contributions and patches please use the Pull Requests feature at the project's Github site.
+
+Reports about the original code must be registered at:
+<https://github.com/uael/sv/issues>
+
+## Resources
+
+Development of the original projects takes place at:
+<https://github.com/uael/sv/>
+
+the GNU Project software can be found here:
+<https://www.gnu.org/>
+
+## Badges and static analysis
+
+### Travis CI
+
+Travis CI is a hosted, distributed continuous integration service used to build and test software projects hosted at GitHub. We can find this project's dashboards at:
+<https://travis-ci.org/uael/sv>
+
+Usage of this service is configured through the file ".travis.yml".
+
+### Clang's Static Analyzer
+
+The Clang Static Analyzer is a source code analysis tool that finds bugs in C, C++, and Objective-C programs. It is distributed along with Clang and we can find it at:
+<http://clang-analyzer.llvm.org/>
+
+Usage of this service is implemented with make rules; see the relevant section in the file "Makefile.am".
diff --git a/core/src/sv/UNLICENSE b/core/src/sv/UNLICENSE
new file mode 100644
index 000000000..cf1ab25da
--- /dev/null
+++ b/core/src/sv/UNLICENSE
@@ -0,0 +1,24 @@
+This is free and unencumbered software released into the public domain.
+
+Anyone is free to copy, modify, publish, use, compile, sell, or
+distribute this software, either in source code form or as a compiled
+binary, for any purpose, commercial or non-commercial, and by any
+means.
+
+In jurisdictions that recognize copyright laws, the author or authors
+of this software dedicate any and all copyright interest in the
+software to the public domain. We make this dedication for the benefit
+of the public at large and to the detriment of our heirs and
+successors. We intend this dedication to be an overt act of
+relinquishment in perpetuity of all present and future rights to this
+software under copyright law.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+For more information, please refer to <http://unlicense.org>
diff --git a/core/src/sv/appveyor.yml b/core/src/sv/appveyor.yml
new file mode 100644
index 000000000..fb1c88bd9
--- /dev/null
+++ b/core/src/sv/appveyor.yml
@@ -0,0 +1,40 @@
+version: "1.0.{build}"
+
+platform:
+ - Win32
+ - x64
+
+environment:
+ MSVC_DEFAULT_OPTIONS: ON
+ matrix:
+ - msvc: 'Visual Studio 12 2013'
+ - msvc: 'Visual Studio 14 2015'
+
+configuration:
+ - Debug
+ - Release
+
+init:
+ - cmd: cmake --version
+ - cmd: msbuild /version
+
+clone_folder: C:\projects\sv
+
+install:
+ - git submodule update --init --recursive
+
+before_build:
+ - cmd: cd C:\projects\sv
+ - cmd: md build
+ - cmd: cd build
+ - cmd: if "%platform%"=="Win32" set CMAKE_GENERATOR_NAME=%msvc%
+ - cmd: if "%platform%"=="x64" set CMAKE_GENERATOR_NAME=%msvc% Win64
+ - cmd: cmake -G "%CMAKE_GENERATOR_NAME%" -DCMAKE_BUILD_TYPE=%configuration% ..
+
+build:
+ project: C:\projects\sv\build\sv.sln
+ verbosity: quiet
+
+test_script:
+ - ps: cd C:\projects\sv\build
+ - cmd: ctest -VV
diff --git a/core/src/sv/autogen.sh b/core/src/sv/autogen.sh
new file mode 100755
index 000000000..586ab6a35
--- /dev/null
+++ b/core/src/sv/autogen.sh
@@ -0,0 +1,13 @@
+#!/bin/sh
+# autogen.sh --
+#
+# Run this in the top source directory to rebuild the infrastructure.
+
+LIBTOOLIZE=${LIBTOOLIZE:=libtoolize}
+
+set -xe
+test -d m4 || mkdir -p m4
+test -f m4/libtool.m4 || "$LIBTOOLIZE"
+autoreconf --warnings=all --install --verbose "$@"
+
+### end of file
diff --git a/core/src/sv/codecov.yml b/core/src/sv/codecov.yml
new file mode 100644
index 000000000..32f50be1c
--- /dev/null
+++ b/core/src/sv/codecov.yml
@@ -0,0 +1,2 @@
+ignore:
+ - "test" # ignore test folder and all its contents
diff --git a/core/src/sv/configure.ac b/core/src/sv/configure.ac
new file mode 100644
index 000000000..c6cbb6f48
--- /dev/null
+++ b/core/src/sv/configure.ac
@@ -0,0 +1,77 @@
+dnl @configure_input@
+dnl
+
+AC_PREREQ([2.69])
+AC_INIT([libsv],[0.0.1],,[libsv],[http://github.com/uael/sv])
+AC_COPYRIGHT([This is free and unencumbered software released into the public domain.
+
+Anyone is free to copy, modify, publish, use, compile, sell, or
+distribute this software, either in source code form or as a compiled
+binary, for any purpose, commercial or non-commercial, and by any means.
+
+In jurisdictions that recognize copyright laws, the author or authors of
+this software dedicate any and all copyright interest in the software to
+the public domain. We make this dedication for the benefit of the public
+at large and to the detriment of our heirs and successors. We intend
+this dedication to be an overt act of relinquishment in perpetuity of
+all present and future rights to this software under copyright law.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+For more information, please refer to <http://unlicense.org>
+])
+AC_CONFIG_SRCDIR([src])
+AC_CONFIG_MACRO_DIR([m4])
+AC_CONFIG_AUX_DIR([scripts])
+AC_CANONICAL_BUILD
+AC_CANONICAL_HOST
+AC_CANONICAL_TARGET
+AM_INIT_AUTOMAKE([foreign dist-xz no-dist-gzip subdir-objects])
+AM_MAINTAINER_MODE
+
+AM_PROG_AR
+AC_PROG_INSTALL
+AC_PROG_LN_S
+AC_PROG_MAKE_SET
+AC_PROG_MKDIR_P
+
+LT_PREREQ([2.4])
+LT_INIT
+
+dnl This is the version stored in the pkg-config data file.
+AC_SUBST([LIBSV_PKG_CONFIG_VERSION],[0.0.1])
+
+dnl page
+#### libraries interface version
+
+MM_LIBTOOL_LIBRARY_VERSIONS([libsv],1,0,0)
+
+dnl page
+#### basic system inspection
+
+AC_LANG([C])
+AM_PROG_AS
+AC_PROG_CC_C99
+AM_PROG_CC_C_O
+AC_HEADER_STDC
+
+AC_CACHE_SAVE
+
+dnl page
+#### finish
+
+AC_CONFIG_FILES([Makefile]
+ [scripts/libsv.pc])
+AC_OUTPUT
+
+### end of file
+# Local Variables:
+# mode: autoconf
+# page-delimiter: "^dnl page"
+# End:
diff --git a/core/src/sv/include/semver.h b/core/src/sv/include/semver.h
new file mode 100644
index 000000000..bdc005702
--- /dev/null
+++ b/core/src/sv/include/semver.h
@@ -0,0 +1,228 @@
+/*
+ * This is free and unencumbered software released into the public domain.
+ *
+ * Anyone is free to copy, modify, publish, use, compile, sell, or
+ * distribute this software, either in source code form or as a compiled
+ * binary, for any purpose, commercial or non-commercial, and by any
+ * means.
+ *
+ * In jurisdictions that recognize copyright laws, the author or authors
+ * of this software dedicate any and all copyright interest in the
+ * software to the public domain. We make this dedication for the benefit
+ * of the public at large and to the detriment of our heirs and
+ * successors. We intend this dedication to be an overt act of
+ * relinquishment in perpetuity of all present and future rights to this
+ * software under copyright law.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * For more information, please refer to <http://unlicense.org>
+ */
+
+#ifndef SV_H__
+# define SV_H__
+
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifndef SV_COMPILE
+# define SV_COMPILE (0)
+#endif
+
+#ifndef SV_BUILD_DYNAMIC_LINK
+# define SV_BUILD_DYNAMIC_LINK (0)
+#endif
+
+#if SV_BUILD_DYNAMIC_LINK && defined(_MSC_VER)
+# define SV_EXPORT_LINK __declspec(dllexport)
+# define SV_IMPORT_LINK __declspec(dllimport)
+#else
+# define SV_EXPORT_LINK
+# define SV_IMPORT_LINK
+#endif
+#if SV_COMPILE
+# ifdef __cplusplus
+# define SV_API extern "C" SV_EXPORT_LINK
+# else
+# define SV_API extern SV_EXPORT_LINK
+# endif
+#else
+# ifdef __cplusplus
+# define SV_API extern "C" SV_IMPORT_LINK
+# else
+# define SV_API extern SV_IMPORT_LINK
+# endif
+#endif
+
+#ifndef __cplusplus
+# if defined(_MSC_VER) && _MSC_VER < 1900
+# define bool unsigned char
+# define true 1
+# define false 0
+# define __bool_true_false_are_defined 1
+# else
+# include <stdbool.h>
+# endif
+#endif
+
+#if defined(_MSC_VER)
+typedef __int8 int8_t;
+typedef __int16 int16_t;
+typedef __int32 int32_t;
+typedef __int64 int64_t;
+typedef unsigned __int8 uint8_t;
+typedef unsigned __int16 uint16_t;
+typedef unsigned __int32 uint32_t;
+typedef unsigned __int64 uint64_t;
+#ifdef _WIN64
+typedef __int64 intptr_t;
+typedef unsigned __int64 uintptr_t;
+#else
+typedef __int32 intptr_t;
+typedef unsigned __int32 uintptr_t;
+#endif
+#else
+# include <stdint.h>
+#endif
+
+#ifndef sv_malloc
+# define sv_malloc malloc
+#endif
+
+#ifndef sv_free
+# define sv_free free
+#endif
+
+#define SEMVER_NUM_X (-1)
+
+#define semver(self, str) semvern(self, str, strlen(str))
+#define semver_write(self, buffer, len) semver_pwrite(&(self), buffer, len)
+#define semver_cmp(self, other) semver_pcmp(&(self), &(other))
+#define semver_comp(self, str) semver_compn(self, str, strlen(str))
+#define semver_comp_write(self, buffer, len) semver_comp_pwrite(&(self), buffer, len)
+#define semver_comp_match(self, comp) semver_comp_pmatch(&(self), &(comp))
+#define semver_match(self, comp_str) semver_comp_matchn(&(self), comp_str, strlen(comp_str))
+#define semver_range(self, str) semver_rangen(self, str, strlen(str))
+#define semver_range_write(self, buffer, len) semver_range_pwrite(&(self), buffer, len)
+#define semver_range_match(self, range) semver_range_pmatch(&(self), &(range))
+#define semver_rmatch(self, range_str) semver_range_matchn(&(self), range_str, strlen(range_str))
+
+typedef struct semver semver_t;
+typedef struct semver_id semver_id_t;
+typedef struct semver_comp semver_comp_t;
+typedef struct semver_range semver_range_t;
+typedef struct semvers semvers_t;
+
+enum semver_op {
+ SEMVER_OP_EQ = 0,
+ SEMVER_OP_LT,
+ SEMVER_OP_LE,
+ SEMVER_OP_GT,
+ SEMVER_OP_GE,
+};
+
+struct semver_id {
+ bool numeric;
+ int num;
+ size_t len;
+ const char *raw;
+ struct semver_id *next;
+};
+
+struct semver {
+ int major, minor, patch;
+ semver_id_t prerelease, build;
+ size_t len;
+ const char *raw;
+};
+
+SV_API char semvern(semver_t *self, const char *str, size_t len);
+SV_API char semver_tryn(semver_t *self, const char *str, size_t len);
+SV_API void semver_dtor(semver_t *self);
+SV_API int semver_pwrite(const semver_t *self, char *buffer, size_t len);
+SV_API size_t semver_fwrite (const semver_t *self, FILE * stream);
+SV_API char semver_pcmp(const semver_t *self, const semver_t *other);
+SV_API bool semver_comp_pmatch(const semver_t *self, const semver_comp_t *comp);
+SV_API bool semver_comp_matchn(const semver_t *self, const char *comp_str, size_t comp_len);
+SV_API bool semver_range_pmatch(const semver_t *self, const semver_range_t *range);
+SV_API bool semver_range_matchn(const semver_t *self, const char *range_str, size_t range_len);
+
+struct semver_comp {
+ struct semver_comp *next;
+ enum semver_op op;
+ semver_t version;
+};
+
+SV_API char semver_compn(semver_comp_t *self, const char *str, size_t len);
+SV_API void semver_comp_dtor(semver_comp_t *self);
+SV_API int semver_comp_pwrite(const semver_comp_t *self, char *buffer, size_t len);
+SV_API size_t semver_comp_fwrite (const semver_comp_t *self, FILE *stream);
+SV_API char semver_and(semver_comp_t *left, const char *str, size_t len);
+
+struct semver_range {
+ struct semver_range *next;
+ semver_comp_t comp;
+};
+
+SV_API char semver_rangen(semver_range_t *self, const char *str, size_t len);
+SV_API void semver_range_dtor(semver_range_t *self);
+SV_API int semver_range_pwrite(const semver_range_t *self, char *buffer, size_t len);
+SV_API size_t semver_range_fwrite (const semver_range_t *rangep, FILE *stream);
+SV_API char semver_or(semver_range_t *left, const char *str, size_t len);
+
+struct semvers {
+ uint32_t length, capacity;
+ semver_t *data;
+};
+
+SV_API uint32_t semvers_pgrowth(semvers_t *self, int32_t nmin);
+SV_API semver_t semvers_perase(semvers_t *self, uint32_t i);
+SV_API void semvers_psort(semvers_t *self);
+SV_API void semvers_prsort(semvers_t *self);
+SV_API void semvers_pdtor(semvers_t *self);
+SV_API void semvers_pclear(semvers_t *self);
+
+#define semvers_dtor(s) \
+ semvers_pdtor(&(s))
+
+#define semvers_clear(s) \
+ semvers_pclear(&(s))
+
+#define semvers_growth(s, n) \
+ semvers_pgrowth(&(s),n)
+
+#define semvers_grow(s, n) \
+ semvers_pgrowth(&(s),(s).length+(n))
+
+#define semvers_resize(s, n) \
+ ((s).length=semvers_growth(s, n))
+
+#define semvers_erase(s, i) \
+ semvers_perase(&(s), i)
+
+#define semvers_push(s, x) \
+ (semvers_grow(s,1),(s).data[(s).length++]=(x))
+
+#define semvers_pop(s) \
+ (s).data[--(s).length]
+
+#define semvers_unshift(s, x) \
+ (semvers_grow(s,1),memmove((s).data+1,(s).data,(s).length++*sizeof(semver_t)),(s).data[0]=(x))
+
+#define semvers_shift(s) \
+ semvers_erase(s, 0)
+
+#define semvers_sort(s) \
+ semvers_psort(&(s))
+
+#define semvers_rsort(s) \
+ semvers_prsort(&(s))
+
+#endif /* SV_H__ */
diff --git a/core/src/sv/m4/mm-libtool-library-versions.m4 b/core/src/sv/m4/mm-libtool-library-versions.m4
new file mode 100644
index 000000000..26f4194b0
--- /dev/null
+++ b/core/src/sv/m4/mm-libtool-library-versions.m4
@@ -0,0 +1,30 @@
+dnl mm-libtool-library-versions.m4
+
+dnl Set version numbers for libraries built with GNU Libtool.
+dnl
+dnl MM_LIBTOOL_LIBRARY_VERSIONS(stem,current,revision,age)
+dnl
+AC_DEFUN([MM_LIBTOOL_LIBRARY_VERSIONS],
+ [$1_VERSION_INTERFACE_CURRENT=$2
+ $1_VERSION_INTERFACE_REVISION=$3
+ $1_VERSION_INTERFACE_AGE=$4
+ AC_DEFINE_UNQUOTED([$1_VERSION_INTERFACE],
+ [$$1_VERSION_INTERFACE_CURRENT.$$1_VERSION_INTERFACE_REVISION.$$1_VERSION_INTERFACE_AGE],
+ [current interface number])
+ AC_DEFINE_UNQUOTED([$1_VERSION_INTERFACE_CURRENT],
+ [$$1_VERSION_INTERFACE_CURRENT],
+ [current interface number])
+ AC_DEFINE_UNQUOTED([$1_VERSION_INTERFACE_REVISION],
+ [$$1_VERSION_INTERFACE_REVISION],
+ [current interface implementation number])
+ AC_DEFINE_UNQUOTED([$1_VERSION_INTERFACE_AGE],
+ [$$1_VERSION_INTERFACE_AGE],
+ [current interface age number])
+ AC_DEFINE_UNQUOTED([$1_VERSION_INTERFACE_STRING],
+ ["$$1_VERSION_INTERFACE_CURRENT.$$1_VERSION_INTERFACE_REVISION"],
+ [library interface version])
+ AC_SUBST([$1_VERSION_INTERFACE_CURRENT])
+ AC_SUBST([$1_VERSION_INTERFACE_REVISION])
+ AC_SUBST([$1_VERSION_INTERFACE_AGE])])
+
+dnl end of file
diff --git a/core/src/sv/makefile b/core/src/sv/makefile
new file mode 100644
index 000000000..b7b8e543e
--- /dev/null
+++ b/core/src/sv/makefile
@@ -0,0 +1,29 @@
+# prefix
+include $(PRO_DIR)/prefix.mak
+
+# module name
+NAMES = sv
+
+# module type
+sv_TYPE = LIB
+
+# config
+sv_CONFIG = n
+
+# core files
+sv_C_FILES += \
+ src/comp \
+ src/id \
+ src/num \
+ src/range \
+ src/semvers \
+ src/utils \
+ src/version
+
+# includes
+sv_INC_DIRS += include
+
+
+# suffix
+include $(PRO_DIR)/suffix.mak
+
diff --git a/core/src/sv/scripts/libsv.pc.in b/core/src/sv/scripts/libsv.pc.in
new file mode 100644
index 000000000..bce3e8982
--- /dev/null
+++ b/core/src/sv/scripts/libsv.pc.in
@@ -0,0 +1,30 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+
+bindir=@bindir@
+datarootdir=@datarootdir@
+datadir=@datadir@
+docdir=${prefix}/doc
+includedir=@includedir@
+infodir=@infodir@
+htmldir=${docdir}
+libdir=@libdir@
+libexecdir=@libexecdir@
+localstatedir=@localstatedir@
+mandir=@mandir@
+sbindir=@sbindir@
+sharedstatedir=@sharedstatedir@
+sysconfdir=@sysconfdir@
+
+## ------------------------------------------------------------
+
+Name: @PACKAGE_NAME@
+Description: semantic versioning for the C language
+Version: @LIBSV_PKG_CONFIG_VERSION@
+Libs: -L${libdir} -lsv
+Cflags: -I${includedir}
+
+### end of file
+# Local Variables:
+# mode: script
+# End:
diff --git a/core/src/sv/src/comp.c b/core/src/sv/src/comp.c
new file mode 100644
index 000000000..d02fe4dfc
--- /dev/null
+++ b/core/src/sv/src/comp.c
@@ -0,0 +1,382 @@
+/*
+ * This is free and unencumbered software released into the public domain.
+ *
+ * Anyone is free to copy, modify, publish, use, compile, sell, or
+ * distribute this software, either in source code form or as a compiled
+ * binary, for any purpose, commercial or non-commercial, and by any
+ * means.
+ *
+ * In jurisdictions that recognize copyright laws, the author or authors
+ * of this software dedicate any and all copyright interest in the
+ * software to the public domain. We make this dedication for the benefit
+ * of the public at large and to the detriment of our heirs and
+ * successors. We intend this dedication to be an overt act of
+ * relinquishment in perpetuity of all present and future rights to this
+ * software under copyright law.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * For more information, please refer to <http://unlicense.org>
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "comp.h"
+#include "num.h"
+#include "id.h"
+#include "utils.h"
+
+static void semver_xrevert(semver_t *semver) {
+ if (semver->major == SEMVER_NUM_X) {
+ semver->major = semver->minor = semver->patch = 0;
+ } else if (semver->minor == SEMVER_NUM_X) {
+ semver->minor = semver->patch = 0;
+ } else if (semver->patch == SEMVER_NUM_X) {
+ semver->patch = 0;
+ }
+}
+
+static semver_comp_t *semver_xconvert(semver_comp_t *self) {
+ if (self->version.major == SEMVER_NUM_X) {
+ self->op = SEMVER_OP_GE;
+ semver_xrevert(&self->version);
+ return self;
+ }
+ if (self->version.minor == SEMVER_NUM_X) {
+ semver_xrevert(&self->version);
+ self->op = SEMVER_OP_GE;
+ self->next = (semver_comp_t *) sv_malloc(sizeof(semver_comp_t));
+ if (self->next == NULL) {
+ return NULL;
+ }
+ semver_comp_ctor(self->next);
+ self->next->op = SEMVER_OP_LT;
+ self->next->version = self->version;
+ ++self->next->version.major;
+ return self->next;
+ }
+ if (self->version.patch == SEMVER_NUM_X) {
+ semver_xrevert(&self->version);
+ self->op = SEMVER_OP_GE;
+ self->next = (semver_comp_t *) sv_malloc(sizeof(semver_comp_t));
+ if (self->next == NULL) {
+ return NULL;
+ }
+ semver_comp_ctor(self->next);
+ self->next->op = SEMVER_OP_LT;
+ self->next->version = self->version;
+ ++self->next->version.minor;
+ return self->next;
+ }
+ self->op = SEMVER_OP_EQ;
+ return self;
+}
+
+static char parse_partial(semver_t *self, const char *str, size_t len, size_t *offset) {
+ semver_ctor(self);
+ self->major = self->minor = self->patch = SEMVER_NUM_X;
+ if (*offset < len) {
+ self->raw = str + *offset;
+ if (semver_num_read(&self->major, str, len, offset)) {
+ return 0;
+ }
+ if (*offset >= len || str[*offset] != '.') {
+ return 0;
+ }
+ ++*offset;
+ if (semver_num_read(&self->minor, str, len, offset)) {
+ return 1;
+ }
+ if (*offset >= len || str[*offset] != '.') {
+ return 0;
+ }
+ ++*offset;
+ if (semver_num_read(&self->patch, str, len, offset)) {
+ return 1;
+ }
+ if ((str[*offset] == '-' && semver_id_read(&self->prerelease, str, len, (++*offset, offset)))
+ || (str[*offset] == '+' && semver_id_read(&self->build, str, len, (++*offset, offset)))) {
+ return 1;
+ }
+ self->len = str + *offset - self->raw;
+ return 0;
+ }
+ return 0;
+}
+
+static char parse_hiphen(semver_comp_t *self, const char *str, size_t len, size_t *offset) {
+ semver_t partial;
+
+ if (parse_partial(&partial, str, len, offset)) {
+ return 1;
+ }
+ self->op = SEMVER_OP_GE;
+ semver_xrevert(&self->version);
+ self->next = (semver_comp_t *) sv_malloc(sizeof(semver_comp_t));
+ if (self->next == NULL) {
+ return 1;
+ }
+ semver_comp_ctor(self->next);
+ self->next->op = SEMVER_OP_LT;
+ if (partial.minor == SEMVER_NUM_X) {
+ self->next->version.major = partial.major + 1;
+ } else if (partial.patch == SEMVER_NUM_X) {
+ self->next->version.major = partial.major;
+ self->next->version.minor = partial.minor + 1;
+ } else {
+ self->next->op = SEMVER_OP_LE;
+ self->next->version = partial;
+ }
+
+ return 0;
+}
+
+static char parse_tidle(semver_comp_t *self, const char *str, size_t len, size_t *offset) {
+ semver_t partial;
+
+ if (parse_partial(&self->version, str, len, offset)) {
+ return 1;
+ }
+ semver_xrevert(&self->version);
+ self->op = SEMVER_OP_GE;
+ partial = self->version;
+ if (partial.major != 0) {
+ ++partial.major;
+ partial.minor = partial.patch = 0;
+ } else if (partial.minor != 0) {
+ ++partial.minor;
+ partial.patch = 0;
+ } else {
+ ++partial.patch;
+ }
+ self->next = (semver_comp_t *) sv_malloc(sizeof(semver_comp_t));
+ if (self->next == NULL) {
+ return 1;
+ }
+ semver_comp_ctor(self->next);
+ self->next->op = SEMVER_OP_LT;
+ self->next->version = partial;
+ return 0;
+}
+
+static char parse_caret(semver_comp_t *self, const char *str, size_t len, size_t *offset) {
+ semver_t partial;
+
+ if (parse_partial(&self->version, str, len, offset)) {
+ return 1;
+ }
+ semver_xrevert(&self->version);
+ self->op = SEMVER_OP_GE;
+ partial = self->version;
+ if (partial.minor || partial.patch) {
+ ++partial.minor;
+ partial.patch = 0;
+ } else {
+ ++partial.major;
+ partial.minor = partial.patch = 0;
+ }
+ self->next = (semver_comp_t *) sv_malloc(sizeof(semver_comp_t));
+ if (self->next == NULL) {
+ return 1;
+ }
+ semver_comp_ctor(self->next);
+ self->next->op = SEMVER_OP_LT;
+ self->next->version = partial;
+ return 0;
+}
+
+void semver_comp_ctor(semver_comp_t *self) {
+#ifndef _MSC_VER
+ *self = (semver_comp_t) {0};
+#else
+ self->next = NULL;
+ self->op = SEMVER_OP_EQ;
+ semver_ctor(&self->version);
+#endif
+}
+
+void semver_comp_dtor(semver_comp_t *self) {
+ if (self && self->next) {
+ semver_comp_dtor(self->next);
+ free(self->next);
+ self->next = NULL;
+ }
+}
+
+char semver_compn(semver_comp_t *self, const char *str, size_t len) {
+ size_t offset = 0;
+
+ if (len > SV_COMP_MAX_LEN) {
+ return 1;
+ }
+ if (semver_comp_read(self, str, len, &offset) || offset < len) {
+ semver_comp_dtor(self);
+ return 1;
+ }
+ return 0;
+}
+
+char semver_comp_read(semver_comp_t *self, const char *str, size_t len, size_t *offset) {
+ semver_comp_ctor(self);
+ while (*offset < len) {
+ switch (str[*offset]) {
+ case '^':
+ ++*offset;
+ if (parse_tidle(self, str, len, offset)) {
+ return 1;
+ }
+ self = self->next;
+ goto next;
+ case '~':
+ ++*offset;
+ if (parse_caret(self, str, len, offset)) {
+ return 1;
+ }
+ self = self->next;
+ goto next;
+ case '>':
+ ++*offset;
+ if (*offset < len && str[*offset] == '=') {
+ ++*offset;
+ self->op = SEMVER_OP_GE;
+ } else {
+ self->op = SEMVER_OP_GT;
+ }
+ if (parse_partial(&self->version, str, len, offset)) {
+ return 1;
+ }
+ semver_xrevert(&self->version);
+ goto next;
+ case '<':
+ ++*offset;
+ if (*offset < len && str[*offset] == '=') {
+ ++*offset;
+ self->op = SEMVER_OP_LE;
+ } else {
+ self->op = SEMVER_OP_LT;
+ }
+ if (parse_partial(&self->version, str, len, offset)) {
+ return 1;
+ }
+ semver_xrevert(&self->version);
+ goto next;
+ case '=':
+ ++*offset;
+ self->op = SEMVER_OP_EQ;
+ if (parse_partial(&self->version, str, len, offset)) {
+ return 1;
+ }
+ semver_xrevert(&self->version);
+ goto next;
+ default:
+ goto range;
+ }
+ }
+ range:
+ if (parse_partial(&self->version, str, len, offset)) {
+ return 1;
+ }
+ if (*offset < len && str[*offset] == ' '
+ && *offset + 1 < len && str[*offset + 1] == '-'
+ && *offset + 2 < len && str[*offset + 2] == ' ') {
+ *offset += 3;
+ if (parse_hiphen(self, str, len, offset)) {
+ return 1;
+ }
+ self = self->next;
+ } else {
+ self = semver_xconvert(self);
+ if (self == NULL) {
+ return 1;
+ }
+ }
+ next:
+ if (*offset < len && str[*offset] == ' '
+ && *offset < len + 1 && str[*offset + 1] != ' ' && str[*offset + 1] != '|') {
+ ++*offset;
+ if (*offset < len) {
+ self->next = (semver_comp_t *) sv_malloc(sizeof(semver_comp_t));
+ if (self->next == NULL) {
+ return 1;
+ }
+ return semver_comp_read(self->next, str, len, offset);
+ }
+ return 1;
+ }
+ return 0;
+}
+
+char semver_and(semver_comp_t *left, const char *str, size_t len) {
+ semver_comp_t *comp, *tail;
+
+ if (len > 0) {
+ comp = (semver_comp_t *) sv_malloc(sizeof(semver_comp_t));
+ if (NULL == comp) {
+ return 1;
+ }
+ if (semver_compn(comp, str, len)) {
+ sv_free(comp);
+ return 1;
+ }
+ if (NULL == left->next) {
+ left->next = comp;
+ } else {
+ tail = left->next;
+ while (tail->next) tail = tail->next;
+ tail->next = comp;
+ }
+ return 0;
+ }
+ return 1;
+}
+
+bool semver_comp_pmatch(const semver_t *self, const semver_comp_t *comp) {
+ char result = semver_pcmp(self, &comp->version);
+
+ if (result < 0 && comp->op != SEMVER_OP_LT && comp->op != SEMVER_OP_LE) {
+ return false;
+ }
+ if (result > 0 && comp->op != SEMVER_OP_GT && comp->op != SEMVER_OP_GE) {
+ return false;
+ }
+ if (result == 0 && comp->op != SEMVER_OP_EQ && comp->op != SEMVER_OP_LE && comp->op != SEMVER_OP_GE) {
+ return false;
+ }
+ if (comp->next) {
+ return semver_comp_pmatch(self, comp->next);
+ }
+ return true;
+}
+
+bool semver_comp_matchn(const semver_t *self, const char *comp_str, size_t comp_len) {
+ semver_comp_t comp;
+ bool result;
+
+ if (semver_compn(&comp, comp_str, comp_len)) {
+ return false;
+ }
+ result = semver_comp_pmatch(self, &comp);
+ semver_comp_dtor(&comp);
+ return result;
+}
+
+int semver_comp_pwrite(const semver_comp_t *self, char *buffer, size_t len) {
+ char semver[SV_COMP_MAX_LEN];
+
+ semver_write(self->version, semver, SV_COMP_MAX_LEN);
+ if (self->next) {
+ char next[SV_COMP_MAX_LEN];
+ return snprintf(buffer, len, "%s%s %.*s",
+ semver_op_string(self->op), semver, semver_comp_pwrite(self->next, next, SV_COMP_MAX_LEN), next
+ );
+ }
+ return snprintf(buffer, len, "%s%s", semver_op_string(self->op), semver);
+}
diff --git a/core/src/sv/src/comp.h b/core/src/sv/src/comp.h
new file mode 100644
index 000000000..9130ee987
--- /dev/null
+++ b/core/src/sv/src/comp.h
@@ -0,0 +1,38 @@
+/*
+ * This is free and unencumbered software released into the public domain.
+ *
+ * Anyone is free to copy, modify, publish, use, compile, sell, or
+ * distribute this software, either in source code form or as a compiled
+ * binary, for any purpose, commercial or non-commercial, and by any
+ * means.
+ *
+ * In jurisdictions that recognize copyright laws, the author or authors
+ * of this software dedicate any and all copyright interest in the
+ * software to the public domain. We make this dedication for the benefit
+ * of the public at large and to the detriment of our heirs and
+ * successors. We intend this dedication to be an overt act of
+ * relinquishment in perpetuity of all present and future rights to this
+ * software under copyright law.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * For more information, please refer to <http://unlicense.org>
+ */
+
+#ifndef SV_COMP_H__
+# define SV_COMP_H__
+
+#include "version.h"
+
+#define SV_COMP_MAX_LEN (512)
+
+void semver_comp_ctor(semver_comp_t *self);
+char semver_comp_read(semver_comp_t *self, const char *str, size_t len, size_t *offset);
+
+#endif /* SV_COMP_H__ */
diff --git a/core/src/sv/src/id.c b/core/src/sv/src/id.c
new file mode 100644
index 000000000..9341eb02c
--- /dev/null
+++ b/core/src/sv/src/id.c
@@ -0,0 +1,141 @@
+/*
+ * This is free and unencumbered software released into the public domain.
+ *
+ * Anyone is free to copy, modify, publish, use, compile, sell, or
+ * distribute this software, either in source code form or as a compiled
+ * binary, for any purpose, commercial or non-commercial, and by any
+ * means.
+ *
+ * In jurisdictions that recognize copyright laws, the author or authors
+ * of this software dedicate any and all copyright interest in the
+ * software to the public domain. We make this dedication for the benefit
+ * of the public at large and to the detriment of our heirs and
+ * successors. We intend this dedication to be an overt act of
+ * relinquishment in perpetuity of all present and future rights to this
+ * software under copyright law.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * For more information, please refer to <http://unlicense.org>
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <stdio.h>
+
+#include "id.h"
+
+void semver_id_ctor(semver_id_t *self) {
+#ifndef _MSC_VER
+ *self = (semver_id_t) {true};
+#else
+ self->next = NULL;
+ self->len = 0;
+ self->raw = NULL;
+ self->num = 0;
+ self->numeric = true;
+#endif
+}
+
+void semver_id_dtor(semver_id_t *self) {
+ if (self && self->next) {
+ semver_id_dtor(self->next);
+ sv_free(self->next);
+ self->next = NULL;
+ }
+}
+
+char semver_id_read(semver_id_t *self, const char *str, size_t len, size_t *offset) {
+ size_t i = 0;
+ char is_zero = 0;
+
+ semver_id_ctor(self);
+ while (*offset < len) {
+ if (isalnum(str[*offset]) || str[*offset] == '-') {
+ if (!isdigit(str[*offset])) {
+ is_zero = 0;
+ self->numeric = false;
+ } else {
+ if (i == 0) {
+ is_zero = str[*offset] == '0';
+ } else if (is_zero) {
+ return 1;
+ }
+ }
+ ++i, ++*offset;
+ continue;
+ }
+ break;
+ }
+ if (!i) {
+ return 1;
+ }
+ self->raw = str + *offset - i;
+ self->len = i;
+ if (!is_zero && self->numeric) {
+ self->num = (int) strtol(self->raw, NULL, 0);
+ }
+ if (str[*offset] == '.') {
+ self->next = (semver_id_t *) sv_malloc(sizeof(semver_id_t));
+ if (self->next == NULL) {
+ return 1;
+ }
+ ++*offset;
+ return semver_id_read(self->next, str, len, offset);
+ }
+ return 0;
+}
+
+char semver_id_pcmp(const semver_id_t *self, const semver_id_t *other) {
+ char s;
+
+ if (self->len && !other->len) {
+ return -1;
+ }
+ if (!self->len && other->len) {
+ return 1;
+ }
+ if (!self->len) {
+ return 0;
+ }
+
+ if (self->numeric && other->numeric) {
+ if (self->num > other->num) {
+ return 1;
+ }
+ if (self->num < other->num) {
+ return -1;
+ }
+ } else if ((s = (char) memcmp(self->raw, other->raw, self->len > other->len ? self->len : other->len)) != 0) {
+ return s;
+ }
+
+ if (!self->next && other->next) {
+ return -1;
+ }
+ if (self->next && !other->next) {
+ return 1;
+ }
+ if (!self->next) {
+ return 0;
+ }
+
+ return semver_id_pcmp(self->next, other->next);
+}
+
+int semver_id_pwrite(const semver_id_t *self, char *buffer, size_t len) {
+ if (self->next) {
+ char next[SV_MAX_LEN];
+ return snprintf(buffer, len, "%.*s.%.*s",
+ (int) self->len, self->raw, semver_id_pwrite(self->next, next, SV_MAX_LEN), next
+ );
+ }
+ return snprintf(buffer, len, "%.*s", (int) self->len, self->raw);
+}
diff --git a/core/src/sv/src/id.h b/core/src/sv/src/id.h
new file mode 100644
index 000000000..914b4c237
--- /dev/null
+++ b/core/src/sv/src/id.h
@@ -0,0 +1,42 @@
+/*
+ * This is free and unencumbered software released into the public domain.
+ *
+ * Anyone is free to copy, modify, publish, use, compile, sell, or
+ * distribute this software, either in source code form or as a compiled
+ * binary, for any purpose, commercial or non-commercial, and by any
+ * means.
+ *
+ * In jurisdictions that recognize copyright laws, the author or authors
+ * of this software dedicate any and all copyright interest in the
+ * software to the public domain. We make this dedication for the benefit
+ * of the public at large and to the detriment of our heirs and
+ * successors. We intend this dedication to be an overt act of
+ * relinquishment in perpetuity of all present and future rights to this
+ * software under copyright law.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * For more information, please refer to <http://unlicense.org>
+ */
+
+#ifndef SV_ID_H__
+# define SV_ID_H__
+
+#include "version.h"
+
+void semver_id_ctor(semver_id_t *self);
+void semver_id_dtor(semver_id_t *self);
+char semver_id_read(semver_id_t *self, const char *str, size_t len, size_t *offset);
+int semver_id_pwrite(const semver_id_t *self, char *buffer, size_t len);
+char semver_id_pcmp(const semver_id_t *self, const semver_id_t *other);
+
+#define semver_id_write(self, buffer, len) semver_id_pwrite(&(self), buffer, len)
+#define semver_id_comp(self, other) semver_id_pcmp(&(self), &(other))
+
+#endif /* SV_ID_H__ */
diff --git a/core/src/sv/src/num.c b/core/src/sv/src/num.c
new file mode 100644
index 000000000..34410cbfa
--- /dev/null
+++ b/core/src/sv/src/num.c
@@ -0,0 +1,75 @@
+/*
+ * This is free and unencumbered software released into the public domain.
+ *
+ * Anyone is free to copy, modify, publish, use, compile, sell, or
+ * distribute this software, either in source code form or as a compiled
+ * binary, for any purpose, commercial or non-commercial, and by any
+ * means.
+ *
+ * In jurisdictions that recognize copyright laws, the author or authors
+ * of this software dedicate any and all copyright interest in the
+ * software to the public domain. We make this dedication for the benefit
+ * of the public at large and to the detriment of our heirs and
+ * successors. We intend this dedication to be an overt act of
+ * relinquishment in perpetuity of all present and future rights to this
+ * software under copyright law.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * For more information, please refer to <http://unlicense.org>
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include "num.h"
+
+char semver_num_read(int *self, const char *str, size_t len, size_t *offset) {
+ char *endptr;
+
+ *self = 0;
+ if (*offset >= len) {
+ return 1;
+ }
+ switch (str[*offset]) {
+ case 'x':
+ case 'X':
+ case '*':
+ *self = SEMVER_NUM_X;
+ ++*offset;
+ break;
+ case '0':
+ ++*offset;
+ if (*offset < len && isdigit(str[*offset])) {
+ return 1;
+ }
+ *self = 0;
+ break;
+ default:
+ if (isdigit(str[*offset])) {
+ *self = (int) strtol(str + *offset, &endptr, 0);
+ *offset += endptr - str - *offset;
+ } else {
+ return 1;
+ }
+ break;
+ }
+ return 0;
+}
+
+char semver_num_cmp(int self, int other) {
+ if (self > other) {
+ return 1;
+ }
+ if (self < other) {
+ return -1;
+ }
+ return 0;
+}
diff --git a/core/src/sv/src/num.h b/core/src/sv/src/num.h
new file mode 100644
index 000000000..12c4b694c
--- /dev/null
+++ b/core/src/sv/src/num.h
@@ -0,0 +1,36 @@
+/*
+ * This is free and unencumbered software released into the public domain.
+ *
+ * Anyone is free to copy, modify, publish, use, compile, sell, or
+ * distribute this software, either in source code form or as a compiled
+ * binary, for any purpose, commercial or non-commercial, and by any
+ * means.
+ *
+ * In jurisdictions that recognize copyright laws, the author or authors
+ * of this software dedicate any and all copyright interest in the
+ * software to the public domain. We make this dedication for the benefit
+ * of the public at large and to the detriment of our heirs and
+ * successors. We intend this dedication to be an overt act of
+ * relinquishment in perpetuity of all present and future rights to this
+ * software under copyright law.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * For more information, please refer to <http://unlicense.org>
+ */
+
+#ifndef SV_NUM_H__
+# define SV_NUM_H__
+
+#include "version.h"
+
+char semver_num_read(int *self, const char *str, size_t len, size_t *offset);
+char semver_num_cmp(int self, int other);
+
+#endif /* SV_NUM_H__ */
diff --git a/core/src/sv/src/range.c b/core/src/sv/src/range.c
new file mode 100644
index 000000000..c23a9ae81
--- /dev/null
+++ b/core/src/sv/src/range.c
@@ -0,0 +1,135 @@
+/*
+ * This is free and unencumbered software released into the public domain.
+ *
+ * Anyone is free to copy, modify, publish, use, compile, sell, or
+ * distribute this software, either in source code form or as a compiled
+ * binary, for any purpose, commercial or non-commercial, and by any
+ * means.
+ *
+ * In jurisdictions that recognize copyright laws, the author or authors
+ * of this software dedicate any and all copyright interest in the
+ * software to the public domain. We make this dedication for the benefit
+ * of the public at large and to the detriment of our heirs and
+ * successors. We intend this dedication to be an overt act of
+ * relinquishment in perpetuity of all present and future rights to this
+ * software under copyright law.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * For more information, please refer to <http://unlicense.org>
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "range.h"
+#include "comp.h"
+
+void semver_range_ctor(semver_range_t *self) {
+#ifndef _MSC_VER
+ *self = (semver_range_t) {0};
+#else
+ self->next = NULL;
+ semver_comp_ctor(&self->comp);
+#endif
+}
+
+void semver_range_dtor(semver_range_t *self) {
+ if (self && self->next) {
+ semver_range_dtor(self->next);
+ sv_free(self->next);
+ self->next = NULL;
+ }
+}
+
+char semver_rangen(semver_range_t *self, const char *str, size_t len) {
+ size_t offset = 0;
+
+ if (len > SV_RANGE_MAX_LEN) {
+ return 1;
+ }
+ if (semver_range_read(self, str, len, &offset) || offset < len) {
+ semver_range_dtor(self);
+ return 1;
+ }
+ return 0;
+}
+
+char semver_range_read(semver_range_t *self, const char *str, size_t len, size_t *offset) {
+ semver_range_ctor(self);
+ if (semver_comp_read(&self->comp, str, len, offset)) {
+ return 1;
+ }
+ while (*offset < len && str[*offset] == ' ') ++*offset;
+ if (*offset < len && str[*offset] == '|'
+ && *offset + 1 < len && str[*offset + 1] == '|') {
+ *offset += 2;
+ while (*offset < len && str[*offset] == ' ') ++*offset;
+ self->next = (semver_range_t *) sv_malloc(sizeof(semver_range_t));
+ if (self->next == NULL) {
+ return 1;
+ }
+ return semver_range_read(self->next, str, len, offset);
+ }
+ return 0;
+}
+
+char semver_or(semver_range_t *left, const char *str, size_t len) {
+ semver_range_t *range, *tail;
+
+ if (len > 0) {
+ range = (semver_range_t *) sv_malloc(sizeof(semver_range_t));
+ if (NULL == range) {
+ return 1;
+ }
+ if (semver_rangen(range, str, len)) {
+ sv_free(range);
+ return 1;
+ }
+ if (NULL == left->next) {
+ left->next = range;
+ } else {
+ tail = left->next;
+ while (tail->next) tail = tail->next;
+ tail->next = range;
+ }
+ return 0;
+ }
+ return 1;
+}
+
+bool semver_range_pmatch(const semver_t *self, const semver_range_t *range) {
+ return semver_comp_pmatch(self, &range->comp) ? true : range->next ? semver_range_pmatch(self, range->next) : false;
+}
+
+bool semver_range_matchn(const semver_t *self, const char *range_str, size_t range_len) {
+ semver_range_t range;
+ bool result;
+
+ if (semver_rangen(&range, range_str, range_len)) {
+ return false;
+ }
+ result = semver_range_pmatch(self, &range);
+ semver_range_dtor(&range);
+ return result;
+}
+
+int semver_range_pwrite(const semver_range_t *self, char *buffer, size_t len) {
+ char comp[SV_RANGE_MAX_LEN];
+
+ if (self->next) {
+ char next[SV_RANGE_MAX_LEN];
+ return snprintf(buffer, len, "%.*s || %.*s",
+ semver_comp_write(self->comp, comp, SV_RANGE_MAX_LEN), comp,
+ semver_range_pwrite(self->next, next, SV_RANGE_MAX_LEN), next
+ );
+ }
+ return snprintf(buffer, len, "%.*s", semver_comp_write(self->comp, comp, SV_RANGE_MAX_LEN), comp);
+}
diff --git a/core/src/sv/src/range.h b/core/src/sv/src/range.h
new file mode 100644
index 000000000..2c8f0974e
--- /dev/null
+++ b/core/src/sv/src/range.h
@@ -0,0 +1,38 @@
+/*
+ * This is free and unencumbered software released into the public domain.
+ *
+ * Anyone is free to copy, modify, publish, use, compile, sell, or
+ * distribute this software, either in source code form or as a compiled
+ * binary, for any purpose, commercial or non-commercial, and by any
+ * means.
+ *
+ * In jurisdictions that recognize copyright laws, the author or authors
+ * of this software dedicate any and all copyright interest in the
+ * software to the public domain. We make this dedication for the benefit
+ * of the public at large and to the detriment of our heirs and
+ * successors. We intend this dedication to be an overt act of
+ * relinquishment in perpetuity of all present and future rights to this
+ * software under copyright law.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * For more information, please refer to <http://unlicense.org>
+ */
+
+#ifndef SV_RANGE_H__
+# define SV_RANGE_H__
+
+#include "version.h"
+
+#define SV_RANGE_MAX_LEN (512)
+
+void semver_range_ctor(semver_range_t *self);
+char semver_range_read(semver_range_t *self, const char *str, size_t len, size_t *offset);
+
+#endif /* SV_RANGE_H__ */
diff --git a/core/src/sv/src/semvers.c b/core/src/sv/src/semvers.c
new file mode 100644
index 000000000..f8ce9ac9d
--- /dev/null
+++ b/core/src/sv/src/semvers.c
@@ -0,0 +1,108 @@
+/*
+ * This is free and unencumbered software released into the public domain.
+ *
+ * Anyone is free to copy, modify, publish, use, compile, sell, or
+ * distribute this software, either in source code form or as a compiled
+ * binary, for any purpose, commercial or non-commercial, and by any
+ * means.
+ *
+ * In jurisdictions that recognize copyright laws, the author or authors
+ * of this software dedicate any and all copyright interest in the
+ * software to the public domain. We make this dedication for the benefit
+ * of the public at large and to the detriment of our heirs and
+ * successors. We intend this dedication to be an overt act of
+ * relinquishment in perpetuity of all present and future rights to this
+ * software under copyright law.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * For more information, please refer to <http://unlicense.org>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "semvers.h"
+
+#define ISPOW2(n) (((n) & -(n)) == (n))
+
+uint32_t semvers_pgrowth(semvers_t *self, const int32_t nmin) {
+ if (nmin > 0) {
+ uint32_t unmin = (uint32_t) nmin;
+
+ if (self->capacity) {
+ if (self->capacity < unmin) {
+ if (ISPOW2(nmin)) {
+ self->capacity = unmin;
+ } else {
+ do self->capacity *= 2; while (self->capacity < unmin);
+ }
+ self->data = (semver_t *) realloc((char *) self->data, sizeof(semver_t) * self->capacity);
+ }
+ } else {
+ if (unmin == SEMVERS_MIN_CAP || (unmin > SEMVERS_MIN_CAP && ISPOW2(nmin))) {
+ self->capacity = unmin;
+ } else {
+ self->capacity = SEMVERS_MIN_CAP;
+ while (self->capacity < unmin) self->capacity *= 2;
+ }
+ self->data = (semver_t *) sv_malloc(sizeof(semver_t) * self->capacity);
+ }
+ return unmin;
+ }
+ return 0;
+}
+
+semver_t semvers_perase(semvers_t *self, uint32_t i) {
+ semver_t x = self->data[i];
+
+ memmove(self->data + i, self->data + i + 1, --self->length * sizeof(semver_t));
+ return x;
+}
+
+static int semvers_qsort_fn(const void *a, const void *b) {
+ return semver_pcmp((semver_t *) a, (semver_t *) b);
+}
+
+void semvers_psort(semvers_t *self) {
+ qsort((char *) self->data, self->length, sizeof(semver_t), semvers_qsort_fn);
+}
+
+static int semvers_rqsort_fn(const void *a, const void *b) {
+ return semver_pcmp((semver_t *) b, (semver_t *) a);
+}
+
+void semvers_prsort(semvers_t *self) {
+ qsort((char *) self->data, self->length, sizeof(semver_t), semvers_rqsort_fn);
+}
+
+void semvers_pdtor(semvers_t *self) {
+ if (self->data) {
+ uint32_t i;
+
+ for (i = 0; i < self->length; ++i) {
+ semver_dtor(self->data + i);
+ }
+ sv_free(self->data);
+ self->data = NULL;
+ }
+ self->length = self->capacity = 0;
+}
+
+void semvers_pclear(semvers_t *self) {
+ if (self->data) {
+ uint32_t i;
+
+ for (i = 0; i < self->length; ++i) {
+ semver_dtor(self->data + i);
+ }
+ memset((char *) self->data, 0, self->length * sizeof(semver_t));
+ }
+ self->length = 0;
+}
diff --git a/core/src/sv/src/semvers.h b/core/src/sv/src/semvers.h
new file mode 100644
index 000000000..6803380b4
--- /dev/null
+++ b/core/src/sv/src/semvers.h
@@ -0,0 +1,35 @@
+/*
+ * This is free and unencumbered software released into the public domain.
+ *
+ * Anyone is free to copy, modify, publish, use, compile, sell, or
+ * distribute this software, either in source code form or as a compiled
+ * binary, for any purpose, commercial or non-commercial, and by any
+ * means.
+ *
+ * In jurisdictions that recognize copyright laws, the author or authors
+ * of this software dedicate any and all copyright interest in the
+ * software to the public domain. We make this dedication for the benefit
+ * of the public at large and to the detriment of our heirs and
+ * successors. We intend this dedication to be an overt act of
+ * relinquishment in perpetuity of all present and future rights to this
+ * software under copyright law.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * For more information, please refer to <http://unlicense.org>
+ */
+
+#ifndef SV_SEMVERS_H__
+# define SV_SEMVERS_H__
+
+#include "semver.h"
+
+#define SEMVERS_MIN_CAP (4)
+
+#endif /* SV_SEMVERS_H__ */
diff --git a/core/src/sv/src/utils.c b/core/src/sv/src/utils.c
new file mode 100644
index 000000000..166cbe83f
--- /dev/null
+++ b/core/src/sv/src/utils.c
@@ -0,0 +1,96 @@
+/*
+ * This is free and unencumbered software released into the public domain.
+ *
+ * Anyone is free to copy, modify, publish, use, compile, sell, or
+ * distribute this software, either in source code form or as a compiled
+ * binary, for any purpose, commercial or non-commercial, and by any
+ * means.
+ *
+ * In jurisdictions that recognize copyright laws, the author or authors
+ * of this software dedicate any and all copyright interest in the
+ * software to the public domain. We make this dedication for the benefit
+ * of the public at large and to the detriment of our heirs and
+ * successors. We intend this dedication to be an overt act of
+ * relinquishment in perpetuity of all present and future rights to this
+ * software under copyright law.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * For more information, please refer to <http://unlicense.org>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "utils.h"
+#include "comp.h"
+#include "range.h"
+
+/*!\brief Serialise the version to the STREAM. When successful: return the
+ * number of bytes written and set "errno" to zero. When unsuccessful:
+ * set "errno" to an error code.
+ */
+size_t semver_fwrite(const semver_t *self, FILE *stream) {
+ char buffer[SV_MAX_LEN];
+ int cs;
+
+ if ((cs = semver_pwrite(self, buffer, SV_MAX_LEN)) == 0) {
+ return 0;
+ }
+ errno = 0;
+ return fwrite(buffer, sizeof(char), (size_t) cs, stream);
+}
+
+/*!\brief Serialise the comparator to the STREAM. When successful: return the
+ * number of bytes written and set "errno" to zero. When unsuccessful:
+ * set "errno" to an error code.
+ */
+size_t semver_comp_fwrite(const semver_comp_t *self, FILE *stream) {
+ char buffer[SV_COMP_MAX_LEN];
+ int cs;
+
+ if ((cs = semver_comp_pwrite(self, buffer, SV_COMP_MAX_LEN)) == 0) {
+ return 0;
+ }
+ errno = 0;
+ return fwrite(buffer, sizeof(char), (size_t) cs, stream);
+}
+
+/*!\brief Serialise the range to the STREAM. When successful: return the
+ * number of bytes written and set "errno" to zero. When unsuccessful:
+ * set "errno" to an error code.
+ */
+size_t semver_range_fwrite(const semver_range_t *self, FILE *stream) {
+ char buffer[SV_RANGE_MAX_LEN];
+ int cs;
+
+ if ((cs = semver_range_pwrite(self, buffer, SV_RANGE_MAX_LEN)) == 0) {
+ return 0;
+ }
+ errno = 0;
+ return fwrite(buffer, sizeof(char), (size_t) cs, stream);
+}
+
+const char *semver_op_string(enum semver_op op) {
+ switch (op) {
+ case SEMVER_OP_EQ:
+ return "";
+ case SEMVER_OP_LT:
+ return "<";
+ case SEMVER_OP_LE:
+ return "<=";
+ case SEMVER_OP_GT:
+ return ">";
+ case SEMVER_OP_GE:
+ return ">=";
+ default:
+ return NULL;
+ }
+}
diff --git a/core/src/sv/src/utils.h b/core/src/sv/src/utils.h
new file mode 100644
index 000000000..5f09529a6
--- /dev/null
+++ b/core/src/sv/src/utils.h
@@ -0,0 +1,35 @@
+/*
+ * This is free and unencumbered software released into the public domain.
+ *
+ * Anyone is free to copy, modify, publish, use, compile, sell, or
+ * distribute this software, either in source code form or as a compiled
+ * binary, for any purpose, commercial or non-commercial, and by any
+ * means.
+ *
+ * In jurisdictions that recognize copyright laws, the author or authors
+ * of this software dedicate any and all copyright interest in the
+ * software to the public domain. We make this dedication for the benefit
+ * of the public at large and to the detriment of our heirs and
+ * successors. We intend this dedication to be an overt act of
+ * relinquishment in perpetuity of all present and future rights to this
+ * software under copyright law.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * For more information, please refer to <http://unlicense.org>
+ */
+
+#ifndef SV_UTILS_H__
+# define SV_UTILS_H__
+
+#include "version.h"
+
+const char *semver_op_string(enum semver_op op);
+
+#endif /* SV_UTILS_H__ */
diff --git a/core/src/sv/src/version.c b/core/src/sv/src/version.c
new file mode 100644
index 000000000..6670a4287
--- /dev/null
+++ b/core/src/sv/src/version.c
@@ -0,0 +1,175 @@
+/*
+ * This is free and unencumbered software released into the public domain.
+ *
+ * Anyone is free to copy, modify, publish, use, compile, sell, or
+ * distribute this software, either in source code form or as a compiled
+ * binary, for any purpose, commercial or non-commercial, and by any
+ * means.
+ *
+ * In jurisdictions that recognize copyright laws, the author or authors
+ * of this software dedicate any and all copyright interest in the
+ * software to the public domain. We make this dedication for the benefit
+ * of the public at large and to the detriment of our heirs and
+ * successors. We intend this dedication to be an overt act of
+ * relinquishment in perpetuity of all present and future rights to this
+ * software under copyright law.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * For more information, please refer to <http://unlicense.org>
+ */
+
+#include <string.h>
+#include <stdio.h>
+
+#include "version.h"
+#include "num.h"
+#include "id.h"
+
+void semver_ctor(semver_t *self) {
+#ifndef _MSC_VER
+ *self = (semver_t) {0};
+#else
+ self->len = 0;
+ self->raw = NULL;
+ self->major = 0;
+ self->minor = 0;
+ self->patch = 0;
+ semver_id_ctor(&self->prerelease);
+ semver_id_ctor(&self->build);
+#endif
+}
+
+void semver_dtor(semver_t *self) {
+ semver_id_dtor(&self->prerelease);
+ semver_id_dtor(&self->build);
+}
+
+char semvern(semver_t *self, const char *str, size_t len) {
+ size_t offset = 0;
+
+ if (len > SV_MAX_LEN) {
+ return 1;
+ }
+ if (semver_read(self, str, len, &offset) || offset < len) {
+ semver_dtor(self);
+ return 1;
+ }
+ return 0;
+}
+
+char semver_tryn(semver_t *self, const char *str, size_t len) {
+ size_t offset = 0;
+
+ if (len > SV_MAX_LEN) {
+ return 1;
+ }
+ if (semver_try_read(self, str, len, &offset) || offset < len) {
+ semver_dtor(self);
+ return 1;
+ }
+ return 0;
+}
+
+char semver_read(semver_t *self, const char *str, size_t len, size_t *offset) {
+ if (*offset < len) {
+ semver_ctor(self);
+ self->raw = str + *offset;
+ if (str[*offset] == 'v') {
+ ++*offset;
+ }
+ if (semver_num_read(&self->major, str, len, offset) || self->major == SEMVER_NUM_X
+ || *offset >= len || str[*offset] != '.'
+ || semver_num_read(&self->minor, str, len, (++*offset, offset)) || self->minor == SEMVER_NUM_X
+ || *offset >= len || str[*offset] != '.'
+ || semver_num_read(&self->patch, str, len, (++*offset, offset)) || self->patch == SEMVER_NUM_X
+ || (str[*offset] == '-' && semver_id_read(&self->prerelease, str, len, (++*offset, offset)))
+ || (str[*offset] == '+' && semver_id_read(&self->build, str, len, (++*offset, offset)))) {
+ self->len = str + *offset - self->raw;
+ return 1;
+ }
+ self->len = str + *offset - self->raw;
+ return 0;
+ }
+ return 1;
+}
+
+char semver_try_read(semver_t *self, const char *str, size_t len, size_t *offset) {
+ if (*offset < len) {
+ semver_ctor(self);
+ self->raw = str + *offset;
+ if (str[*offset] == 'v') {
+ ++*offset;
+ }
+ if (semver_num_read(&self->major, str, len, offset) || self->major == SEMVER_NUM_X) {
+ fail:
+ self->len = str + *offset - self->raw;
+ return 1;
+ }
+ if (*offset < len && str[*offset] == '.'
+ && (semver_num_read(&self->minor, str, len, (++*offset, offset)) || self->minor == SEMVER_NUM_X)) {
+ goto fail;
+ }
+ if (*offset < len && str[*offset] == '.'
+ && (semver_num_read(&self->patch, str, len, (++*offset, offset)) || self->patch == SEMVER_NUM_X)) {
+ goto fail;
+ }
+ if (*offset < len && str[*offset] == '-') {
+ ++*offset;
+ }
+ semver_id_read(&self->prerelease, str, len, offset);
+ if (*offset < len && str[*offset] == '+') {
+ ++*offset;
+ }
+ semver_id_read(&self->build, str, len, offset);
+ self->len = str + *offset - self->raw;
+ return 0;
+ }
+ return 1;
+}
+
+char semver_pcmp(const semver_t *self, const semver_t *other) {
+ char result;
+
+ if ((result = semver_num_cmp(self->major, other->major)) != 0) {
+ return result;
+ }
+ if ((result = semver_num_cmp(self->minor, other->minor)) != 0) {
+ return result;
+ }
+ if ((result = semver_num_cmp(self->patch, other->patch)) != 0) {
+ return result;
+ }
+ return semver_id_comp(self->prerelease, other->prerelease);
+}
+
+int semver_pwrite(const semver_t *self, char *buffer, size_t len) {
+ char prerelease[SV_MAX_LEN], build[SV_MAX_LEN];
+
+ if (self->prerelease.len && self->build.len) {
+ return snprintf(buffer, len, "%d.%d.%d-%.*s+%.*s",
+ self->major, self->minor, self->patch,
+ semver_id_write(self->prerelease, prerelease, SV_MAX_LEN), prerelease,
+ semver_id_write(self->build, build, SV_MAX_LEN), build
+ );
+ }
+ if (self->prerelease.len) {
+ return snprintf(buffer, len, "%d.%d.%d-%.*s",
+ self->major, self->minor, self->patch,
+ semver_id_write(self->prerelease, prerelease, SV_MAX_LEN), prerelease
+ );
+ }
+ if (self->build.len) {
+ return snprintf(buffer, len, "%d.%d.%d+%.*s",
+ self->major, self->minor, self->patch,
+ semver_id_write(self->build, build, SV_MAX_LEN), build
+ );
+ }
+ return snprintf(buffer, len, "%d.%d.%d", self->major, self->minor, self->patch);
+}
diff --git a/core/src/sv/src/version.h b/core/src/sv/src/version.h
new file mode 100644
index 000000000..df1abe5c2
--- /dev/null
+++ b/core/src/sv/src/version.h
@@ -0,0 +1,43 @@
+/*
+ * This is free and unencumbered software released into the public domain.
+ *
+ * Anyone is free to copy, modify, publish, use, compile, sell, or
+ * distribute this software, either in source code form or as a compiled
+ * binary, for any purpose, commercial or non-commercial, and by any
+ * means.
+ *
+ * In jurisdictions that recognize copyright laws, the author or authors
+ * of this software dedicate any and all copyright interest in the
+ * software to the public domain. We make this dedication for the benefit
+ * of the public at large and to the detriment of our heirs and
+ * successors. We intend this dedication to be an overt act of
+ * relinquishment in perpetuity of all present and future rights to this
+ * software under copyright law.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * For more information, please refer to <http://unlicense.org>
+ */
+
+#ifndef SV_VERSION_H__
+# define SV_VERSION_H__
+
+#include "semver.h"
+
+#ifdef _MSC_VER
+# define snprintf(s, maxlen, fmt, ...) _snprintf_s(s, _TRUNCATE, maxlen, fmt, __VA_ARGS__)
+#endif
+
+#define SV_MAX_LEN (256)
+
+void semver_ctor(semver_t *self);
+char semver_read(semver_t *self, const char *str, size_t len, size_t *offset);
+char semver_try_read(semver_t *self, const char *str, size_t len, size_t *offset);
+
+#endif /* SV_VERSION_H__ */
diff --git a/core/src/sv/test/CMakeLists.txt b/core/src/sv/test/CMakeLists.txt
new file mode 100644
index 000000000..89d4a0eec
--- /dev/null
+++ b/core/src/sv/test/CMakeLists.txt
@@ -0,0 +1,27 @@
+add_executable(version version.c)
+target_link_libraries(version ${PROJECT_NAME})
+add_test(version version)
+
+add_executable(comp comp.c)
+target_link_libraries(comp ${PROJECT_NAME})
+add_test(comp comp)
+
+add_executable(range range.c)
+target_link_libraries(range ${PROJECT_NAME})
+add_test(range range)
+
+add_executable(match match.c)
+target_link_libraries(match ${PROJECT_NAME})
+add_test(match match)
+
+add_executable(utils utils.c)
+target_link_libraries(utils ${PROJECT_NAME})
+add_test(utils utils)
+
+add_executable(usage usage.c)
+target_link_libraries(usage ${PROJECT_NAME})
+add_test(usage usage)
+
+add_executable(semvers semvers.c)
+target_link_libraries(semvers ${PROJECT_NAME})
+add_test(semvers semvers)
diff --git a/core/src/sv/test/comp.c b/core/src/sv/test/comp.c
new file mode 100644
index 000000000..faa68a500
--- /dev/null
+++ b/core/src/sv/test/comp.c
@@ -0,0 +1,333 @@
+/*
+ * This is free and unencumbered software released into the public domain.
+ *
+ * Anyone is free to copy, modify, publish, use, compile, sell, or
+ * distribute this software, either in source code form or as a compiled
+ * binary, for any purpose, commercial or non-commercial, and by any
+ * means.
+ *
+ * In jurisdictions that recognize copyright laws, the author or authors
+ * of this software dedicate any and all copyright interest in the
+ * software to the public domain. We make this dedication for the benefit
+ * of the public at large and to the detriment of our heirs and
+ * successors. We intend this dedication to be an overt act of
+ * relinquishment in perpetuity of all present and future rights to this
+ * software under copyright law.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * For more information, please refer to <http://unlicense.org>
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "semver.h"
+
+#define STRNSIZE(s) (s), sizeof(s)-1
+
+int test_read(const char *expected, const char *str, size_t len) {
+ unsigned slen;
+ char buffer[1024];
+ semver_comp_t comp = {0};
+
+ printf("test: `%.*s`", (int) len, str);
+ if (semver_compn(&comp, str, len)) {
+ puts(" \tcouldn't parse");
+ return 1;
+ }
+ slen = (unsigned) semver_comp_write(comp, buffer, 1024);
+ printf(" \t=> \t`%.*s`", slen, buffer);
+ if (memcmp(expected, buffer, (size_t) slen > len ? slen : len) != 0) {
+ printf(" != `%s`\n", expected);
+ semver_comp_dtor(&comp);
+ return 1;
+ }
+ printf(" == `%s`\n", expected);
+ semver_comp_dtor(&comp);
+ return 0;
+}
+
+int test_and(const char *expected, const char *base_str, size_t base_len, const char *str, size_t len) {
+ unsigned slen;
+ char buffer[1024];
+ semver_comp_t comp = {0};
+
+ printf("test and: `%.*s`", (int) base_len, base_str);
+ if (semver_compn(&comp, base_str, base_len)) {
+ puts(" \tcouldn't parse");
+ return 1;
+ }
+ if (semver_and(&comp, str, len)) {
+ puts(" \tand failed");
+ return 1;
+ }
+ slen = (unsigned) semver_comp_write(comp, buffer, 1024);
+ printf(" \t=> \t`%.*s`", slen, buffer);
+ if (memcmp(expected, buffer, (size_t) slen > base_len + len + 1 ? slen : base_len + len + 1) != 0) {
+ printf(" != `%s`\n", expected);
+ semver_comp_dtor(&comp);
+ return 1;
+ }
+ printf(" == `%s`\n", expected);
+ semver_comp_dtor(&comp);
+ return 0;
+}
+
+int main(void) {
+ puts("failure:");
+ if (test_read("", STRNSIZE("* ")) == 0) {
+ return EXIT_FAILURE;
+ }
+ if (test_read("", STRNSIZE("* ")) == 0) {
+ return EXIT_FAILURE;
+ }
+ if (test_read("", STRNSIZE("* |")) == 0) {
+ return EXIT_FAILURE;
+ }
+ if (test_read("", STRNSIZE("* || *")) == 0) {
+ return EXIT_FAILURE;
+ }
+ if (test_read("", STRNSIZE("abc")) == 0) {
+ return EXIT_FAILURE;
+ }
+ if (test_read("", STRNSIZE(">")) == 0) {
+ return EXIT_FAILURE;
+ }
+ if (test_read("", STRNSIZE("<=")) == 0) {
+ return EXIT_FAILURE;
+ }
+ if (test_read("", STRNSIZE("~")) == 0) {
+ return EXIT_FAILURE;
+ }
+ if (test_read("", STRNSIZE("^")) == 0) {
+ return EXIT_FAILURE;
+ }
+ if (test_read("", STRNSIZE("=")) == 0) {
+ return EXIT_FAILURE;
+ }
+ if (test_read("", STRNSIZE(">a")) == 0) {
+ return EXIT_FAILURE;
+ }
+ if (test_read("", STRNSIZE("<a")) == 0) {
+ return EXIT_FAILURE;
+ }
+ if (test_read("", STRNSIZE("~a")) == 0) {
+ return EXIT_FAILURE;
+ }
+ if (test_read("", STRNSIZE("^a")) == 0) {
+ return EXIT_FAILURE;
+ }
+ if (test_read("", STRNSIZE("=a")) == 0) {
+ return EXIT_FAILURE;
+ }
+ if (test_read("", STRNSIZE(">1.a")) == 0) {
+ return EXIT_FAILURE;
+ }
+ if (test_read("", STRNSIZE("<1.a")) == 0) {
+ return EXIT_FAILURE;
+ }
+ if (test_read("", STRNSIZE("~1.a")) == 0) {
+ return EXIT_FAILURE;
+ }
+ if (test_read("", STRNSIZE("^1.a")) == 0) {
+ return EXIT_FAILURE;
+ }
+ if (test_read("", STRNSIZE("=1.a")) == 0) {
+ return EXIT_FAILURE;
+ }
+ if (test_read("", STRNSIZE("1.2.3 ")) == 0) {
+ return EXIT_FAILURE;
+ }
+ if (test_read("", STRNSIZE("1.2.3 -")) == 0) {
+ return EXIT_FAILURE;
+ }
+ if (test_read("", STRNSIZE("1.2.3 - ")) == 0) {
+ return EXIT_FAILURE;
+ }
+ if (test_read("", STRNSIZE("1.2.3 -a")) == 0) {
+ return EXIT_FAILURE;
+ }
+ if (test_read("", STRNSIZE("1.2.3 - a")) == 0) {
+ return EXIT_FAILURE;
+ }
+ if (test_read("", STRNSIZE("1.2.3 - 1.2.a")) == 0) {
+ return EXIT_FAILURE;
+ }
+ if (test_read("", STRNSIZE("a.2.3")) == 0) {
+ return EXIT_FAILURE;
+ }
+ if (test_read("", STRNSIZE("1.a.3")) == 0) {
+ return EXIT_FAILURE;
+ }
+ if (test_read("", STRNSIZE("1.2.a")) == 0) {
+ return EXIT_FAILURE;
+ }
+ if (test_read("", STRNSIZE("1.2.3-")) == 0) {
+ return EXIT_FAILURE;
+ }
+ if (test_read("", STRNSIZE("1.2.3-alpha+")) == 0) {
+ return EXIT_FAILURE;
+ }
+ if (test_read("", STRNSIZE("1.2.3+")) == 0) {
+ return EXIT_FAILURE;
+ }
+ if (test_read("1.2.3", STRNSIZE("1.2.3"))) {
+ return EXIT_FAILURE;
+ }
+
+ puts("\nsome prerelease and build:");
+ if (test_read(">=0.0.0 1.2.3-alpha", STRNSIZE("* 1.2.3-alpha"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_read(">=0.0.0 1.2.3-alpha.2", STRNSIZE("* 1.2.3-alpha.2"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_read(">=0.0.0 1.2.3+77", STRNSIZE("* 1.2.3+77"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_read(">=0.0.0 1.2.3+77.2", STRNSIZE("* 1.2.3+77.2"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_read(">=0.0.0 1.2.3-alpha.2+77", STRNSIZE("* 1.2.3-alpha.2+77"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_read(">=0.0.0 1.2.3-alpha.2+77.2", STRNSIZE("* 1.2.3-alpha.2+77.2"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_read(">=0.0.0 1.2.3-al-pha.2+77", STRNSIZE("* 1.2.3-al-pha.2+77"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_read(">=0.0.0 1.2.3-al-pha.2+77.2", STRNSIZE("* 1.2.3-al-pha.2+77.2"))) {
+ return EXIT_FAILURE;
+ }
+
+ puts("\nx-range:");
+ if (test_read(">=0.0.0", STRNSIZE("*"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_read(">=1.0.0 <2.0.0", STRNSIZE("1.x"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_read(">=1.2.0 <1.3.0", STRNSIZE("1.2.x"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_read(">=0.0.0", STRNSIZE(""))) {
+ return EXIT_FAILURE;
+ }
+ if (test_read(">=1.0.0 <2.0.0", STRNSIZE("1"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_read(">=1.2.0 <1.3.0", STRNSIZE("1.2"))) {
+ return EXIT_FAILURE;
+ }
+
+ puts("\nhyphen:");
+ if (test_read(">=1.2.3 <=2.3.4", STRNSIZE("1.2.3 - 2.3.4"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_read(">=1.2.0 <=2.3.4", STRNSIZE("1.2 - 2.3.4"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_read(">=1.2.3 <2.4.0", STRNSIZE("1.2.3 - 2.3"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_read(">=1.2.3 <3.0.0", STRNSIZE("1.2.3 - 2"))) {
+ return EXIT_FAILURE;
+ }
+
+ puts("\ntidle:");
+ if (test_read(">=1.2.3 <1.3.0", STRNSIZE("~1.2.3"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_read(">=1.2.0 <1.3.0", STRNSIZE("~1.2"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_read(">=1.0.0 <2.0.0", STRNSIZE("~1"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_read(">=0.2.3 <0.3.0", STRNSIZE("~0.2.3"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_read(">=0.2.0 <0.3.0", STRNSIZE("~0.2"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_read(">=0.0.0 <1.0.0", STRNSIZE("~0"))) {
+ return EXIT_FAILURE;
+ }
+
+ puts("\ncaret:");
+ if (test_read(">=1.2.3 <2.0.0", STRNSIZE("^1.2.3"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_read(">=0.2.3 <0.3.0", STRNSIZE("^0.2.3"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_read(">=0.0.3 <0.0.4", STRNSIZE("^0.0.3"))) {
+ return EXIT_FAILURE;
+ }
+
+ puts("\nprimitive:");
+ if (test_read(">=1.2.3 <2.0.0", STRNSIZE(">=1.2.3 <2.0"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_read(">=0.2.3 <0.3.0", STRNSIZE(">=0.2.3 <0.3"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_read(">=0.5.0 <0.0.4", STRNSIZE(">=0.5 <0.0.4"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_read(">0.0.3", STRNSIZE(">0.0.3"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_read("0.0.3", STRNSIZE("=0.0.3"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_read("9.0.0", STRNSIZE("=9"))) {
+ return EXIT_FAILURE;
+ }
+
+ puts("\nand:");
+ if (test_and(">=0.0.0 >=0.0.3 <0.0.4", STRNSIZE("*"), STRNSIZE("^0.0.3"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_and(">=1.0.0 <2.0.0 >=0.0.3 <0.0.4", STRNSIZE("1.x"), STRNSIZE("^0.0.3"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_and(">=1.2.0 <1.3.0 >=0.0.3 <0.0.4", STRNSIZE("1.2.x"), STRNSIZE("^0.0.3"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_and(">=1.2.0 <1.3.0 >=1.2.0 <1.3.0 >=0.0.3 <0.0.4", STRNSIZE("1.2 1.2.x"), STRNSIZE("^0.0.3"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_and(">=1.0.0 <2.0.0 >=0.0.3 <0.0.4", STRNSIZE("1"), STRNSIZE("^0.0.3"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_and(">=1.2.0 <1.3.0 >=0.0.3 <0.0.4", STRNSIZE("1.2"), STRNSIZE("^0.0.3"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_and("", STRNSIZE("1.2"), STRNSIZE("")) == 0) {
+ return EXIT_FAILURE;
+ }
+ if (test_and("", STRNSIZE("1.2"), STRNSIZE("a")) == 0) {
+ return EXIT_FAILURE;
+ }
+ if (test_and("", STRNSIZE("1.2"), STRNSIZE("1.2.x abc")) == 0) {
+ return EXIT_FAILURE;
+ }
+ if (test_read("", STRNSIZE("Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget "
+ "dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascet"
+ "ur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, s"))
+ == 0) {
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/core/src/sv/test/match.c b/core/src/sv/test/match.c
new file mode 100644
index 000000000..d960bb7fc
--- /dev/null
+++ b/core/src/sv/test/match.c
@@ -0,0 +1,357 @@
+/*
+ * This is free and unencumbered software released into the public domain.
+ *
+ * Anyone is free to copy, modify, publish, use, compile, sell, or
+ * distribute this software, either in source code form or as a compiled
+ * binary, for any purpose, commercial or non-commercial, and by any
+ * means.
+ *
+ * In jurisdictions that recognize copyright laws, the author or authors
+ * of this software dedicate any and all copyright interest in the
+ * software to the public domain. We make this dedication for the benefit
+ * of the public at large and to the detriment of our heirs and
+ * successors. We intend this dedication to be an overt act of
+ * relinquishment in perpetuity of all present and future rights to this
+ * software under copyright law.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * For more information, please refer to <http://unlicense.org>
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "semver.h"
+
+#define STRNSIZE(s) (s), sizeof(s)-1
+
+int test_matchn(bool expected, const char *semver_str, size_t semver_len, const char *comp_str, size_t comp_len) {
+ bool result;
+ semver_t semver = {0};
+
+ printf("test: `%.*s` ^ `%.*s`", (int) semver_len, semver_str, (int) comp_len, comp_str);
+ if (semvern(&semver, semver_str, semver_len)) {
+ puts(" \tcouldn't parse semver");
+ return 1;
+ }
+ result = semver_comp_matchn(&semver, comp_str, comp_len);
+ printf(" \t=> %d\t", result);
+ if (result != expected) {
+ printf(" != `%d`\n", expected);
+ semver_dtor(&semver);
+ return 1;
+ }
+ printf(" == `%d`\n", expected);
+ semver_dtor(&semver);
+ return 0;
+}
+
+int test_rmatchn(bool expected, const char *semver_str, size_t semver_len, const char *range_str, size_t range_len) {
+ bool result;
+ semver_t semver = {0};
+
+ printf("test: `%.*s` ^ `%.*s`", (int) semver_len, semver_str, (int) range_len, range_str);
+ if (semvern(&semver, semver_str, semver_len)) {
+ puts(" \tcouldn't parse semver");
+ return 1;
+ }
+ result = semver_range_matchn(&semver, range_str, range_len);
+ printf(" \t=> %d\t", result);
+ if (result != expected) {
+ printf(" != `%d`\n", expected);
+ semver_dtor(&semver);
+ return 1;
+ }
+ printf(" == `%d`\n", expected);
+ semver_dtor(&semver);
+ return 0;
+}
+
+int main(void) {
+ if (test_matchn(true, STRNSIZE("v1.2.3"), STRNSIZE("1.2.3"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_matchn(true, STRNSIZE("v1.2.3"), STRNSIZE("1.2.x"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_matchn(true, STRNSIZE("v1.2.3"), STRNSIZE("1.x.x"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_matchn(true, STRNSIZE("v1.2.3"), STRNSIZE("1.x"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_matchn(true, STRNSIZE("v1.2.3"), STRNSIZE("1"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_matchn(true, STRNSIZE("v1.2.3"), STRNSIZE("*"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_matchn(true, STRNSIZE("v1.2.3"), STRNSIZE(">1"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_matchn(false, STRNSIZE("v1.2.3"), STRNSIZE(">2"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_matchn(false, STRNSIZE("v1.2.3"), STRNSIZE(">=2"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_matchn(false, STRNSIZE("v1.2.3"), STRNSIZE("<1"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_matchn(false, STRNSIZE("v1.2.3"), STRNSIZE("<=1"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_matchn(true, STRNSIZE("v1.2.3"), STRNSIZE(">=1.2.3"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_matchn(false, STRNSIZE("v1.2.3"), STRNSIZE(">1.2.3"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_matchn(false, STRNSIZE("v1.2.3"), STRNSIZE("<1.2.3"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_matchn(true, STRNSIZE("v1.2.3"), STRNSIZE("<=1.2.3"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_matchn(false, STRNSIZE("v1.2.3"), STRNSIZE("2.x"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_matchn(true, STRNSIZE("0.0.1-98"), STRNSIZE("<0.0.1-99"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_matchn(true, STRNSIZE("0.0.1-98"), STRNSIZE("<=0.0.1-99"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_matchn(true, STRNSIZE("0.0.1-98"), STRNSIZE("<=0.0.1-98"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_matchn(true, STRNSIZE("0.0.1-98"), STRNSIZE("=0.0.1-98"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_matchn(true, STRNSIZE("0.0.1-98"), STRNSIZE(">=0.0.1-98"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_matchn(true, STRNSIZE("0.0.1-98"), STRNSIZE(">=0.0.1-97"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_matchn(true, STRNSIZE("0.0.1-98"), STRNSIZE(">0.0.1-97"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_matchn(true, STRNSIZE("0.0.1-alpha"), STRNSIZE("0.0.1-alpha"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_matchn(true, STRNSIZE("0.0.1-98"), STRNSIZE("<0.0.1-99"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_matchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("<0.0.1-alpha.99"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_matchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("<=0.0.1-alpha.99"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_matchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("<=0.0.1-alpha.98"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_matchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("=0.0.1-alpha.98"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_matchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE(">=0.0.1-alpha.98"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_matchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE(">=0.0.1-alpha.97"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_matchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE(">0.0.1-alpha.97"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_matchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("<0.0.1-alpha.99.1"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_matchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("<=0.0.1-alpha.99.1"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_matchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("<=0.0.1-alpha.98.1"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_matchn(false, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("=0.0.1-alpha.98.1"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_matchn(false, STRNSIZE("0.0.1-alpha.98"), STRNSIZE(">=0.0.1-alpha.98.1"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_matchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE(">=0.0.1-alpha.97.1"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_matchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE(">0.0.1-alpha.97.1"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_matchn(true, STRNSIZE("0.0.1-alpha.98.1.3"), STRNSIZE("<0.0.1-alpha.99.1"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_matchn(true, STRNSIZE("0.0.1-alpha.98.1.3"), STRNSIZE("<=0.0.1-alpha.99.1"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_matchn(false, STRNSIZE("0.0.1-alpha.98.1.3"), STRNSIZE("<=0.0.1-alpha.98.1"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_matchn(false, STRNSIZE("0.0.1-alpha.98.1.3"), STRNSIZE("=0.0.1-alpha.98.1"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_matchn(true, STRNSIZE("0.0.1-alpha.98.1.3"), STRNSIZE(">=0.0.1-alpha.98.1"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_matchn(true, STRNSIZE("0.0.1-alpha.98.1.3"), STRNSIZE(">=0.0.1-alpha.97.1"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_matchn(true, STRNSIZE("0.0.1-alpha.98.1.3"), STRNSIZE(">0.0.1-alpha.97.1"))) {
+ return EXIT_FAILURE;
+ }
+
+ if (test_rmatchn(true, STRNSIZE("v1.2.3"), STRNSIZE("9.x || 1.2.3"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_rmatchn(true, STRNSIZE("v1.2.3"), STRNSIZE("9.x || 1.2.x"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_rmatchn(true, STRNSIZE("v1.2.3"), STRNSIZE("9.x || 1.x.x"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_rmatchn(true, STRNSIZE("v1.2.3"), STRNSIZE("9.x || 1.x"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_rmatchn(true, STRNSIZE("v1.2.3"), STRNSIZE("9.x || 1"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_rmatchn(true, STRNSIZE("v1.2.3"), STRNSIZE("9.x || *"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_rmatchn(true, STRNSIZE("v1.2.3"), STRNSIZE("9.x || >1"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_rmatchn(false, STRNSIZE("v1.2.3"), STRNSIZE("9.x || >2"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_rmatchn(false, STRNSIZE("v1.2.3"), STRNSIZE("9.x || >=2"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_rmatchn(false, STRNSIZE("v1.2.3"), STRNSIZE("9.x || <1"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_rmatchn(false, STRNSIZE("v1.2.3"), STRNSIZE("9.x || <=1"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_rmatchn(true, STRNSIZE("v1.2.3"), STRNSIZE("9.x || >=1.2.3"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_rmatchn(false, STRNSIZE("v1.2.3"), STRNSIZE("9.x || >1.2.3"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_rmatchn(false, STRNSIZE("v1.2.3"), STRNSIZE("9.x || <1.2.3"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_rmatchn(true, STRNSIZE("v1.2.3"), STRNSIZE("9.x || <=1.2.3"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_rmatchn(false, STRNSIZE("v1.2.3"), STRNSIZE("9.x || 2.x"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_rmatchn(true, STRNSIZE("0.0.1-98"), STRNSIZE("9.x || <0.0.1-99"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_rmatchn(true, STRNSIZE("0.0.1-98"), STRNSIZE("9.x || <=0.0.1-99"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_rmatchn(true, STRNSIZE("0.0.1-98"), STRNSIZE("9.x || <=0.0.1-98"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_rmatchn(true, STRNSIZE("0.0.1-98"), STRNSIZE("9.x || =0.0.1-98"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_rmatchn(true, STRNSIZE("0.0.1-98"), STRNSIZE("9.x || >=0.0.1-98"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_rmatchn(true, STRNSIZE("0.0.1-98"), STRNSIZE("9.x || >=0.0.1-97"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_rmatchn(true, STRNSIZE("0.0.1-98"), STRNSIZE("9.x || >0.0.1-97"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_rmatchn(true, STRNSIZE("0.0.1-alpha"), STRNSIZE("9.x || 0.0.1-alpha"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_rmatchn(true, STRNSIZE("0.0.1-98"), STRNSIZE("9.x || <0.0.1-99"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_rmatchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("9.x || <0.0.1-alpha.99"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_rmatchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("9.x || <=0.0.1-alpha.99"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_rmatchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("9.x || <=0.0.1-alpha.98"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_rmatchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("9.x || =0.0.1-alpha.98"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_rmatchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("9.x || >=0.0.1-alpha.98"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_rmatchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("9.x || >=0.0.1-alpha.97"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_rmatchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("9.x || >0.0.1-alpha.97"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_rmatchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("9.x || <0.0.1-alpha.99.1"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_rmatchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("9.x || <=0.0.1-alpha.99.1"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_rmatchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("9.x || <=0.0.1-alpha.98.1"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_rmatchn(false, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("9.x || =0.0.1-alpha.98.1"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_rmatchn(false, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("9.x || >=0.0.1-alpha.98.1"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_rmatchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("9.x || >=0.0.1-alpha.97.1"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_rmatchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("9.x || >0.0.1-alpha.97.1"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_rmatchn(true, STRNSIZE("0.0.1-alpha.98.1.3"), STRNSIZE("9.x || <0.0.1-alpha.99.1"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_rmatchn(true, STRNSIZE("0.0.1-alpha.98.1.3"), STRNSIZE("9.x || <=0.0.1-alpha.99.1"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_rmatchn(false, STRNSIZE("0.0.1-alpha.98.1.3"), STRNSIZE("9.x || <=0.0.1-alpha.98.1"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_rmatchn(false, STRNSIZE("0.0.1-alpha.98.1.3"), STRNSIZE("9.x || =0.0.1-alpha.98.1"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_rmatchn(true, STRNSIZE("0.0.1-alpha.98.1.3"), STRNSIZE("9.x || >=0.0.1-alpha.98.1"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_rmatchn(true, STRNSIZE("0.0.1-alpha.98.1.3"), STRNSIZE("9.x || >=0.0.1-alpha.97.1"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_rmatchn(true, STRNSIZE("0.0.1-alpha.98.1.3"), STRNSIZE("9.x || >0.0.1-alpha.97.1"))) {
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/core/src/sv/test/range.c b/core/src/sv/test/range.c
new file mode 100644
index 000000000..17611ab25
--- /dev/null
+++ b/core/src/sv/test/range.c
@@ -0,0 +1,200 @@
+/*
+ * This is free and unencumbered software released into the public domain.
+ *
+ * Anyone is free to copy, modify, publish, use, compile, sell, or
+ * distribute this software, either in source code form or as a compiled
+ * binary, for any purpose, commercial or non-commercial, and by any
+ * means.
+ *
+ * In jurisdictions that recognize copyright laws, the author or authors
+ * of this software dedicate any and all copyright interest in the
+ * software to the public domain. We make this dedication for the benefit
+ * of the public at large and to the detriment of our heirs and
+ * successors. We intend this dedication to be an overt act of
+ * relinquishment in perpetuity of all present and future rights to this
+ * software under copyright law.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * For more information, please refer to <http://unlicense.org>
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "semver.h"
+
+#define STRNSIZE(s) (s), sizeof(s)-1
+
+int test_read(const char *expected, const char *str, size_t len) {
+ unsigned slen;
+ char buffer[1024];
+ semver_range_t range = {0};
+
+ printf("test: `%.*s`", (int) len, str);
+ if (semver_rangen(&range, str, len)) {
+ puts(" \tcouldn't parse");
+ return 1;
+ }
+ slen = (unsigned) semver_range_write(range, buffer, 1024);
+ printf(" \t=> \t`%.*s`", slen, buffer);
+ if (memcmp(expected, buffer, (size_t) slen > len ? slen : len) != 0) {
+ printf(" != `%s`\n", expected);
+ semver_range_dtor(&range);
+ return 1;
+ }
+ printf(" == `%s`\n", expected);
+ semver_range_dtor(&range);
+ return 0;
+}
+
+int test_or(const char *expected, const char *base_str, size_t base_len, const char *str, size_t len) {
+ unsigned slen;
+ char buffer[1024];
+ semver_range_t range = {0};
+
+ printf("test and: `%.*s`", (int) base_len, base_str);
+ if (semver_rangen(&range, base_str, base_len)) {
+ puts(" \tcouldn't parse base");
+ return 1;
+ }
+ if (semver_or(&range, str, len)) {
+ puts(" \tand failed");
+ return 1;
+ }
+ slen = (unsigned) semver_range_write(range, buffer, 1024);
+ printf(" \t=> \t`%.*s`", slen, buffer);
+ if (memcmp(expected, buffer, (size_t) slen > base_len + len + 1 ? slen : base_len + len + 1) != 0) {
+ printf(" != `%s`\n", expected);
+ semver_range_dtor(&range);
+ return 1;
+ }
+ printf(" == `%s`\n", expected);
+ semver_range_dtor(&range);
+ return 0;
+}
+
+int main(void) {
+ puts("failure:");
+ if (test_read("", STRNSIZE("* |")) == 0) {
+ return EXIT_FAILURE;
+ }
+ if (test_read("", STRNSIZE("* ||a")) == 0) {
+ return EXIT_FAILURE;
+ }
+ if (test_read("", STRNSIZE("* || a")) == 0) {
+ return EXIT_FAILURE;
+ }
+ if (test_read("", STRNSIZE("* || 1.a")) == 0) {
+ return EXIT_FAILURE;
+ }
+ if (test_read("", STRNSIZE("Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget "
+ "dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascet"
+ "ur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, s"))
+ == 0) {
+ return EXIT_FAILURE;
+ }
+
+ puts("\nx-range:");
+ if (test_read(">=0.0.0 || 1.2.3", STRNSIZE("* || 1.2.3"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_read(">=1.0.0 <2.0.0 || >=2.0.0 <3.0.0", STRNSIZE("1.x || 2.x"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_read(">=1.2.0 <1.3.0 || 3.0.0", STRNSIZE("1.2.x || 3.0.0"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_read(">=0.0.0", STRNSIZE(""))) {
+ return EXIT_FAILURE;
+ }
+ if (test_read(">=1.0.0 <2.0.0 || >=2.0.0 <3.0.0 || >=3.0.0 <4.0.0", STRNSIZE("1 || 2 || 3"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_read(">=1.2.0 <1.3.0 || >=5.0.0", STRNSIZE("1.2 || >=5"))) {
+ return EXIT_FAILURE;
+ }
+
+ puts("\nhyphen:");
+ if (test_read(">=1.2.3 <=2.3.4 || >=5.0.0", STRNSIZE("1.2.3 - 2.3.4 || >=5"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_read(">=1.2.0 <=2.3.4 || >=5.0.0", STRNSIZE("1.2 - 2.3.4 || >=5"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_read(">=1.2.3 <2.4.0 || >=5.0.0", STRNSIZE("1.2.3 - 2.3 || >=5"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_read(">=1.2.3 <3.0.0 || >=5.0.0", STRNSIZE("1.2.3 - 2 || >=5"))) {
+ return EXIT_FAILURE;
+ }
+
+ puts("\ntidle:");
+ if (test_read(">=1.2.3 <1.3.0 || >=5.0.0", STRNSIZE("~1.2.3 || >=5"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_read(">=1.2.0 <1.3.0 || >=5.0.0", STRNSIZE("~1.2 || >=5"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_read(">=1.0.0 <2.0.0 || >=5.0.0", STRNSIZE("~1 || >=5"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_read(">=0.2.3 <0.3.0 || >=5.0.0", STRNSIZE("~0.2.3 || >=5"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_read(">=0.2.0 <0.3.0 || >=5.0.0", STRNSIZE("~0.2 || >=5"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_read(">=0.0.0 <1.0.0 || >=5.0.0", STRNSIZE("~0 || >=5"))) {
+ return EXIT_FAILURE;
+ }
+
+ puts("\ncaret:");
+ if (test_read(">=1.2.3 <2.0.0 || >=5.0.0", STRNSIZE("^1.2.3 || >=5"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_read(">=0.2.3 <0.3.0 || >=5.0.0", STRNSIZE("^0.2.3 || >=5"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_read(">=0.0.3 <0.0.4 || >=5.0.0", STRNSIZE("^0.0.3 || >=5"))) {
+ return EXIT_FAILURE;
+ }
+
+ puts("\nand:");
+ if (test_or(">=0.0.0 || >=0.0.3 <0.0.4", STRNSIZE("*"), STRNSIZE("^0.0.3"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_or(">=1.0.0 <2.0.0 || >=0.0.3 <0.0.4", STRNSIZE("1.x"), STRNSIZE("^0.0.3"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_or(">=1.2.0 <1.3.0 || >=0.0.3 <0.0.4", STRNSIZE("1.2.x"), STRNSIZE("^0.0.3"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_or(">=1.2.0 <1.3.0 || >=1.2.0 <1.3.0 || >=0.0.3 <0.0.4", STRNSIZE("1.2 || 1.2.x"), STRNSIZE("^0.0.3"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_or(">=1.0.0 <2.0.0 || >=0.0.3 <0.0.4", STRNSIZE("1"), STRNSIZE("^0.0.3"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_or(">=1.2.0 <1.3.0 || >=0.0.3 <0.0.4", STRNSIZE("1.2"), STRNSIZE("^0.0.3"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_or("", STRNSIZE("1.2"), STRNSIZE("")) == 0) {
+ return EXIT_FAILURE;
+ }
+ if (test_or("", STRNSIZE("1.2"), STRNSIZE("a")) == 0) {
+ return EXIT_FAILURE;
+ }
+ if (test_or("", STRNSIZE("1.2"), STRNSIZE("1.2.x || abc")) == 0) {
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/core/src/sv/test/semver.c b/core/src/sv/test/semver.c
new file mode 100644
index 000000000..762f4ce40
--- /dev/null
+++ b/core/src/sv/test/semver.c
@@ -0,0 +1,106 @@
+/*
+ * This is free and unencumbered software released into the public domain.
+ *
+ * Anyone is free to copy, modify, publish, use, compile, sell, or
+ * distribute this software, either in source code form or as a compiled
+ * binary, for any purpose, commercial or non-commercial, and by any
+ * means.
+ *
+ * In jurisdictions that recognize copyright laws, the author or authors
+ * of this software dedicate any and all copyright interest in the
+ * software to the public domain. We make this dedication for the benefit
+ * of the public at large and to the detriment of our heirs and
+ * successors. We intend this dedication to be an overt act of
+ * relinquishment in perpetuity of all present and future rights to this
+ * software under copyright law.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * For more information, please refer to <http://unlicense.org>
+ */
+
+#include <semver.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#define STRNSIZE(s) (s), sizeof(s)-1
+
+int test_semver(const char *expected, const char *str, size_t len) {
+ size_t offset = 0;
+ unsigned slen;
+ char buffer[1024];
+ semver_t semver = {0};
+
+ printf("test: `%.*s`", (int) len, str);
+ if (semver_read(&semver, str, len, &offset)) {
+ puts(" \tcouldn't parse");
+ return 1;
+ }
+ slen = (unsigned) semver_write(semver, buffer, 1024);
+ printf(" \t=> \t`%.*s`", slen, buffer);
+ if (memcmp(expected, buffer, (size_t) slen > len ? slen : len) != 0) {
+ printf(" != `%s`\n", expected);
+ semver_dtor(&semver);
+ return 1;
+ }
+ printf(" == `%s`\n", expected);
+ semver_dtor(&semver);
+ return 0;
+}
+
+int main(void) {
+ if (test_semver("1.2.3", STRNSIZE("1.2.3"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_semver("1.2.3-alpha", STRNSIZE("v1.2.3-alpha"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_semver("1.2.3-alpha.2", STRNSIZE("1.2.3-alpha.2"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_semver("1.2.3+77", STRNSIZE("v1.2.3+77"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_semver("1.2.3+77.2", STRNSIZE("1.2.3+77.2"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_semver("1.2.3-alpha.2+77", STRNSIZE("v1.2.3-alpha.2+77"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_semver("1.2.3-alpha.2+77.2", STRNSIZE("1.2.3-alpha.2+77.2"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_semver("1.2.3-al-pha.2+77", STRNSIZE("v1.2.3-al-pha.2+77"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_semver("1.2.3-al-pha.2+77.2", STRNSIZE("1.2.3-al-pha.2+77.2"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_semver("", STRNSIZE("")) == 0) {
+ return EXIT_FAILURE;
+ }
+ if (test_semver("", STRNSIZE("vv1.2.3")) == 0) {
+ return EXIT_FAILURE;
+ }
+ if (test_semver("", STRNSIZE("v1.2")) == 0) {
+ return EXIT_FAILURE;
+ }
+ if (test_semver("", STRNSIZE("v1.2.x")) == 0) {
+ return EXIT_FAILURE;
+ }
+ if (test_semver("", STRNSIZE("v1.2.3-")) == 0) {
+ return EXIT_FAILURE;
+ }
+ if (test_semver("", STRNSIZE("v1.2.3+")) == 0) {
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/core/src/sv/test/semvers.c b/core/src/sv/test/semvers.c
new file mode 100644
index 000000000..fec6072bd
--- /dev/null
+++ b/core/src/sv/test/semvers.c
@@ -0,0 +1,115 @@
+/*
+ * This is free and unencumbered software released into the public domain.
+ *
+ * Anyone is free to copy, modify, publish, use, compile, sell, or
+ * distribute this software, either in source code form or as a compiled
+ * binary, for any purpose, commercial or non-commercial, and by any
+ * means.
+ *
+ * In jurisdictions that recognize copyright laws, the author or authors
+ * of this software dedicate any and all copyright interest in the
+ * software to the public domain. We make this dedication for the benefit
+ * of the public at large and to the detriment of our heirs and
+ * successors. We intend this dedication to be an overt act of
+ * relinquishment in perpetuity of all present and future rights to this
+ * software under copyright law.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * For more information, please refer to <http://unlicense.org>
+ */
+
+#include <stdlib.h>
+#include <assert.h>
+
+#include "semver.h"
+
+#define STRNSIZE(s) (s), sizeof(s)-1
+
+int main(void) {
+ semver_t v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10;
+ semvers_t semvers = {0};
+
+ semver_tryn(&v0, STRNSIZE("2.0.0"));
+ semver_tryn(&v1, STRNSIZE("2.0.1"));
+ semver_tryn(&v2, STRNSIZE("2.0.2"));
+ semver_tryn(&v3, STRNSIZE("v2.0.0"));
+ semver_tryn(&v4, STRNSIZE("v2.0.1"));
+ semver_tryn(&v5, STRNSIZE("v2.0.2"));
+ semver_tryn(&v6, STRNSIZE("v2.0.3"));
+ semver_tryn(&v7, STRNSIZE("v2.1.0-beta1"));
+ semver_tryn(&v8, STRNSIZE("v2.1.0-beta2"));
+ semver_tryn(&v9, STRNSIZE("v2.0"));
+ semver_tryn(&v10, STRNSIZE("v2.1"));
+
+ if (semver_rmatch(v0, ">2.0.1")) semvers_push(semvers, v0);
+ if (semver_rmatch(v1, ">2.0.1")) semvers_unshift(semvers, v1);
+ if (semver_rmatch(v2, ">2.0.1")) semvers_push(semvers, v2);
+ if (semver_rmatch(v3, ">2.0.1")) semvers_unshift(semvers, v3);
+ if (semver_rmatch(v4, ">2.0.1")) semvers_push(semvers, v4);
+ if (semver_rmatch(v5, ">2.0.1")) semvers_unshift(semvers, v5);
+ if (semver_rmatch(v6, ">2.0.1")) semvers_push(semvers, v6);
+ if (semver_rmatch(v7, ">2.0.1")) semvers_unshift(semvers, v7);
+ if (semver_rmatch(v8, ">2.0.1")) semvers_push(semvers, v8);
+ if (semver_rmatch(v9, ">2.0.1")) semvers_unshift(semvers, v9);
+ if (semver_rmatch(v10, ">2.0.1")) semvers_push(semvers, v10);
+ if (semver_rmatch(v0, ">2.0.1")) semvers_push(semvers, v0);
+ if (semver_rmatch(v1, ">2.0.1")) semvers_unshift(semvers, v1);
+ if (semver_rmatch(v2, ">2.0.1")) semvers_push(semvers, v2);
+ if (semver_rmatch(v3, ">2.0.1")) semvers_unshift(semvers, v3);
+ if (semver_rmatch(v4, ">2.0.1")) semvers_push(semvers, v4);
+ if (semver_rmatch(v5, ">2.0.1")) semvers_unshift(semvers, v5);
+ if (semver_rmatch(v6, ">2.0.1")) semvers_push(semvers, v6);
+ if (semver_rmatch(v7, ">2.0.1")) semvers_unshift(semvers, v7);
+ if (semver_rmatch(v8, ">2.0.1")) semvers_push(semvers, v8);
+ if (semver_rmatch(v9, ">2.0.1")) semvers_unshift(semvers, v9);
+ if (semver_rmatch(v10, ">2.0.1")) semvers_push(semvers, v10);
+ if (semver_rmatch(v0, ">2.0.1")) semvers_push(semvers, v0);
+ if (semver_rmatch(v1, ">2.0.1")) semvers_unshift(semvers, v1);
+ if (semver_rmatch(v2, ">2.0.1")) semvers_push(semvers, v2);
+ if (semver_rmatch(v3, ">2.0.1")) semvers_unshift(semvers, v3);
+ if (semver_rmatch(v4, ">2.0.1")) semvers_push(semvers, v4);
+ if (semver_rmatch(v5, ">2.0.1")) semvers_unshift(semvers, v5);
+ if (semver_rmatch(v6, ">2.0.1")) semvers_push(semvers, v6);
+ if (semver_rmatch(v7, ">2.0.1")) semvers_unshift(semvers, v7);
+ if (semver_rmatch(v8, ">2.0.1")) semvers_push(semvers, v8);
+ if (semver_rmatch(v9, ">2.0.1")) semvers_unshift(semvers, v9);
+ if (semver_rmatch(v10, ">2.0.1")) semvers_push(semvers, v10);
+
+ if (semvers.length != 18) {
+ return EXIT_FAILURE;
+ }
+ if (semvers.capacity != 32) {
+ return EXIT_FAILURE;
+ }
+
+ semvers_sort(semvers);
+
+ for (unsigned i = 0; i < semvers.length; ++i) {
+ semver_fwrite(semvers.data + i, stdout);
+ putc('\n', stdout);
+ }
+
+ v0 = semvers_pop(semvers);
+ v1 = semvers_shift(semvers);
+
+ assert(memcmp("v2.1", v0.raw, v0.len) == 0);
+ assert(memcmp("v2.0.2", v1.raw, v1.len) == 0 || memcmp("2.0.2", v1.raw, v1.len) == 0);
+
+ semvers_rsort(semvers);
+ putc('\n', stdout);
+ for (unsigned i = 0; i < semvers.length; ++i) {
+ semver_fwrite(semvers.data + i, stdout);
+ putc('\n', stdout);
+ }
+
+ semvers_dtor(semvers);
+
+ return EXIT_SUCCESS;
+}
diff --git a/core/src/sv/test/usage.c b/core/src/sv/test/usage.c
new file mode 100644
index 000000000..818608137
--- /dev/null
+++ b/core/src/sv/test/usage.c
@@ -0,0 +1,46 @@
+/*
+ * This is free and unencumbered software released into the public domain.
+ *
+ * Anyone is free to copy, modify, publish, use, compile, sell, or
+ * distribute this software, either in source code form or as a compiled
+ * binary, for any purpose, commercial or non-commercial, and by any
+ * means.
+ *
+ * In jurisdictions that recognize copyright laws, the author or authors
+ * of this software dedicate any and all copyright interest in the
+ * software to the public domain. We make this dedication for the benefit
+ * of the public at large and to the detriment of our heirs and
+ * successors. We intend this dedication to be an overt act of
+ * relinquishment in perpetuity of all present and future rights to this
+ * software under copyright law.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * For more information, please refer to <http://unlicense.org>
+ */
+
+#include <stdlib.h>
+#include <assert.h>
+
+#include "semver.h"
+
+int main(void) {
+ semver_t semver = {0};
+
+ semver(&semver, "v1.2.3-alpha.1");
+
+ assert(1 == semver.major);
+ assert(2 == semver.minor);
+ assert(3 == semver.patch);
+ assert(0 == memcmp("alpha", semver.prerelease.raw, sizeof("alpha")-1));
+ assert(0 == memcmp("1", semver.prerelease.next->raw, sizeof("1")-1));
+ assert(true == semver_rmatch(semver, "1.2.1 || >=1.2.3-alpha <1.2.5"));
+
+ semver_dtor(&semver);
+}
diff --git a/core/src/sv/test/utils.c b/core/src/sv/test/utils.c
new file mode 100644
index 000000000..89ae4cd1b
--- /dev/null
+++ b/core/src/sv/test/utils.c
@@ -0,0 +1,102 @@
+/*
+ * This is free and unencumbered software released into the public domain.
+ *
+ * Anyone is free to copy, modify, publish, use, compile, sell, or
+ * distribute this software, either in source code form or as a compiled
+ * binary, for any purpose, commercial or non-commercial, and by any
+ * means.
+ *
+ * In jurisdictions that recognize copyright laws, the author or authors
+ * of this software dedicate any and all copyright interest in the
+ * software to the public domain. We make this dedication for the benefit
+ * of the public at large and to the detriment of our heirs and
+ * successors. We intend this dedication to be an overt act of
+ * relinquishment in perpetuity of all present and future rights to this
+ * software under copyright law.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * For more information, please refer to <http://unlicense.org>
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "semver.h"
+
+int test_version_fwrite(void) {
+ static const char input_str[] = "1.2.3-alpha.1+x86-64";
+ semver_t version;
+ int rv;
+
+ rv = semver(&version, input_str);
+ if (0 == rv) {
+ printf("test_version_fwrite: ");
+ semver_fwrite(&version, stdout);
+ if (0 == errno) {
+ printf("\n");
+ rv = 0;
+ }
+ }
+ semver_dtor(&version);
+ return rv;
+}
+
+int test_comparator_fwrite(void) {
+ static const char input_str[] = "<=1.2.3";
+ semver_comp_t comp;
+ int rv;
+
+ rv = semver_comp(&comp, input_str);
+ if (0 == rv) {
+ printf("test_comparator_fwrite: ");
+ semver_comp_fwrite(&comp, stdout);
+ if (0 == errno) {
+ printf("\n");
+ rv = 0;
+ }
+ }
+ semver_comp_dtor(&comp);
+ return rv;
+}
+
+int test_range_fwrite(void) {
+ static const char input_str[] = ">=1.2.3 <4.0.0";
+ semver_range_t range;
+ int rv;
+
+ rv = semver_range(&range, input_str);
+ if (0 == rv) {
+ printf("test_range_fwrite: ");
+ semver_range_fwrite(&range, stdout);
+ if (0 == errno) {
+ printf("\n");
+ rv = 0;
+ }
+ }
+ semver_range_dtor(&range);
+ return rv;
+}
+
+int main(void) {
+ if (test_version_fwrite()) {
+ return EXIT_FAILURE;
+ }
+
+ if (test_comparator_fwrite()) {
+ return EXIT_FAILURE;
+ }
+
+ if (test_range_fwrite()) {
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/core/src/sv/test/version.c b/core/src/sv/test/version.c
new file mode 100644
index 000000000..a10b6e645
--- /dev/null
+++ b/core/src/sv/test/version.c
@@ -0,0 +1,236 @@
+/*
+ * This is free and unencumbered software released into the public domain.
+ *
+ * Anyone is free to copy, modify, publish, use, compile, sell, or
+ * distribute this software, either in source code form or as a compiled
+ * binary, for any purpose, commercial or non-commercial, and by any
+ * means.
+ *
+ * In jurisdictions that recognize copyright laws, the author or authors
+ * of this software dedicate any and all copyright interest in the
+ * software to the public domain. We make this dedication for the benefit
+ * of the public at large and to the detriment of our heirs and
+ * successors. We intend this dedication to be an overt act of
+ * relinquishment in perpetuity of all present and future rights to this
+ * software under copyright law.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * For more information, please refer to <http://unlicense.org>
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "semver.h"
+
+#define STRNSIZE(s) (s), sizeof(s)-1
+
+int test_read(const char *expected, const char *str, size_t len) {
+ unsigned slen;
+ char buffer[1024];
+ semver_t semver = {0};
+
+ printf("test: `%.*s`", (int) len, str);
+ if (semvern(&semver, str, len)) {
+ puts(" \tcouldn't parse");
+ return 1;
+ }
+ slen = (unsigned) semver_write(semver, buffer, 1024);
+ printf(" \t=> \t`%.*s`", slen, buffer);
+ if (memcmp(expected, buffer, (size_t) slen > len ? slen : len) != 0) {
+ printf(" != `%s`\n", expected);
+ semver_dtor(&semver);
+ return 1;
+ }
+ printf(" == `%s`\n", expected);
+ semver_dtor(&semver);
+ return 0;
+}
+
+int test_try_read(const char *expected, const char *str, size_t len) {
+ unsigned slen;
+ char buffer[1024];
+ semver_t semver = {0};
+
+ printf("test: `%.*s`", (int) len, str);
+ if (semver_tryn(&semver, str, len)) {
+ puts(" \tcouldn't parse");
+ return 1;
+ }
+ slen = (unsigned) semver_write(semver, buffer, 1024);
+ printf(" \t=> \t`%.*s`", slen, buffer);
+ if (memcmp(expected, buffer, (size_t) slen > len ? slen : len) != 0) {
+ printf(" != `%s`\n", expected);
+ semver_dtor(&semver);
+ return 1;
+ }
+ printf(" == `%s`\n", expected);
+ semver_dtor(&semver);
+ return 0;
+}
+
+int main(void) {
+ puts("normal:");
+ if (test_read("0.2.3", STRNSIZE("0.2.3"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_read("1.2.3", STRNSIZE("1.2.3"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_read("1.2.3-alpha", STRNSIZE("v1.2.3-alpha"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_read("1.2.3-alpha.2", STRNSIZE("1.2.3-alpha.2"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_read("1.2.3+77", STRNSIZE("v1.2.3+77"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_read("1.2.3+0", STRNSIZE("v1.2.3+0"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_read("1.2.3+77.2", STRNSIZE("1.2.3+77.2"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_read("1.2.3-alpha.2+77", STRNSIZE("v1.2.3-alpha.2+77"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_read("1.2.3-alpha.2+77.2", STRNSIZE("1.2.3-alpha.2+77.2"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_read("1.2.3-al-pha.2+77", STRNSIZE("v1.2.3-al-pha.2+77"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_read("1.2.3-al-pha.2+77.2", STRNSIZE("1.2.3-al-pha.2+77.2"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_read("", STRNSIZE("")) == 0) {
+ return EXIT_FAILURE;
+ }
+ if (test_read("", STRNSIZE("vv1.2.3")) == 0) {
+ return EXIT_FAILURE;
+ }
+ if (test_read("", STRNSIZE("v1.2")) == 0) {
+ return EXIT_FAILURE;
+ }
+ if (test_read("", STRNSIZE("v1.2.x")) == 0) {
+ return EXIT_FAILURE;
+ }
+ if (test_read("", STRNSIZE("v1.2.3-")) == 0) {
+ return EXIT_FAILURE;
+ }
+ if (test_read("", STRNSIZE("v1.2.3+")) == 0) {
+ return EXIT_FAILURE;
+ }
+ if (test_read("", STRNSIZE("v1.2.3+01")) == 0) {
+ return EXIT_FAILURE;
+ }
+ if (test_read("", STRNSIZE("v0.01.3")) == 0) {
+ return EXIT_FAILURE;
+ }
+ if (test_read("", STRNSIZE("Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget "
+ "dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascet"
+ "ur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, s"))
+ == 0) {
+ return EXIT_FAILURE;
+ }
+
+ puts("try:");
+ if (test_try_read("0.2.3", STRNSIZE("0.2.3"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_try_read("1.2.3", STRNSIZE("1.2.3"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_try_read("1.2.3-alpha", STRNSIZE("v1.2.3-alpha"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_try_read("1.2.3-alpha.2", STRNSIZE("1.2.3-alpha.2"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_try_read("1.2.3+77", STRNSIZE("v1.2.3+77"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_try_read("1.2.3+0", STRNSIZE("v1.2.3+0"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_try_read("1.2.3+77.2", STRNSIZE("1.2.3+77.2"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_try_read("1.2.3-alpha.2+77", STRNSIZE("v1.2.3-alpha.2+77"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_try_read("1.2.3-alpha.2+77.2", STRNSIZE("1.2.3-alpha.2+77.2"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_try_read("1.2.3-al-pha.2+77", STRNSIZE("v1.2.3-al-pha.2+77"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_try_read("1.2.3-al-pha.2+77.2", STRNSIZE("1.2.3-al-pha.2+77.2"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_try_read("", STRNSIZE("")) == 0) {
+ return EXIT_FAILURE;
+ }
+ if (test_try_read("", STRNSIZE("vv1.2.3")) == 0) {
+ return EXIT_FAILURE;
+ }
+ if (test_try_read("", STRNSIZE("v1.2")) == 0) {
+ return EXIT_FAILURE;
+ }
+ if (test_try_read("", STRNSIZE("v1.2.x")) == 0) {
+ return EXIT_FAILURE;
+ }
+ if (test_try_read("", STRNSIZE("v1.2.3-")) == 0) {
+ return EXIT_FAILURE;
+ }
+ if (test_try_read("", STRNSIZE("v1.2.3+")) == 0) {
+ return EXIT_FAILURE;
+ }
+ if (test_try_read("", STRNSIZE("v1.2.3+01")) == 0) {
+ return EXIT_FAILURE;
+ }
+ if (test_try_read("", STRNSIZE("v0.01.3")) == 0) {
+ return EXIT_FAILURE;
+ }
+ if (test_try_read("", STRNSIZE("Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget "
+ "dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascet"
+ "ur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, s"))
+ == 0) {
+ return EXIT_FAILURE;
+ }
+ if (test_try_read("0.2.0", STRNSIZE("0.2"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_try_read("1.0.0", STRNSIZE("v1"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_try_read("1.2.0-alpha", STRNSIZE("v1.2alpha"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_try_read("1.2.3-alpha.2", STRNSIZE("1.2.3alpha.2"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_try_read("1.0.0+77", STRNSIZE("v1+77"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_try_read("1.2.0+0", STRNSIZE("v1.2+0"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_try_read("1.0.0+77.2", STRNSIZE("v1+77.2"))) {
+ return EXIT_FAILURE;
+ }
+ if (test_try_read("1.2.3-alpha.2+77", STRNSIZE("v1.2.3alpha.2+77"))) {
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/core/src/sv/test/xmake.lua b/core/src/sv/test/xmake.lua
new file mode 100644
index 000000000..4169560e8
--- /dev/null
+++ b/core/src/sv/test/xmake.lua
@@ -0,0 +1,45 @@
+set_default(false)
+set_languages("c99")
+set_kind("binary")
+add_deps("sv")
+add_links("sv")
+add_includedirs("../include")
+add_linkdirs("$(buildir)")
+
+target("version_test")
+ add_files("version.c")
+
+target("comp_test")
+ add_files("comp.c")
+
+target("range_test")
+ add_files("range.c")
+
+target("match_test")
+ add_files("match.c")
+
+target("semvers_test")
+ add_files("semvers.c")
+
+target("utils_test")
+ add_files("utils.c")
+
+target("usage_test")
+ add_files("usage.c")
+
+task("check")
+ on_run(function ()
+ import("core.project.task")
+ task.run("run", {target = "version_test"})
+ task.run("run", {target = "comp_test"})
+ task.run("run", {target = "range_test"})
+ task.run("run", {target = "match_test"})
+ task.run("run", {target = "semvers_test"})
+ task.run("run", {target = "utils_test"})
+ task.run("run", {target = "usage_test"})
+ end)
+ set_menu {
+ usage = "xmake check"
+ , description = "Run tests !"
+ , options = {}
+ }
diff --git a/core/src/sv/xmake.lua b/core/src/sv/xmake.lua
new file mode 100644
index 000000000..490c8bf01
--- /dev/null
+++ b/core/src/sv/xmake.lua
@@ -0,0 +1,31 @@
+set_project("libsv")
+set_version("0.0.1")
+
+set_warnings("all", "error")
+
+if is_os("macosx") or is_os("ios") then
+ add_cflags("-Wno-nullability-completeness")
+ add_cxxflags("-Wno-nullability-completeness")
+end
+
+if is_mode("release") then
+ set_symbols("hidden")
+ set_optimize("fastest")
+ set_strip("all")
+end
+
+if is_mode("debug") then
+ set_symbols("debug")
+ set_optimize("none")
+end
+
+target("sv")
+ set_default(true)
+ set_languages("c99")
+ set_kind("$(kind)")
+ set_headerdir("$(buildir)/include")
+ add_headers("include/(*.h)")
+ add_includedirs("$(buildir)", "include")
+ add_files("src/*.c")
+
+add_subdirs("test")
diff --git a/core/src/xmake/hash/prefix.h b/core/src/xmake/hash/prefix.h
new file mode 100644
index 000000000..5df85a1d3
--- /dev/null
+++ b/core/src/xmake/hash/prefix.h
@@ -0,0 +1,36 @@
+/*!The Make-like Build Utility based on Lua
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Copyright (C) 2015 - 2017, TBOOX Open Source Group.
+ *
+ * @author ruki
+ * @file prefix.h
+ *
+ */
+#ifndef XM_HASH_PREFIX_H
+#define XM_HASH_PREFIX_H
+
+/* //////////////////////////////////////////////////////////////////////////////////////
+ * includes
+ */
+#include "../prefix.h"
+
+
+#endif
+
+
diff --git a/core/src/xmake/hash/sha256.c b/core/src/xmake/hash/sha256.c
new file mode 100644
index 000000000..6a9b1f5df
--- /dev/null
+++ b/core/src/xmake/hash/sha256.c
@@ -0,0 +1,110 @@
+/*!The Make-like Build Utility based on Lua
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Copyright (C) 2015 - 2017, TBOOX Open Source Group.
+ *
+ * @author ruki
+ * @file sha256.c
+ *
+ */
+
+/* //////////////////////////////////////////////////////////////////////////////////////
+ * trace
+ */
+#define TB_TRACE_MODULE_NAME "sha256"
+#define TB_TRACE_MODULE_DEBUG (0)
+
+/* //////////////////////////////////////////////////////////////////////////////////////
+ * includes
+ */
+#include "prefix.h"
+
+/* //////////////////////////////////////////////////////////////////////////////////////
+ * implementation
+ */
+tb_int_t xm_hash_sha256(lua_State* lua)
+{
+ // check
+ tb_assert_and_check_return_val(lua, 0);
+
+ // get the filename
+ tb_char_t const* filename = luaL_checkstring(lua, 1);
+ tb_check_return_val(filename, 0);
+
+ // load data from file
+ tb_bool_t ok = tb_false;
+ tb_stream_ref_t stream = tb_stream_init_from_file(filename, TB_FILE_MODE_RO);
+ if (stream)
+ {
+ // open stream
+ if (tb_stream_open(stream))
+ {
+ // init sha256
+ tb_sha_t sha;
+ tb_sha_init(&sha, TB_SHA_MODE_SHA2_256);
+
+ // read data and update sha256
+ tb_byte_t data[TB_STREAM_BLOCK_MAXN];
+ while (!tb_stream_beof(stream))
+ {
+ // read data
+ tb_long_t real = tb_stream_read(stream, data, sizeof(data));
+
+ // ok?
+ if (real > 0) tb_sha_spak(&sha, data, real);
+ // no data? continue it
+ else if (!real)
+ {
+ // wait
+ real = tb_stream_wait(stream, TB_STREAM_WAIT_READ, tb_stream_timeout(stream));
+ tb_check_break(real > 0);
+
+ // has read?
+ tb_assert_and_check_break(real & TB_STREAM_WAIT_READ);
+ }
+ // failed or end?
+ else break;
+ }
+
+ // exit sha256
+ tb_byte_t buffer[32];
+ tb_sha_exit(&sha, buffer, sizeof(buffer));
+
+ // make sha256 string
+ tb_size_t i = 0;
+ tb_size_t n = sha.digest_len << 2;
+ tb_char_t s[256] = {0};
+ for (i = 0; i < n; ++i) tb_snprintf(s + (i << 1), 3, "%02x", buffer[i]);
+
+ // save result
+ lua_pushstring(lua, s);
+
+ // ok
+ ok = tb_true;
+ }
+
+ // exit stream
+ tb_stream_exit(stream);
+ }
+
+ // failed? return nil
+ if (!ok) lua_pushnil(lua);
+
+ // ok
+ return 1;
+}
diff --git a/core/src/xmake/os/uuid.c b/core/src/xmake/hash/uuid.c
index 044bbe83d..9dc8e0eb7 100644
--- a/core/src/xmake/os/uuid.c
+++ b/core/src/xmake/hash/uuid.c
@@ -37,7 +37,7 @@
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
-tb_int_t xm_os_uuid(lua_State* lua)
+tb_int_t xm_hash_uuid(lua_State* lua)
{
// check
tb_assert_and_check_return_val(lua, 0);
diff --git a/core/src/xmake/machine.c b/core/src/xmake/machine.c
index 7f1acfbd0..e1a080d3a 100644
--- a/core/src/xmake/machine.c
+++ b/core/src/xmake/machine.c
@@ -60,13 +60,13 @@ typedef struct __xm_machine_impl_t
// the os functions
tb_int_t xm_os_argv(lua_State* lua);
tb_int_t xm_os_find(lua_State* lua);
-tb_int_t xm_os_uuid(lua_State* lua);
tb_int_t xm_os_isdir(lua_State* lua);
tb_int_t xm_os_rmdir(lua_State* lua);
tb_int_t xm_os_mkdir(lua_State* lua);
tb_int_t xm_os_cpdir(lua_State* lua);
tb_int_t xm_os_chdir(lua_State* lua);
tb_int_t xm_os_mtime(lua_State* lua);
+tb_int_t xm_os_sleep(lua_State* lua);
tb_int_t xm_os_mclock(lua_State* lua);
tb_int_t xm_os_curdir(lua_State* lua);
tb_int_t xm_os_tmpdir(lua_State* lua);
@@ -93,6 +93,10 @@ tb_int_t xm_path_absolute(lua_State* lua);
tb_int_t xm_path_translate(lua_State* lua);
tb_int_t xm_path_is_absolute(lua_State* lua);
+// the hash functions
+tb_int_t xm_hash_uuid(lua_State* lua);
+tb_int_t xm_hash_sha256(lua_State* lua);
+
// the winreg functions
#ifdef TB_CONFIG_OS_WINDOWS
tb_int_t xm_winreg_query(lua_State* lua);
@@ -120,6 +124,11 @@ tb_int_t xm_readline_add_history(lua_State* lua);
tb_int_t xm_readline_clear_history(lua_State* lua);
#endif
+// the semver functions
+tb_int_t xm_semver_parse(lua_State* lua);
+tb_int_t xm_semver_satisfies(lua_State* lua);
+tb_int_t xm_semver_select(lua_State* lua);
+
/* //////////////////////////////////////////////////////////////////////////////////////
* globals
*/
@@ -129,13 +138,13 @@ static luaL_Reg const g_os_functions[] =
{
{ "argv", xm_os_argv }
, { "find", xm_os_find }
-, { "uuid", xm_os_uuid }
, { "isdir", xm_os_isdir }
, { "rmdir", xm_os_rmdir }
, { "mkdir", xm_os_mkdir }
, { "cpdir", xm_os_cpdir }
, { "chdir", xm_os_chdir }
, { "mtime", xm_os_mtime }
+, { "sleep", xm_os_sleep }
, { "mclock", xm_os_mclock }
, { "curdir", xm_os_curdir }
, { "tmpdir", xm_os_tmpdir }
@@ -168,6 +177,14 @@ static luaL_Reg const g_path_functions[] =
, { tb_null, tb_null }
};
+// the hash functions
+static luaL_Reg const g_hash_functions[] =
+{
+ { "uuid", xm_hash_uuid }
+, { "sha256", xm_hash_sha256 }
+, { tb_null, tb_null }
+};
+
// the string functions
static luaL_Reg const g_string_functions[] =
{
@@ -215,6 +232,15 @@ static luaL_Reg const g_readline_functions[] =
};
#endif
+// the semver functions
+static luaL_Reg const g_semver_functions[] =
+{
+ { "parse", xm_semver_parse }
+, { "satisfies", xm_semver_satisfies }
+, { "select", xm_semver_select }
+, { tb_null, tb_null }
+};
+
/* //////////////////////////////////////////////////////////////////////////////////////
* private implementation
*/
@@ -422,6 +448,9 @@ xm_machine_ref_t xm_machine_init()
// bind path functions
luaL_register(impl->lua, "path", g_path_functions);
+ // bind hash functions
+ luaL_register(impl->lua, "hash", g_hash_functions);
+
// bind string functions
luaL_register(impl->lua, "string", g_string_functions);
@@ -441,6 +470,9 @@ xm_machine_ref_t xm_machine_init()
luaL_register(impl->lua, "readline", g_readline_functions);
#endif
+ // bind semver functions
+ luaL_register(impl->lua, "semver", g_semver_functions);
+
// init host
#if defined(TB_CONFIG_OS_WINDOWS)
lua_pushstring(impl->lua, "windows");
diff --git a/core/src/xmake/makefile b/core/src/xmake/makefile
index e9f5badce..aa003cc35 100644
--- a/core/src/xmake/makefile
+++ b/core/src/xmake/makefile
@@ -16,13 +16,13 @@ xmake_C_FILES += \
machine \
os/argv \
os/find \
- os/uuid \
os/isdir \
os/rmdir \
os/mkdir \
os/cpdir \
os/chdir \
os/mtime \
+ os/sleep \
os/mclock \
os/curdir \
os/tmpdir \
@@ -44,6 +44,8 @@ xmake_C_FILES += \
path/absolute \
path/translate \
path/is_absolute \
+ hash/uuid \
+ hash/sha256 \
winreg/query \
string/endswith \
string/startswith \
@@ -53,6 +55,10 @@ xmake_C_FILES += \
process/waitlist \
process/close \
sandbox/interactive \
+ semver/parse \
+ semver/satisfies \
+ semver/select \
+ semver/semver \
readline/readline \
readline/history_list \
readline/add_history \
@@ -65,7 +71,8 @@ xmake_CXFLAGS += $(if $(findstring readline,$(base_LIBNAMES)),-DXM_CONFIG_API
# includes
xmake_INC_DIRS += \
- ../luajit/src
+ ../luajit/src \
+ ../sv/include
# suffix
diff --git a/core/src/xmake/os/sleep.c b/core/src/xmake/os/sleep.c
new file mode 100644
index 000000000..4615c274f
--- /dev/null
+++ b/core/src/xmake/os/sleep.c
@@ -0,0 +1,53 @@
+/*!The Make-like Build Utility based on Lua
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Copyright (C) 2015 - 2017, TBOOX Open Source Group.
+ *
+ * @author ruki
+ * @file sleep.c
+ *
+ */
+
+/* //////////////////////////////////////////////////////////////////////////////////////
+ * trace
+ */
+#define TB_TRACE_MODULE_NAME "sleep"
+#define TB_TRACE_MODULE_DEBUG (0)
+
+/* //////////////////////////////////////////////////////////////////////////////////////
+ * includes
+ */
+#include "prefix.h"
+
+/* //////////////////////////////////////////////////////////////////////////////////////
+ * implementation
+ */
+tb_int_t xm_os_sleep(lua_State* lua)
+{
+ // check
+ tb_assert_and_check_return_val(lua, 0);
+
+ // get the interval (ms)
+ tb_long_t interval = (tb_long_t)luaL_checklong(lua, 1);
+
+ // sleep it
+ if (interval >= 0) tb_msleep(interval);
+
+ // ok
+ return 0;
+}
diff --git a/core/src/xmake/semver/parse.c b/core/src/xmake/semver/parse.c
new file mode 100644
index 000000000..976f198fb
--- /dev/null
+++ b/core/src/xmake/semver/parse.c
@@ -0,0 +1,65 @@
+/*!The Make-like Build Utility based on Lua
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Copyright (C) 2015 - 2017, TBOOX Open Source Group.
+ *
+ * @author uael
+ * @file parse.c
+ *
+ */
+
+/* //////////////////////////////////////////////////////////////////////////////////////
+ * trace
+ */
+#define TB_TRACE_MODULE_NAME "parse"
+#define TB_TRACE_MODULE_DEBUG (0)
+
+/* //////////////////////////////////////////////////////////////////////////////////////
+ * includes
+ */
+#include "prefix.h"
+
+/* //////////////////////////////////////////////////////////////////////////////////////
+ * implementation
+ */
+
+// parse wrapper
+tb_int_t xm_semver_parse(lua_State* lua)
+{
+ semver_t semver = {0};
+
+ // check
+ tb_assert_and_check_return_val(lua, 0);
+
+ // get the version string
+ tb_char_t const* str = luaL_checkstring(lua, 1);
+ tb_check_return_val(str, 0);
+
+ if (semvern(&semver, str, tb_strlen(str))) {
+ lua_pushnil(lua);
+ lua_pushfstring(lua, "Unable to parse semver '%s'", str);
+
+ return 2;
+ }
+
+ lua_pushsemver(lua, semver);
+ semver_dtor(&semver);
+
+ // ok
+ return 1;
+}
diff --git a/core/src/xmake/semver/prefix.h b/core/src/xmake/semver/prefix.h
new file mode 100644
index 000000000..17c4e9f5a
--- /dev/null
+++ b/core/src/xmake/semver/prefix.h
@@ -0,0 +1,37 @@
+/*!The Make-like Build Utility based on Lua
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Copyright (C) 2015 - 2017, TBOOX Open Source Group.
+ *
+ * @author uael
+ * @file prefix.h
+ *
+ */
+#ifndef XM_SEMVER_PREFIX_H
+#define XM_SEMVER_PREFIX_H
+
+/* //////////////////////////////////////////////////////////////////////////////////////
+ * includes
+ */
+#include "../prefix.h"
+
+#include "semver.h"
+
+void lua_pushsemver(lua_State *lua, semver_t semver);
+
+#endif
diff --git a/core/src/xmake/semver/satisfies.c b/core/src/xmake/semver/satisfies.c
new file mode 100644
index 000000000..f3b34890f
--- /dev/null
+++ b/core/src/xmake/semver/satisfies.c
@@ -0,0 +1,78 @@
+/*!The Make-like Build Utility based on Lua
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Copyright (C) 2015 - 2017, TBOOX Open Source Group.
+ *
+ * @author uael
+ * @file satisfies.c
+ *
+ */
+
+/* //////////////////////////////////////////////////////////////////////////////////////
+ * trace
+ */
+#define TB_TRACE_MODULE_NAME "satisfies"
+#define TB_TRACE_MODULE_DEBUG (0)
+
+/* //////////////////////////////////////////////////////////////////////////////////////
+ * includes
+ */
+#include "prefix.h"
+
+/* //////////////////////////////////////////////////////////////////////////////////////
+ * implementation
+ */
+
+// satisfies wrapper
+tb_int_t xm_semver_satisfies(lua_State* lua)
+{
+ semver_t semver = {0};
+ semver_range_t range = {0};
+
+ // check
+ tb_assert_and_check_return_val(lua, 0);
+
+ // get the version string
+ tb_char_t const* str = luaL_checkstring(lua, 1);
+ tb_char_t const* range_str = luaL_checkstring(lua, 2);
+
+ tb_check_return_val(str, 0);
+ tb_check_return_val(range_str, 0);
+
+ if (semvern(&semver, str, tb_strlen(str))) {
+ lua_pushnil(lua);
+ lua_pushfstring(lua, "Unable to parse semver '%s'", str);
+
+ return 2;
+ }
+
+ if (semver_rangen(&range, range_str, tb_strlen(range_str))) {
+ semver_dtor(&semver);
+ lua_pushnil(lua);
+ lua_pushfstring(lua, "Unable to parse semver range '%s'", range_str);
+
+ return 2;
+ }
+
+ lua_pushboolean(lua, semver_range_match(semver, range));
+ semver_dtor(&semver);
+ semver_range_dtor(&range);
+
+ // ok
+ return 1;
+}
diff --git a/core/src/xmake/semver/select.c b/core/src/xmake/semver/select.c
new file mode 100644
index 000000000..6400de6a8
--- /dev/null
+++ b/core/src/xmake/semver/select.c
@@ -0,0 +1,160 @@
+/*!The Make-like Build Utility based on Lua
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Copyright (C) 2015 - 2017, TBOOX Open Source Group.
+ *
+ * @author uael
+ * @file select.c
+ *
+ */
+
+/* //////////////////////////////////////////////////////////////////////////////////////
+ * trace
+ */
+#define TB_TRACE_MODULE_NAME "select"
+#define TB_TRACE_MODULE_DEBUG (0)
+
+/* //////////////////////////////////////////////////////////////////////////////////////
+ * includes
+ */
+#include <stdlib.h>
+#include "prefix.h"
+
+/* //////////////////////////////////////////////////////////////////////////////////////
+ * implementation
+ */
+
+// satisfies wrapper
+tb_int_t xm_semver_select(lua_State* lua)
+{
+ semver_t semver = {0};
+ semvers_t matches = {0};
+ semver_range_t range = {0};
+ lua_Integer i;
+ size_t range_len = 0, source_len;
+ tb_char_t const* source_str;
+ tb_char_t const* source;
+ tb_bool_t is_range;
+
+ lua_settop(lua, 4);
+
+ // check
+ tb_assert_and_check_return_val(lua, 0);
+
+ // get the version string
+ tb_char_t const* range_str = luaL_checkstring(lua, 1);
+ tb_check_return_val(range_str, 0);
+ range_len = tb_strlen(range_str);
+
+ is_range = semver_rangen(&range, range_str, range_len) == 0;
+ if (is_range) {
+ source = "versions";
+ luaL_checktype(lua, 2, LUA_TTABLE);
+ for (i = lua_objlen(lua, 2); i > 0; --i) {
+ lua_pushinteger(lua, i);
+ lua_gettable(lua, 2);
+
+ source_str = luaL_checkstring(lua, -1);
+ tb_check_return_val(source_str, 0);
+
+ if (semver_tryn(&semver, source_str, tb_strlen(source_str)) == 0) {
+ if (semver_range_match(semver, range)) {
+ semvers_push(matches, semver);
+ } else {
+ semver_dtor(&semver);
+ }
+ }
+ }
+ if (matches.length) {
+ goto match;
+ }
+ semvers_clear(matches);
+ source = "tags";
+ luaL_checktype(lua, 3, LUA_TTABLE);
+ for (i = lua_objlen(lua, 3); i > 0; --i) {
+ lua_pushinteger(lua, i);
+ lua_gettable(lua, 3);
+
+ source_str = luaL_checkstring(lua, -1);
+ tb_check_return_val(source_str, 0);
+
+ if (semver_tryn(&semver, source_str, tb_strlen(source_str)) == 0) {
+ if (semver_range_match(semver, range)) {
+ semvers_push(matches, semver);
+ } else {
+ semver_dtor(&semver);
+ }
+ }
+ }
+ if (matches.length) {
+ goto match;
+ }
+ semvers_dtor(matches);
+ semver_range_dtor(&range);
+ }
+
+ source = "branches";
+ luaL_checktype(lua, 4, LUA_TTABLE);
+ for (i = lua_objlen(lua, 4); i > 0; --i) {
+ lua_pushinteger(lua, i);
+ lua_gettable(lua, 4);
+
+ source_str = luaL_checkstring(lua, -1);
+ tb_check_return_val(source_str, 0);
+ source_len = tb_strlen(source_str);
+
+ if (source_len == range_len && tb_memcmp(source_str, range_str, source_len) == 0) {
+ lua_createtable(lua, 0, 2);
+
+ lua_pushlstring(lua, source_str, source_len);
+ lua_setfield(lua, -2, "version");
+
+ lua_pushstring(lua, source);
+ lua_setfield(lua, -2, "source");
+
+ return 1;
+ }
+ }
+
+ if (!is_range) {
+ lua_pushnil(lua);
+ lua_pushfstring(lua, "Unable to parse semver range '%s'", range_str);
+
+ return 2;
+ }
+ lua_pushnil(lua);
+ lua_pushfstring(lua, "Unable to select version for range '%s'", range_str);
+
+ return 2;
+ match:
+ semvers_sort(matches);
+ semver = semvers_pop(matches);
+ lua_createtable(lua, 0, 2);
+
+ lua_pushstring(lua, semver.raw);
+ lua_setfield(lua, -2, "version");
+
+ lua_pushstring(lua, source);
+ lua_setfield(lua, -2, "source");
+
+ semvers_dtor(matches);
+ semver_dtor(&semver);
+ semver_range_dtor(&range);
+
+ return 1;
+}
diff --git a/core/src/xmake/semver/semver.c b/core/src/xmake/semver/semver.c
new file mode 100644
index 000000000..27dfb3fb6
--- /dev/null
+++ b/core/src/xmake/semver/semver.c
@@ -0,0 +1,91 @@
+/*!The Make-like Build Utility based on Lua
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Copyright (C) 2015 - 2017, TBOOX Open Source Group.
+ *
+ * @author uael
+ * @file semver.c
+ *
+ */
+
+/* //////////////////////////////////////////////////////////////////////////////////////
+ * trace
+ */
+#define TB_TRACE_MODULE_NAME "semver"
+#define TB_TRACE_MODULE_DEBUG (0)
+
+/* //////////////////////////////////////////////////////////////////////////////////////
+ * includes
+ */
+#include "prefix.h"
+
+/* //////////////////////////////////////////////////////////////////////////////////////
+ * implementation
+ */
+
+void lua_pushsemver(lua_State *lua, const semver_t semver)
+{
+ semver_id_t const *id;
+ tb_uchar_t i = 0;
+
+ lua_createtable(lua, 0, 7);
+
+ lua_pushstring(lua, semver.raw);
+ lua_setfield(lua, -2, "raw");
+
+ lua_pushlstring(lua, semver.raw, semver.len);
+ lua_setfield(lua, -2, "version");
+
+ lua_pushinteger(lua, semver.major);
+ lua_setfield(lua, -2, "major");
+
+ lua_pushinteger(lua, semver.minor);
+ lua_setfield(lua, -2, "minor");
+
+ lua_pushinteger(lua, semver.patch);
+ lua_setfield(lua, -2, "patch");
+
+ lua_pushstring(lua, "prerelease");
+ lua_newtable(lua);
+ id = &semver.prerelease;
+ while (id && id->len) {
+ if (id->numeric) {
+ lua_pushinteger(lua, id->num);
+ } else {
+ lua_pushlstring(lua, id->raw, id->len);
+ }
+ id = id->next;
+ lua_rawseti(lua, -2, ++i);
+ }
+ lua_settable(lua, -3);
+
+ i = 0;
+ lua_pushstring(lua, "build");
+ lua_newtable(lua);
+ id = &semver.build;
+ while (id && id->len) {
+ if (id->numeric) {
+ lua_pushinteger(lua, id->num);
+ } else {
+ lua_pushlstring(lua, id->raw, id->len);
+ }
+ id = id->next;
+ lua_rawseti(lua, -2, ++i);
+ }
+ lua_settable(lua, -3);
+}
diff --git a/core/src/xmake/xmake.lua b/core/src/xmake/xmake.lua
index 484d94b98..acc71ed46 100644
--- a/core/src/xmake/xmake.lua
+++ b/core/src/xmake/xmake.lua
@@ -5,7 +5,7 @@ target("xmake")
set_kind("static")
-- add deps
- add_deps("luajit")
+ add_deps("sv", "luajit")
-- add defines
add_defines("__tb_prefix__=\"xmake\"")