summaryrefslogtreecommitdiff
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
parent34706ba053dda9dd86902cacf42a6c1878c85234 (diff)
merge repo and require codes
-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
-rw-r--r--core/xmake.lua11
-rwxr-xr-xdocs/get.sh161
-rwxr-xr-xtests/modules/semver/test.lua119
-rwxr-xr-xtests/projects/requires/src/main.c7
-rw-r--r--tests/projects/requires/test.lua10
-rw-r--r--tests/projects/requires/xmake.lua48
-rw-r--r--xmake/actions/install/install_admin.lua3
-rw-r--r--xmake/actions/require/action/build.lua193
-rw-r--r--xmake/actions/require/action/download.lua201
-rw-r--r--xmake/actions/require/action/install.lua260
-rw-r--r--xmake/actions/require/clear.lua40
-rw-r--r--xmake/actions/require/environment.lua218
-rw-r--r--xmake/actions/require/info.lua29
-rw-r--r--xmake/actions/require/install.lua89
-rw-r--r--xmake/actions/require/list.lua38
-rw-r--r--xmake/actions/require/main.lua100
-rw-r--r--xmake/actions/require/package.lua360
-rw-r--r--xmake/actions/require/repository.lua152
-rw-r--r--xmake/actions/require/search.lua29
-rw-r--r--xmake/actions/require/xmake.lua61
-rw-r--r--xmake/actions/uninstall/uninstall_admin.lua3
-rw-r--r--xmake/core/base/os.lua2
-rw-r--r--xmake/core/main.lua4
-rw-r--r--xmake/core/package/package.lua419
-rw-r--r--xmake/core/package/repository.lua134
-rw-r--r--xmake/core/project/project.lua37
-rw-r--r--xmake/core/sandbox/modules/hash.lua59
-rw-r--r--xmake/core/sandbox/modules/import/core/base/semver.lua86
-rw-r--r--xmake/core/sandbox/modules/import/core/package/package.lua82
-rw-r--r--xmake/core/sandbox/modules/import/core/package/repository.lua119
-rw-r--r--xmake/core/sandbox/modules/import/core/project/project.lua6
-rw-r--r--xmake/core/sandbox/modules/interpreter/os.lua2
-rw-r--r--xmake/core/sandbox/modules/os.lua11
-rw-r--r--xmake/core/sandbox/modules/utils.lua20
-rw-r--r--xmake/core/sandbox/modules/vprint.lua27
-rw-r--r--xmake/core/sandbox/modules/vprintf.lua27
-rw-r--r--xmake/modules/detect/tools/find_ping.lua48
-rw-r--r--xmake/modules/devel/git/checkurl.lua35
-rw-r--r--xmake/modules/devel/git/refs.lua8
-rw-r--r--xmake/modules/net/fasturl.lua92
-rw-r--r--xmake/modules/net/ping.lua73
-rw-r--r--xmake/plugins/doxygen/main.lua3
-rw-r--r--xmake/plugins/macro/macros/package.lua3
-rw-r--r--xmake/plugins/project/vstudio/impl/vs200x_solution.lua8
-rw-r--r--xmake/plugins/project/vstudio/impl/vs200x_vcproj.lua2
-rw-r--r--xmake/plugins/project/vstudio/impl/vs201x_solution.lua8
-rw-r--r--xmake/plugins/project/vstudio/impl/vs201x_vcxproj.lua2
-rw-r--r--xmake/plugins/project/vstudio/impl/vs201x_vcxproj_filters.lua2
-rw-r--r--xmake/plugins/repo/main.lua158
-rw-r--r--xmake/plugins/repo/xmake.lua54
106 files changed, 8756 insertions, 231 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\"")
diff --git a/core/xmake.lua b/core/xmake.lua
index 581f91224..141b81c6b 100644
--- a/core/xmake.lua
+++ b/core/xmake.lua
@@ -5,7 +5,7 @@ set_project("xmake")
set_version("2.1.5")
-- set xmake min version
-set_xmakever("2.1.2")
+set_xmakever("2.1.5")
-- set warning all as error
set_warnings("all", "error")
@@ -14,7 +14,7 @@ set_warnings("all", "error")
set_languages("c99", "cxx11")
-- disable some compiler errors
-add_cxflags("-Wno-error=deprecated-declarations", "-fno-strict-aliasing")
+add_cxflags("-Wno-error=deprecated-declarations", "-fno-strict-aliasing", "-Wno-error=nullability-completeness")
-- add defines
add_defines("_GNU_SOURCE=1", "_FILE_OFFSET_BITS=64", "_LARGEFILE_SOURCE")
@@ -41,11 +41,6 @@ if is_plat("windows") then
add_ldflags("-nodefaultlib:\"msvcrt.lib\"")
end
--- for macosx
-if is_plat("macosx") then
- add_ldflags("-all_load", "-pagezero_size 10000", "-image_base 100000000")
-end
-
-- for mode coverage
if is_mode("coverage") then
add_ldflags("-coverage", "-fprofile-arcs", "-ftest-coverage")
@@ -55,4 +50,4 @@ end
add_packagedirs("pkg")
-- add projects
-add_subdirs("src/luajit", "src/xmake", "src/demo")
+add_subdirs("src/sv","src/luajit", "src/xmake", "src/demo")
diff --git a/docs/get.sh b/docs/get.sh
deleted file mode 100755
index 6e417b98c..000000000
--- a/docs/get.sh
+++ /dev/null
@@ -1,161 +0,0 @@
-#!/bin/bash
-
-# xmake getter
-# usage: bash <(curl -s <my location>) [[mirror:]branch] [commit/__install_only__]
-
-set -o pipefail
-
-if [ 0 -ne "$(id -u)" ]
-then
- sudoprefix=sudo
-else
- sudoprefix=
-fi
-
-tmpdir=/tmp/.xmake_getter$$
-
-remote_get_content(){
- if curl --version >/dev/null 2>&1
- then
- curl -fsSL "$1"
- elif wget --version >/dev/null 2>&1
- then
- wget -q "$1" -O -
- fi
-}
-
-if [ "$1" = "__uninstall__" ]
-then
- # uninstall
- makefile=$(remote_get_content https://github.com/tboox/xmake/raw/master/makefile)
- while which xmake >/dev/null 2>&1
- do
- pre=$(which xmake | sed 's/\/bin\/xmake$//')
- # don't care if make exists -- if there's no make, how xmake built and installed?
- echo "$makefile" | make -f - uninstall prefix="$pre" 2>/dev/null || echo "$makefile" | $sudoprefix make -f - uninstall prefix="$pre" || exit $?
- done
- exit
-fi
-
-# below is installation
-# print a LOGO!
-echo ' _ '
-echo ' __ ___ __ __ __ _| | ______ '
-echo ' \ \/ / | \/ |/ _ | |/ / __ \ '
-echo ' > < | \__/ | /_| | < ___/ '
-echo ' /_/\_\_|_| |_|\__ \|_|\_\____| getter '
-echo ' '
-
-if [ 'x__local__' != "x$1" ]
-then
- brew --version >/dev/null 2>&1 && brew install --HEAD xmake && xmake --version && exit
-fi
-
-my_exit(){
- rv=$?
- if [ "x$1" != x ]
- then
- echo -ne '\x1b[41;37m'
- echo "$1"
- echo -ne '\x1b[0m'
- fi
- rm -rf $tmpdir 2>/dev/null
- if [ "x$2" != x ]
- then
- if [ $rv -eq 0 ];then rv=$2;fi
- fi
- exit "$rv"
-}
-test_tools()
-{
- prog='#include<stdio.h>\n#include<readline/readline.h>\nint main(){readline(0);return 0;}'
- {
- git --version &&
- make --version &&
- {
- echo -e "$prog" | cc -xc - -o /dev/null -lreadline ||
- echo -e "$prog" | gcc -xc - -o /dev/null -lreadline ||
- echo -e "$prog" | clang -xc - -o /dev/null -lreadline
- }
- } >/dev/null 2>&1
-}
-install_tools()
-{
- { apt-get --version >/dev/null 2>&1 && $sudoprefix apt-get install -y git build-essential libreadline-dev ccache; } ||
- { yum --version >/dev/null 2>&1 && $sudoprefix yum install -y git readline-devel ccache && $sudoprefix yum groupinstall -y 'Development Tools'; } ||
- { zypper --version >/dev/null 2>&1 && $sudoprefix zypper --non-interactive install git readline-devel ccache && $sudoprefix zypper --non-interactive install -t pattern devel_C_C++; } ||
- { pacman -V >/dev/null 2>&1 && $sudoprefix pacman -S --noconfirm --needed git base-devel ccache; }
-}
-test_tools || { install_tools && test_tools; } || my_exit "$(echo -e 'Dependencies Installation Fail\nThe getter currently only support these package managers\n\t* apt\n\t* yum\n\t* zypper\n\t* pacman\nPlease install following dependencies manually:\n\t* git\n\t* build essential like `make`, `gcc`, etc\n\t* libreadline-dev (readline-devel)\n\t* ccache (optional)')" 1
-branch=master
-mirror=tboox
-IFS=':'
-if [ x != "x$1" ]
-then
- brancharr=($1)
- if [ ${#brancharr[@]} -eq 1 ]
- then
- branch=${brancharr[0]}
- fi
- if [ ${#brancharr[@]} -eq 2 ]
- then
- branch=${brancharr[1]}
- mirror=${brancharr[0]}
- fi
- echo "Branch: $branch"
-fi
-if [ 'x__local__' != "x$branch" ]
-then
- git clone --depth=50 -b "$branch" "https://github.com/$mirror/xmake.git" $tmpdir || my_exit "$(echo -e 'Clone Fail\nCheck your network or branch name')"
- if [ x != "x$2" ]
- then
- cd $tmpdir || my_exit 'Chdir Error'
- git checkout -qf "$2"
- cd - || my_exit 'Chdir Error'
- fi
-else
- tmpdir=`pwd`
-fi
-if [ 'x__install_only__' != "x$2" ]
-then
- make -C $tmpdir --no-print-directory build
- rv=$?
- if [ $rv -ne 0 ]
- then
- make -C $tmpdir/core --no-print-directory error
- my_exit "$(echo -e 'Build Fail\nDetail:\n' | cat - /tmp/xmake.out)" $rv
- fi
-fi
-
-if [ "$prefix" = "" ]
-then
- prefix=~/.local
-fi
-
-if [ "x$prefix" != x ]
-then
- make -C $tmpdir --no-print-directory install prefix="$prefix"|| my_exit 'Install Fail'
-else
- $sudoprefix make -C $tmpdir --no-print-directory install || my_exit 'Install Fail'
-fi
-write_profile()
-{
- grep -sq ".xmake/profile" $1 || echo "[[ -s \"\$HOME/.xmake/profile\" ]] && source \"\$HOME/.xmake/profile\" # load xmake profile" >> $1
-}
-install_profile()
-{
- if [ ! -d ~/.xmake ]; then mkdir ~/.xmake; fi
- echo "export PATH=$prefix/bin:\$PATH" > ~/.xmake/profile
- if [[ "$SHELL" = */zsh ]]; then write_profile ~/.zshrc
- elif [[ "$SHELL" = */ksh ]]; then write_profile ~/.kshrc
- elif [[ "$SHELL" = */bash ]]; then write_profile ~/.bashrc
- fi
- write_profile ~/.bash_profile
-}
-install_profile
-if xmake --version >/dev/null 2>&1; then xmake --version; else
- source ~/.xmake/profile
- xmake --version
- echo "Reload shell profile by running the following command now!"
- echo -e "\x1b[1msource ~/.xmake/profile\x1b[0m"
-fi
diff --git a/tests/modules/semver/test.lua b/tests/modules/semver/test.lua
new file mode 100755
index 000000000..884eaf82e
--- /dev/null
+++ b/tests/modules/semver/test.lua
@@ -0,0 +1,119 @@
+-- imports
+import("core.base.semver")
+
+-- select version
+function _check_semver_select(results, required_ver, versions, tags, branches)
+
+ -- select it
+ local version, source = semver.select(required_ver, versions or {}, tags or {}, branches or {})
+ if (version.version or version) ~= results[1] or source ~= results[2] then
+ print("semver.select(\"%s\", {\"%s\"}, {\"%s\"}, {\"%s\"})"
+ , required_ver
+ , table.concat(versions or {}, "\", \"")
+ , table.concat(tags or {}, "\", \"")
+ , table.concat(branches or {}, "\", \""))
+ raise("{\"%s\", \"%s\"} != {\"%s\", \"%s\"}", version.version or version, source or "", results[1] or "", results[2] or "")
+ end
+end
+
+-- test select version
+function _test_semver_select()
+
+ _check_semver_select({"1.5.1", "versions"}
+ , ">=1.5.0 <1.6.0"
+ , {"1.4.0", "1.5.0", "1.5.1"})
+
+ _check_semver_select({"1.5.1", "versions"}
+ , "^1.5.0"
+ ,{"1.4.0", "1.5.0", "1.5.1"})
+
+ _check_semver_select({"master", "branches"}
+ , "master"
+ , {"1.4.0", "1.5.0", "1.5.1"}
+ , {"v1.2.0", "v1.6.0"}
+ , {"master", "dev"})
+
+ print("semver.select: ok!")
+end
+
+-- select version
+function _check_semver_satisfies(expected, version, range)
+
+ -- select it
+ local result = semver.satisfies(version, range)
+ if expected ~= result then
+ print("semver.satisfies(\"%s\", \"%s\")"
+ , version
+ , range)
+ raise("\"%s\" != \"%s\"", expected, result)
+ end
+end
+
+-- test satisfies version
+function _test_semver_satisfies()
+
+ _check_semver_satisfies(true, "1.5.1", ">=1.5.0 <1.6.0")
+ _check_semver_satisfies(true, "1.5.1", "^1.5.0")
+
+ print("semver.satisfies: ok!")
+end
+
+-- parse version
+function _check_semver_parse(version_str, major, minor, patch, prerelease, build)
+
+ -- create it
+ local version = semver.parse(version_str)
+
+ if version.major ~= major then
+ raise("major: \"%s\" != \"%s\"", version.major or "", major or "")
+ end
+
+ if version.minor ~= minor then
+ raise("minor: \"%s\" != \"%s\"", version.minor or "", minor or "")
+ end
+
+ if version.patch ~= patch then
+ raise("patch: \"%s\" != \"%s\"", version.patch or "", patch or "")
+ end
+
+ if table.concat(version.prerelease or {}, ".") ~= table.concat(prerelease or {}, ".") then
+ raise("prerelease: \"%s\" != \"%s\""
+ , table.concat(version.prerelease or {}, ".") or ""
+ , table.concat(prerelease or {}, ".") or "")
+ end
+
+ if table.concat(version.build or {}, ".") ~= table.concat(build or {}, ".") then
+ raise("build: \"%s\" != \"%s\""
+ , table.concat(version.build or {}, ".") or ""
+ , table.concat(build or {}, ".") or "")
+ end
+end
+
+-- test parse version
+function _test_semver_parse()
+
+ _check_semver_parse("1.2.3", 1, 2, 3)
+ _check_semver_parse("1.2.3-beta", 1, 2, 3, {"beta"})
+ _check_semver_parse("1.2.3-beta+77", 1, 2, 3, {"beta"}, {"77"})
+ _check_semver_parse("v1.2.3-alpha.1+77", 1, 2, 3, {"alpha", "1"}, {"77"})
+ _check_semver_parse("v3.2.1-alpha.1+77.foo", 3, 2, 1, {"alpha", "1"}, {"77", "foo"})
+
+ print("semver.parse: ok!")
+end
+
+--
+-- run tests:
+--
+-- $ make test name=semver
+--
+function main()
+
+ -- test semver
+ _test_semver_parse()
+
+ -- test semver satisfies
+ _test_semver_satisfies()
+
+ -- test select version
+ _test_semver_select()
+end
diff --git a/tests/projects/requires/src/main.c b/tests/projects/requires/src/main.c
new file mode 100755
index 000000000..9ae580511
--- /dev/null
+++ b/tests/projects/requires/src/main.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main(int argc, char** argv)
+{
+ printf("hello world!\n");
+ return 0;
+}
diff --git a/tests/projects/requires/test.lua b/tests/projects/requires/test.lua
new file mode 100644
index 000000000..eacf35408
--- /dev/null
+++ b/tests/projects/requires/test.lua
@@ -0,0 +1,10 @@
+-- imports
+import("..build")
+
+-- main entry
+function main()
+
+ -- TODO
+ -- build project
+-- build()
+end
diff --git a/tests/projects/requires/xmake.lua b/tests/projects/requires/xmake.lua
new file mode 100644
index 000000000..f96866d10
--- /dev/null
+++ b/tests/projects/requires/xmake.lua
@@ -0,0 +1,48 @@
+-- define package
+package("mbedtls")
+ set_urls("https://github.com/ARMmbed/mbedtls.git")
+ add_requires("https://github.com/glennrp/libpng.git@libpng >=1.6.28")
+package_end()
+
+-- group packages
+package("zlib-mbedtls")
+ add_requires("zlib >=1.2.11")
+ add_requires("mbedtls master optional")
+package_end()
+
+-- requires
+add_requires("zlib-mbedtls")
+add_requires("[email protected] >=1.5.1 <1.6.1 optional")
+
+-- the debug mode
+if is_mode("debug") then
+
+ -- enable the debug symbols
+ set_symbols("debug")
+
+ -- disable optimization
+ set_optimize("none")
+end
+
+-- the release mode
+if is_mode("release") then
+
+ -- set the symbols visibility: hidden
+ set_symbols("hidden")
+
+ -- enable fastest optimization
+ set_optimize("fastest")
+
+ -- strip all symbols
+ set_strip("all")
+end
+
+-- add target
+target("console_c")
+
+ -- set kind
+ set_kind("binary")
+
+ -- add files
+ add_files("src/*.c")
+
diff --git a/xmake/actions/install/install_admin.lua b/xmake/actions/install/install_admin.lua
index f641628ea..7028e5c09 100644
--- a/xmake/actions/install/install_admin.lua
+++ b/xmake/actions/install/install_admin.lua
@@ -41,9 +41,6 @@ function main(targetname, installdir)
-- load platform
platform.load(config.plat())
- -- laod project
- project.load()
-
-- save the current option and push a new option context
option.save()
diff --git a/xmake/actions/require/action/build.lua b/xmake/actions/require/action/build.lua
new file mode 100644
index 000000000..0ae19a44c
--- /dev/null
+++ b/xmake/actions/require/action/build.lua
@@ -0,0 +1,193 @@
+--!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 build.lua
+--
+
+-- imports
+import("core.base.option")
+import("core.project.config")
+import("core.sandbox.sandbox")
+
+-- build for xmake file
+function _build_for_xmakefile(package, buildfile)
+
+ -- configure it first
+ os.vrun("xmake f -p $(plat) -a $(arch) -m $(mode) -c")
+
+ -- build it
+ os.vrun("xmake -r")
+
+ -- ok
+ return true
+end
+
+-- build for makefile
+function _build_for_makefile(package, buildfile)
+
+ -- build it
+ os.vrun("make")
+
+ -- ok
+ return true
+end
+
+-- build for configure
+function _build_for_configure(package, buildfile)
+
+ -- make prefix directory
+ os.mkdir(".prefix")
+
+ -- configure it first
+ os.vrun("./configure --prefix=%s", path.absolute(".prefix"))
+
+ -- build it
+ os.vrun("make")
+
+ -- install to .prefix
+ os.vrun("make install")
+
+ -- ok
+ return true
+end
+
+-- build for cmakelist
+function _build_for_cmakelists(package, buildfile)
+
+ -- make makefile first
+ os.vrun("cmake -DCMAKE_INSTALL_PREFIX=%s .", path.absolute(".prefix"))
+
+ -- build it
+ os.vrun("make")
+
+ -- install to .prefix
+ os.vrun("make install")
+
+ -- ok
+ return true
+end
+
+-- build for *.sln
+function _build_for_sln(package, buildfile)
+
+ -- build it for windows
+ if config.plat() == "windows" then
+ os.vrun("msbuild %s -nologo -t:Rebuild -p:Configuration=Release", buildfile)
+ return true
+ end
+ return false
+end
+
+-- on build the given package
+function _on_build_package(package)
+
+ -- TODO *.vcproj, premake.lua, scons, autogen.sh, Makefile.am, ...
+ -- init build scripts
+ local buildscripts =
+ {
+ {"xmake.lua", _build_for_xmakefile }
+ , {"*.sln", _build_for_sln }
+ , {"CMakeLists.txt", _build_for_cmakelists }
+ , {"configure", _build_for_configure }
+ , {"[mM]akefile", _build_for_makefile }
+ }
+
+ -- attempt to build it
+ for _, buildscript in pairs(buildscripts) do
+
+ -- save the current directory
+ local oldir = os.curdir()
+
+ -- try building
+ local ok = try
+ {
+ function ()
+
+ -- attempt to build it if file exists
+ local files = os.files(buildscript[1])
+ if #files > 0 then
+ return buildscript[2](package, files[1])
+ end
+ end,
+
+ catch
+ {
+ function (errors)
+
+ -- trace verbose info
+ if errors then
+ vprint(errors)
+ end
+ end
+ }
+ }
+
+ -- restore directory
+ os.cd(oldir)
+
+ -- ok?
+ if ok then return end
+ end
+
+ -- failed
+ raise("attempt to build package %s failed!", package:name())
+end
+
+-- run script
+function _run_script(script, package)
+
+ -- TODO
+ -- register filter handler before building
+-- sandbox.filter_register(script, "package.build", function (var)
+-- end)
+
+ -- run it
+ script(package)
+
+ -- cancel filter handler before building
+-- sandbox.filter_register(script, "package.build", nil)
+end
+
+-- build the given package
+function main(package)
+
+ -- the package scripts
+ local scripts =
+ {
+ package:script("build_before")
+ , package:script("build", _on_build_package)
+ , package:script("build_after")
+ }
+
+ -- save the current directory
+ local oldir = os.curdir()
+
+ -- build it
+ for i = 1, 3 do
+ local script = scripts[i]
+ if script ~= nil then
+ _run_script(script, package)
+ end
+ end
+
+ -- restore the current directory
+ os.cd(oldir)
+end
diff --git a/xmake/actions/require/action/download.lua b/xmake/actions/require/action/download.lua
new file mode 100644
index 000000000..cfc41706f
--- /dev/null
+++ b/xmake/actions/require/action/download.lua
@@ -0,0 +1,201 @@
+--!The Make-like download 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 download.lua
+--
+
+-- imports
+import("core.base.option")
+import("net.http")
+import("devel.git")
+import("utils.archive")
+
+-- empty chars
+function _emptychars()
+ return " "
+end
+
+-- checkout codes from git
+function _checkout(package, url, sourcedir)
+
+ -- use previous source directory if exists
+ local packagedir = path.join(sourcedir, package:name())
+ if os.isdir(packagedir) and not option.get("force") then
+
+ -- clean the previous build files
+ git.clean({repodir = packagedir, force = true})
+ return
+ end
+
+ -- remove temporary directory
+ os.rm(sourcedir .. ".tmp")
+
+ -- download package from branches?
+ packagedir = path.join(sourcedir .. ".tmp", package:name())
+ if package:version_from("branches") then
+
+ -- only shadow clone this branch
+ git.clone(url, {depth = 1, branch = package:version_str(), outputdir = packagedir})
+
+ -- download package from tags or versions?
+ else
+
+ -- clone whole history and tags
+ git.clone(url, {outputdir = packagedir})
+
+ -- attempt to checkout the given version
+ git.checkout(package:version_str(), {repodir = packagedir})
+ end
+
+ -- move to source directory
+ os.rm(sourcedir)
+ os.mv(sourcedir .. ".tmp", sourcedir)
+
+ -- trace
+ cprint("\r${yellow} => ${clear}clone %s %s .. ${green}ok%s", url, package:version_str(), _emptychars())
+end
+
+-- download codes from ftp/http/https
+function _download(package, url, sourcedir)
+
+ -- get package file
+ local packagefile = path.filename(url)
+
+ -- the package file have been downloaded?
+ local sha256 = package:sha256()
+ if option.get("force") or not os.isfile(packagefile) or (sha256 and sha256 ~= hash.sha256(packagefile)) then
+
+ -- attempt to remove package file first
+ os.rm(packagefile)
+
+ -- download package file
+ http.download(url, packagefile)
+
+ -- check hash
+ if sha256 and sha256 ~= hash.sha256(packagefile) then
+ raise("unmatched checksum!")
+ end
+ end
+
+ -- extract package file
+ os.rm(sourcedir .. ".tmp")
+ archive.extract(packagefile, sourcedir .. ".tmp")
+
+ -- move to source directory
+ os.rm(sourcedir)
+ os.mv(sourcedir .. ".tmp", sourcedir)
+
+ -- trace
+ cprint("\r${yellow} => ${clear}download %s .. ${green}ok%s", url, _emptychars())
+end
+
+-- get sorted urls
+function _urls(package)
+
+ -- sort urls from the version source
+ local urls = {{}, {}}
+ for _, url in ipairs(package:urls()) do
+ if git.checkurl(url) then
+ table.insert(urls[1], url)
+ else
+ table.insert(urls[2], url)
+ end
+ end
+ if package:version_from("tags", "branches") then
+ return table.join(urls[1], urls[2])
+ else
+ return table.join(urls[2], urls[1])
+ end
+end
+
+-- download the given package
+function main(package)
+
+ -- skip phony package without urls
+ if #package:urls() == 0 then
+ return
+ end
+
+ -- get working directory of this package
+ local workdir = package:cachedir()
+
+ -- ensure the working directory first
+ os.mkdir(workdir)
+
+ -- enter the working directory
+ local oldir = os.cd(workdir)
+
+ -- download package from urls
+ local urls = _urls(package)
+ for idx, url in ipairs(urls) do
+
+ -- filter url
+ url = package:filter():handle(url)
+
+ -- download url
+ local ok = try
+ {
+ function ()
+
+ -- download package
+ local sourcedir = "source"
+ if git.checkurl(url) then
+ _checkout(package, url, sourcedir)
+ else
+ _download(package, url, sourcedir)
+ end
+
+ -- ok
+ return true
+ end,
+ catch
+ {
+ function (errors)
+
+ -- verbose?
+ if option.get("verbose") and errors then
+ cprint("${bright red}error: ${clear}%s", errors)
+ end
+
+ -- trace
+ if git.checkurl(url) then
+ cprint("\r${yellow} => ${clear}clone %s %s .. ${red}failed%s", url, package:version_str(), _emptychars())
+ else
+ cprint("\r${yellow} => ${clear}download %s .. ${red}failed%s", url, _emptychars())
+ end
+
+ -- failed? break it
+ if idx == #urls then
+ raise("download failed!")
+ end
+ end
+ }
+ }
+
+ -- ok? break it
+ if ok then break end
+ end
+
+ -- leave working directory
+ os.cd(oldir)
+end
+
+
diff --git a/xmake/actions/require/action/install.lua b/xmake/actions/require/action/install.lua
new file mode 100644
index 000000000..a5a3292cc
--- /dev/null
+++ b/xmake/actions/require/action/install.lua
@@ -0,0 +1,260 @@
+--!The Make-like install 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 install.lua
+--
+
+-- imports
+import("core.base.option")
+import("core.project.target")
+import("build")
+
+-- install for xmake file
+function _install_for_xmakefile(package)
+
+ -- package to install directory
+ os.vrun("xmake p -o %s", package:installdir())
+
+ -- ok
+ return true
+end
+
+-- install for generic
+function _install_for_generic(package)
+
+ -- the package name
+ local name = package:name()
+
+ -- the install directory
+ local installdir = path.join(package:installdir(), name .. ".pkg")
+
+ -- the linkdir
+ local linkdir = path.join(installdir, "lib/$(mode)/$(plat)/$(arch)")
+ os.mkdir(linkdir)
+
+ -- the includedir
+ local includedir = path.join(installdir, "inc")
+ os.mkdir(includedir)
+
+ -- the prefix directory exists?
+ local prefixdir = ""
+ if os.isdir(".prefix") and not os.emptydir(".prefix") then
+ prefixdir = ".prefix" .. path.seperator()
+ end
+
+ -- install the library files and ignore hidden files (.xxx)
+ if not os.trycp(prefixdir .. "**" .. target.filename("*", "static"), linkdir) and
+ not os.trycp(prefixdir .. "**" .. target.filename("*", "shared"), linkdir) then
+ raise("the library files not found in package %s", name)
+ end
+
+ -- install the header files
+ for _, headerfile in ipairs(table.join((os.files(prefixdir .. "**.h")), (os.files(prefixdir .. "**.hpp")))) do
+
+ -- the destinate header
+ local dstheaderfile = nil
+ if #prefixdir > 0 then
+ dstheaderfile = path.absolute(path.relative(headerfile, path.join(prefixdir, "include")), includedir)
+ else
+ dstheaderfile = path.join(includedir, path.filename(headerfile))
+ end
+
+ -- install header file
+ os.cp(headerfile, dstheaderfile)
+ end
+
+ -- make xmake.lua
+ local file = io.open(path.join(installdir, "xmake.lua"), "w")
+ if file then
+
+ -- the xmake.lua content
+ local content = [[
+-- the %s package
+option("%s")
+
+ -- show menu
+ set_showmenu(true)
+
+ -- set category
+ set_category("package")
+
+ -- set description
+ set_description("The %s package")
+
+ -- add defines to config.h if checking ok
+ add_defines_h_if_ok("$(prefix)_PACKAGE_HAVE_%s")
+
+ -- add links for checking
+ add_links("%s")
+
+ -- add link directories
+ add_linkdirs("lib/$(mode)/$(plat)/$(arch)")
+
+ -- add include directories
+ add_includedirs("inc")
+]]
+
+ -- save file
+ file:writef(content, name, name, name, name:upper(), name)
+
+ -- exit file
+ file:close()
+ end
+
+ -- ok
+ return true
+end
+
+-- on install the given package
+function _on_install_package(package)
+
+ -- init install scripts
+ local installscripts =
+ {
+ {"xmake.lua", _install_for_xmakefile }
+ , {"*", _install_for_generic }
+ }
+
+ -- attempt to install it
+ for _, installscript in pairs(installscripts) do
+
+ -- save the current directory
+ local oldir = os.curdir()
+
+ -- try installing
+ local ok = try
+ {
+ function ()
+
+ -- attempt to install it if file exists
+ local files = os.files(installscript[1])
+ if #files > 0 then
+ return installscript[2](package)
+ end
+ end,
+
+ catch
+ {
+ function (errors)
+
+ -- trace verbose info
+ if errors then
+ vprint(errors)
+ end
+ end
+ }
+ }
+
+ -- restore directory
+ os.cd(oldir)
+
+ -- ok?
+ if ok then return end
+ end
+
+ -- failed
+ raise("attempt to install package %s failed!", package:name())
+end
+
+-- install the given package
+function main(package)
+
+ -- skip phony package without urls
+ if #package:urls() == 0 then
+ return
+ end
+
+ -- get working directory of this package
+ local workdir = package:cachedir()
+
+ -- enter source files directory
+ local oldir = nil
+ for _, srcdir in ipairs(os.dirs(path.join(workdir, "source", "*"))) do
+ oldir = os.cd(srcdir)
+ break
+ end
+
+ -- trace
+ cprintf("${yellow} => ${clear}installing %s-%s .. ", package:name(), package:version_str())
+ if option.get("verbose") then
+ print("")
+ end
+
+ -- install it
+ try
+ {
+ function ()
+
+ -- the package scripts
+ local scripts =
+ {
+ package:script("install_before")
+ , package:script("install", _on_install_package)
+ , package:script("install_after")
+ }
+
+ -- create the install task
+ local installtask = function ()
+
+ -- build it
+ build(package)
+
+ -- install it
+ for i = 1, 3 do
+ local script = scripts[i]
+ if script ~= nil then
+ script(package)
+ end
+ end
+ end
+
+ -- install package
+ if option.get("verbose") then
+ installtask()
+ else
+ process.asyncrun(installtask)
+ end
+
+ -- trace
+ cprint("${green}ok")
+ end,
+
+ catch
+ {
+ function (errors)
+
+ -- verbose?
+ if option.get("verbose") and errors then
+ cprint("${bright red}error: ${clear}%s", errors)
+ end
+
+ -- trace
+ cprint("${red}failed")
+
+ -- failed
+ raise("install failed!")
+ end
+ }
+ }
+
+ -- leave source codes directory
+ os.cd(oldir)
+end
diff --git a/xmake/actions/require/clear.lua b/xmake/actions/require/clear.lua
new file mode 100644
index 000000000..169723ef3
--- /dev/null
+++ b/xmake/actions/require/clear.lua
@@ -0,0 +1,40 @@
+--!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 clear.lua
+--
+
+-- imports
+import("core.project.cache")
+import("core.package.package")
+
+-- clear all installed package caches
+function main()
+
+ -- clear cache directory
+ os.rm(package.cachedir())
+
+ -- clear require cache
+ cache.enter("local.require")
+ cache.clear()
+ cache.flush()
+end
+
diff --git a/xmake/actions/require/environment.lua b/xmake/actions/require/environment.lua
new file mode 100644
index 000000000..937ede435
--- /dev/null
+++ b/xmake/actions/require/environment.lua
@@ -0,0 +1,218 @@
+--!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 environment.lua
+--
+
+-- imports
+import("core.base.option")
+import("core.platform.environment")
+import("net.http")
+import("net.fasturl")
+import("utils.archive")
+
+-- enter linux environment
+function _enter_linux()
+
+ -- add $programdir to $path for running xmake
+ os.addenv("PATH", os.programdir())
+end
+
+-- enter macosx environment
+function _enter_macosx()
+
+ -- add $programdir to $path for running xmake
+ os.addenv("PATH", os.programdir())
+end
+
+-- enter windows environment (xmake/winenv/cmd)
+--
+-- @note curl and tar has been placed in the xmake installation package
+--
+function _enter_windows()
+
+ -- init winenv directory
+ local winenv_dir = path.translate("~/.xmake/winenv")
+
+ -- add $programdir/winenv/cmd to $path
+ os.addenv("PATH", path.join(os.programdir(), "winenv", "bin"))
+
+ -- load winenv
+ for _, script_dir in ipairs(os.files(path.join(winenv_dir, "**", "winenv.lua")), path.directory) do
+ import("winenv", {rootdir = script_dir}).main(script_dir)
+ return
+ end
+
+ -- trace
+ cprintf("installing winenv .. ")
+ if option.get("verbose") then
+ print("")
+ end
+
+ -- init winenv.zip file path
+ local winenv_zip = os.tmpfile() .. ".zip"
+ local winenv_zip_tmp = winenv_zip .. ".tmp"
+
+ -- init winenv.zip urls
+ local winenv_arch = ifelse(os.arch() == "x64", "win64", "win32")
+ local winenv_urls =
+ {
+ format("https://github.com/tboox/xmake-%senv/archive/master.zip", winenv_arch)
+ , format("https://coding.net/u/waruqi/p/xmake-%senv/git/archive/master", winenv_arch)
+ }
+ fasturl.add(winenv_urls)
+
+ -- download winenv.zip file
+ for _, winenv_url in ipairs(fasturl.sort(winenv_urls)) do
+ local ok = try
+ {
+ function ()
+
+ -- no cached winenv.zip file?
+ if not os.isfile(winenv_zip) or option.get("force") then
+
+ -- remove winenv.zip.tmp file first
+ os.rm(winenv_zip_tmp)
+
+ -- create a download task
+ local task = function ()
+ http.download(winenv_url, winenv_zip_tmp)
+ end
+
+ -- download winenv.zip
+ if option.get("verbose") then
+ task()
+ else
+ process.asyncrun(task)
+ end
+
+ -- attempt to remove previous winenv.zip first
+ os.rm(winenv_zip)
+
+ -- rename winenv.zip.tmp to winenv.zip
+ os.mv(winenv_zip_tmp, winenv_zip)
+ end
+
+ -- ok
+ return true
+ end,
+
+ catch
+ {
+ function (errors)
+
+ -- verbose?
+ if option.get("verbose") then
+ cprint("${bright red}error: ${clear}%s", errors)
+ end
+ end
+ }
+ }
+
+ -- ok?
+ if ok then
+
+ -- remove winenv directory first
+ os.rm(winenv_dir)
+
+ -- extract winenv.zip file
+ archive.extract(winenv_zip, winenv_dir)
+
+ -- load winenv
+ for _, script_dir in ipairs(os.files(path.join(winenv_dir, "**", "winenv.lua")), path.directory) do
+ import("winenv", {rootdir = script_dir}).main(script_dir)
+ break
+ end
+
+ -- trace
+ cprint("${green}ok")
+
+ -- ok
+ return
+ end
+ end
+
+ -- failed
+ cprint("${red}failed")
+ raise()
+end
+
+-- enter host environment
+function _enter_host()
+
+ -- save old $path environment
+ _g._PATH_ENV = os.getenv("PATH")
+
+ -- init loaders
+ local loaders =
+ {
+ linux = _enter_linux
+ , macosx = _enter_macosx
+ , windows = _enter_windows
+ }
+
+ -- enter host environment
+ local loader = loaders[os.host()]
+ if loader then
+ loader()
+ end
+end
+
+-- leave host environment
+function _leave_host()
+
+ -- restore old $path environment
+ os.setenv("PATH", _g._PATH_ENV)
+end
+
+-- enter environment
+--
+-- ensure that we can find some basic tools: git, make/nmake/cmake, msbuild ...
+--
+-- If these tools not exist, we will install it first.
+--
+function enter()
+
+ -- enter host environment
+ _enter_host()
+
+ -- set search pathes of toolchains
+ environment.enter("toolchains")
+
+ -- TODO set toolchains for CC, LD, ..
+
+ -- TODO set flags of toolchains
+end
+
+-- leave environment
+function leave()
+
+ -- restore search pathes of toolchains
+ environment.leave("toolchains")
+
+ -- TODO restore toolchains for CC, LD
+
+ -- TODO set flags of toolchains
+
+
+ -- leave host environment
+ _leave_host()
+end
diff --git a/xmake/actions/require/info.lua b/xmake/actions/require/info.lua
new file mode 100644
index 000000000..1e5d95a80
--- /dev/null
+++ b/xmake/actions/require/info.lua
@@ -0,0 +1,29 @@
+--!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 info.lua
+--
+
+-- show the given package info
+function main(packages)
+ -- TODO
+end
+
diff --git a/xmake/actions/require/install.lua b/xmake/actions/require/install.lua
new file mode 100644
index 000000000..421945d52
--- /dev/null
+++ b/xmake/actions/require/install.lua
@@ -0,0 +1,89 @@
+--!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 package.lua
+--
+
+-- imports
+import("core.base.option")
+import("core.project.project")
+import("action")
+import("package")
+import("repository")
+import("environment")
+
+-- install packages
+function main(requires)
+
+ -- enter environment
+ environment.enter()
+
+ -- TODO need optimization
+ -- pull all repositories first
+ repository.pull()
+
+ -- load packages
+ local packages = package.load_packages(requires or project.requires())
+
+ -- download packages
+ local waitindex = 0
+ local waitchars = {'\\', '|', '/', '-'}
+ process.runjobs(function (index)
+
+ local instance = packages[index]
+ if instance then
+
+ -- download package
+ action.download(instance)
+ end
+
+ end, #packages, ifelse(option.get("verbose"), 1, 4), 300, function (indices)
+
+ -- do not print progress info if be verbose
+ if option.get("verbose") then
+ return
+ end
+
+ -- update waitchar index
+ waitindex = ((waitindex + 1) % #waitchars)
+
+ -- make downloading packages list
+ local downloading = {}
+ for _, index in ipairs(indices) do
+ local instance = packages[index]
+ if instance then
+ table.insert(downloading, instance:name())
+ end
+ end
+
+ -- trace
+ cprintf("\r${yellow} => ${clear}downloading %s .. %s", table.concat(downloading, ", "), waitchars[waitindex + 1])
+ end)
+
+ -- install all required packages from repositories
+ for _, instance in ipairs(packages) do
+ action.install(instance)
+ end
+
+ -- leave environment
+ environment.leave()
+end
+
diff --git a/xmake/actions/require/list.lua b/xmake/actions/require/list.lua
new file mode 100644
index 000000000..056fdab16
--- /dev/null
+++ b/xmake/actions/require/list.lua
@@ -0,0 +1,38 @@
+--!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 list.lua
+--
+
+-- imports
+import("core.project.project")
+import("package")
+
+-- list packages
+function main()
+
+ -- list all requires
+ print("Tha package dependencies:")
+ for packagename, requireinfo in pairs(package.load_requires(project.requires())) do
+ print(" %s %s", packagename, requireinfo.version)
+ end
+end
+
diff --git a/xmake/actions/require/main.lua b/xmake/actions/require/main.lua
new file mode 100644
index 000000000..23fce2766
--- /dev/null
+++ b/xmake/actions/require/main.lua
@@ -0,0 +1,100 @@
+--!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 main.lua
+--
+
+-- imports
+import("core.base.option")
+import("core.base.task")
+import("core.project.config")
+import("core.project.project")
+import("core.platform.platform")
+import("list")
+import("info")
+import("clear")
+import("search")
+import("install")
+
+--
+-- the default repositories:
+-- xmake-repo https://github.com/tboox/xmake-repo.git
+--
+-- add other repositories:
+-- xmake repo --add other-repo https://github.com/other/other-repo.git
+-- or
+-- add_repositories("other-repo https://github.com/other/other-repo.git")
+--
+-- add requires:
+--
+-- add_requires("tboox.tbox >=1.5.1", "zlib >=1.2.11")
+-- add_requires("zlib master")
+-- add_requires("[email protected] >=1.5.1")
+-- add_requires("https://github.com/tboox/[email protected] >=1.5.1")
+--
+-- add package dependencies:
+--
+-- target("test")
+-- add_packages("tboox.tbox", "zlib")
+--
+
+-- load project
+function _load_project()
+
+ -- config it first
+ task.run("config")
+
+ -- enter project directory
+ os.cd(project.directory())
+end
+
+-- main
+function main()
+
+ -- load project first
+ _load_project()
+
+ -- clear all installed packages cache
+ if option.get("clear") then
+
+ clear(option.get("global"))
+
+ -- search for the given packages from repositories
+ elseif option.get("search") then
+
+ search(option.get("packages"))
+
+ -- show the given package info
+ elseif option.get("info") then
+
+ info(option.get("packages"))
+
+ -- list all package dependencies
+ elseif option.get("list") then
+
+ list()
+
+ -- install and update all outdated package dependencies by default if no arguments
+ else
+ install(option.get("requires"))
+ end
+end
+
diff --git a/xmake/actions/require/package.lua b/xmake/actions/require/package.lua
new file mode 100644
index 000000000..6b401ab73
--- /dev/null
+++ b/xmake/actions/require/package.lua
@@ -0,0 +1,360 @@
+--!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 package.lua
+--
+
+-- imports
+import("core.base.semver")
+import("core.base.option")
+import("core.base.global")
+import("core.project.cache")
+import("core.project.project")
+import("core.package.package", {alias = "core_package"})
+import("devel.git")
+import("net.fasturl")
+import("repository")
+
+--
+-- parse require string
+--
+-- add_requires("tboox.tbox >=1.5.1", "zlib >=1.2.11")
+-- add_requires("zlib master")
+-- add_requires("[email protected] >=1.5.1")
+-- add_requires("https://github.com/tboox/[email protected] >=1.5.1")
+-- add_requires("tboox.tbox >=1.5.1 <1.6.0 optional")
+--
+function _parse_require(require_str)
+
+ -- get it from cache first
+ local requires = _g._REQUIRES or {}
+ local required = requires[require_str]
+ if required then
+ return required.packagename, required.requireinfo
+ end
+
+ -- split package and version info
+ local splitinfo = require_str:split('%s+')
+ assert(splitinfo and #splitinfo > 0, "require(\"%s\"): invalid!", require_str)
+
+ -- get package info
+ local packageinfo = splitinfo[1]
+
+ -- get mode at last position
+ --
+ -- .e.g
+ --
+ -- must
+ -- optional
+ --
+ local mode = "must"
+ if #splitinfo > 1 then
+
+ -- get mode
+ local modes = {must = true, optional = true}
+ local value = splitinfo[#splitinfo]:lower()
+ if modes[value] then
+ mode = value
+ table.remove(splitinfo)
+ end
+ end
+
+ -- get version
+ --
+ -- .e.g
+ --
+ -- >=1.5.1 <1.6.0
+ -- master || >1.4
+ -- ~1.2.3
+ -- ^1.1
+ --
+ local version = "master"
+ if #splitinfo > 1 then
+ version = table.concat(table.slice(splitinfo, 2), " ")
+ end
+ assert(version, "require(\"%s\"): unknown version!", require_str)
+
+ -- get repository name, package name and package url
+ local reponame = nil
+ local packageurl = nil
+ local packagename = nil
+ local pos = packageinfo:find_last('@', true)
+ if pos then
+
+ -- get package name
+ packagename = packageinfo:sub(pos + 1)
+
+ -- get reponame or packageurl
+ local repo_or_pkgurl = packageinfo:sub(1, pos - 1)
+
+ -- is package url?
+ if repo_or_pkgurl:find('[/\\]') then
+ packageurl = repo_or_pkgurl
+ else
+ reponame = repo_or_pkgurl
+ end
+ else
+ packagename = packageinfo
+ end
+
+ -- check package name
+ assert(packagename, "require(\"%s\"): the package name not found!", require_str)
+
+ -- init required item
+ local required = {}
+ required.packagename = packagename
+ required.requireinfo = {reponame = reponame, packageurl = packageurl, version = version, mode = mode}
+
+ -- save this required item to cache
+ requires[require_str] = required
+ _g._REQUIRES = requires
+
+ -- ok
+ return required.packagename, required.requireinfo
+end
+
+-- load package instance from the given package url
+function _load_package_from_url(packagename, packageurl)
+
+ -- load it
+ return core_package.load_from_url(packagename, packageurl)
+end
+
+-- load package instance from project
+function _load_package_from_project(packagename)
+
+ -- load it
+ return core_package.load_from_project(packagename)
+end
+
+-- load package instance from repositories
+function _load_package_from_repository(packagename, reponame)
+
+ -- get package directory from the given package name
+ local packagedir, is_global = repository.packagedir(packagename, reponame)
+ if packagedir then
+ -- load it
+ return core_package.load_from_repository(packagename, is_global, packagedir)
+ end
+end
+
+-- load required packages
+function _load_package(packagename, requireinfo)
+
+ -- attempt to get it from cache first
+ local packages = _g._PACKAGES or {}
+ local instance = packages[packagename]
+ if instance then
+
+ -- satisfy required version?
+ if not semver.satisfies(instance:version(), requireinfo.version) then
+ raise("package(%s): version conflict, '%s' does not satisfy '%s'!", packagename, instance:version(), requireinfo.version)
+ end
+
+ -- ok
+ return instance
+ end
+
+ -- load package instance
+ instance = nil
+ if requireinfo.packageurl then
+ -- load package from the given package url
+ instance = _load_package_from_url(packagename, requireinfo.packageurl)
+ else
+ -- load package from project first
+ instance = _load_package_from_project(packagename)
+ if not instance then
+ -- load package from repositories
+ instance = _load_package_from_repository(packagename, requireinfo.reponame)
+ end
+ end
+
+ -- check
+ assert(instance, "package(%s) not found!", packagename)
+
+ -- save require info to package
+ instance:requireinfo_set(requireinfo)
+
+ -- save this package instance to cache
+ packages[packagename] = instance
+ _g._PACKAGES = packages
+
+ -- ok
+ return instance
+end
+
+-- load all required packages
+function _load_packages(requires)
+
+ -- no requires?
+ if not requires or #requires == 0 then
+ return {}
+ end
+
+ -- load packages
+ local packages = {}
+ for packagename, requireinfo in pairs(load_requires(requires)) do
+
+ -- load package instance
+ local package = _load_package(packagename, requireinfo)
+
+ -- load required packages and save them first of this package
+ requires = package:get("requires")
+ if requires then
+ table.join2(packages, _load_packages(requires))
+ end
+
+ -- save this package instance
+ table.insert(packages, package)
+ end
+
+ -- ok?
+ return packages
+end
+
+-- load all git refs from packages
+function _load_packages_gitrefs(packages)
+
+ -- enter cache scope
+ cache.enter("local.require")
+
+ -- load cache
+ local gitrefs = nil
+ if option.get("force") then
+ gitrefs = {}
+ else
+ gitrefs = cache.get("gitrefs") or {}
+ end
+
+ -- run tasks
+ local results = {}
+ process.runjobs(function (index)
+ local package = packages[index]
+ if package then
+
+ -- attempt to get refs from cache first
+ local refs = gitrefs[package:name()]
+ if refs then
+ results[package:name()] = {tags = refs.tags, branches = refs.branches}
+ else
+ -- attempt to get refs from the git url
+ local tags = {}
+ local branches = {}
+ for _, url in ipairs(package:urls()) do
+ if git.checkurl(url) then
+
+ -- fetch refs
+ tags, branches = git.refs(url)
+
+ -- save result
+ results[package:name()] = {tags = tags, branches = branches}
+
+ -- cache result
+ gitrefs[package:name()] = {tags = tags, branches = branches}
+ break
+ end
+ end
+ end
+ end
+ end, #packages)
+
+ -- save cache
+ cache.set("gitrefs", gitrefs)
+ cache.flush()
+
+ -- ok?
+ return results
+end
+
+-- select package version
+function _select_package_version(package, required_ver, gitrefs)
+
+ -- get versions
+ local versions = package:get("versions")
+
+ -- attempt to get tags and branches from the git url
+ local refs = {}
+ if gitrefs then
+ refs = gitrefs[package:name()] or {}
+ end
+
+ -- select required version
+ return semver.select(required_ver, versions, refs.tags, refs.branches)
+end
+
+-- the cache directory
+function cachedir()
+ return path.join(global.directory(), "cache", "packages")
+end
+
+-- load requires
+function load_requires(requires)
+
+ -- parse requires
+ local requireinfos = {}
+ for _, require_str in ipairs(requires) do
+
+ -- parse require info
+ local packagename, requireinfo = _parse_require(require_str)
+
+ -- save this required package
+ requireinfos[packagename] = requireinfo
+ end
+
+ -- ok
+ return requireinfos
+end
+
+-- load all required packages
+function load_packages(requires)
+
+ -- laod all required packages recursively
+ local packages = _load_packages(requires)
+
+ -- add all urls to fasturl and prepare to sort them together
+ for _, package in ipairs(packages) do
+ fasturl.add(package:urls())
+ end
+
+ -- load git refs from packages
+ local gitrefs = _load_packages_gitrefs(packages)
+
+ -- sort and update urls
+ for _, package in ipairs(packages) do
+
+ -- sort package urls
+ package:urls_set(fasturl.sort(package:urls()))
+
+ -- exists urls? otherwise be phony package (only as package group)
+ if #package:urls() > 0 then
+
+ -- select package version
+ local version, source = _select_package_version(package, package:requireinfo().version, gitrefs)
+
+ -- save version to package
+ package:version_set(version, source)
+ end
+ end
+
+ -- ok
+ return packages
+end
+
diff --git a/xmake/actions/require/repository.lua b/xmake/actions/require/repository.lua
new file mode 100644
index 000000000..5576b4103
--- /dev/null
+++ b/xmake/actions/require/repository.lua
@@ -0,0 +1,152 @@
+--!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 repository.lua
+--
+
+-- imports
+import("core.base.option")
+import("core.package.repository")
+import("devel.git")
+
+-- get all repositories
+function repositories()
+
+ -- get it from cache it
+ if _g._REPOSITORIES then
+ return _g._REPOSITORIES
+ end
+
+ -- get all repositories (local first)
+ local repos = table.join(repository.repositories(false), repository.repositories(true))
+
+ -- save repositories
+ _g._REPOSITORIES = repos
+
+ -- ok
+ return repos
+end
+
+-- pull repositories
+function pull(position)
+
+ -- trace
+ printf("updating repositories .. ")
+ if option.get("verbose") then
+ print("")
+ end
+
+ -- create a pull task
+ local task = function ()
+
+ -- pull all repositories
+ local pulled = {}
+ for _, repo in ipairs(repositories()) do
+
+ -- the repository directory
+ local repodir = path.join(repository.directory(repo.global), repo.name)
+
+ -- remove repeat and only pull the first repository
+ if not pulled[repodir] then
+ if os.isdir(repodir) then
+
+ -- trace
+ vprint("pulling repository(%s): %s to %s ..", repo.name, repo.url, repodir)
+
+ -- pull it
+ git.pull({verbose = option.get("verbose"), branch = "master", repodir = repodir})
+ else
+ -- trace
+ vprint("cloning repository(%s): %s to %s ..", repo.name, repo.url, repodir)
+
+ -- clone it
+ git.clone(repo.url, {verbose = option.get("verbose"), branch = "master", outputdir = repodir})
+ end
+
+ -- pull this repository ok
+ pulled[repodir] = true
+ end
+ end
+ end
+
+ -- pull repositories
+ if option.get("verbose") then
+ task()
+ else
+ process.asyncrun(task)
+ end
+
+ -- trace
+ cprint("${green}ok")
+end
+
+-- get package directory from repositories
+function packagedir(packagename, reponame)
+
+ -- get it from cache it
+ local packagedirs = _g._PACKAGEDIRS or {}
+ local foundir = packagedirs[packagename]
+ if foundir then
+ return foundir[1], foundir[2]
+ end
+
+ -- find the package directory from the given repository
+ if reponame then
+ for _, from in ipairs({"local", "global"}) do
+ local is_global = (from == "global")
+ for _, repodir in ipairs(repository.directory(is_global)) do
+ local dir = path.join(repodir, reponame, "packages", (packagename:gsub('%.', path.seperator())))
+ if os.isdir(dir) then
+ foundir = {dir, is_global}
+ break
+ end
+ end
+ if foundir then
+ break
+ end
+ end
+ else
+ -- find the package directory from all repositories
+ for _, repo in ipairs(repositories()) do
+
+ -- the package directory
+ local dir = path.join(repository.directory(repo.global), repo.name, "packages", (packagename:gsub('%.', path.seperator())))
+ if os.isdir(dir) then
+ foundir = {dir, repo.global}
+ break
+ end
+ end
+ end
+
+ -- found?
+ if foundir then
+
+ -- save package directory
+ packagedirs[packagename] = foundir
+
+ -- update cache
+ _g._PACKAGEDIRS = packagedirs
+ end
+
+ -- ok
+ return foundir[1], foundir[2]
+end
+
diff --git a/xmake/actions/require/search.lua b/xmake/actions/require/search.lua
new file mode 100644
index 000000000..569f99115
--- /dev/null
+++ b/xmake/actions/require/search.lua
@@ -0,0 +1,29 @@
+--!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 search.lua
+--
+
+-- search for the given packages from repositories
+function main(packages)
+ -- TODO
+end
+
diff --git a/xmake/actions/require/xmake.lua b/xmake/actions/require/xmake.lua
new file mode 100644
index 000000000..6c5b7cacd
--- /dev/null
+++ b/xmake/actions/require/xmake.lua
@@ -0,0 +1,61 @@
+--!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 require.lua
+--
+
+-- define task
+task("require")
+
+ -- set category
+ set_category("action")
+
+ -- on run
+ on_run("main")
+
+ -- set menu
+ set_menu {
+ -- usage
+ usage = "xmake require [options] [packages]"
+
+ -- description
+ , description = "Install and update required packages."
+
+ -- xmake q
+ , shortname = 'q'
+
+ -- options
+ , options =
+ {
+ {'c', "clear", "k", nil, "Clear all installed package caches." }
+ , {'f', "force", "k", nil, "Force to reinstall all package dependencies." }
+ , {'l', "list", "k", nil, "List all package dependencies." }
+ , { }
+ , {nil, "info", "k", nil, "Show the given package info." }
+ , {'s', "search", "k", nil, "Search for the given packages from repositories." }
+ , { }
+ , {nil, "requires", "vs", nil, "The package requires.",
+ ".e.g",
+ " $ xmake require zlib tboox.tbox",
+ " $ xmake require \"zlib >=1.2.11\" \"tboox.tbox master\"",
+ " $ xmake require \"[email protected]:tboox/[email protected] >=1.6.0 <1.6.1 || master\"" }
+ }
+ }
diff --git a/xmake/actions/uninstall/uninstall_admin.lua b/xmake/actions/uninstall/uninstall_admin.lua
index 891b4a857..a8ac07468 100644
--- a/xmake/actions/uninstall/uninstall_admin.lua
+++ b/xmake/actions/uninstall/uninstall_admin.lua
@@ -41,9 +41,6 @@ function main(targetname, installdir)
-- load platform
platform.load(config.plat())
- -- laod project
- project.load()
-
-- save the current option and push a new option context
option.save()
diff --git a/xmake/core/base/os.lua b/xmake/core/base/os.lua
index ad01c67f1..fbe208b9b 100644
--- a/xmake/core/base/os.lua
+++ b/xmake/core/base/os.lua
@@ -468,7 +468,7 @@ end
function os.tmpfile()
-- make it
- return path.join(os.tmpdir(), "_" .. (os.uuid():gsub("-", "")))
+ return path.join(os.tmpdir(), "_" .. (hash.uuid():gsub("-", "")))
end
-- run command
diff --git a/xmake/core/main.lua b/xmake/core/main.lua
index ef0edd874..227d0e970 100644
--- a/xmake/core/main.lua
+++ b/xmake/core/main.lua
@@ -36,6 +36,7 @@ local privilege = require("base/privilege")
local task = require("base/task")
local project = require("project/project")
local history = require("project/history")
+local package = require("package/package")
-- init the option menu
local menu =
@@ -51,7 +52,6 @@ local menu =
}
-
-- show logo
function main._show_logo()
@@ -62,6 +62,7 @@ function main._show_logo()
\ \/ / | \/ |/ _ | |/ / __ \
> < | \__/ | /_| | < ___/
/_/\_\_|_| |_|\__ \|_|\_\____|
+
by ruki, ${underline}tboox.org${clear}
${point_right} ${bright}Manual${clear}: ${underline}http://xmake.io/#/home${clear}
@@ -162,6 +163,7 @@ function main._init()
-- define task and package apis first before loading project's xmake.lua - calling option.init()
project.define_apis(task.apis())
+ project.define_apis(package.apis())
end
-- the main function
diff --git a/xmake/core/package/package.lua b/xmake/core/package/package.lua
new file mode 100644
index 000000000..e5ca87b84
--- /dev/null
+++ b/xmake/core/package/package.lua
@@ -0,0 +1,419 @@
+--!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 package governing permissions and
+-- limitations under the License.
+--
+-- Copyright (C) 2015 - 2017, TBOOX Open Source Group.
+--
+-- @author ruki
+-- @file package.lua
+--
+
+-- define module
+local package = package or {}
+local _instance = _instance or {}
+
+-- load modules
+local os = require("base/os")
+local io = require("base/io")
+local path = require("base/path")
+local utils = require("base/utils")
+local table = require("base/table")
+local filter = require("base/filter")
+local global = require("base/global")
+local interpreter = require("base/interpreter")
+local sandbox = require("sandbox/sandbox")
+local config = require("project/config")
+local project = require("project/project")
+local platform = require("platform/platform")
+
+-- new an instance
+function _instance.new(name, info, rootdir)
+
+ -- new an instance
+ local instance = table.inherit(_instance)
+
+ -- init instance
+ instance._NAME = name
+ instance._INFO = info
+ instance._ROOTDIR = rootdir
+ instance._FILTER = filter.new()
+
+ -- register filter handler
+ instance._FILTER:register("package", function (variable)
+
+ -- init maps
+ local maps =
+ {
+ version = instance:version_str()
+ }
+
+ -- map it
+ return maps[variable]
+ end)
+
+ -- ok
+ return instance
+end
+
+-- get the package configure
+function _instance:get(name)
+
+ -- the info
+ local info = self._INFO
+
+ -- get if from info first
+ local value = info[name]
+ if value ~= nil then
+ return value
+ end
+end
+
+-- get the package name
+function _instance:name()
+ return self._NAME
+end
+
+-- get the package filter
+function _instance:filter()
+ return self._FILTER
+end
+
+-- get urls
+function _instance:urls()
+ return self._URLS or table.wrap(self:get("urls"))
+end
+
+-- get urls
+function _instance:urls_set(urls)
+ self._URLS = urls
+end
+
+-- get sha256
+function _instance:sha256()
+
+ -- get it from cache first
+ if self._SHA256 then
+ return self._SHA256
+ end
+
+ -- find sha256
+ local version = self:version()
+ local sha256s = table.wrap(self:get("sha256s"))
+ local versions = table.wrap(self:get("versions"))
+ if version then
+ for idx, ver in ipairs(versions) do
+ if ver == version then
+ self._SHA256 = sha256s[idx]
+ break
+ end
+ end
+ end
+
+ -- get it
+ return self._SHA256
+end
+
+-- is global package?
+function _instance:global()
+ return self._ISGLOBAL
+end
+
+-- is optional package?
+function _instance:optional()
+
+ -- optional?
+ return self._REQUIREINFO.mode == "optional"
+end
+
+-- get the cached directory of this package
+function _instance:cachedir()
+ return path.join(package.cachedir(), self:name() .. "-" .. (self:version_str() or "group"))
+end
+
+-- get the installed directory of this package
+function _instance:installdir()
+ return path.join(package.installdir(self:global()), self:name() .. "-" .. (self:version_str() or "group"))
+end
+
+-- get the version
+function _instance:version()
+
+ -- get it
+ return self._VERSION or {}
+end
+
+-- get the version string
+function _instance:version_str()
+
+ -- get it
+ return self:version().raw or self:version().version
+end
+
+-- the verson from tags, branches or versions?
+function _instance:version_from(...)
+
+ -- from source?
+ for _, source in ipairs({...}) do
+ return self:version().source == source
+ end
+end
+
+-- set the version
+function _instance:version_set(version, source)
+
+ -- init package version
+ if type(version) == "string" then
+ version = {version = version, source = source}
+ else
+ version.source = source
+ end
+
+ -- save version
+ self._VERSION = version
+end
+
+-- get the require info
+function _instance:requireinfo()
+ return self._REQUIREINFO
+end
+
+-- set the require info
+function _instance:requireinfo_set(requireinfo)
+ self._REQUIREINFO = requireinfo
+end
+
+-- get xxx_script
+function _instance:script(name, generic)
+
+ -- get script
+ local script = self:get(name)
+ if type(script) == "function" then
+ return script
+ elseif type(script) == "table" then
+
+ -- match script for special plat and arch
+ local plat = (config.get("plat") or "")
+ local pattern = plat .. '|' .. (config.get("arch") or "")
+ for _pattern, _script in pairs(script) do
+ if not _pattern:startswith("__") and pattern:find('^' .. _pattern .. '$') then
+ return _script
+ end
+ end
+
+ -- match script for special plat
+ for _pattern, _script in pairs(script) do
+ if not _pattern:startswith("__") and plat:find('^' .. _pattern .. '$') then
+ return _script
+ end
+ end
+
+ -- get generic script
+ return script["__generic__"] or generic
+ end
+
+ -- only generic script
+ return generic
+end
+
+-- the interpreter
+function package._interpreter()
+
+ -- the interpreter has been initialized? return it directly
+ if package._INTERPRETER then
+ return package._INTERPRETER
+ end
+
+ -- init interpreter
+ local interp = interpreter.new()
+ assert(interp)
+
+ -- define apis
+ interp:api_define(package.apis())
+
+ -- save interpreter
+ package._INTERPRETER = interp
+
+ -- ok?
+ return interp
+end
+
+-- get package apis
+function package.apis()
+
+ return
+ {
+ values =
+ {
+ -- package.set_xxx
+ "package.set_urls"
+ , "package.set_sha256s"
+ , "package.set_versions"
+ , "package.set_homepage"
+ , "package.set_description"
+ -- package.add_xxx
+ , "package.add_requires"
+ }
+ , script =
+ {
+ -- package.on_xxx
+ "package.on_build"
+ , "package.on_install"
+ , "package.on_test"
+
+ -- package.before_xxx
+ , "package.before_build"
+ , "package.before_install"
+ , "package.before_test"
+
+ -- package.before_xxx
+ , "package.after_build"
+ , "package.after_install"
+ , "package.after_test"
+ }
+ }
+end
+
+-- get install directory
+function package.installdir(is_global)
+
+ -- get directory
+ if is_global then
+ return path.join(global.directory(), "packages")
+ else
+ return path.join(config.directory(), "packages")
+ end
+end
+
+-- the cache directory
+function package.cachedir()
+ return path.join(global.directory(), "cache", "packages")
+end
+
+-- load the package from the package url
+function package.load_from_url(packagename, packageurl)
+
+ -- make a temporary package file
+ local packagefile = os.tmpfile() .. ".lua"
+
+ -- make package description
+ local packagedata = string.format([[
+ package("%s")
+ set_urls("%s")
+ ]], packagename, packageurl)
+
+ -- write a temporary package description to file
+ local ok, errors = io.writefile(packagefile, packagedata)
+ if not ok then
+ return nil, errors
+ end
+
+ -- load package instance
+ local instance, errors = package.load_from_repository(packagename, false, nil, packagefile)
+
+ -- remove the package file
+ os.rm(packagefile)
+
+ -- ok?
+ return instance, errors
+end
+
+-- load the package from the project file
+function package.load_from_project(packagename)
+
+ -- get it directly from cache first
+ package._PACKAGES = package._PACKAGES or {}
+ if package._PACKAGES[packagename] then
+ return package._PACKAGES[packagename]
+ end
+
+ -- load packages (with cache)
+ local packages, errors = project.packages()
+ if not packages then
+ return nil, errors
+ end
+
+ -- get interpreter
+ local interp = errors or package._interpreter()
+
+ -- not found?
+ if not packages[packagename] then
+ return
+ end
+
+ -- new an instance
+ local instance, errors = _instance.new(packagename, packages[packagename], interp:rootdir())
+ if not instance then
+ return nil, errors
+ end
+
+ -- mark as loval package
+ instance._ISGLOBAL = false
+
+ -- save instance to the cache
+ package._PACKAGES[packagename] = instance
+
+ -- ok
+ return instance
+end
+
+-- load the package from the package directory or package description file
+function package.load_from_repository(packagename, is_global, packagedir, packagefile)
+
+ -- get it directly from cache first
+ package._PACKAGES = package._PACKAGES or {}
+ if package._PACKAGES[packagename] then
+ return package._PACKAGES[packagename]
+ end
+
+ -- find the package script path
+ local scriptpath = packagefile
+ if not packagefile and packagedir then
+ scriptpath = path.join(packagedir, "xmake.lua")
+ end
+ if not scriptpath or not os.isfile(scriptpath) then
+ return nil, string.format("the package %s not found!", packagename)
+ end
+
+ -- load package and disable filter, we will process filter after a while
+ local results, errors = package._interpreter():load(scriptpath, "package", true, false)
+ if not results and os.isfile(scriptpath) then
+ return nil, errors
+ end
+
+ -- check the package name
+ if not results[packagename] then
+ return nil, string.format("the package %s not found!", name)
+ end
+
+ -- new an instance
+ local instance, errors = _instance.new(packagename, results[packagename], package._interpreter():rootdir())
+ if not instance then
+ return nil, errors
+ end
+
+ -- mark as global package?
+ instance._ISGLOBAL = is_global
+
+ -- save instance to the cache
+ package._PACKAGES[packagename] = instance
+
+ -- ok
+ return instance
+end
+
+-- return module
+return package
diff --git a/xmake/core/package/repository.lua b/xmake/core/package/repository.lua
new file mode 100644
index 000000000..6a4bcc9f0
--- /dev/null
+++ b/xmake/core/package/repository.lua
@@ -0,0 +1,134 @@
+--!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 repository.lua
+--
+
+-- define module
+local repository = repository or {}
+
+-- load modules
+local utils = require("base/utils")
+local string = require("base/string")
+local global = require("base/global")
+local cache = require("project/cache")
+local config = require("project/config")
+
+-- get cache
+function repository._cache(is_global)
+
+ -- get position
+ local position = utils.ifelse(is_global, "global", "local")
+
+ -- get it from cache first if exists
+ if repository._CACHE and repository._CACHE[position] then
+ return repository._CACHE[position]
+ end
+
+ -- init cache
+ repository._CACHE = repository._CACHE or {}
+ repository._CACHE[position] = cache(position .. ".repository")
+
+ -- ok
+ return repository._CACHE[position]
+end
+
+-- get the local or global package directory
+function repository.directory(is_global)
+
+ -- get directory
+ if is_global then
+ return path.join(global.directory(), "repositories")
+ else
+ return path.join(config.directory(), "repositories")
+ end
+end
+
+-- get repository url from the given name
+function repository.get(name, is_global)
+
+ -- get it
+ local repositories = repository.repositories(is_global)
+ if repositories then
+ return repositories[name]
+ end
+end
+
+-- add repository url to the given name
+function repository.add(name, url, is_global)
+
+ -- no name?
+ if not name then
+ return false, string.format("please set name to repository: %s", url)
+ end
+
+ -- get repositories
+ local repositories = repository.repositories(is_global) or {}
+
+ -- set it
+ repositories[name] = url
+
+ -- save repositories
+ repository._cache(is_global):set("repositories", repositories)
+
+ -- flush it
+ return repository._cache(is_global):flush()
+end
+
+-- remove repository from gobal or local directory
+function repository.remove(name, is_global)
+
+ -- get repositories
+ local repositories = repository.repositories(is_global) or {}
+ if not repositories[name] then
+ return false, string.format("repository(%s): not found!", name)
+ end
+
+ -- remove it
+ repositories[name] = nil
+
+ -- save repositories
+ repository._cache(is_global):set("repositories", repositories)
+
+ -- flush it
+ return repository._cache(is_global):flush()
+end
+
+-- clear all repositories
+function repository.clear(is_global)
+
+ -- clear repositories
+ repository._cache(is_global):set("repositories", {})
+
+ -- flush it
+ return repository._cache(is_global):flush()
+end
+
+
+-- get all repositories from global or local directory
+function repository.repositories(is_global)
+
+ -- get repositories
+ return repository._cache(is_global):get("repositories")
+end
+
+-- return module
+return repository
diff --git a/xmake/core/project/project.lua b/xmake/core/project/project.lua
index 6c844e4f0..d57721d76 100644
--- a/xmake/core/project/project.lua
+++ b/xmake/core/project/project.lua
@@ -209,6 +209,9 @@ function project.interpreter()
"set_project"
, "set_version"
, "set_modes"
+ -- add_xxx
+ , "add_requires"
+ , "add_repositories"
-- target.set_xxx
, "target.set_kind"
, "target.set_strip"
@@ -235,8 +238,8 @@ function project.interpreter()
-- option.add_xxx
, "option.add_deps"
, "option.add_vectorexts"
- , "option.add_bindings" -- deprecated
- , "option.add_rbindings" -- deprecated
+ , "option.add_bindings" -- deprecated
+ , "option.add_rbindings" -- deprecated
}
, pathes =
{
@@ -633,6 +636,36 @@ function project.tasks()
return results, interp
end
+-- get packages
+function project.packages()
+
+ -- get it from cache first
+ if project._PACKAGES then
+ return project._PACKAGES, interp
+ end
+
+ -- get interpreter
+ local interp = project.interpreter()
+ assert(interp)
+
+ -- the project file is not found?
+ if not os.isfile(os.projectfile()) then
+ return {}, nil
+ end
+
+ -- load the tasks from the the project file and disable filter, we will process filter after a while
+ local results, errors = interp:load(os.projectfile(), "package", true, false)
+ if not results then
+ return nil, errors
+ end
+
+ -- save results to cache
+ project._PACKAGES = results
+
+ -- ok?
+ return results, interp
+end
+
-- get the mtimes
function project.mtimes()
return project.interpreter():mtimes()
diff --git a/xmake/core/sandbox/modules/hash.lua b/xmake/core/sandbox/modules/hash.lua
new file mode 100644
index 000000000..7143aa511
--- /dev/null
+++ b/xmake/core/sandbox/modules/hash.lua
@@ -0,0 +1,59 @@
+--!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 hash.lua
+--
+
+-- load modules
+local raise = require("sandbox/modules/raise")
+
+-- define module
+local sandbox_hash = sandbox_hash or {}
+
+-- make a new uuid
+function sandbox_hash.uuid(name)
+
+ -- make it
+ local uuid = hash.uuid(name)
+ if not uuid then
+ raise("cannot make uuid %s", name)
+ end
+
+ -- ok?
+ return uuid
+end
+
+-- make sha256 from the given file
+function sandbox_hash.sha256(file)
+
+ -- make it
+ local sha256 = hash.sha256(file)
+ if not sha256 then
+ raise("cannot make sha256 for %s", file)
+ end
+
+ -- ok?
+ return sha256
+end
+
+-- return module
+return sandbox_hash
+
diff --git a/xmake/core/sandbox/modules/import/core/base/semver.lua b/xmake/core/sandbox/modules/import/core/base/semver.lua
new file mode 100644
index 000000000..ee4c6e685
--- /dev/null
+++ b/xmake/core/sandbox/modules/import/core/base/semver.lua
@@ -0,0 +1,86 @@
+--!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 semver.lua
+--
+
+-- define module
+local sandbox_core_base_semver = sandbox_core_base_semver or {}
+
+-- load modules
+local table = require("base/table")
+local raise = require("sandbox/modules/raise")
+
+-- parse a version string into a props table containing all semver infos
+--
+-- semver.parse('1.2.3') => { major = 1, minor = 2, patch = 3, ... }
+-- semver.parse('a.b.c') => nil
+--
+function sandbox_core_base_semver.parse(version)
+
+ -- compare version
+ local result, errors = semver.parse(version)
+ if errors then
+ raise(errors)
+ end
+
+ -- ok
+ return result
+end
+
+-- this version satisfies in the given version range
+--
+-- semver.satisfies('1.2.3', '1.x || >=2.5.0 || 5.0.0 - 7.2.3') => true
+--
+function sandbox_core_base_semver.satisfies(version, range)
+ -- satisfies version
+ local result, errors = semver.satisfies(version, range)
+ if errors then
+ raise(errors)
+ end
+
+ -- ok
+ return result
+end
+
+-- select required version from versions, tags and branches
+--
+-- .e.g
+--
+-- local version, source = semver.select(">=1.5.0 <1.6", {"1.5.0", "1.5.1"}, {"v1.5.0", ..}, {"master", "dev"})
+--
+-- @version the selected version number
+-- @source the version source, .e.g versions, tags, branchs
+--
+function sandbox_core_base_semver.select(range, versions, tags, branches)
+
+ -- select version
+ local verinfo, errors = semver.select(range, versions or {}, tags or {}, branches or {})
+ if not verinfo then
+ raise(errors)
+ end
+
+ -- ok
+ return verinfo.version, verinfo.source
+end
+
+-- return module
+return sandbox_core_base_semver
diff --git a/xmake/core/sandbox/modules/import/core/package/package.lua b/xmake/core/sandbox/modules/import/core/package/package.lua
new file mode 100644
index 000000000..10d62f493
--- /dev/null
+++ b/xmake/core/sandbox/modules/import/core/package/package.lua
@@ -0,0 +1,82 @@
+--!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 package.lua
+--
+
+-- define module
+local sandbox_core_package_package = sandbox_core_package_package or {}
+
+-- load modules
+local package = require("package/package")
+local raise = require("sandbox/modules/raise")
+
+-- get cache directory
+function sandbox_core_package_package.cachedir()
+ return package.cachedir()
+end
+
+-- get install directory
+function sandbox_core_package_package.installdir(is_global)
+ return package.installdir(is_global)
+end
+
+-- load the package from the project file
+function sandbox_core_package_package.load_from_project(packagename)
+
+ -- load package instance
+ local instance, errors = package.load_from_project(packagename)
+ if errors then
+ raise(errors)
+ end
+
+ -- ok
+ return instance
+end
+
+-- load the package from repositories
+function sandbox_core_package_package.load_from_repository(packagename, is_global, packagedir, packagefile)
+
+ -- load package instance
+ local instance, errors = package.load_from_repository(packagename, is_global, packagedir, packagefile)
+ if not instance then
+ raise(errors)
+ end
+
+ -- ok
+ return instance
+end
+
+-- load the package from the package url
+function sandbox_core_package_package.load_from_url(packagename, packageurl)
+
+ -- load package instance
+ local instance, errors = package.load_from_url(packagename, packageurl)
+ if not instance then
+ raise(errors)
+ end
+
+ -- ok
+ return instance
+end
+
+-- return module
+return sandbox_core_package_package
diff --git a/xmake/core/sandbox/modules/import/core/package/repository.lua b/xmake/core/sandbox/modules/import/core/package/repository.lua
new file mode 100644
index 000000000..3336ab4e1
--- /dev/null
+++ b/xmake/core/sandbox/modules/import/core/package/repository.lua
@@ -0,0 +1,119 @@
+--!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 repository.lua
+--
+
+-- define module
+local sandbox_core_package_repository = sandbox_core_package_repository or {}
+
+-- load modules
+local project = require("project/project")
+local repository = require("package/repository")
+local raise = require("sandbox/modules/raise")
+local import = require("sandbox/modules/import")
+
+-- get repository directory
+function sandbox_core_package_repository.directory(is_global)
+ return repository.directory(is_global)
+end
+
+-- get repository url from the given name
+function sandbox_core_package_repository.get(name, is_global)
+
+ -- get it
+ return repository.get(name, is_global)
+end
+
+-- add repository url to the given name
+function sandbox_core_package_repository.add(name, url, is_global)
+
+ -- add it
+ local ok, errors = repository.add(name, url, is_global)
+ if not ok then
+ raise(errors)
+ end
+end
+
+-- remove repository from gobal or local directory
+function sandbox_core_package_repository.remove(name, is_global)
+
+ -- remove it
+ local ok, errors = repository.remove(name, is_global)
+ if not ok then
+ raise(errors)
+ end
+end
+
+-- clear all repositories from global or local directory
+function sandbox_core_package_repository.clear(is_global)
+
+ -- clear all repositories
+ local ok, errors = repository.clear(is_global)
+ if not ok then
+ raise(errors)
+ end
+end
+
+-- get all repositories from global or local directory
+function sandbox_core_package_repository.repositories(is_global)
+
+ -- add main global xmake repository
+ local repositories = {}
+ if is_global then
+
+ -- import fasturl
+ import("net.fasturl")
+
+ -- sort main urls
+ local mainurls = {"https://github.com/tboox/xmake-repo.git", "https://git.oschina.net/tboox/xmake-repo.git"}
+ fasturl.add(mainurls)
+ mainurls = fasturl.sort(mainurls)
+
+ -- add main urls
+ for _, mainurl in ipairs(mainurls) do
+ table.insert(repositories, {name = "xmake-repo", url = mainurl, global = true})
+ end
+ end
+
+ -- load repositories from repository cache
+ for name, url in pairs(table.wrap(repository.repositories(is_global))) do
+ table.insert(repositories, {name = name, url = url, global = is_global})
+ end
+
+ -- load repositories from project file
+ if not is_global then
+ for _, repo in ipairs(table.wrap(project.get("repositories"))) do
+ local repoinfo = repo:split(' ')
+ if #repoinfo == 2 then
+ table.insert(repositories, {name = repoinfo[1], url = repoinfo[2], global = is_global})
+ else
+ raise("invalid repository: %s", repo)
+ end
+ end
+ end
+
+ -- get the repositories
+ return repositories
+end
+
+-- return module
+return sandbox_core_package_repository
diff --git a/xmake/core/sandbox/modules/import/core/project/project.lua b/xmake/core/sandbox/modules/import/core/project/project.lua
index 4a7beb3e0..bae02f7a0 100644
--- a/xmake/core/sandbox/modules/import/core/project/project.lua
+++ b/xmake/core/sandbox/modules/import/core/project/project.lua
@@ -34,6 +34,7 @@ local project = require("project/project")
local sandbox = require("sandbox/sandbox")
local raise = require("sandbox/modules/raise")
local environment = require("platform/environment")
+local package = require("package/package")
-- load project
function sandbox_core_project.load()
@@ -161,5 +162,10 @@ function sandbox_core_project.modes()
return project.get("modes")
end
+-- get the project requires
+function sandbox_core_project.requires()
+ return project.get("requires")
+end
+
-- return module
return sandbox_core_project
diff --git a/xmake/core/sandbox/modules/interpreter/os.lua b/xmake/core/sandbox/modules/interpreter/os.lua
index b956726eb..ec650a212 100644
--- a/xmake/core/sandbox/modules/interpreter/os.lua
+++ b/xmake/core/sandbox/modules/interpreter/os.lua
@@ -44,7 +44,7 @@ sandbox_os.programdir = os.programdir
sandbox_os.programfile = os.programfile
sandbox_os.projectdir = os.projectdir
sandbox_os.projectfile = os.projectfile
-sandbox_os.uuid = os.uuid
+sandbox_os.uuid = hash.uuid
-- match files
function sandbox_os.files(pattern, ...)
diff --git a/xmake/core/sandbox/modules/os.lua b/xmake/core/sandbox/modules/os.lua
index 839d5cbba..65608327b 100644
--- a/xmake/core/sandbox/modules/os.lua
+++ b/xmake/core/sandbox/modules/os.lua
@@ -443,17 +443,6 @@ function sandbox_os.exists(file_or_dir)
return os.exists(file_or_dir)
end
--- make a new uuid
-function sandbox_os.uuid(name)
-
- -- make it
- local uuid = os.uuid(name)
- assert(uuid)
-
- -- ok?
- return uuid
-end
-
-- return module
return sandbox_os
diff --git a/xmake/core/sandbox/modules/utils.lua b/xmake/core/sandbox/modules/utils.lua
index 40d2c6170..e282ef80e 100644
--- a/xmake/core/sandbox/modules/utils.lua
+++ b/xmake/core/sandbox/modules/utils.lua
@@ -26,6 +26,7 @@
local io = require("base/io")
local utils = require("base/utils")
local colors = require("base/colors")
+local option = require("base/option")
local try = require("sandbox/modules/try")
local catch = require("sandbox/modules/catch")
local vformat = require("sandbox/modules/vformat")
@@ -72,7 +73,7 @@ function sandbox_utils.print(format, ...)
{
function ()
-- attempt to print format string first
- utils._iowrite(vformat(format, unpack(args)) .. "\n")
+ utils._print(vformat(format, unpack(args)))
end,
catch
{
@@ -100,7 +101,7 @@ end
function sandbox_utils.cprint(format, ...)
-- done
- utils._iowrite(colors(vformat(format, ...)) .. "\n")
+ utils._print(colors(vformat(format, ...)))
end
-- print format string, the builtin variables and colors without newline
@@ -110,6 +111,20 @@ function sandbox_utils.cprintf(format, ...)
utils._iowrite(colors(vformat(format, ...)))
end
+-- print() if enable verbose
+function sandbox_utils.vprint(format, ...)
+ if option.get("verbose") then
+ sandbox_utils.print(format, ...)
+ end
+end
+
+-- vprintf() if enable verbose
+function sandbox_utils.vprintf(format, ...)
+ if option.get("verbose") then
+ sandbox_utils.printf(format, ...)
+ end
+end
+
-- assert
function sandbox_utils.assert(value, format, ...)
@@ -126,7 +141,6 @@ function sandbox_utils.assert(value, format, ...)
return value
end
-
-- return module
return sandbox_utils
diff --git a/xmake/core/sandbox/modules/vprint.lua b/xmake/core/sandbox/modules/vprint.lua
new file mode 100644
index 000000000..49064afae
--- /dev/null
+++ b/xmake/core/sandbox/modules/vprint.lua
@@ -0,0 +1,27 @@
+--!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 vprint.lua
+--
+
+-- load module
+return require("sandbox/modules/utils").vprint
+
diff --git a/xmake/core/sandbox/modules/vprintf.lua b/xmake/core/sandbox/modules/vprintf.lua
new file mode 100644
index 000000000..58f211666
--- /dev/null
+++ b/xmake/core/sandbox/modules/vprintf.lua
@@ -0,0 +1,27 @@
+--!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 vprintf.lua
+--
+
+-- load module
+return require("sandbox/modules/utils").vprintf
+
diff --git a/xmake/modules/detect/tools/find_ping.lua b/xmake/modules/detect/tools/find_ping.lua
new file mode 100644
index 000000000..ae3d571bf
--- /dev/null
+++ b/xmake/modules/detect/tools/find_ping.lua
@@ -0,0 +1,48 @@
+--!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 find_ping.lua
+--
+
+-- imports
+import("lib.detect.find_program")
+
+-- find ping
+--
+--
+-- @param opt the argument options
+--
+-- @return program
+--
+function main(opt)
+
+ -- init options
+ opt = opt or {}
+
+ -- find program
+ return find_program(opt.program or "ping", opt.pathes, opt.check or function (program)
+ if os.host() == "windows" then
+ os.run("%s -n 1 127.0.0.1", program)
+ else
+ os.run("%s -c 1 127.0.0.1", program)
+ end
+ end)
+end
diff --git a/xmake/modules/devel/git/checkurl.lua b/xmake/modules/devel/git/checkurl.lua
new file mode 100644
index 000000000..225351458
--- /dev/null
+++ b/xmake/modules/devel/git/checkurl.lua
@@ -0,0 +1,35 @@
+--!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 checkurl.lua
+--
+
+-- check git url
+--
+-- @param url is git url?
+--
+-- @return true or false
+--
+function main(url)
+
+ -- check it
+ return url:endswith(".git") or os.isdir(url .. ".git")
+end
diff --git a/xmake/modules/devel/git/refs.lua b/xmake/modules/devel/git/refs.lua
index 306b2fd26..7af98b854 100644
--- a/xmake/modules/devel/git/refs.lua
+++ b/xmake/modules/devel/git/refs.lua
@@ -30,13 +30,13 @@ import("ls_remote")
--
-- @param url the remote url, optional
--
--- @return the refs
+-- @return the tags, branches
--
-- @code
--
-- import("devel.git")
--
--- local refs = git.refs(url)
+-- local tags, branches = git.refs(url)
--
-- @endcode
--
@@ -45,7 +45,7 @@ function main(url)
-- get refs
local refs = ls_remote("refs", url)
if not refs or #refs == 0 then
- return {}
+ return {}, {}
end
-- get tags and branches
@@ -60,5 +60,5 @@ function main(url)
end
-- ok
- return {tags = tags, branches = branches}
+ return tags, branches
end
diff --git a/xmake/modules/net/fasturl.lua b/xmake/modules/net/fasturl.lua
new file mode 100644
index 000000000..8cc90f035
--- /dev/null
+++ b/xmake/modules/net/fasturl.lua
@@ -0,0 +1,92 @@
+--!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 fasturl.lua
+--
+
+-- imports
+import("ping")
+
+-- parse host from url
+function _parse_host(url)
+
+ -- init host cache
+ _g._URLHOSTS = _g._URLHOSTS or {}
+
+ -- http[s]://xxx.com/.. or [email protected]:xxx/xxx.git
+ local host = _g._URLHOSTS[url] or url:match("://(.-)/") or url:match("@(.-):")
+
+ -- save to cache
+ _g._URLHOSTS[url] = host
+
+ -- ok
+ return host
+end
+
+-- add urls
+function add(urls)
+
+ -- get current ping info
+ local pinginfo = _g._PINGINFO or {}
+
+ -- add ping hosts
+ _g._PINGHOSTS = _g._PINGHOSTS or {}
+ for _, url in ipairs(urls) do
+
+ -- parse host
+ local host = _parse_host(url)
+
+ -- this host has not been tested?
+ if host and not pinginfo[host] then
+ table.insert(_g._PINGHOSTS, host)
+ end
+ end
+end
+
+-- sort urls
+function sort(urls)
+
+ -- ping hosts
+ local pinghosts = table.unique(_g._PINGHOSTS or {})
+ if pinghosts and #pinghosts > 0 then
+
+ -- ping them and test speed
+ local pinginfo = ping(unpack(pinghosts))
+
+ -- merge to ping info
+ _g._PINGINFO = table.join(_g._PINGINFO or {}, pinginfo)
+ end
+
+ -- sort urls by the ping info
+ local pinginfo = _g._PINGINFO or {}
+ table.sort(urls, function(a, b)
+ a = pinginfo[_parse_host(a) or ""] or 65536
+ b = pinginfo[_parse_host(b) or ""] or 65536
+ return a < b
+ end)
+
+ -- clear hosts
+ _g._PINGHOSTS = {}
+
+ -- ok
+ return urls
+end
+
diff --git a/xmake/modules/net/ping.lua b/xmake/modules/net/ping.lua
new file mode 100644
index 000000000..9a2bd21f2
--- /dev/null
+++ b/xmake/modules/net/ping.lua
@@ -0,0 +1,73 @@
+--!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 ping.lua
+--
+
+-- imports
+import("detect.tools.find_ping")
+
+-- send ping to hosts
+--
+-- @param ... the hosts
+--
+-- @return the time or -1
+--
+function main(...)
+
+ -- find ping
+ local ping = find_ping()
+ if not ping then
+ return {}
+ end
+
+ -- run tasks
+ local hosts = {...}
+ local results = {}
+ process.runjobs(function (index)
+ local host = hosts[index]
+ if host then
+ try
+ {
+ function ()
+
+ -- ping it
+ local data = nil
+ if os.host() == "windows" then
+ data = os.iorun("%s -n 1 %s", ping, host)
+ else
+ data = os.iorun("%s -c 1 %s", ping, host)
+ end
+
+ -- find time
+ local time = data:match("time=(.-)ms", 1, true)
+ if time then
+ results[host] = tonumber(time:trim())
+ end
+ end
+ }
+ end
+ end, #hosts)
+
+ -- ok?
+ return results
+end
+
diff --git a/xmake/plugins/doxygen/main.lua b/xmake/plugins/doxygen/main.lua
index c13327959..fe9c0df4d 100644
--- a/xmake/plugins/doxygen/main.lua
+++ b/xmake/plugins/doxygen/main.lua
@@ -44,9 +44,6 @@ function main()
-- load configure
config.load()
- -- load project
- project.load()
-
-- enable recursive
--
-- RECURSIVE = YES
diff --git a/xmake/plugins/macro/macros/package.lua b/xmake/plugins/macro/macros/package.lua
index 27f15969c..c9fef7977 100644
--- a/xmake/plugins/macro/macros/package.lua
+++ b/xmake/plugins/macro/macros/package.lua
@@ -73,9 +73,6 @@ function main(argv)
-- load configure
config.load()
- -- load project
- project.load()
-
-- enter the project directory
os.cd(project.directory())
diff --git a/xmake/plugins/project/vstudio/impl/vs200x_solution.lua b/xmake/plugins/project/vstudio/impl/vs200x_solution.lua
index b076d35bd..26117a557 100644
--- a/xmake/plugins/project/vstudio/impl/vs200x_solution.lua
+++ b/xmake/plugins/project/vstudio/impl/vs200x_solution.lua
@@ -43,12 +43,12 @@ function _make_projects(slnfile, vsinfo)
if not target:isphony() then
-- enter project
- slnfile:enter("Project(\"{%s}\") = \"%s\", \"%s\\%s.vcproj\", \"{%s}\"", vctool, targetname, targetname, targetname, os.uuid(targetname))
+ slnfile:enter("Project(\"{%s}\") = \"%s\", \"%s\\%s.vcproj\", \"{%s}\"", vctool, targetname, targetname, targetname, hash.uuid(targetname))
-- add dependences
for _, dep in ipairs(target:get("deps")) do
slnfile:enter("ProjectSection(ProjectDependencies) = postProject")
- slnfile:print("{%s} = {%s}", os.uuid(dep), os.uuid(dep))
+ slnfile:print("{%s} = {%s}", hash.uuid(dep), hash.uuid(dep))
slnfile:leave("EndProjectSection")
end
@@ -73,8 +73,8 @@ function _make_global(slnfile, vsinfo)
slnfile:enter("GlobalSection(ProjectConfigurationPlatforms) = postSolution")
for targetname, target in pairs(project.targets()) do
if not target:isphony() then
- slnfile:print("{%s}.$(mode)|Win32.ActiveCfg = $(mode)|Win32", os.uuid(targetname))
- slnfile:print("{%s}.$(mode)|Win32.Build.0 = $(mode)|Win32", os.uuid(targetname))
+ slnfile:print("{%s}.$(mode)|Win32.ActiveCfg = $(mode)|Win32", hash.uuid(targetname))
+ slnfile:print("{%s}.$(mode)|Win32.Build.0 = $(mode)|Win32", hash.uuid(targetname))
end
end
slnfile:leave("EndGlobalSection")
diff --git a/xmake/plugins/project/vstudio/impl/vs200x_vcproj.lua b/xmake/plugins/project/vstudio/impl/vs200x_vcproj.lua
index 102ab8399..eb0706cf8 100644
--- a/xmake/plugins/project/vstudio/impl/vs200x_vcproj.lua
+++ b/xmake/plugins/project/vstudio/impl/vs200x_vcproj.lua
@@ -133,7 +133,7 @@ function _make_header(vcprojfile, vsinfo, target)
vcprojfile:print("ProjectType=\"Visual C++\"")
vcprojfile:print("Version=\"%s0\"", assert(versions["vs" .. vsinfo.vstudio_version]))
vcprojfile:print("Name=\"%s\"", targetname)
- vcprojfile:print("ProjectGUID=\"{%s}\"", os.uuid(targetname))
+ vcprojfile:print("ProjectGUID=\"{%s}\"", hash.uuid(targetname))
vcprojfile:print("RootNamespace=\"%s\"", targetname)
vcprojfile:print("TargetFrameworkVersion=\"196613\"")
vcprojfile:print(">")
diff --git a/xmake/plugins/project/vstudio/impl/vs201x_solution.lua b/xmake/plugins/project/vstudio/impl/vs201x_solution.lua
index 40ac3e0f5..73bc1655d 100644
--- a/xmake/plugins/project/vstudio/impl/vs201x_solution.lua
+++ b/xmake/plugins/project/vstudio/impl/vs201x_solution.lua
@@ -43,12 +43,12 @@ function _make_projects(slnfile, vsinfo)
if not target:isphony() then
-- enter project
- slnfile:enter("Project(\"{%s}\") = \"%s\", \"%s\\%s.vcxproj\", \"{%s}\"", vctool, targetname, targetname, targetname, os.uuid(targetname))
+ slnfile:enter("Project(\"{%s}\") = \"%s\", \"%s\\%s.vcxproj\", \"{%s}\"", vctool, targetname, targetname, targetname, hash.uuid(targetname))
-- add dependences
for _, dep in ipairs(target:get("deps")) do
slnfile:enter("ProjectSection(ProjectDependencies) = postProject")
- slnfile:print("{%s} = {%s}", os.uuid(dep), os.uuid(dep))
+ slnfile:print("{%s} = {%s}", hash.uuid(dep), hash.uuid(dep))
slnfile:leave("EndProjectSection")
end
@@ -79,8 +79,8 @@ function _make_global(slnfile, vsinfo)
if not target:isphony() then
for _, mode in ipairs(vsinfo.modes) do
for _, arch in ipairs({"x86", "x64"}) do
- slnfile:print("{%s}.%s|%s.ActiveCfg = %s|%s", os.uuid(targetname), mode, arch, mode, arch)
- slnfile:print("{%s}.%s|%s.Build.0 = %s|%s", os.uuid(targetname), mode, arch, mode, arch)
+ slnfile:print("{%s}.%s|%s.ActiveCfg = %s|%s", hash.uuid(targetname), mode, arch, mode, arch)
+ slnfile:print("{%s}.%s|%s.Build.0 = %s|%s", hash.uuid(targetname), mode, arch, mode, arch)
end
end
end
diff --git a/xmake/plugins/project/vstudio/impl/vs201x_vcxproj.lua b/xmake/plugins/project/vstudio/impl/vs201x_vcxproj.lua
index 7abe20a54..fbff38a72 100644
--- a/xmake/plugins/project/vstudio/impl/vs201x_vcxproj.lua
+++ b/xmake/plugins/project/vstudio/impl/vs201x_vcxproj.lua
@@ -157,7 +157,7 @@ function _make_configurations(vcxprojfile, vsinfo, target, vcxprojdir)
-- make Globals
vcxprojfile:enter("<PropertyGroup Label=\"Globals\">")
- vcxprojfile:print("<ProjectGuid>{%s}</ProjectGuid>", os.uuid(targetname))
+ vcxprojfile:print("<ProjectGuid>{%s}</ProjectGuid>", hash.uuid(targetname))
vcxprojfile:print("<RootNamespace>%s</RootNamespace>", targetname)
if vsinfo.vstudio_version >= "2015" then
vcxprojfile:print("<WindowsTargetPlatformVersion>%s</WindowsTargetPlatformVersion>", sdkver or sdk_versions["vs" .. vsinfo.vstudio_version])
diff --git a/xmake/plugins/project/vstudio/impl/vs201x_vcxproj_filters.lua b/xmake/plugins/project/vstudio/impl/vs201x_vcxproj_filters.lua
index f15fa9c5f..7361611e2 100644
--- a/xmake/plugins/project/vstudio/impl/vs201x_vcxproj_filters.lua
+++ b/xmake/plugins/project/vstudio/impl/vs201x_vcxproj_filters.lua
@@ -75,7 +75,7 @@ function _make_filters(filtersfile, vsinfo, target, vcxprojdir)
while filter and filter ~= '.' do
if not exists[filter] then
filtersfile:enter("<Filter Include=\"%s\">", filter)
- filtersfile:print("<UniqueIdentifier>{%s}</UniqueIdentifier>", os.uuid(filter))
+ filtersfile:print("<UniqueIdentifier>{%s}</UniqueIdentifier>", hash.uuid(filter))
filtersfile:leave("</Filter>")
exists[filter] = true
end
diff --git a/xmake/plugins/repo/main.lua b/xmake/plugins/repo/main.lua
new file mode 100644
index 000000000..58d9b2090
--- /dev/null
+++ b/xmake/plugins/repo/main.lua
@@ -0,0 +1,158 @@
+--!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 main.lua
+--
+
+-- imports
+import("core.base.option")
+import("core.project.config")
+import("core.project.project")
+import("core.platform.platform")
+import("core.package.repository")
+import("devel.git")
+
+-- add repository url
+function _add(name, url, is_global)
+
+ -- add url
+ repository.add(name, url, is_global)
+
+ -- remove previous repository if exists
+ local repodir = path.join(repository.directory(is_global), name)
+ if os.isdir(repodir) then
+ os.rmdir(repodir)
+ end
+
+ -- clone repository
+ git.clone(url, {verbose = option.get("verbose"), branch = "master", outputdir = repodir})
+
+ -- trace
+ cprint("${bright}add %s repository(%s): %s ok!", ifelse(is_global, "global", "local"), name, url)
+end
+
+-- remove repository url
+function _remove(name, is_global)
+
+ -- remove url
+ repository.remove(name, is_global)
+
+ -- remove repository
+ local repodir = path.join(repository.directory(is_global), name)
+ if os.isdir(repodir) then
+ os.rmdir(repodir)
+ end
+
+ -- trace
+ cprint("${bright}remove %s repository(%s): %s ok!", ifelse(is_global, "global", "local"), name, url)
+end
+
+-- clear all repositories
+function _clear(is_global)
+
+ -- clear all urls
+ repository.clear(is_global)
+
+ -- remove all repositories
+ local repodir = repository.directory(is_global)
+ if os.isdir(repodir) then
+ os.rmdir(repodir)
+ end
+
+ -- trace
+ cprint("${bright}clear %s repositories: ok!", ifelse(is_global, "global", "local"))
+end
+
+-- list all repositories
+function _list(is_global)
+
+ -- list all repositories
+ local count = 0
+ for _, position in ipairs({"local", "global"}) do
+
+ -- trace
+ print("%s repositories:", position)
+
+ -- list all
+ for _, repo in pairs(repository.repositories(position == "global")) do
+
+ -- trace
+ print(" %s %s", repo.name, repo.url)
+
+ -- update count
+ count = count + 1
+ end
+
+ -- trace
+ print("")
+ end
+
+ -- trace
+ print("%d repositories were found!", count)
+end
+
+-- load project
+function _load_project()
+
+ -- enter project directory
+ os.cd(project.directory())
+
+ -- load config
+ config.load()
+
+ -- load platform
+ platform.load(config.plat())
+end
+
+-- main
+function main()
+
+ -- load project if operate local repositories
+ if not option.get("global") then
+ _load_project()
+ end
+
+ -- add repository url
+ if option.get("add") then
+
+ _add(option.get("name"), option.get("url"), option.get("global"))
+
+ -- remove repository url
+ elseif option.get("remove") then
+
+ _remove(option.get("name"), option.get("global"))
+
+ -- clear all repositories
+ elseif option.get("clear") then
+
+ _clear(option.get("global"))
+
+ -- list all repositories
+ elseif option.get("list") then
+
+ _list(option.get("global"))
+
+ -- show help
+ else
+ option.show_help()
+ end
+end
+
diff --git a/xmake/plugins/repo/xmake.lua b/xmake/plugins/repo/xmake.lua
new file mode 100644
index 000000000..6f38fdc12
--- /dev/null
+++ b/xmake/plugins/repo/xmake.lua
@@ -0,0 +1,54 @@
+--!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 repo.lua
+--
+
+-- define task
+task("repo")
+
+ -- set category
+ set_category("plugin")
+
+ -- on run
+ on_run("main")
+
+ -- set menu
+ set_menu {
+ -- usage
+ usage = "xmake repo [options] [name] [url]"
+
+ -- description
+ , description = "Manage package repositories."
+
+ -- options
+ , options =
+ {
+ {'a', "add", "k", nil, "Add the given remote repository url." }
+ , {'r', "remove", "k", nil, "Remove the given remote repository url." }
+ , {'l', "list", "k", nil, "List all added repositories." }
+ , {'g', "global", "k", nil, "Save repository to global. (default: local)" }
+ , {'c', "clear", "k", nil, "Clear all added repositories." }
+ , { }
+ , {nil, "name", "v", nil, "The repository name." }
+ , {nil, "url", "v", nil, "The repository url" }
+ }
+ }