├── codecov.yml ├── autogen.sh ├── cmake └── properties.cmake ├── xmake.lua ├── scripts └── libsv.pc.in ├── test ├── CMakeLists.txt ├── xmake.lua ├── usage.c ├── utils.c ├── semvers.c ├── range.c ├── version.c ├── comp.c └── match.c ├── UNLICENSE ├── m4 └── mm-libtool-library-versions.m4 ├── src ├── semvers.h ├── utils.h ├── num.h ├── comp.h ├── range.h ├── version.h ├── id.h ├── num.c ├── utils.c ├── semvers.c ├── range.c ├── id.c ├── version.c └── comp.c ├── configure.ac ├── Makefile.am ├── .github └── workflows │ └── cmake-multi-platform.yml ├── include └── semver.h ├── CMakeLists.txt ├── README.md └── INSTALL /codecov.yml: -------------------------------------------------------------------------------- 1 | ignore: 2 | - "test" # ignore test folder and all its contents 3 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # autogen.sh -- 3 | # 4 | # Run this in the top source directory to rebuild the infrastructure. 5 | 6 | LIBTOOLIZE=${LIBTOOLIZE:=libtoolize} 7 | 8 | set -xe 9 | test -d m4 || mkdir -p m4 10 | test -f m4/libtool.m4 || "$LIBTOOLIZE" 11 | autoreconf --warnings=all --install --verbose "$@" 12 | 13 | ### end of file 14 | -------------------------------------------------------------------------------- /cmake/properties.cmake: -------------------------------------------------------------------------------- 1 | project(sv C) 2 | set(${PROJECT_NAME}_VENDOR "uael") 3 | set(${PROJECT_NAME}_CONTACT "github.com/uael/sv/issues") 4 | set(${PROJECT_NAME}_SUMMARY "libsv - Public domain cross-platform semantic versioning in c99") 5 | set(${PROJECT_NAME}_MAJOR 1) 6 | set(${PROJECT_NAME}_MINOR 0) 7 | set(${PROJECT_NAME}_PATCH 0) 8 | set(${PROJECT_NAME}_README README.md) 9 | set(${PROJECT_NAME}_LICENSE UNLICENSE) 10 | set(${PROJECT_NAME}_COMPILE_OPTIONS -Wno-missing-field-initializers) -------------------------------------------------------------------------------- /xmake.lua: -------------------------------------------------------------------------------- 1 | set_project("libsv") 2 | set_version("0.0.1") 3 | set_xmakever("3.0.1") 4 | 5 | add_rules("mode.debug", "mode.release") 6 | set_warnings("all", "error") 7 | 8 | if is_plat("macosx", "iphoneos") then 9 | add_cflags("-Wno-nullability-completeness") 10 | add_cxxflags("-Wno-nullability-completeness") 11 | end 12 | 13 | target("sv") 14 | set_default(true) 15 | set_languages("c99") 16 | set_kind("$(kind)") 17 | add_headerfiles("include/(*.h)") 18 | add_includedirs("include", {public = true}) 19 | add_files("src/*.c") 20 | 21 | includes("test") 22 | -------------------------------------------------------------------------------- /scripts/libsv.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@prefix@ 2 | exec_prefix=@exec_prefix@ 3 | 4 | bindir=@bindir@ 5 | datarootdir=@datarootdir@ 6 | datadir=@datadir@ 7 | docdir=${prefix}/doc 8 | includedir=@includedir@ 9 | infodir=@infodir@ 10 | htmldir=${docdir} 11 | libdir=@libdir@ 12 | libexecdir=@libexecdir@ 13 | localstatedir=@localstatedir@ 14 | mandir=@mandir@ 15 | sbindir=@sbindir@ 16 | sharedstatedir=@sharedstatedir@ 17 | sysconfdir=@sysconfdir@ 18 | 19 | ## ------------------------------------------------------------ 20 | 21 | Name: @PACKAGE_NAME@ 22 | Description: semantic versioning for the C language 23 | Version: @LIBSV_PKG_CONFIG_VERSION@ 24 | Libs: -L${libdir} -lsv 25 | Cflags: -I${includedir} 26 | 27 | ### end of file 28 | # Local Variables: 29 | # mode: script 30 | # End: 31 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(version version.c) 2 | target_link_libraries(version ${PROJECT_NAME}) 3 | add_test(version version) 4 | 5 | add_executable(comp comp.c) 6 | target_link_libraries(comp ${PROJECT_NAME}) 7 | add_test(comp comp) 8 | 9 | add_executable(range range.c) 10 | target_link_libraries(range ${PROJECT_NAME}) 11 | add_test(range range) 12 | 13 | add_executable(match match.c) 14 | target_link_libraries(match ${PROJECT_NAME}) 15 | add_test(match match) 16 | 17 | add_executable(utils utils.c) 18 | target_link_libraries(utils ${PROJECT_NAME}) 19 | add_test(utils utils) 20 | 21 | add_executable(usage usage.c) 22 | target_link_libraries(usage ${PROJECT_NAME}) 23 | add_test(usage usage) 24 | 25 | add_executable(semvers semvers.c) 26 | target_link_libraries(semvers ${PROJECT_NAME}) 27 | add_test(semvers semvers) 28 | -------------------------------------------------------------------------------- /test/xmake.lua: -------------------------------------------------------------------------------- 1 | set_default(false) 2 | set_languages("c99") 3 | set_kind("binary") 4 | add_deps("sv") 5 | add_links("sv") 6 | add_includedirs("../include") 7 | add_linkdirs("$(builddir)") 8 | 9 | target("version_test") 10 | add_files("version.c") 11 | 12 | target("comp_test") 13 | add_files("comp.c") 14 | 15 | target("range_test") 16 | add_files("range.c") 17 | 18 | target("match_test") 19 | add_files("match.c") 20 | 21 | target("semvers_test") 22 | add_files("semvers.c") 23 | 24 | target("utils_test") 25 | add_files("utils.c") 26 | 27 | target("usage_test") 28 | add_files("usage.c") 29 | 30 | task("check") 31 | on_run(function () 32 | import("core.project.task") 33 | task.run("run", {target = "version_test"}) 34 | task.run("run", {target = "comp_test"}) 35 | task.run("run", {target = "range_test"}) 36 | task.run("run", {target = "match_test"}) 37 | task.run("run", {target = "semvers_test"}) 38 | task.run("run", {target = "utils_test"}) 39 | task.run("run", {target = "usage_test"}) 40 | end) 41 | set_menu { 42 | usage = "xmake check" 43 | , description = "Run tests !" 44 | , options = {} 45 | } 46 | -------------------------------------------------------------------------------- /UNLICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /m4/mm-libtool-library-versions.m4: -------------------------------------------------------------------------------- 1 | dnl mm-libtool-library-versions.m4 2 | 3 | dnl Set version numbers for libraries built with GNU Libtool. 4 | dnl 5 | dnl MM_LIBTOOL_LIBRARY_VERSIONS(stem,current,revision,age) 6 | dnl 7 | AC_DEFUN([MM_LIBTOOL_LIBRARY_VERSIONS], 8 | [$1_VERSION_INTERFACE_CURRENT=$2 9 | $1_VERSION_INTERFACE_REVISION=$3 10 | $1_VERSION_INTERFACE_AGE=$4 11 | AC_DEFINE_UNQUOTED([$1_VERSION_INTERFACE], 12 | [$$1_VERSION_INTERFACE_CURRENT.$$1_VERSION_INTERFACE_REVISION.$$1_VERSION_INTERFACE_AGE], 13 | [current interface number]) 14 | AC_DEFINE_UNQUOTED([$1_VERSION_INTERFACE_CURRENT], 15 | [$$1_VERSION_INTERFACE_CURRENT], 16 | [current interface number]) 17 | AC_DEFINE_UNQUOTED([$1_VERSION_INTERFACE_REVISION], 18 | [$$1_VERSION_INTERFACE_REVISION], 19 | [current interface implementation number]) 20 | AC_DEFINE_UNQUOTED([$1_VERSION_INTERFACE_AGE], 21 | [$$1_VERSION_INTERFACE_AGE], 22 | [current interface age number]) 23 | AC_DEFINE_UNQUOTED([$1_VERSION_INTERFACE_STRING], 24 | ["$$1_VERSION_INTERFACE_CURRENT.$$1_VERSION_INTERFACE_REVISION"], 25 | [library interface version]) 26 | AC_SUBST([$1_VERSION_INTERFACE_CURRENT]) 27 | AC_SUBST([$1_VERSION_INTERFACE_REVISION]) 28 | AC_SUBST([$1_VERSION_INTERFACE_AGE])]) 29 | 30 | dnl end of file 31 | -------------------------------------------------------------------------------- /src/semvers.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This is free and unencumbered software released into the public domain. 3 | * 4 | * Anyone is free to copy, modify, publish, use, compile, sell, or 5 | * distribute this software, either in source code form or as a compiled 6 | * binary, for any purpose, commercial or non-commercial, and by any 7 | * means. 8 | * 9 | * In jurisdictions that recognize copyright laws, the author or authors 10 | * of this software dedicate any and all copyright interest in the 11 | * software to the public domain. We make this dedication for the benefit 12 | * of the public at large and to the detriment of our heirs and 13 | * successors. We intend this dedication to be an overt act of 14 | * relinquishment in perpetuity of all present and future rights to this 15 | * software under copyright law. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | * OTHER DEALINGS IN THE SOFTWARE. 24 | * 25 | * For more information, please refer to 26 | */ 27 | 28 | #ifndef SV_SEMVERS_H__ 29 | # define SV_SEMVERS_H__ 30 | 31 | #include "semver.h" 32 | 33 | #define SEMVERS_MIN_CAP (4) 34 | 35 | #endif /* SV_SEMVERS_H__ */ 36 | -------------------------------------------------------------------------------- /src/utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This is free and unencumbered software released into the public domain. 3 | * 4 | * Anyone is free to copy, modify, publish, use, compile, sell, or 5 | * distribute this software, either in source code form or as a compiled 6 | * binary, for any purpose, commercial or non-commercial, and by any 7 | * means. 8 | * 9 | * In jurisdictions that recognize copyright laws, the author or authors 10 | * of this software dedicate any and all copyright interest in the 11 | * software to the public domain. We make this dedication for the benefit 12 | * of the public at large and to the detriment of our heirs and 13 | * successors. We intend this dedication to be an overt act of 14 | * relinquishment in perpetuity of all present and future rights to this 15 | * software under copyright law. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | * OTHER DEALINGS IN THE SOFTWARE. 24 | * 25 | * For more information, please refer to 26 | */ 27 | 28 | #ifndef SV_UTILS_H__ 29 | # define SV_UTILS_H__ 30 | 31 | #include "version.h" 32 | 33 | const char *semver_op_string(enum semver_op op); 34 | 35 | #endif /* SV_UTILS_H__ */ 36 | -------------------------------------------------------------------------------- /src/num.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This is free and unencumbered software released into the public domain. 3 | * 4 | * Anyone is free to copy, modify, publish, use, compile, sell, or 5 | * distribute this software, either in source code form or as a compiled 6 | * binary, for any purpose, commercial or non-commercial, and by any 7 | * means. 8 | * 9 | * In jurisdictions that recognize copyright laws, the author or authors 10 | * of this software dedicate any and all copyright interest in the 11 | * software to the public domain. We make this dedication for the benefit 12 | * of the public at large and to the detriment of our heirs and 13 | * successors. We intend this dedication to be an overt act of 14 | * relinquishment in perpetuity of all present and future rights to this 15 | * software under copyright law. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | * OTHER DEALINGS IN THE SOFTWARE. 24 | * 25 | * For more information, please refer to 26 | */ 27 | 28 | #ifndef SV_NUM_H__ 29 | # define SV_NUM_H__ 30 | 31 | #include "version.h" 32 | 33 | char semver_num_read(int *self, const char *str, size_t len, size_t *offset); 34 | int semver_num_cmp(int self, int other); 35 | 36 | #endif /* SV_NUM_H__ */ 37 | -------------------------------------------------------------------------------- /src/comp.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This is free and unencumbered software released into the public domain. 3 | * 4 | * Anyone is free to copy, modify, publish, use, compile, sell, or 5 | * distribute this software, either in source code form or as a compiled 6 | * binary, for any purpose, commercial or non-commercial, and by any 7 | * means. 8 | * 9 | * In jurisdictions that recognize copyright laws, the author or authors 10 | * of this software dedicate any and all copyright interest in the 11 | * software to the public domain. We make this dedication for the benefit 12 | * of the public at large and to the detriment of our heirs and 13 | * successors. We intend this dedication to be an overt act of 14 | * relinquishment in perpetuity of all present and future rights to this 15 | * software under copyright law. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | * OTHER DEALINGS IN THE SOFTWARE. 24 | * 25 | * For more information, please refer to 26 | */ 27 | 28 | #ifndef SV_COMP_H__ 29 | # define SV_COMP_H__ 30 | 31 | #include "version.h" 32 | 33 | #define SV_COMP_MAX_LEN (512) 34 | 35 | void semver_comp_ctor(semver_comp_t *self); 36 | char semver_comp_read(semver_comp_t *self, const char *str, size_t len, size_t *offset); 37 | 38 | #endif /* SV_COMP_H__ */ 39 | -------------------------------------------------------------------------------- /src/range.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This is free and unencumbered software released into the public domain. 3 | * 4 | * Anyone is free to copy, modify, publish, use, compile, sell, or 5 | * distribute this software, either in source code form or as a compiled 6 | * binary, for any purpose, commercial or non-commercial, and by any 7 | * means. 8 | * 9 | * In jurisdictions that recognize copyright laws, the author or authors 10 | * of this software dedicate any and all copyright interest in the 11 | * software to the public domain. We make this dedication for the benefit 12 | * of the public at large and to the detriment of our heirs and 13 | * successors. We intend this dedication to be an overt act of 14 | * relinquishment in perpetuity of all present and future rights to this 15 | * software under copyright law. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | * OTHER DEALINGS IN THE SOFTWARE. 24 | * 25 | * For more information, please refer to 26 | */ 27 | 28 | #ifndef SV_RANGE_H__ 29 | # define SV_RANGE_H__ 30 | 31 | #include "version.h" 32 | 33 | #define SV_RANGE_MAX_LEN (512) 34 | 35 | void semver_range_ctor(semver_range_t *self); 36 | char semver_range_read(semver_range_t *self, const char *str, size_t len, size_t *offset); 37 | 38 | #endif /* SV_RANGE_H__ */ 39 | -------------------------------------------------------------------------------- /src/version.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This is free and unencumbered software released into the public domain. 3 | * 4 | * Anyone is free to copy, modify, publish, use, compile, sell, or 5 | * distribute this software, either in source code form or as a compiled 6 | * binary, for any purpose, commercial or non-commercial, and by any 7 | * means. 8 | * 9 | * In jurisdictions that recognize copyright laws, the author or authors 10 | * of this software dedicate any and all copyright interest in the 11 | * software to the public domain. We make this dedication for the benefit 12 | * of the public at large and to the detriment of our heirs and 13 | * successors. We intend this dedication to be an overt act of 14 | * relinquishment in perpetuity of all present and future rights to this 15 | * software under copyright law. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | * OTHER DEALINGS IN THE SOFTWARE. 24 | * 25 | * For more information, please refer to 26 | */ 27 | 28 | #ifndef SV_VERSION_H__ 29 | # define SV_VERSION_H__ 30 | 31 | #include "semver.h" 32 | 33 | #ifdef _MSC_VER 34 | # define snprintf(s, maxlen, fmt, ...) _snprintf_s(s, _TRUNCATE, maxlen, fmt, __VA_ARGS__) 35 | #endif 36 | 37 | #define SV_MAX_LEN (256) 38 | 39 | void semver_ctor(semver_t *self); 40 | char semver_read(semver_t *self, const char *str, size_t len, size_t *offset); 41 | char semver_try_read(semver_t *self, const char *str, size_t len, size_t *offset); 42 | 43 | #endif /* SV_VERSION_H__ */ 44 | -------------------------------------------------------------------------------- /test/usage.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This is free and unencumbered software released into the public domain. 3 | * 4 | * Anyone is free to copy, modify, publish, use, compile, sell, or 5 | * distribute this software, either in source code form or as a compiled 6 | * binary, for any purpose, commercial or non-commercial, and by any 7 | * means. 8 | * 9 | * In jurisdictions that recognize copyright laws, the author or authors 10 | * of this software dedicate any and all copyright interest in the 11 | * software to the public domain. We make this dedication for the benefit 12 | * of the public at large and to the detriment of our heirs and 13 | * successors. We intend this dedication to be an overt act of 14 | * relinquishment in perpetuity of all present and future rights to this 15 | * software under copyright law. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | * OTHER DEALINGS IN THE SOFTWARE. 24 | * 25 | * For more information, please refer to 26 | */ 27 | 28 | #include 29 | #include 30 | 31 | #include "semver.h" 32 | 33 | int main(void) { 34 | semver_t semver = {0}; 35 | 36 | semver(&semver, "v1.2.3-alpha.1"); 37 | 38 | assert(1 == semver.major); 39 | assert(2 == semver.minor); 40 | assert(3 == semver.patch); 41 | assert(0 == memcmp("alpha", semver.prerelease.raw, sizeof("alpha")-1)); 42 | assert(0 == memcmp("1", semver.prerelease.next->raw, sizeof("1")-1)); 43 | assert(true == semver_rmatch(semver, "1.2.1 || >=1.2.3-alpha <1.2.5")); 44 | 45 | semver_dtor(&semver); 46 | } 47 | -------------------------------------------------------------------------------- /src/id.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This is free and unencumbered software released into the public domain. 3 | * 4 | * Anyone is free to copy, modify, publish, use, compile, sell, or 5 | * distribute this software, either in source code form or as a compiled 6 | * binary, for any purpose, commercial or non-commercial, and by any 7 | * means. 8 | * 9 | * In jurisdictions that recognize copyright laws, the author or authors 10 | * of this software dedicate any and all copyright interest in the 11 | * software to the public domain. We make this dedication for the benefit 12 | * of the public at large and to the detriment of our heirs and 13 | * successors. We intend this dedication to be an overt act of 14 | * relinquishment in perpetuity of all present and future rights to this 15 | * software under copyright law. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | * OTHER DEALINGS IN THE SOFTWARE. 24 | * 25 | * For more information, please refer to 26 | */ 27 | 28 | #ifndef SV_ID_H__ 29 | # define SV_ID_H__ 30 | 31 | #include "version.h" 32 | 33 | void semver_id_ctor(semver_id_t *self); 34 | void semver_id_dtor(semver_id_t *self); 35 | char semver_id_read_prerelease(semver_id_t *self, const char *str, size_t len, size_t *offset); 36 | char semver_id_read_build(semver_id_t *self, const char *str, size_t len, size_t *offset); 37 | int semver_id_pwrite(const semver_id_t *self, char *buffer, size_t len); 38 | int semver_id_pcmp(const semver_id_t *self, const semver_id_t *other); 39 | 40 | #define semver_id_write(self, buffer, len) semver_id_pwrite(&(self), buffer, len) 41 | #define semver_id_comp(self, other) semver_id_pcmp(&(self), &(other)) 42 | 43 | #endif /* SV_ID_H__ */ 44 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | dnl @configure_input@ 2 | dnl 3 | 4 | AC_PREREQ([2.69]) 5 | AC_INIT([libsv],[0.0.1],,[libsv],[http://github.com/uael/sv]) 6 | AC_COPYRIGHT([This is free and unencumbered software released into the public domain. 7 | 8 | Anyone is free to copy, modify, publish, use, compile, sell, or 9 | distribute this software, either in source code form or as a compiled 10 | binary, for any purpose, commercial or non-commercial, and by any means. 11 | 12 | In jurisdictions that recognize copyright laws, the author or authors of 13 | this software dedicate any and all copyright interest in the software to 14 | the public domain. We make this dedication for the benefit of the public 15 | at large and to the detriment of our heirs and successors. We intend 16 | this dedication to be an overt act of relinquishment in perpetuity of 17 | all present and future rights to this software under copyright law. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 24 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | 27 | For more information, please refer to 28 | ]) 29 | AC_CONFIG_SRCDIR([src]) 30 | AC_CONFIG_MACRO_DIR([m4]) 31 | AC_CONFIG_AUX_DIR([scripts]) 32 | AC_CANONICAL_BUILD 33 | AC_CANONICAL_HOST 34 | AC_CANONICAL_TARGET 35 | AM_INIT_AUTOMAKE([foreign dist-xz no-dist-gzip subdir-objects]) 36 | AM_MAINTAINER_MODE 37 | 38 | AM_PROG_AR 39 | AC_PROG_INSTALL 40 | AC_PROG_LN_S 41 | AC_PROG_MAKE_SET 42 | AC_PROG_MKDIR_P 43 | 44 | LT_PREREQ([2.4]) 45 | LT_INIT 46 | 47 | dnl This is the version stored in the pkg-config data file. 48 | AC_SUBST([LIBSV_PKG_CONFIG_VERSION],[0.0.1]) 49 | 50 | dnl page 51 | #### libraries interface version 52 | 53 | MM_LIBTOOL_LIBRARY_VERSIONS([libsv],1,0,0) 54 | 55 | dnl page 56 | #### basic system inspection 57 | 58 | AC_LANG([C]) 59 | AM_PROG_AS 60 | AC_PROG_CC_C99 61 | AM_PROG_CC_C_O 62 | AC_HEADER_STDC 63 | 64 | AC_CACHE_SAVE 65 | 66 | dnl page 67 | #### finish 68 | 69 | AC_CONFIG_FILES([Makefile] 70 | [scripts/libsv.pc]) 71 | AC_OUTPUT 72 | 73 | ### end of file 74 | # Local Variables: 75 | # mode: autoconf 76 | # page-delimiter: "^dnl page" 77 | # End: 78 | -------------------------------------------------------------------------------- /src/num.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This is free and unencumbered software released into the public domain. 3 | * 4 | * Anyone is free to copy, modify, publish, use, compile, sell, or 5 | * distribute this software, either in source code form or as a compiled 6 | * binary, for any purpose, commercial or non-commercial, and by any 7 | * means. 8 | * 9 | * In jurisdictions that recognize copyright laws, the author or authors 10 | * of this software dedicate any and all copyright interest in the 11 | * software to the public domain. We make this dedication for the benefit 12 | * of the public at large and to the detriment of our heirs and 13 | * successors. We intend this dedication to be an overt act of 14 | * relinquishment in perpetuity of all present and future rights to this 15 | * software under copyright law. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | * OTHER DEALINGS IN THE SOFTWARE. 24 | * 25 | * For more information, please refer to 26 | */ 27 | 28 | #include 29 | #include 30 | #include 31 | 32 | #include "num.h" 33 | 34 | char semver_num_read(int *self, const char *str, size_t len, size_t *offset) { 35 | char *endptr; 36 | 37 | *self = 0; 38 | if (*offset >= len) { 39 | return 1; 40 | } 41 | switch (str[*offset]) { 42 | case 'x': 43 | case 'X': 44 | case '*': 45 | *self = SEMVER_NUM_X; 46 | ++*offset; 47 | break; 48 | case '0': 49 | ++*offset; 50 | if (*offset < len && isdigit(str[*offset])) { 51 | *self = (int) strtol(str + *offset, &endptr, 0); 52 | *offset += endptr - str - *offset; 53 | } else *self = 0; 54 | break; 55 | default: 56 | if (isdigit(str[*offset])) { 57 | *self = (int) strtol(str + *offset, &endptr, 0); 58 | *offset += endptr - str - *offset; 59 | } else { 60 | return 1; 61 | } 62 | break; 63 | } 64 | return 0; 65 | } 66 | 67 | int semver_num_cmp(int self, int other) { 68 | if (self > other) { 69 | return 1; 70 | } 71 | if (self < other) { 72 | return -1; 73 | } 74 | return 0; 75 | } 76 | -------------------------------------------------------------------------------- /test/utils.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This is free and unencumbered software released into the public domain. 3 | * 4 | * Anyone is free to copy, modify, publish, use, compile, sell, or 5 | * distribute this software, either in source code form or as a compiled 6 | * binary, for any purpose, commercial or non-commercial, and by any 7 | * means. 8 | * 9 | * In jurisdictions that recognize copyright laws, the author or authors 10 | * of this software dedicate any and all copyright interest in the 11 | * software to the public domain. We make this dedication for the benefit 12 | * of the public at large and to the detriment of our heirs and 13 | * successors. We intend this dedication to be an overt act of 14 | * relinquishment in perpetuity of all present and future rights to this 15 | * software under copyright law. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | * OTHER DEALINGS IN THE SOFTWARE. 24 | * 25 | * For more information, please refer to 26 | */ 27 | 28 | #include 29 | #include 30 | #include 31 | 32 | #include "semver.h" 33 | 34 | int test_version_fwrite(void) { 35 | static const char input_str[] = "1.2.3-alpha.1+x86-64"; 36 | semver_t version; 37 | int rv; 38 | 39 | rv = semver(&version, input_str); 40 | if (0 == rv) { 41 | printf("test_version_fwrite: "); 42 | semver_fwrite(&version, stdout); 43 | if (0 == errno) { 44 | printf("\n"); 45 | rv = 0; 46 | } 47 | } 48 | semver_dtor(&version); 49 | return rv; 50 | } 51 | 52 | int test_comparator_fwrite(void) { 53 | static const char input_str[] = "<=1.2.3"; 54 | semver_comp_t comp; 55 | int rv; 56 | 57 | rv = semver_comp(&comp, input_str); 58 | if (0 == rv) { 59 | printf("test_comparator_fwrite: "); 60 | semver_comp_fwrite(&comp, stdout); 61 | if (0 == errno) { 62 | printf("\n"); 63 | rv = 0; 64 | } 65 | } 66 | semver_comp_dtor(&comp); 67 | return rv; 68 | } 69 | 70 | int test_range_fwrite(void) { 71 | static const char input_str[] = ">=1.2.3 <4.0.0"; 72 | semver_range_t range; 73 | int rv; 74 | 75 | rv = semver_range(&range, input_str); 76 | if (0 == rv) { 77 | printf("test_range_fwrite: "); 78 | semver_range_fwrite(&range, stdout); 79 | if (0 == errno) { 80 | printf("\n"); 81 | rv = 0; 82 | } 83 | } 84 | semver_range_dtor(&range); 85 | return rv; 86 | } 87 | 88 | int main(void) { 89 | if (test_version_fwrite()) { 90 | return EXIT_FAILURE; 91 | } 92 | 93 | if (test_comparator_fwrite()) { 94 | return EXIT_FAILURE; 95 | } 96 | 97 | if (test_range_fwrite()) { 98 | return EXIT_FAILURE; 99 | } 100 | 101 | return EXIT_SUCCESS; 102 | } 103 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | ## Process this file with automake to produce Makefile.in 2 | 3 | ACLOCAL_AMFLAGS = -I m4 4 | AUTOMAKE_OPTIONS = foreign 5 | dist_doc_DATA = UNLICENSE README.md 6 | AM_CFLAGS = -I$(srcdir)/src -I$(srcdir)/include -Wall $(AX_CFLAGS) 7 | 8 | ## -------------------------------------------------------------------- 9 | 10 | EXTRA_DIST = scripts/libsv.pc.in 11 | pkgconfigdir = $(libdir)/pkgconfig 12 | nodist_pkgconfig_DATA = scripts/libsv.pc 13 | 14 | ## -------------------------------------------------------------------- 15 | 16 | # Commented out because at present there is no Texinfo documentation 17 | # included. It will come later. (Marco Maggi; May 17, 2017) 18 | # 19 | # AM_MAKEINFOFLAGS = --no-split 20 | # info_TEXINFOS = doc/semver.texi 21 | # doc_semver_TEXINFOS = doc/macros.texi 22 | 23 | #page 24 | #### libraries 25 | 26 | libsv_CURRENT = @libsv_VERSION_INTERFACE_CURRENT@ 27 | libsv_REVISION = @libsv_VERSION_INTERFACE_REVISION@ 28 | libsv_AGE = @libsv_VERSION_INTERFACE_AGE@ 29 | 30 | include_HEADERS = include/semver.h 31 | 32 | lib_LTLIBRARIES = libsv.la 33 | libsv_la_LDFLAGS = -version-info $(libsv_CURRENT):$(libsv_REVISION):$(libsv_AGE) 34 | libsv_la_SOURCES = \ 35 | src/comp.c \ 36 | src/id.c \ 37 | src/num.c \ 38 | src/range.c \ 39 | src/semvers.c \ 40 | src/version.c \ 41 | src/utils.c 42 | 43 | #page 44 | #### test 45 | 46 | check_PROGRAMS = \ 47 | test/version \ 48 | test/comp \ 49 | test/match \ 50 | test/range \ 51 | test/semvers \ 52 | test/utils \ 53 | test/usage 54 | 55 | TESTS = $(check_PROGRAMS) 56 | 57 | libsv_test_cppflags = -I$(srcdir)/src -I$(srcdir)/include 58 | libsv_test_ldadd = libsv.la 59 | 60 | test_version_CPPFLAGS = $(libsv_test_cppflags) 61 | test_version_LDADD = $(libsv_test_ldadd) 62 | 63 | test_comp_CPPFLAGS = $(libsv_test_cppflags) 64 | test_comp_LDADD = $(libsv_test_ldadd) 65 | 66 | test_match_CPPFLAGS = $(libsv_test_cppflags) 67 | test_match_LDADD = $(libsv_test_ldadd) 68 | 69 | test_range_CPPFLAGS = $(libsv_test_cppflags) 70 | test_range_LDADD = $(libsv_test_ldadd) 71 | 72 | test_semvers_CPPFLAGS = $(libsv_test_cppflags) 73 | test_semvers_LDADD = $(libsv_test_ldadd) 74 | 75 | test_utils_CPPFLAGS = $(libsv_test_cppflags) 76 | test_utils_LDADD = $(libsv_test_ldadd) 77 | 78 | test_usage_CPPFLAGS = $(libsv_test_cppflags) 79 | test_usage_LDADD = $(libsv_test_ldadd) 80 | 81 | installcheck-local: $(TEST) 82 | @for f in $(TEST); do $(builddir)/$$f; done 83 | 84 | #page 85 | #### Static analysis with Clang's Static Analyzer 86 | # 87 | # See the documentation for the command line tool at: 88 | # 89 | # 90 | # 91 | # To run the tool we must do: 92 | # 93 | # $ make clean 94 | # $ make clang-static-analysis 95 | # 96 | # The program "scan-build" works by overriding the CC and CXX 97 | # environment variables. 98 | # 99 | 100 | .PHONY: clang-static-analysis 101 | 102 | clang-static-analysis: 103 | scan-build make 104 | 105 | ### end of file 106 | -------------------------------------------------------------------------------- /src/utils.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This is free and unencumbered software released into the public domain. 3 | * 4 | * Anyone is free to copy, modify, publish, use, compile, sell, or 5 | * distribute this software, either in source code form or as a compiled 6 | * binary, for any purpose, commercial or non-commercial, and by any 7 | * means. 8 | * 9 | * In jurisdictions that recognize copyright laws, the author or authors 10 | * of this software dedicate any and all copyright interest in the 11 | * software to the public domain. We make this dedication for the benefit 12 | * of the public at large and to the detriment of our heirs and 13 | * successors. We intend this dedication to be an overt act of 14 | * relinquishment in perpetuity of all present and future rights to this 15 | * software under copyright law. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | * OTHER DEALINGS IN THE SOFTWARE. 24 | * 25 | * For more information, please refer to 26 | */ 27 | 28 | #include 29 | #include 30 | #include 31 | 32 | #include "utils.h" 33 | #include "comp.h" 34 | #include "range.h" 35 | 36 | /*!\brief Serialise the version to the STREAM. When successful: return the 37 | * number of bytes written and set "errno" to zero. When unsuccessful: 38 | * set "errno" to an error code. 39 | */ 40 | size_t semver_fwrite(const semver_t *self, FILE *stream) { 41 | char buffer[SV_MAX_LEN]; 42 | int cs; 43 | 44 | if ((cs = semver_pwrite(self, buffer, SV_MAX_LEN)) == 0) { 45 | return 0; 46 | } 47 | errno = 0; 48 | return fwrite(buffer, sizeof(char), (size_t) cs, stream); 49 | } 50 | 51 | /*!\brief Serialise the comparator to the STREAM. When successful: return the 52 | * number of bytes written and set "errno" to zero. When unsuccessful: 53 | * set "errno" to an error code. 54 | */ 55 | size_t semver_comp_fwrite(const semver_comp_t *self, FILE *stream) { 56 | char buffer[SV_COMP_MAX_LEN]; 57 | int cs; 58 | 59 | if ((cs = semver_comp_pwrite(self, buffer, SV_COMP_MAX_LEN)) == 0) { 60 | return 0; 61 | } 62 | errno = 0; 63 | return fwrite(buffer, sizeof(char), (size_t) cs, stream); 64 | } 65 | 66 | /*!\brief Serialise the range to the STREAM. When successful: return the 67 | * number of bytes written and set "errno" to zero. When unsuccessful: 68 | * set "errno" to an error code. 69 | */ 70 | size_t semver_range_fwrite(const semver_range_t *self, FILE *stream) { 71 | char buffer[SV_RANGE_MAX_LEN]; 72 | int cs; 73 | 74 | if ((cs = semver_range_pwrite(self, buffer, SV_RANGE_MAX_LEN)) == 0) { 75 | return 0; 76 | } 77 | errno = 0; 78 | return fwrite(buffer, sizeof(char), (size_t) cs, stream); 79 | } 80 | 81 | const char *semver_op_string(enum semver_op op) { 82 | switch (op) { 83 | case SEMVER_OP_EQ: 84 | return ""; 85 | case SEMVER_OP_LT: 86 | return "<"; 87 | case SEMVER_OP_LE: 88 | return "<="; 89 | case SEMVER_OP_GT: 90 | return ">"; 91 | case SEMVER_OP_GE: 92 | return ">="; 93 | default: 94 | return NULL; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /.github/workflows/cmake-multi-platform.yml: -------------------------------------------------------------------------------- 1 | # This starter workflow is for a CMake project running on multiple platforms. There is a different starter workflow if you just want a single platform. 2 | # See: https://github.com/actions/starter-workflows/blob/main/ci/cmake-single-platform.yml 3 | name: CMake on multiple platforms 4 | 5 | on: 6 | push: 7 | branches: [ "master" ] 8 | pull_request: 9 | branches: [ "master" ] 10 | 11 | jobs: 12 | build: 13 | runs-on: ${{ matrix.os }} 14 | 15 | strategy: 16 | # Set fail-fast to false to ensure that feedback is delivered for all matrix combinations. Consider changing this to true when your workflow is stable. 17 | fail-fast: false 18 | 19 | # Set up a matrix to run the following 3 configurations: 20 | # 1. 21 | # 2. 22 | # 3. 23 | # 24 | # To add more build types (Release, Debug, RelWithDebInfo, etc.) customize the build_type list. 25 | matrix: 26 | os: [ubuntu-latest, windows-latest] 27 | build_type: [Release] 28 | c_compiler: [gcc, clang, cl] 29 | include: 30 | - os: windows-latest 31 | c_compiler: cl 32 | cpp_compiler: cl 33 | - os: ubuntu-latest 34 | c_compiler: gcc 35 | cpp_compiler: g++ 36 | - os: ubuntu-latest 37 | c_compiler: clang 38 | cpp_compiler: clang++ 39 | exclude: 40 | - os: windows-latest 41 | c_compiler: gcc 42 | - os: windows-latest 43 | c_compiler: clang 44 | - os: ubuntu-latest 45 | c_compiler: cl 46 | 47 | steps: 48 | - uses: actions/checkout@v3 49 | 50 | - name: Set reusable strings 51 | # Turn repeated input strings (such as the build output directory) into step outputs. These step outputs can be used throughout the workflow file. 52 | id: strings 53 | shell: bash 54 | run: | 55 | echo "build-output-dir=${{ github.workspace }}/build" >> "$GITHUB_OUTPUT" 56 | 57 | - name: Configure CMake 58 | # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. 59 | # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type 60 | run: > 61 | cmake -B ${{ steps.strings.outputs.build-output-dir }} 62 | -DCMAKE_CXX_COMPILER=${{ matrix.cpp_compiler }} 63 | -DCMAKE_C_COMPILER=${{ matrix.c_compiler }} 64 | -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} 65 | -S ${{ github.workspace }} 66 | 67 | - name: Build 68 | # Build your program with the given configuration. Note that --config is needed because the default Windows generator is a multi-config generator (Visual Studio generator). 69 | run: cmake --build ${{ steps.strings.outputs.build-output-dir }} --config ${{ matrix.build_type }} 70 | 71 | - name: Test 72 | working-directory: ${{ steps.strings.outputs.build-output-dir }} 73 | # Execute tests defined by the CMake configuration. Note that --build-config is needed because the default Windows generator is a multi-config generator (Visual Studio generator). 74 | # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail 75 | run: ctest --build-config ${{ matrix.build_type }} 76 | -------------------------------------------------------------------------------- /src/semvers.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This is free and unencumbered software released into the public domain. 3 | * 4 | * Anyone is free to copy, modify, publish, use, compile, sell, or 5 | * distribute this software, either in source code form or as a compiled 6 | * binary, for any purpose, commercial or non-commercial, and by any 7 | * means. 8 | * 9 | * In jurisdictions that recognize copyright laws, the author or authors 10 | * of this software dedicate any and all copyright interest in the 11 | * software to the public domain. We make this dedication for the benefit 12 | * of the public at large and to the detriment of our heirs and 13 | * successors. We intend this dedication to be an overt act of 14 | * relinquishment in perpetuity of all present and future rights to this 15 | * software under copyright law. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | * OTHER DEALINGS IN THE SOFTWARE. 24 | * 25 | * For more information, please refer to 26 | */ 27 | 28 | #include 29 | #include 30 | 31 | #include "semvers.h" 32 | 33 | #define ISPOW2(n) (((n) & -(n)) == (n)) 34 | 35 | uint32_t semvers_pgrowth(semvers_t *self, const int32_t nmin) { 36 | if (nmin > 0) { 37 | uint32_t unmin = (uint32_t) nmin; 38 | 39 | if (self->capacity) { 40 | if (self->capacity < unmin) { 41 | if (ISPOW2(nmin)) { 42 | self->capacity = unmin; 43 | } else { 44 | do self->capacity *= 2; while (self->capacity < unmin); 45 | } 46 | self->data = (semver_t *) realloc((char *) self->data, sizeof(semver_t) * self->capacity); 47 | } 48 | } else { 49 | if (unmin == SEMVERS_MIN_CAP || (unmin > SEMVERS_MIN_CAP && ISPOW2(nmin))) { 50 | self->capacity = unmin; 51 | } else { 52 | self->capacity = SEMVERS_MIN_CAP; 53 | while (self->capacity < unmin) self->capacity *= 2; 54 | } 55 | self->data = (semver_t *) sv_malloc(sizeof(semver_t) * self->capacity); 56 | } 57 | return unmin; 58 | } 59 | return 0; 60 | } 61 | 62 | semver_t semvers_perase(semvers_t *self, uint32_t i) { 63 | semver_t x = self->data[i]; 64 | 65 | memmove(self->data + i, self->data + i + 1, --self->length * sizeof(semver_t)); 66 | return x; 67 | } 68 | 69 | static int semvers_qsort_fn(const void *a, const void *b) { 70 | return semver_pcmp((semver_t *) a, (semver_t *) b); 71 | } 72 | 73 | void semvers_psort(semvers_t *self) { 74 | qsort((char *) self->data, self->length, sizeof(semver_t), semvers_qsort_fn); 75 | } 76 | 77 | static int semvers_rqsort_fn(const void *a, const void *b) { 78 | return semver_pcmp((semver_t *) b, (semver_t *) a); 79 | } 80 | 81 | void semvers_prsort(semvers_t *self) { 82 | qsort((char *) self->data, self->length, sizeof(semver_t), semvers_rqsort_fn); 83 | } 84 | 85 | void semvers_pdtor(semvers_t *self) { 86 | if (self->data) { 87 | uint32_t i; 88 | 89 | for (i = 0; i < self->length; ++i) { 90 | semver_dtor(self->data + i); 91 | } 92 | sv_free(self->data); 93 | self->data = NULL; 94 | } 95 | self->length = self->capacity = 0; 96 | } 97 | 98 | void semvers_pclear(semvers_t *self) { 99 | if (self->data) { 100 | uint32_t i; 101 | 102 | for (i = 0; i < self->length; ++i) { 103 | semver_dtor(self->data + i); 104 | } 105 | memset((char *) self->data, 0, self->length * sizeof(semver_t)); 106 | } 107 | self->length = 0; 108 | } 109 | -------------------------------------------------------------------------------- /src/range.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This is free and unencumbered software released into the public domain. 3 | * 4 | * Anyone is free to copy, modify, publish, use, compile, sell, or 5 | * distribute this software, either in source code form or as a compiled 6 | * binary, for any purpose, commercial or non-commercial, and by any 7 | * means. 8 | * 9 | * In jurisdictions that recognize copyright laws, the author or authors 10 | * of this software dedicate any and all copyright interest in the 11 | * software to the public domain. We make this dedication for the benefit 12 | * of the public at large and to the detriment of our heirs and 13 | * successors. We intend this dedication to be an overt act of 14 | * relinquishment in perpetuity of all present and future rights to this 15 | * software under copyright law. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | * OTHER DEALINGS IN THE SOFTWARE. 24 | * 25 | * For more information, please refer to 26 | */ 27 | 28 | #include 29 | #include 30 | #include 31 | 32 | #include "range.h" 33 | #include "comp.h" 34 | 35 | void semver_range_ctor(semver_range_t *self) { 36 | #ifndef _MSC_VER 37 | *self = (semver_range_t) {0}; 38 | #else 39 | self->next = NULL; 40 | semver_comp_ctor(&self->comp); 41 | #endif 42 | } 43 | 44 | void semver_range_dtor(semver_range_t *self) { 45 | if (self && self->next) { 46 | semver_range_dtor(self->next); 47 | sv_free(self->next); 48 | self->next = NULL; 49 | } 50 | } 51 | 52 | char semver_rangen(semver_range_t *self, const char *str, size_t len) { 53 | size_t offset = 0; 54 | 55 | if (len > SV_RANGE_MAX_LEN) { 56 | return 1; 57 | } 58 | if (semver_range_read(self, str, len, &offset) || offset < len) { 59 | semver_range_dtor(self); 60 | return 1; 61 | } 62 | return 0; 63 | } 64 | 65 | char semver_range_read(semver_range_t *self, const char *str, size_t len, size_t *offset) { 66 | semver_range_ctor(self); 67 | if (semver_comp_read(&self->comp, str, len, offset)) { 68 | return 1; 69 | } 70 | while (*offset < len && str[*offset] == ' ') ++*offset; 71 | if (*offset < len && str[*offset] == '|' 72 | && *offset + 1 < len && str[*offset + 1] == '|') { 73 | *offset += 2; 74 | while (*offset < len && str[*offset] == ' ') ++*offset; 75 | self->next = (semver_range_t *) sv_malloc(sizeof(semver_range_t)); 76 | if (self->next == NULL) { 77 | return 1; 78 | } 79 | return semver_range_read(self->next, str, len, offset); 80 | } 81 | return 0; 82 | } 83 | 84 | char semver_or(semver_range_t *left, const char *str, size_t len) { 85 | semver_range_t *range, *tail; 86 | 87 | if (len > 0) { 88 | range = (semver_range_t *) sv_malloc(sizeof(semver_range_t)); 89 | if (NULL == range) { 90 | return 1; 91 | } 92 | if (semver_rangen(range, str, len)) { 93 | sv_free(range); 94 | return 1; 95 | } 96 | if (NULL == left->next) { 97 | left->next = range; 98 | } else { 99 | tail = left->next; 100 | while (tail->next) tail = tail->next; 101 | tail->next = range; 102 | } 103 | return 0; 104 | } 105 | return 1; 106 | } 107 | 108 | bool semver_range_pmatch(const semver_t *self, const semver_range_t *range) { 109 | return semver_comp_pmatch(self, &range->comp) ? true : range->next ? semver_range_pmatch(self, range->next) : false; 110 | } 111 | 112 | bool semver_range_matchn(const semver_t *self, const char *range_str, size_t range_len) { 113 | semver_range_t range; 114 | bool result; 115 | 116 | if (semver_rangen(&range, range_str, range_len)) { 117 | return false; 118 | } 119 | result = semver_range_pmatch(self, &range); 120 | semver_range_dtor(&range); 121 | return result; 122 | } 123 | 124 | int semver_range_pwrite(const semver_range_t *self, char *buffer, size_t len) { 125 | char comp[SV_RANGE_MAX_LEN]; 126 | 127 | if (self->next) { 128 | char next[SV_RANGE_MAX_LEN]; 129 | return snprintf(buffer, len, "%.*s || %.*s", 130 | semver_comp_write(self->comp, comp, SV_RANGE_MAX_LEN), comp, 131 | semver_range_pwrite(self->next, next, SV_RANGE_MAX_LEN), next 132 | ); 133 | } 134 | return snprintf(buffer, len, "%.*s", semver_comp_write(self->comp, comp, SV_RANGE_MAX_LEN), comp); 135 | } 136 | -------------------------------------------------------------------------------- /test/semvers.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This is free and unencumbered software released into the public domain. 3 | * 4 | * Anyone is free to copy, modify, publish, use, compile, sell, or 5 | * distribute this software, either in source code form or as a compiled 6 | * binary, for any purpose, commercial or non-commercial, and by any 7 | * means. 8 | * 9 | * In jurisdictions that recognize copyright laws, the author or authors 10 | * of this software dedicate any and all copyright interest in the 11 | * software to the public domain. We make this dedication for the benefit 12 | * of the public at large and to the detriment of our heirs and 13 | * successors. We intend this dedication to be an overt act of 14 | * relinquishment in perpetuity of all present and future rights to this 15 | * software under copyright law. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | * OTHER DEALINGS IN THE SOFTWARE. 24 | * 25 | * For more information, please refer to 26 | */ 27 | 28 | #include 29 | #include 30 | 31 | #include "semver.h" 32 | 33 | #define STRNSIZE(s) (s), sizeof(s)-1 34 | 35 | int main(void) { 36 | semver_t v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10; 37 | semvers_t semvers = {0}; 38 | 39 | semver_tryn(&v0, STRNSIZE("2.0.0")); 40 | semver_tryn(&v1, STRNSIZE("2.0.1")); 41 | semver_tryn(&v2, STRNSIZE("2.0.2")); 42 | semver_tryn(&v3, STRNSIZE("v2.0.0")); 43 | semver_tryn(&v4, STRNSIZE("v2.0.1")); 44 | semver_tryn(&v5, STRNSIZE("v2.0.2")); 45 | semver_tryn(&v6, STRNSIZE("v2.0.3")); 46 | semver_tryn(&v7, STRNSIZE("v2.1.0-beta1")); 47 | semver_tryn(&v8, STRNSIZE("v2.1.0-beta2")); 48 | semver_tryn(&v9, STRNSIZE("v2.0")); 49 | semver_tryn(&v10, STRNSIZE("v2.1")); 50 | 51 | if (semver_rmatch(v0, ">2.0.1")) semvers_push(semvers, v0); 52 | if (semver_rmatch(v1, ">2.0.1")) semvers_unshift(semvers, v1); 53 | if (semver_rmatch(v2, ">2.0.1")) semvers_push(semvers, v2); 54 | if (semver_rmatch(v3, ">2.0.1")) semvers_unshift(semvers, v3); 55 | if (semver_rmatch(v4, ">2.0.1")) semvers_push(semvers, v4); 56 | if (semver_rmatch(v5, ">2.0.1")) semvers_unshift(semvers, v5); 57 | if (semver_rmatch(v6, ">2.0.1")) semvers_push(semvers, v6); 58 | if (semver_rmatch(v7, ">2.0.1")) semvers_unshift(semvers, v7); 59 | if (semver_rmatch(v8, ">2.0.1")) semvers_push(semvers, v8); 60 | if (semver_rmatch(v9, ">2.0.1")) semvers_unshift(semvers, v9); 61 | if (semver_rmatch(v10, ">2.0.1")) semvers_push(semvers, v10); 62 | if (semver_rmatch(v0, ">2.0.1")) semvers_push(semvers, v0); 63 | if (semver_rmatch(v1, ">2.0.1")) semvers_unshift(semvers, v1); 64 | if (semver_rmatch(v2, ">2.0.1")) semvers_push(semvers, v2); 65 | if (semver_rmatch(v3, ">2.0.1")) semvers_unshift(semvers, v3); 66 | if (semver_rmatch(v4, ">2.0.1")) semvers_push(semvers, v4); 67 | if (semver_rmatch(v5, ">2.0.1")) semvers_unshift(semvers, v5); 68 | if (semver_rmatch(v6, ">2.0.1")) semvers_push(semvers, v6); 69 | if (semver_rmatch(v7, ">2.0.1")) semvers_unshift(semvers, v7); 70 | if (semver_rmatch(v8, ">2.0.1")) semvers_push(semvers, v8); 71 | if (semver_rmatch(v9, ">2.0.1")) semvers_unshift(semvers, v9); 72 | if (semver_rmatch(v10, ">2.0.1")) semvers_push(semvers, v10); 73 | if (semver_rmatch(v0, ">2.0.1")) semvers_push(semvers, v0); 74 | if (semver_rmatch(v1, ">2.0.1")) semvers_unshift(semvers, v1); 75 | if (semver_rmatch(v2, ">2.0.1")) semvers_push(semvers, v2); 76 | if (semver_rmatch(v3, ">2.0.1")) semvers_unshift(semvers, v3); 77 | if (semver_rmatch(v4, ">2.0.1")) semvers_push(semvers, v4); 78 | if (semver_rmatch(v5, ">2.0.1")) semvers_unshift(semvers, v5); 79 | if (semver_rmatch(v6, ">2.0.1")) semvers_push(semvers, v6); 80 | if (semver_rmatch(v7, ">2.0.1")) semvers_unshift(semvers, v7); 81 | if (semver_rmatch(v8, ">2.0.1")) semvers_push(semvers, v8); 82 | if (semver_rmatch(v9, ">2.0.1")) semvers_unshift(semvers, v9); 83 | if (semver_rmatch(v10, ">2.0.1")) semvers_push(semvers, v10); 84 | 85 | if (semvers.length != 18) { 86 | return EXIT_FAILURE; 87 | } 88 | if (semvers.capacity != 32) { 89 | return EXIT_FAILURE; 90 | } 91 | 92 | semvers_sort(semvers); 93 | 94 | for (unsigned i = 0; i < semvers.length; ++i) { 95 | semver_fwrite(semvers.data + i, stdout); 96 | putc('\n', stdout); 97 | } 98 | 99 | v0 = semvers_pop(semvers); 100 | v1 = semvers_shift(semvers); 101 | 102 | assert(memcmp("v2.1", v0.raw, v0.len) == 0); 103 | assert(memcmp("v2.0.2", v1.raw, v1.len) == 0 || memcmp("2.0.2", v1.raw, v1.len) == 0); 104 | 105 | semvers_rsort(semvers); 106 | putc('\n', stdout); 107 | for (unsigned i = 0; i < semvers.length; ++i) { 108 | semver_fwrite(semvers.data + i, stdout); 109 | putc('\n', stdout); 110 | } 111 | 112 | semvers_dtor(semvers); 113 | 114 | return EXIT_SUCCESS; 115 | } 116 | -------------------------------------------------------------------------------- /src/id.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This is free and unencumbered software released into the public domain. 3 | * 4 | * Anyone is free to copy, modify, publish, use, compile, sell, or 5 | * distribute this software, either in source code form or as a compiled 6 | * binary, for any purpose, commercial or non-commercial, and by any 7 | * means. 8 | * 9 | * In jurisdictions that recognize copyright laws, the author or authors 10 | * of this software dedicate any and all copyright interest in the 11 | * software to the public domain. We make this dedication for the benefit 12 | * of the public at large and to the detriment of our heirs and 13 | * successors. We intend this dedication to be an overt act of 14 | * relinquishment in perpetuity of all present and future rights to this 15 | * software under copyright law. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | * OTHER DEALINGS IN THE SOFTWARE. 24 | * 25 | * For more information, please refer to 26 | */ 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #include "id.h" 34 | 35 | void semver_id_ctor(semver_id_t *self) { 36 | #ifndef _MSC_VER 37 | *self = (semver_id_t) {true, 0, 0, NULL, NULL}; 38 | #else 39 | self->next = NULL; 40 | self->len = 0; 41 | self->raw = NULL; 42 | self->num = 0; 43 | self->numeric = true; 44 | #endif 45 | } 46 | 47 | void semver_id_dtor(semver_id_t *self) { 48 | if (self && self->next) { 49 | semver_id_dtor(self->next); 50 | sv_free(self->next); 51 | self->next = NULL; 52 | } 53 | } 54 | 55 | char semver_id_read_prerelease(semver_id_t *self, const char *str, size_t len, size_t *offset) { 56 | size_t i = 0; 57 | char is_zero = 0; 58 | 59 | semver_id_ctor(self); 60 | while (*offset < len) { 61 | if (isalnum(str[*offset]) || str[*offset] == '-') { 62 | if (!isdigit(str[*offset])) { 63 | is_zero = 0; 64 | self->numeric = false; 65 | } else { 66 | if (i == 0) { 67 | is_zero = str[*offset] == '0'; 68 | } else if (is_zero) { 69 | return 1; 70 | } 71 | } 72 | ++i, ++*offset; 73 | continue; 74 | } 75 | break; 76 | } 77 | if (!i) { 78 | return 1; 79 | } 80 | self->raw = str + *offset - i; 81 | self->len = i; 82 | if (!is_zero && self->numeric) { 83 | self->num = (int) strtol(self->raw, NULL, 0); 84 | } 85 | if (str[*offset] == '.') { 86 | self->next = (semver_id_t *) sv_malloc(sizeof(semver_id_t)); 87 | if (self->next == NULL) { 88 | return 1; 89 | } 90 | ++*offset; 91 | return semver_id_read_prerelease(self->next, str, len, offset); 92 | } 93 | return 0; 94 | } 95 | 96 | char semver_id_read_build(semver_id_t *self, const char *str, size_t len, size_t *offset) { 97 | size_t i = 0; 98 | char is_zero = 0; 99 | 100 | semver_id_ctor(self); 101 | while (*offset < len) { 102 | if (isalnum(str[*offset]) || str[*offset] == '-') { 103 | if (!isdigit(str[*offset])) { 104 | is_zero = 0; 105 | self->numeric = false; 106 | } else { 107 | if (i == 0) { 108 | is_zero = str[*offset] == '0'; 109 | } else if (is_zero) { 110 | self->numeric = false; 111 | } 112 | } 113 | ++i, ++*offset; 114 | continue; 115 | } 116 | break; 117 | } 118 | if (!i) { 119 | return 1; 120 | } 121 | self->raw = str + *offset - i; 122 | self->len = i; 123 | if (self->numeric) { 124 | self->num = (int) strtol(self->raw, NULL, 0); 125 | } 126 | if (str[*offset] == '.') { 127 | self->next = (semver_id_t *) sv_malloc(sizeof(semver_id_t)); 128 | if (self->next == NULL) { 129 | return 1; 130 | } 131 | ++*offset; 132 | return semver_id_read_build(self->next, str, len, offset); 133 | } 134 | return 0; 135 | } 136 | 137 | int semver_id_pcmp(const semver_id_t *self, const semver_id_t *other) { 138 | int s; 139 | 140 | if (self->len && !other->len) { 141 | return -1; 142 | } 143 | if (!self->len && other->len) { 144 | return 1; 145 | } 146 | if (!self->len) { 147 | return 0; 148 | } 149 | 150 | if (self->numeric && other->numeric) { 151 | if (self->num > other->num) { 152 | return 1; 153 | } 154 | if (self->num < other->num) { 155 | return -1; 156 | } 157 | } else if ((s = (int) memcmp(self->raw, other->raw, self->len > other->len ? self->len : other->len)) != 0) { 158 | return s; 159 | } 160 | 161 | if (!self->next && other->next) { 162 | return -1; 163 | } 164 | if (self->next && !other->next) { 165 | return 1; 166 | } 167 | if (!self->next) { 168 | return 0; 169 | } 170 | 171 | return semver_id_pcmp(self->next, other->next); 172 | } 173 | 174 | int semver_id_pwrite(const semver_id_t *self, char *buffer, size_t len) { 175 | if (self->next) { 176 | char next[SV_MAX_LEN]; 177 | return snprintf(buffer, len, "%.*s.%.*s", 178 | (int) self->len, self->raw, semver_id_pwrite(self->next, next, SV_MAX_LEN), next 179 | ); 180 | } 181 | return snprintf(buffer, len, "%.*s", (int) self->len, self->raw); 182 | } 183 | -------------------------------------------------------------------------------- /src/version.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This is free and unencumbered software released into the public domain. 3 | * 4 | * Anyone is free to copy, modify, publish, use, compile, sell, or 5 | * distribute this software, either in source code form or as a compiled 6 | * binary, for any purpose, commercial or non-commercial, and by any 7 | * means. 8 | * 9 | * In jurisdictions that recognize copyright laws, the author or authors 10 | * of this software dedicate any and all copyright interest in the 11 | * software to the public domain. We make this dedication for the benefit 12 | * of the public at large and to the detriment of our heirs and 13 | * successors. We intend this dedication to be an overt act of 14 | * relinquishment in perpetuity of all present and future rights to this 15 | * software under copyright law. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | * OTHER DEALINGS IN THE SOFTWARE. 24 | * 25 | * For more information, please refer to 26 | */ 27 | 28 | #include 29 | #include 30 | 31 | #include "version.h" 32 | #include "num.h" 33 | #include "id.h" 34 | 35 | void semver_ctor(semver_t *self) { 36 | #ifndef _MSC_VER 37 | *self = (semver_t) {0}; 38 | #else 39 | self->len = 0; 40 | self->raw = NULL; 41 | self->major = 0; 42 | self->minor = 0; 43 | self->patch = 0; 44 | semver_id_ctor(&self->prerelease); 45 | semver_id_ctor(&self->build); 46 | #endif 47 | } 48 | 49 | void semver_dtor(semver_t *self) { 50 | semver_id_dtor(&self->prerelease); 51 | semver_id_dtor(&self->build); 52 | } 53 | 54 | char semvern(semver_t *self, const char *str, size_t len) { 55 | size_t offset = 0; 56 | 57 | if (len > SV_MAX_LEN) { 58 | return 1; 59 | } 60 | if (semver_read(self, str, len, &offset) || offset < len) { 61 | semver_dtor(self); 62 | return 1; 63 | } 64 | return 0; 65 | } 66 | 67 | char semver_tryn(semver_t *self, const char *str, size_t len) { 68 | size_t offset = 0; 69 | 70 | if (len > SV_MAX_LEN) { 71 | return 1; 72 | } 73 | if (semver_try_read(self, str, len, &offset) || offset < len) { 74 | semver_dtor(self); 75 | return 1; 76 | } 77 | return 0; 78 | } 79 | 80 | char semver_read(semver_t *self, const char *str, size_t len, size_t *offset) { 81 | if (*offset < len) { 82 | semver_ctor(self); 83 | self->raw = str + *offset; 84 | if (str[*offset] == 'v') { 85 | ++*offset; 86 | } 87 | if (semver_num_read(&self->major, str, len, offset) || self->major == SEMVER_NUM_X 88 | || *offset >= len || str[*offset] != '.' 89 | || semver_num_read(&self->minor, str, len, (++*offset, offset)) || self->minor == SEMVER_NUM_X 90 | || *offset >= len || str[*offset] != '.' 91 | || semver_num_read(&self->patch, str, len, (++*offset, offset)) || self->patch == SEMVER_NUM_X 92 | || (str[*offset] == '-' && semver_id_read_prerelease(&self->prerelease, str, len, (++*offset, offset))) 93 | || (str[*offset] == '+' && semver_id_read_build(&self->build, str, len, (++*offset, offset)))) { 94 | self->len = str + *offset - self->raw; 95 | return 1; 96 | } 97 | self->len = str + *offset - self->raw; 98 | return 0; 99 | } 100 | return 1; 101 | } 102 | 103 | char semver_try_read(semver_t *self, const char *str, size_t len, size_t *offset) { 104 | if (*offset < len) { 105 | semver_ctor(self); 106 | self->raw = str + *offset; 107 | if (str[*offset] == 'v') { 108 | ++*offset; 109 | } 110 | if (semver_num_read(&self->major, str, len, offset) || self->major == SEMVER_NUM_X) { 111 | fail: 112 | self->len = str + *offset - self->raw; 113 | return 1; 114 | } 115 | if (*offset < len && str[*offset] == '.' 116 | && (semver_num_read(&self->minor, str, len, (++*offset, offset)) || self->minor == SEMVER_NUM_X)) { 117 | goto fail; 118 | } 119 | if (*offset < len && str[*offset] == '.' 120 | && (semver_num_read(&self->patch, str, len, (++*offset, offset)) || self->patch == SEMVER_NUM_X)) { 121 | goto fail; 122 | } 123 | if (*offset < len && str[*offset] == '-') { 124 | ++*offset; 125 | } 126 | semver_id_read_prerelease(&self->prerelease, str, len, offset); 127 | if (*offset < len && str[*offset] == '+') { 128 | ++*offset; 129 | } 130 | semver_id_read_build(&self->build, str, len, offset); 131 | self->len = str + *offset - self->raw; 132 | return 0; 133 | } 134 | return 1; 135 | } 136 | 137 | int semver_pcmp(const semver_t *self, const semver_t *other) { 138 | int result; 139 | 140 | if ((result = semver_num_cmp(self->major, other->major)) != 0) { 141 | return result; 142 | } 143 | if ((result = semver_num_cmp(self->minor, other->minor)) != 0) { 144 | return result; 145 | } 146 | if ((result = semver_num_cmp(self->patch, other->patch)) != 0) { 147 | return result; 148 | } 149 | return semver_id_comp(self->prerelease, other->prerelease); 150 | } 151 | 152 | int semver_pwrite(const semver_t *self, char *buffer, size_t len) { 153 | char prerelease[SV_MAX_LEN], build[SV_MAX_LEN]; 154 | 155 | if (self->prerelease.len && self->build.len) { 156 | return snprintf(buffer, len, "%d.%d.%d-%.*s+%.*s", 157 | self->major, self->minor, self->patch, 158 | semver_id_write(self->prerelease, prerelease, SV_MAX_LEN), prerelease, 159 | semver_id_write(self->build, build, SV_MAX_LEN), build 160 | ); 161 | } 162 | if (self->prerelease.len) { 163 | return snprintf(buffer, len, "%d.%d.%d-%.*s", 164 | self->major, self->minor, self->patch, 165 | semver_id_write(self->prerelease, prerelease, SV_MAX_LEN), prerelease 166 | ); 167 | } 168 | if (self->build.len) { 169 | return snprintf(buffer, len, "%d.%d.%d+%.*s", 170 | self->major, self->minor, self->patch, 171 | semver_id_write(self->build, build, SV_MAX_LEN), build 172 | ); 173 | } 174 | return snprintf(buffer, len, "%d.%d.%d", self->major, self->minor, self->patch); 175 | } 176 | -------------------------------------------------------------------------------- /test/range.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This is free and unencumbered software released into the public domain. 3 | * 4 | * Anyone is free to copy, modify, publish, use, compile, sell, or 5 | * distribute this software, either in source code form or as a compiled 6 | * binary, for any purpose, commercial or non-commercial, and by any 7 | * means. 8 | * 9 | * In jurisdictions that recognize copyright laws, the author or authors 10 | * of this software dedicate any and all copyright interest in the 11 | * software to the public domain. We make this dedication for the benefit 12 | * of the public at large and to the detriment of our heirs and 13 | * successors. We intend this dedication to be an overt act of 14 | * relinquishment in perpetuity of all present and future rights to this 15 | * software under copyright law. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | * OTHER DEALINGS IN THE SOFTWARE. 24 | * 25 | * For more information, please refer to 26 | */ 27 | 28 | #include 29 | #include 30 | #include 31 | 32 | #include "semver.h" 33 | 34 | #define STRNSIZE(s) (s), sizeof(s)-1 35 | 36 | int test_read(const char *expected, const char *str, size_t len) { 37 | unsigned slen; 38 | char buffer[1024]; 39 | semver_range_t range = {0}; 40 | 41 | printf("test: `%.*s`", (int) len, str); 42 | if (semver_rangen(&range, str, len)) { 43 | puts(" \tcouldn't parse"); 44 | return 1; 45 | } 46 | slen = (unsigned) semver_range_write(range, buffer, 1024); 47 | printf(" \t=> \t`%.*s`", slen, buffer); 48 | if (memcmp(expected, buffer, (size_t) slen > len ? slen : len) != 0) { 49 | printf(" != `%s`\n", expected); 50 | semver_range_dtor(&range); 51 | return 1; 52 | } 53 | printf(" == `%s`\n", expected); 54 | semver_range_dtor(&range); 55 | return 0; 56 | } 57 | 58 | int test_or(const char *expected, const char *base_str, size_t base_len, const char *str, size_t len) { 59 | unsigned slen; 60 | char buffer[1024]; 61 | semver_range_t range = {0}; 62 | 63 | printf("test and: `%.*s`", (int) base_len, base_str); 64 | if (semver_rangen(&range, base_str, base_len)) { 65 | puts(" \tcouldn't parse base"); 66 | return 1; 67 | } 68 | if (semver_or(&range, str, len)) { 69 | puts(" \tand failed"); 70 | return 1; 71 | } 72 | slen = (unsigned) semver_range_write(range, buffer, 1024); 73 | printf(" \t=> \t`%.*s`", slen, buffer); 74 | if (memcmp(expected, buffer, (size_t) slen > base_len + len + 1 ? slen : base_len + len + 1) != 0) { 75 | printf(" != `%s`\n", expected); 76 | semver_range_dtor(&range); 77 | return 1; 78 | } 79 | printf(" == `%s`\n", expected); 80 | semver_range_dtor(&range); 81 | return 0; 82 | } 83 | 84 | int main(void) { 85 | puts("failure:"); 86 | if (test_read("", STRNSIZE("* |")) == 0) { 87 | return EXIT_FAILURE; 88 | } 89 | if (test_read("", STRNSIZE("* ||a")) == 0) { 90 | return EXIT_FAILURE; 91 | } 92 | if (test_read("", STRNSIZE("* || a")) == 0) { 93 | return EXIT_FAILURE; 94 | } 95 | if (test_read("", STRNSIZE("* || 1.a")) == 0) { 96 | return EXIT_FAILURE; 97 | } 98 | if (test_read("", STRNSIZE("Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget " 99 | "dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascet" 100 | "ur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, s")) 101 | == 0) { 102 | return EXIT_FAILURE; 103 | } 104 | 105 | puts("\nx-range:"); 106 | if (test_read(">=0.0.0 || 1.2.3", STRNSIZE("* || 1.2.3"))) { 107 | return EXIT_FAILURE; 108 | } 109 | if (test_read(">=1.0.0 <2.0.0 || >=2.0.0 <3.0.0", STRNSIZE("1.x || 2.x"))) { 110 | return EXIT_FAILURE; 111 | } 112 | if (test_read(">=1.2.0 <1.3.0 || 3.0.0", STRNSIZE("1.2.x || 3.0.0"))) { 113 | return EXIT_FAILURE; 114 | } 115 | if (test_read(">=0.0.0", STRNSIZE(""))) { 116 | return EXIT_FAILURE; 117 | } 118 | 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"))) { 119 | return EXIT_FAILURE; 120 | } 121 | if (test_read(">=1.2.0 <1.3.0 || >=5.0.0", STRNSIZE("1.2 || >=5"))) { 122 | return EXIT_FAILURE; 123 | } 124 | 125 | puts("\nhyphen:"); 126 | if (test_read(">=1.2.3 <=2.3.4 || >=5.0.0", STRNSIZE("1.2.3 - 2.3.4 || >=5"))) { 127 | return EXIT_FAILURE; 128 | } 129 | if (test_read(">=1.2.0 <=2.3.4 || >=5.0.0", STRNSIZE("1.2 - 2.3.4 || >=5"))) { 130 | return EXIT_FAILURE; 131 | } 132 | if (test_read(">=1.2.3 <2.4.0 || >=5.0.0", STRNSIZE("1.2.3 - 2.3 || >=5"))) { 133 | return EXIT_FAILURE; 134 | } 135 | if (test_read(">=1.2.3 <3.0.0 || >=5.0.0", STRNSIZE("1.2.3 - 2 || >=5"))) { 136 | return EXIT_FAILURE; 137 | } 138 | 139 | puts("\ntilde:"); 140 | if (test_read(">=1.2.3 <1.3.0 || >=5.0.0", STRNSIZE("~1.2.3 || >=5"))) { 141 | return EXIT_FAILURE; 142 | } 143 | if (test_read(">=1.2.0 <1.3.0 || >=5.0.0", STRNSIZE("~1.2 || >=5"))) { 144 | return EXIT_FAILURE; 145 | } 146 | if (test_read(">=1.0.0 <2.0.0 || >=5.0.0", STRNSIZE("~1 || >=5"))) { 147 | return EXIT_FAILURE; 148 | } 149 | if (test_read(">=0.2.3 <0.3.0 || >=5.0.0", STRNSIZE("~0.2.3 || >=5"))) { 150 | return EXIT_FAILURE; 151 | } 152 | if (test_read(">=0.2.0 <0.3.0 || >=5.0.0", STRNSIZE("~0.2 || >=5"))) { 153 | return EXIT_FAILURE; 154 | } 155 | if (test_read(">=0.0.0 <1.0.0 || >=5.0.0", STRNSIZE("~0 || >=5"))) { 156 | return EXIT_FAILURE; 157 | } 158 | 159 | puts("\ncaret:"); 160 | if (test_read(">=1.2.3 <2.0.0 || >=5.0.0", STRNSIZE("^1.2.3 || >=5"))) { 161 | return EXIT_FAILURE; 162 | } 163 | if (test_read(">=0.2.3 <0.3.0 || >=5.0.0", STRNSIZE("^0.2.3 || >=5"))) { 164 | return EXIT_FAILURE; 165 | } 166 | if (test_read(">=0.0.3 <0.0.4 || >=5.0.0", STRNSIZE("^0.0.3 || >=5"))) { 167 | return EXIT_FAILURE; 168 | } 169 | 170 | puts("\nand:"); 171 | if (test_or(">=0.0.0 || >=0.0.3 <0.0.4", STRNSIZE("*"), STRNSIZE("^0.0.3"))) { 172 | return EXIT_FAILURE; 173 | } 174 | if (test_or(">=1.0.0 <2.0.0 || >=0.0.3 <0.0.4", STRNSIZE("1.x"), STRNSIZE("^0.0.3"))) { 175 | return EXIT_FAILURE; 176 | } 177 | if (test_or(">=1.2.0 <1.3.0 || >=0.0.3 <0.0.4", STRNSIZE("1.2.x"), STRNSIZE("^0.0.3"))) { 178 | return EXIT_FAILURE; 179 | } 180 | 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"))) { 181 | return EXIT_FAILURE; 182 | } 183 | if (test_or(">=1.0.0 <2.0.0 || >=0.0.3 <0.0.4", STRNSIZE("1"), STRNSIZE("^0.0.3"))) { 184 | return EXIT_FAILURE; 185 | } 186 | if (test_or(">=1.2.0 <1.3.0 || >=0.0.3 <0.0.4", STRNSIZE("1.2"), STRNSIZE("^0.0.3"))) { 187 | return EXIT_FAILURE; 188 | } 189 | if (test_or("", STRNSIZE("1.2"), STRNSIZE("")) == 0) { 190 | return EXIT_FAILURE; 191 | } 192 | if (test_or("", STRNSIZE("1.2"), STRNSIZE("a")) == 0) { 193 | return EXIT_FAILURE; 194 | } 195 | if (test_or("", STRNSIZE("1.2"), STRNSIZE("1.2.x || abc")) == 0) { 196 | return EXIT_FAILURE; 197 | } 198 | 199 | return EXIT_SUCCESS; 200 | } 201 | -------------------------------------------------------------------------------- /include/semver.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This is free and unencumbered software released into the public domain. 3 | * 4 | * Anyone is free to copy, modify, publish, use, compile, sell, or 5 | * distribute this software, either in source code form or as a compiled 6 | * binary, for any purpose, commercial or non-commercial, and by any 7 | * means. 8 | * 9 | * In jurisdictions that recognize copyright laws, the author or authors 10 | * of this software dedicate any and all copyright interest in the 11 | * software to the public domain. We make this dedication for the benefit 12 | * of the public at large and to the detriment of our heirs and 13 | * successors. We intend this dedication to be an overt act of 14 | * relinquishment in perpetuity of all present and future rights to this 15 | * software under copyright law. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | * OTHER DEALINGS IN THE SOFTWARE. 24 | * 25 | * For more information, please refer to 26 | */ 27 | 28 | #ifndef SV_H__ 29 | # define SV_H__ 30 | 31 | #include 32 | #include 33 | #include 34 | 35 | #ifndef SV_COMPILE 36 | # define SV_COMPILE (0) 37 | #endif 38 | 39 | #ifndef SV_BUILD_DYNAMIC_LINK 40 | # define SV_BUILD_DYNAMIC_LINK (0) 41 | #endif 42 | 43 | #if SV_BUILD_DYNAMIC_LINK && defined(_MSC_VER) 44 | # define SV_EXPORT_LINK __declspec(dllexport) 45 | # define SV_IMPORT_LINK __declspec(dllimport) 46 | #else 47 | # define SV_EXPORT_LINK 48 | # define SV_IMPORT_LINK 49 | #endif 50 | #if SV_COMPILE 51 | # ifdef __cplusplus 52 | # define SV_API extern "C" SV_EXPORT_LINK 53 | # else 54 | # define SV_API extern SV_EXPORT_LINK 55 | # endif 56 | #else 57 | # ifdef __cplusplus 58 | # define SV_API extern "C" SV_IMPORT_LINK 59 | # else 60 | # define SV_API extern SV_IMPORT_LINK 61 | # endif 62 | #endif 63 | 64 | #ifndef __cplusplus 65 | # if defined(_MSC_VER) && _MSC_VER < 1900 66 | # define bool unsigned char 67 | # define true 1 68 | # define false 0 69 | # define __bool_true_false_are_defined 1 70 | # else 71 | # include 72 | # endif 73 | #endif 74 | 75 | #if defined(_MSC_VER) && (_MSC_VER < 1600) 76 | typedef __int8 int8_t; 77 | typedef __int16 int16_t; 78 | typedef __int32 int32_t; 79 | typedef __int64 int64_t; 80 | typedef unsigned __int8 uint8_t; 81 | typedef unsigned __int16 uint16_t; 82 | typedef unsigned __int32 uint32_t; 83 | typedef unsigned __int64 uint64_t; 84 | #ifdef _WIN64 85 | typedef __int64 intptr_t; 86 | typedef unsigned __int64 uintptr_t; 87 | #else 88 | typedef __int32 intptr_t; 89 | typedef unsigned __int32 uintptr_t; 90 | #endif 91 | #else 92 | # include 93 | #endif 94 | 95 | #ifndef sv_malloc 96 | # define sv_malloc malloc 97 | #endif 98 | 99 | #ifndef sv_free 100 | # define sv_free free 101 | #endif 102 | 103 | #define SEMVER_NUM_X (-1) 104 | 105 | #define semver(self, str) semvern(self, str, strlen(str)) 106 | #define semver_write(self, buffer, len) semver_pwrite(&(self), buffer, len) 107 | #define semver_cmp(self, other) semver_pcmp(&(self), &(other)) 108 | #define semver_comp(self, str) semver_compn(self, str, strlen(str)) 109 | #define semver_comp_write(self, buffer, len) semver_comp_pwrite(&(self), buffer, len) 110 | #define semver_comp_match(self, comp) semver_comp_pmatch(&(self), &(comp)) 111 | #define semver_match(self, comp_str) semver_comp_matchn(&(self), comp_str, strlen(comp_str)) 112 | #define semver_range(self, str) semver_rangen(self, str, strlen(str)) 113 | #define semver_range_write(self, buffer, len) semver_range_pwrite(&(self), buffer, len) 114 | #define semver_range_match(self, range) semver_range_pmatch(&(self), &(range)) 115 | #define semver_rmatch(self, range_str) semver_range_matchn(&(self), range_str, strlen(range_str)) 116 | 117 | typedef struct semver semver_t; 118 | typedef struct semver_id semver_id_t; 119 | typedef struct semver_comp semver_comp_t; 120 | typedef struct semver_range semver_range_t; 121 | typedef struct semvers semvers_t; 122 | 123 | enum semver_op { 124 | SEMVER_OP_EQ = 0, 125 | SEMVER_OP_LT, 126 | SEMVER_OP_LE, 127 | SEMVER_OP_GT, 128 | SEMVER_OP_GE, 129 | }; 130 | 131 | struct semver_id { 132 | bool numeric; 133 | int num; 134 | size_t len; 135 | const char *raw; 136 | struct semver_id *next; 137 | }; 138 | 139 | struct semver { 140 | int major, minor, patch; 141 | semver_id_t prerelease, build; 142 | size_t len; 143 | const char *raw; 144 | }; 145 | 146 | SV_API char semvern(semver_t *self, const char *str, size_t len); 147 | SV_API char semver_tryn(semver_t *self, const char *str, size_t len); 148 | SV_API void semver_dtor(semver_t *self); 149 | SV_API int semver_pwrite(const semver_t *self, char *buffer, size_t len); 150 | SV_API size_t semver_fwrite (const semver_t *self, FILE * stream); 151 | SV_API int semver_pcmp(const semver_t *self, const semver_t *other); 152 | SV_API bool semver_comp_pmatch(const semver_t *self, const semver_comp_t *comp); 153 | SV_API bool semver_comp_matchn(const semver_t *self, const char *comp_str, size_t comp_len); 154 | SV_API bool semver_range_pmatch(const semver_t *self, const semver_range_t *range); 155 | SV_API bool semver_range_matchn(const semver_t *self, const char *range_str, size_t range_len); 156 | 157 | struct semver_comp { 158 | struct semver_comp *next; 159 | enum semver_op op; 160 | semver_t version; 161 | }; 162 | 163 | SV_API char semver_compn(semver_comp_t *self, const char *str, size_t len); 164 | SV_API void semver_comp_dtor(semver_comp_t *self); 165 | SV_API int semver_comp_pwrite(const semver_comp_t *self, char *buffer, size_t len); 166 | SV_API size_t semver_comp_fwrite (const semver_comp_t *self, FILE *stream); 167 | SV_API char semver_and(semver_comp_t *left, const char *str, size_t len); 168 | 169 | struct semver_range { 170 | struct semver_range *next; 171 | semver_comp_t comp; 172 | }; 173 | 174 | SV_API char semver_rangen(semver_range_t *self, const char *str, size_t len); 175 | SV_API void semver_range_dtor(semver_range_t *self); 176 | SV_API int semver_range_pwrite(const semver_range_t *self, char *buffer, size_t len); 177 | SV_API size_t semver_range_fwrite (const semver_range_t *rangep, FILE *stream); 178 | SV_API char semver_or(semver_range_t *left, const char *str, size_t len); 179 | 180 | struct semvers { 181 | uint32_t length, capacity; 182 | semver_t *data; 183 | }; 184 | 185 | SV_API uint32_t semvers_pgrowth(semvers_t *self, int32_t nmin); 186 | SV_API semver_t semvers_perase(semvers_t *self, uint32_t i); 187 | SV_API void semvers_psort(semvers_t *self); 188 | SV_API void semvers_prsort(semvers_t *self); 189 | SV_API void semvers_pdtor(semvers_t *self); 190 | SV_API void semvers_pclear(semvers_t *self); 191 | 192 | #define semvers_dtor(s) \ 193 | semvers_pdtor(&(s)) 194 | 195 | #define semvers_clear(s) \ 196 | semvers_pclear(&(s)) 197 | 198 | #define semvers_growth(s, n) \ 199 | semvers_pgrowth(&(s),n) 200 | 201 | #define semvers_pgrow(s, n) \ 202 | semvers_pgrowth((s),(s)->length+(n)) 203 | 204 | #define semvers_grow(s, n) \ 205 | semvers_pgrow(&(s), n) 206 | 207 | #define semvers_resize(s, n) \ 208 | ((s).length=semvers_growth(s, n)) 209 | 210 | #define semvers_erase(s, i) \ 211 | semvers_perase(&(s), i) 212 | 213 | #define semvers_ppush(s, x) \ 214 | (semvers_pgrow(s,1),(s)->data[(s)->length++]=(x)) 215 | 216 | #define semvers_push(s, x) \ 217 | semvers_ppush(&(s), x) 218 | 219 | #define semvers_ppop(s) \ 220 | (s)->data[--(s)->length] 221 | 222 | #define semvers_pop(s) \ 223 | semvers_ppop(&(s)) 224 | 225 | #define semvers_unshift(s, x) \ 226 | (semvers_grow(s,1),memmove((s).data+1,(s).data,(s).length++*sizeof(semver_t)),(s).data[0]=(x)) 227 | 228 | #define semvers_shift(s) \ 229 | semvers_erase(s, 0) 230 | 231 | #define semvers_sort(s) \ 232 | semvers_psort(&(s)) 233 | 234 | #define semvers_rsort(s) \ 235 | semvers_prsort(&(s)) 236 | 237 | #endif /* SV_H__ */ 238 | -------------------------------------------------------------------------------- /test/version.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This is free and unencumbered software released into the public domain. 3 | * 4 | * Anyone is free to copy, modify, publish, use, compile, sell, or 5 | * distribute this software, either in source code form or as a compiled 6 | * binary, for any purpose, commercial or non-commercial, and by any 7 | * means. 8 | * 9 | * In jurisdictions that recognize copyright laws, the author or authors 10 | * of this software dedicate any and all copyright interest in the 11 | * software to the public domain. We make this dedication for the benefit 12 | * of the public at large and to the detriment of our heirs and 13 | * successors. We intend this dedication to be an overt act of 14 | * relinquishment in perpetuity of all present and future rights to this 15 | * software under copyright law. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | * OTHER DEALINGS IN THE SOFTWARE. 24 | * 25 | * For more information, please refer to 26 | */ 27 | 28 | #include 29 | #include 30 | #include 31 | 32 | #include "semver.h" 33 | 34 | #define STRNSIZE(s) (s), sizeof(s)-1 35 | 36 | int test_read(const char *expected, const char *str, size_t len) { 37 | unsigned slen; 38 | char buffer[1024]; 39 | semver_t semver = {0}; 40 | 41 | printf("test: `%.*s`", (int) len, str); 42 | if (semvern(&semver, str, len)) { 43 | puts(" \tcouldn't parse"); 44 | return 1; 45 | } 46 | slen = (unsigned) semver_write(semver, buffer, 1024); 47 | printf(" \t=> \t`%.*s`", slen, buffer); 48 | if (memcmp(expected, buffer, (size_t) slen > len ? slen : len) != 0) { 49 | printf(" != `%s`\n", expected); 50 | semver_dtor(&semver); 51 | return 1; 52 | } 53 | printf(" == `%s`\n", expected); 54 | semver_dtor(&semver); 55 | return 0; 56 | } 57 | 58 | int test_try_read(const char *expected, const char *str, size_t len) { 59 | unsigned slen; 60 | char buffer[1024]; 61 | semver_t semver = {0}; 62 | 63 | printf("test: `%.*s`", (int) len, str); 64 | if (semver_tryn(&semver, str, len)) { 65 | puts(" \tcouldn't parse"); 66 | return 1; 67 | } 68 | slen = (unsigned) semver_write(semver, buffer, 1024); 69 | printf(" \t=> \t`%.*s`", slen, buffer); 70 | if (memcmp(expected, buffer, (size_t) slen > len ? slen : len) != 0) { 71 | printf(" != `%s`\n", expected); 72 | semver_dtor(&semver); 73 | return 1; 74 | } 75 | printf(" == `%s`\n", expected); 76 | semver_dtor(&semver); 77 | return 0; 78 | } 79 | 80 | int main(void) { 81 | puts("normal:"); 82 | if (test_read("0.2.3", STRNSIZE("0.2.3"))) { 83 | return EXIT_FAILURE; 84 | } 85 | if (test_read("1.2.3", STRNSIZE("1.2.3"))) { 86 | return EXIT_FAILURE; 87 | } 88 | if (test_read("1.2.3-alpha", STRNSIZE("v1.2.3-alpha"))) { 89 | return EXIT_FAILURE; 90 | } 91 | if (test_read("1.2.3-alpha.2", STRNSIZE("1.2.3-alpha.2"))) { 92 | return EXIT_FAILURE; 93 | } 94 | if (test_read("1.2.3+77", STRNSIZE("v1.2.3+77"))) { 95 | return EXIT_FAILURE; 96 | } 97 | if (test_read("1.2.3+0", STRNSIZE("v1.2.3+0"))) { 98 | return EXIT_FAILURE; 99 | } 100 | if (test_read("1.2.3+77.2", STRNSIZE("1.2.3+77.2"))) { 101 | return EXIT_FAILURE; 102 | } 103 | if (test_read("1.2.3-alpha.2+77", STRNSIZE("v1.2.3-alpha.2+77"))) { 104 | return EXIT_FAILURE; 105 | } 106 | if (test_read("1.2.3-alpha.2+77.2", STRNSIZE("1.2.3-alpha.2+77.2"))) { 107 | return EXIT_FAILURE; 108 | } 109 | if (test_read("1.2.3-al-pha.2+77", STRNSIZE("v1.2.3-al-pha.2+77"))) { 110 | return EXIT_FAILURE; 111 | } 112 | if (test_read("1.2.3-al-pha.2+77.2", STRNSIZE("1.2.3-al-pha.2+77.2"))) { 113 | return EXIT_FAILURE; 114 | } 115 | if (test_read("", STRNSIZE("")) == 0) { 116 | return EXIT_FAILURE; 117 | } 118 | if (test_read("", STRNSIZE("vv1.2.3")) == 0) { 119 | return EXIT_FAILURE; 120 | } 121 | if (test_read("", STRNSIZE("v1.2")) == 0) { 122 | return EXIT_FAILURE; 123 | } 124 | if (test_read("", STRNSIZE("v1.2.x")) == 0) { 125 | return EXIT_FAILURE; 126 | } 127 | if (test_read("", STRNSIZE("v1.2.3-")) == 0) { 128 | return EXIT_FAILURE; 129 | } 130 | if (test_read("", STRNSIZE("v1.2.3+")) == 0) { 131 | return EXIT_FAILURE; 132 | } 133 | if (test_read("", STRNSIZE("v1.2.3+01")) == 0) { 134 | return EXIT_FAILURE; 135 | } 136 | if (test_read("", STRNSIZE("v0.01.3")) == 0) { 137 | return EXIT_FAILURE; 138 | } 139 | if (test_read("", STRNSIZE("Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget " 140 | "dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascet" 141 | "ur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, s")) 142 | == 0) { 143 | return EXIT_FAILURE; 144 | } 145 | 146 | puts("try:"); 147 | if (test_try_read("0.2.3", STRNSIZE("0.2.3"))) { 148 | return EXIT_FAILURE; 149 | } 150 | if (test_try_read("1.2.3", STRNSIZE("1.2.3"))) { 151 | return EXIT_FAILURE; 152 | } 153 | if (test_try_read("1.2.3-alpha", STRNSIZE("v1.2.3-alpha"))) { 154 | return EXIT_FAILURE; 155 | } 156 | if (test_try_read("1.2.3-alpha.2", STRNSIZE("1.2.3-alpha.2"))) { 157 | return EXIT_FAILURE; 158 | } 159 | if (test_try_read("1.2.3+77", STRNSIZE("v1.2.3+77"))) { 160 | return EXIT_FAILURE; 161 | } 162 | if (test_try_read("1.2.3+0", STRNSIZE("v1.2.3+0"))) { 163 | return EXIT_FAILURE; 164 | } 165 | if (test_try_read("1.2.3+77.2", STRNSIZE("1.2.3+77.2"))) { 166 | return EXIT_FAILURE; 167 | } 168 | if (test_try_read("1.2.3-alpha.2+77", STRNSIZE("v1.2.3-alpha.2+77"))) { 169 | return EXIT_FAILURE; 170 | } 171 | if (test_try_read("1.2.3-alpha.2+77.2", STRNSIZE("1.2.3-alpha.2+77.2"))) { 172 | return EXIT_FAILURE; 173 | } 174 | if (test_try_read("1.2.3-al-pha.2+77", STRNSIZE("v1.2.3-al-pha.2+77"))) { 175 | return EXIT_FAILURE; 176 | } 177 | if (test_try_read("1.2.3-al-pha.2+77.2", STRNSIZE("1.2.3-al-pha.2+77.2"))) { 178 | return EXIT_FAILURE; 179 | } 180 | if (test_try_read("", STRNSIZE("")) == 0) { 181 | return EXIT_FAILURE; 182 | } 183 | if (test_try_read("", STRNSIZE("vv1.2.3")) == 0) { 184 | return EXIT_FAILURE; 185 | } 186 | if (test_try_read("", STRNSIZE("v1.2")) == 0) { 187 | return EXIT_FAILURE; 188 | } 189 | if (test_try_read("", STRNSIZE("v1.2.x")) == 0) { 190 | return EXIT_FAILURE; 191 | } 192 | if (test_try_read("", STRNSIZE("v1.2.3-")) == 0) { 193 | return EXIT_FAILURE; 194 | } 195 | if (test_try_read("", STRNSIZE("v1.2.3+")) == 0) { 196 | return EXIT_FAILURE; 197 | } 198 | if (test_try_read("", STRNSIZE("v1.2.3+01")) == 0) { 199 | return EXIT_FAILURE; 200 | } 201 | if (test_try_read("", STRNSIZE("v0.01.3")) == 0) { 202 | return EXIT_FAILURE; 203 | } 204 | if (test_try_read("", STRNSIZE("Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget " 205 | "dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascet" 206 | "ur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, s")) 207 | == 0) { 208 | return EXIT_FAILURE; 209 | } 210 | if (test_try_read("0.2.0", STRNSIZE("0.2"))) { 211 | return EXIT_FAILURE; 212 | } 213 | if (test_try_read("1.0.0", STRNSIZE("v1"))) { 214 | return EXIT_FAILURE; 215 | } 216 | if (test_try_read("1.2.0-alpha", STRNSIZE("v1.2alpha"))) { 217 | return EXIT_FAILURE; 218 | } 219 | if (test_try_read("1.2.3-alpha.2", STRNSIZE("1.2.3alpha.2"))) { 220 | return EXIT_FAILURE; 221 | } 222 | if (test_try_read("1.0.0+77", STRNSIZE("v1+77"))) { 223 | return EXIT_FAILURE; 224 | } 225 | if (test_try_read("1.2.0+0", STRNSIZE("v1.2+0"))) { 226 | return EXIT_FAILURE; 227 | } 228 | if (test_try_read("1.0.0+77.2", STRNSIZE("v1+77.2"))) { 229 | return EXIT_FAILURE; 230 | } 231 | if (test_try_read("1.2.3-alpha.2+77", STRNSIZE("v1.2.3alpha.2+77"))) { 232 | return EXIT_FAILURE; 233 | } 234 | 235 | return EXIT_SUCCESS; 236 | } 237 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include(CMakeParseArguments) 2 | 3 | project(sv C) 4 | cmake_minimum_required(VERSION 3.5 FATAL_ERROR) 5 | 6 | if (NOT EXISTS ${CMAKE_CURRENT_LIST_DIR}/cmake/properties.cmake) 7 | message(FATAL_ERROR "cmake/properties.cmake file should exists.") 8 | endif () 9 | include(${CMAKE_CURRENT_LIST_DIR}/cmake/properties.cmake) 10 | 11 | include(GNUInstallDirs) # include this *AFTER* PROJECT(), otherwise paths are wrong. 12 | 13 | get_directory_property(${PROJECT_NAME}_PARENT PARENT_DIRECTORY) 14 | if (NOT ${PROJECT_NAME}_PARENT) 15 | set(${PROJECT_NAME}_DEVEL TRUE) 16 | endif () 17 | 18 | if (NOT COMMAND project_dependency) 19 | function(project_dependency DEP) 20 | cmake_parse_arguments(DL_ARGS "TEST;LINK" "" "" ${ARGN}) 21 | if (DL_ARGS_TEST) 22 | set(${PROJECT_NAME}_TEST_DEPS ${${PROJECT_NAME}_TEST_DEPS} ${DEP} PARENT_SCOPE) 23 | else () 24 | set(${PROJECT_NAME}_DEPS ${${PROJECT_NAME}_DEPS} ${DEP} PARENT_SCOPE) 25 | endif () 26 | set(${DEP}_LINK ${DL_ARGS_LINK} PARENT_SCOPE) 27 | if (NOT DL_ARGS_TEST OR ${PROJECT_NAME}_DEVEL) 28 | set(DL_ARGS_BUILD_DIR "${CMAKE_BINARY_DIR}/vendor/${DEP}") 29 | set(DL_ARGS_SOURCE_DIR "${CMAKE_SOURCE_DIR}/vendor/${DEP}") 30 | file(WRITE "${DL_ARGS_BUILD_DIR}/CMakeLists.txt" 31 | "cmake_minimum_required(VERSION 3.5 FATAL_ERROR)\n" 32 | "project(vendor-${DEP} NONE)\n" 33 | "include(ExternalProject)\n" 34 | "ExternalProject_Add(vendor-${DEP}\n" 35 | "${DL_ARGS_UNPARSED_ARGUMENTS}\nSOURCE_DIR \"${DL_ARGS_SOURCE_DIR}\"\n" 36 | "CONFIGURE_COMMAND \"\"\nBUILD_COMMAND \"\"\nINSTALL_COMMAND \"\"\nTEST_COMMAND \"\")") 37 | execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" 38 | -D "CMAKE_MAKE_PROGRAM:FILE=${CMAKE_MAKE_PROGRAM}" . 39 | RESULT_VARIABLE result OUTPUT_QUIET 40 | WORKING_DIRECTORY "${DL_ARGS_BUILD_DIR}") 41 | if (result) 42 | message(FATAL_ERROR "Config step for ${DEP} failed: ${result}") 43 | endif () 44 | execute_process(COMMAND ${CMAKE_COMMAND} --build . 45 | RESULT_VARIABLE result OUTPUT_QUIET 46 | WORKING_DIRECTORY "${DL_ARGS_BUILD_DIR}") 47 | if (result) 48 | message(FATAL_ERROR "Build step for ${DEP} failed: ${result}") 49 | endif () 50 | add_subdirectory(${DL_ARGS_SOURCE_DIR}) 51 | endif () 52 | endfunction() 53 | endif () 54 | 55 | if (EXISTS ${CMAKE_CURRENT_LIST_DIR}/cmake/dependencies.cmake) 56 | include(${CMAKE_CURRENT_LIST_DIR}/cmake/dependencies.cmake) 57 | endif () 58 | 59 | if ("${CMAKE_C_COMPILER_ID}" MATCHES "Clang") 60 | set(CLANG TRUE) 61 | elseif ("${CMAKE_C_COMPILER_ID}" MATCHES "GNU") 62 | set(GCC TRUE) 63 | elseif ("${CMAKE_C_COMPILER_ID}" MATCHES "Intel") 64 | set(ICC TRUE) 65 | elseif (NOT MSVC) 66 | message(FATAL_ERROR "Unknown compiler") 67 | endif () 68 | 69 | set(CMAKE_C_STANDARD 99) 70 | 71 | option(BUILD_SHARED_LIBS "Build using shared libraries" ON) 72 | option(COVERAGE "Turn on COVERAGE support" OFF) 73 | if (COVERAGE AND NOT MSVC) 74 | set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} --coverage") 75 | endif () 76 | 77 | set(${PROJECT_NAME}_HEADERS) 78 | set(${PROJECT_NAME}_SOURCES) 79 | set(${PROJECT_NAME}_INCLUDE_DIR ${CMAKE_CURRENT_LIST_DIR}/include) 80 | set(${PROJECT_NAME}_SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/src) 81 | set(${PROJECT_NAME}_TEST_DIR ${CMAKE_CURRENT_LIST_DIR}/test) 82 | 83 | set(${PROJECT_NAME}_HEADERS ${${PROJECT_NAME}_INCLUDE_DIR}/semver.h) 84 | if (EXISTS ${${PROJECT_NAME}_INCLUDE_DIR}) 85 | file(GLOB_RECURSE ${PROJECT_NAME}_HEADERS ${${PROJECT_NAME}_HEADERS} ${${PROJECT_NAME}_INCLUDE_DIR}/${PROJECT_NAME}/*.h) 86 | endif () 87 | if (EXISTS ${${PROJECT_NAME}_SOURCE_DIR}) 88 | file(GLOB_RECURSE ${PROJECT_NAME}_SOURCES ${${PROJECT_NAME}_SOURCES} ${${PROJECT_NAME}_SOURCE_DIR}/*.c) 89 | endif () 90 | 91 | add_library(${PROJECT_NAME} ${${PROJECT_NAME}_SOURCES} ${${PROJECT_NAME}_HEADERS}) 92 | set_target_properties(${PROJECT_NAME} PROPERTIES PUBLIC_HEADER "${${PROJECT_NAME}_HEADERS}") 93 | set_target_properties(${PROJECT_NAME} PROPERTIES VERSION "${${PROJECT_NAME}_MAJOR}.${${PROJECT_NAME}_MINOR}.${${PROJECT_NAME}_PATCH}") 94 | set_target_properties(${PROJECT_NAME} PROPERTIES SOVERSION ${${PROJECT_NAME}_MAJOR}) 95 | 96 | target_compile_definitions(${PROJECT_NAME} PRIVATE SV_COMPILE=1) 97 | if (${BUILD_SHARED_LIBS}) 98 | target_compile_definitions(${PROJECT_NAME} PRIVATE SV_BUILD_DYNAMIC_LINK=1) 99 | endif () 100 | 101 | if (${PROJECT_NAME}_DEPS) 102 | foreach (DEP ${${PROJECT_NAME}_DEPS}) 103 | add_dependencies(${PROJECT_NAME} ${DEP}) 104 | if (${DEP}_LINK) 105 | target_link_libraries(${PROJECT_NAME} ${DEP}) 106 | endif () 107 | endforeach () 108 | endif () 109 | 110 | if (EXISTS ${${PROJECT_NAME}_INCLUDE_DIR}) 111 | target_include_directories(${PROJECT_NAME} PUBLIC ${${PROJECT_NAME}_INCLUDE_DIR}) 112 | endif () 113 | if (EXISTS ${${PROJECT_NAME}_SOURCE_DIR}) 114 | target_include_directories(${PROJECT_NAME} PRIVATE ${${PROJECT_NAME}_SOURCE_DIR}) 115 | endif () 116 | 117 | if (MSVC) 118 | if (${PROJECT_NAME}_MSVC_COMPILE_OPTIONS) 119 | target_compile_options(${PROJECT_NAME} 120 | PRIVATE /Oy 121 | PRIVATE /O$<$:d>$<$:x> 122 | PRIVATE ${${PROJECT_NAME}_MSVC_COMPILE_OPTIONS}) 123 | else () 124 | target_compile_options(${PROJECT_NAME} 125 | PRIVATE /Oy 126 | PRIVATE /O$<$:d>$<$:x>) 127 | endif () 128 | else () 129 | if (${PROJECT_NAME}_COMPILE_OPTIONS) 130 | target_compile_options(${PROJECT_NAME} 131 | PRIVATE -Wall -Werror -Wextra -fomit-frame-pointer 132 | PRIVATE -O$<$:0 -g3>$<$:3> 133 | PRIVATE ${${PROJECT_NAME}_COMPILE_OPTIONS}) 134 | else () 135 | target_compile_options(${PROJECT_NAME} 136 | PRIVATE -Wall -Werror -Wextra -fomit-frame-pointer 137 | PRIVATE -O$<$:0 -g3>$<$:3>) 138 | endif () 139 | endif () 140 | 141 | if (MSVC) 142 | set(CMAKE_FLAGS 143 | CMAKE_C_FLAGS CMAKE_CXX_FLAGS 144 | CMAKE_C_FLAGS_DEBUG CMAKE_CXX_FLAGS_DEBUG 145 | CMAKE_C_FLAGS_RELEASE CMAKE_CXX_FLAGS_RELEASE) 146 | foreach (CMAKE_FLAG ${CMAKE_FLAGS}) 147 | string(REPLACE "/MD" "/MT" ${CMAKE_FLAG} "${${CMAKE_FLAG}}") 148 | string(REPLACE "/MDd" "/MTd" ${CMAKE_FLAG} "${${CMAKE_FLAG}}") 149 | endforeach () 150 | endif () 151 | 152 | if (${PROJECT_NAME}_DEVEL) 153 | if (EXISTS ${${PROJECT_NAME}_TEST_DIR}) 154 | enable_testing() 155 | 156 | file(GLOB ctest_SOURCES ${ctest_SOURCES} ${${PROJECT_NAME}_TEST_DIR}/*.c) 157 | foreach (ctest_SRC ${ctest_SOURCES}) 158 | get_filename_component(ctest_NAME ${ctest_SRC} NAME_WE) 159 | add_executable(test_${ctest_NAME} ${ctest_SRC}) 160 | add_dependencies(test_${ctest_NAME} ${PROJECT_NAME}) 161 | target_link_libraries(test_${ctest_NAME} ${PROJECT_NAME}) 162 | if (${PROJECT_NAME}_TEST_DEPS) 163 | foreach (DEP ${${PROJECT_NAME}_TEST_DEPS}) 164 | add_dependencies(test_${ctest_NAME} ${DEP}) 165 | if (${DEP}_LINK) 166 | target_link_libraries(test_${ctest_NAME} ${DEP}) 167 | endif () 168 | endforeach () 169 | endif () 170 | add_test(${ctest_NAME} test_${ctest_NAME}) 171 | endforeach () 172 | endif () 173 | else () 174 | set(${PROJECT_NAME}_HEADERS ${PROJECT_NAME}_HEADERS PARENT_SCOPE) 175 | set(${PROJECT_NAME}_SOURCES ${PROJECT_NAME}_SOURCES PARENT_SCOPE) 176 | set(${PROJECT_NAME}_INCLUDE_DIR ${PROJECT_NAME}_INCLUDE_DIR PARENT_SCOPE) 177 | set(${PROJECT_NAME}_SOURCE_DIR ${PROJECT_NAME}_SOURCE_DIR PARENT_SCOPE) 178 | set(${PROJECT_NAME}_TEST_DIR ${PROJECT_NAME}_TEST_DIR PARENT_SCOPE) 179 | endif () 180 | 181 | block() 182 | set(prefix ${CMAKE_INSTALL_PREFIX}) 183 | set(exec_prefix ${CMAKE_INSTALL_PREFIX}) 184 | set(bindir ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}) 185 | set(datarootdir ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATAROOTDIR}) 186 | set(includedir ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}) 187 | set(infodir ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INFODIR}) 188 | set(libdir ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}) 189 | set(libexecdir ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBEXECDIR}) 190 | set(localstatedir ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LOCALSTATEDIR}) 191 | set(mandir ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_MANDIR}) 192 | set(sbindir ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_SBINDIR}) 193 | set(sharedstatedir ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_SHAREDSTATEDIR}) 194 | set(sysconfdir ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_SYSCONFDIR}) 195 | set(PACKAGE_NAME ${PROJECT_NAME}) 196 | set(LIBSV_PKG_CONFIG_VERSION 197 | ${${PROJECT_NAME}_MAJOR}.${${PROJECT_NAME}_MINOR}.${${PROJECT_NAME}_PATCH}) 198 | configure_file("scripts/libsv.pc.in" "scripts/libsv.pc" @ONLY) 199 | install( 200 | FILES "${CMAKE_CURRENT_BINARY_DIR}/scripts/libsv.pc" 201 | COMPONENT Devel 202 | DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") 203 | endblock() 204 | 205 | install(TARGETS ${PROJECT_NAME} 206 | RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} 207 | ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} 208 | PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}) 209 | if (EXISTS ${${PROJECT_NAME}_INCLUDE_DIR}/${PROJECT_NAME}.h) 210 | install(FILES ${${PROJECT_NAME}_INCLUDE_DIR}/${PROJECT_NAME}.h 211 | DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) 212 | endif () 213 | 214 | set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "${PROJECT_NAME}_SUMMARY") 215 | set(CPACK_PACKAGE_VENDOR "${PROJECT_NAME}_VENDOR") 216 | set(CPACK_PACKAGE_CONTACT "${PROJECT_NAME}_CONTACT") 217 | set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_LIST_DIR}/${${PROJECT_NAME}_README}") 218 | set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_LIST_DIR}/${${PROJECT_NAME}_LICENSE}") 219 | set(CPACK_PACKAGE_VERSION_MAJOR "${${PROJECT_NAME}_MAJOR}") 220 | set(CPACK_PACKAGE_VERSION_MINOR "${${PROJECT_NAME}_MINOR}") 221 | set(CPACK_PACKAGE_VERSION_PATCH "${${PROJECT_NAME}_PATCH}") 222 | set(CPACK_PACKAGE_INSTALL_DIRECTORY "${PROJECT_NAME}") 223 | if (WIN32 AND NOT UNIX) 224 | set(CPACK_NSIS_DISPLAY_NAME "${CPACK_PACKAGE_INSTALL_DIRECTORY}") 225 | set(CPACK_NSIS_CONTACT "${PROJECT_NAME}_VENDOR_CONTACT") 226 | set(CPACK_NSIS_MODIFY_PATH ON) 227 | set(CPACK_GENERATOR "NSIS;ZIP") 228 | else () 229 | set(CPACK_GENERATOR "TGZ;RPM;DEB") 230 | endif () 231 | include(CPack) 232 | -------------------------------------------------------------------------------- /test/comp.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This is free and unencumbered software released into the public domain. 3 | * 4 | * Anyone is free to copy, modify, publish, use, compile, sell, or 5 | * distribute this software, either in source code form or as a compiled 6 | * binary, for any purpose, commercial or non-commercial, and by any 7 | * means. 8 | * 9 | * In jurisdictions that recognize copyright laws, the author or authors 10 | * of this software dedicate any and all copyright interest in the 11 | * software to the public domain. We make this dedication for the benefit 12 | * of the public at large and to the detriment of our heirs and 13 | * successors. We intend this dedication to be an overt act of 14 | * relinquishment in perpetuity of all present and future rights to this 15 | * software under copyright law. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | * OTHER DEALINGS IN THE SOFTWARE. 24 | * 25 | * For more information, please refer to 26 | */ 27 | 28 | #include 29 | #include 30 | #include 31 | 32 | #include "semver.h" 33 | 34 | #define STRNSIZE(s) (s), sizeof(s)-1 35 | 36 | int test_read(const char *expected, const char *str, size_t len) { 37 | unsigned slen; 38 | char buffer[1024]; 39 | semver_comp_t comp = {0}; 40 | 41 | printf("test: `%.*s`", (int) len, str); 42 | if (semver_compn(&comp, str, len)) { 43 | puts(" \tcouldn't parse"); 44 | return 1; 45 | } 46 | slen = (unsigned) semver_comp_write(comp, buffer, 1024); 47 | printf(" \t=> \t`%.*s`", slen, buffer); 48 | if (memcmp(expected, buffer, (size_t) slen > len ? slen : len) != 0) { 49 | printf(" != `%s`\n", expected); 50 | semver_comp_dtor(&comp); 51 | return 1; 52 | } 53 | printf(" == `%s`\n", expected); 54 | semver_comp_dtor(&comp); 55 | return 0; 56 | } 57 | 58 | int test_and(const char *expected, const char *base_str, size_t base_len, const char *str, size_t len) { 59 | unsigned slen; 60 | char buffer[1024]; 61 | semver_comp_t comp = {0}; 62 | 63 | printf("test and: `%.*s`", (int) base_len, base_str); 64 | if (semver_compn(&comp, base_str, base_len)) { 65 | puts(" \tcouldn't parse"); 66 | return 1; 67 | } 68 | if (semver_and(&comp, str, len)) { 69 | puts(" \tand failed"); 70 | return 1; 71 | } 72 | slen = (unsigned) semver_comp_write(comp, buffer, 1024); 73 | printf(" \t=> \t`%.*s`", slen, buffer); 74 | if (memcmp(expected, buffer, (size_t) slen > base_len + len + 1 ? slen : base_len + len + 1) != 0) { 75 | printf(" != `%s`\n", expected); 76 | semver_comp_dtor(&comp); 77 | return 1; 78 | } 79 | printf(" == `%s`\n", expected); 80 | semver_comp_dtor(&comp); 81 | return 0; 82 | } 83 | 84 | int main(void) { 85 | puts("failure:"); 86 | if (test_read("", STRNSIZE("* ")) == 0) { 87 | return EXIT_FAILURE; 88 | } 89 | if (test_read("", STRNSIZE("* ")) == 0) { 90 | return EXIT_FAILURE; 91 | } 92 | if (test_read("", STRNSIZE("* |")) == 0) { 93 | return EXIT_FAILURE; 94 | } 95 | if (test_read("", STRNSIZE("* || *")) == 0) { 96 | return EXIT_FAILURE; 97 | } 98 | if (test_read("", STRNSIZE("abc")) == 0) { 99 | return EXIT_FAILURE; 100 | } 101 | if (test_read("", STRNSIZE(">")) == 0) { 102 | return EXIT_FAILURE; 103 | } 104 | if (test_read("", STRNSIZE("<=")) == 0) { 105 | return EXIT_FAILURE; 106 | } 107 | if (test_read("", STRNSIZE("~")) == 0) { 108 | return EXIT_FAILURE; 109 | } 110 | if (test_read("", STRNSIZE("^")) == 0) { 111 | return EXIT_FAILURE; 112 | } 113 | if (test_read("", STRNSIZE("=")) == 0) { 114 | return EXIT_FAILURE; 115 | } 116 | if (test_read("", STRNSIZE(">a")) == 0) { 117 | return EXIT_FAILURE; 118 | } 119 | if (test_read("", STRNSIZE("1.a")) == 0) { 132 | return EXIT_FAILURE; 133 | } 134 | if (test_read("", STRNSIZE("<1.a")) == 0) { 135 | return EXIT_FAILURE; 136 | } 137 | if (test_read("", STRNSIZE("~1.a")) == 0) { 138 | return EXIT_FAILURE; 139 | } 140 | if (test_read("", STRNSIZE("^1.a")) == 0) { 141 | return EXIT_FAILURE; 142 | } 143 | if (test_read("", STRNSIZE("=1.a")) == 0) { 144 | return EXIT_FAILURE; 145 | } 146 | if (test_read("", STRNSIZE("1.2.3 ")) == 0) { 147 | return EXIT_FAILURE; 148 | } 149 | if (test_read("", STRNSIZE("1.2.3 -")) == 0) { 150 | return EXIT_FAILURE; 151 | } 152 | if (test_read("", STRNSIZE("1.2.3 - ")) == 0) { 153 | return EXIT_FAILURE; 154 | } 155 | if (test_read("", STRNSIZE("1.2.3 -a")) == 0) { 156 | return EXIT_FAILURE; 157 | } 158 | if (test_read("", STRNSIZE("1.2.3 - a")) == 0) { 159 | return EXIT_FAILURE; 160 | } 161 | if (test_read("", STRNSIZE("1.2.3 - 1.2.a")) == 0) { 162 | return EXIT_FAILURE; 163 | } 164 | if (test_read("", STRNSIZE("a.2.3")) == 0) { 165 | return EXIT_FAILURE; 166 | } 167 | if (test_read("", STRNSIZE("1.a.3")) == 0) { 168 | return EXIT_FAILURE; 169 | } 170 | if (test_read("", STRNSIZE("1.2.a")) == 0) { 171 | return EXIT_FAILURE; 172 | } 173 | if (test_read("", STRNSIZE("1.2.3-")) == 0) { 174 | return EXIT_FAILURE; 175 | } 176 | if (test_read("", STRNSIZE("1.2.3-alpha+")) == 0) { 177 | return EXIT_FAILURE; 178 | } 179 | if (test_read("", STRNSIZE("1.2.3+")) == 0) { 180 | return EXIT_FAILURE; 181 | } 182 | if (test_read("1.2.3", STRNSIZE("1.2.3"))) { 183 | return EXIT_FAILURE; 184 | } 185 | 186 | puts("\nsome prerelease and build:"); 187 | if (test_read(">=0.0.0 1.2.3-alpha", STRNSIZE("* 1.2.3-alpha"))) { 188 | return EXIT_FAILURE; 189 | } 190 | if (test_read(">=0.0.0 1.2.3-alpha.2", STRNSIZE("* 1.2.3-alpha.2"))) { 191 | return EXIT_FAILURE; 192 | } 193 | if (test_read(">=0.0.0 1.2.3+77", STRNSIZE("* 1.2.3+77"))) { 194 | return EXIT_FAILURE; 195 | } 196 | if (test_read(">=0.0.0 1.2.3+77.2", STRNSIZE("* 1.2.3+77.2"))) { 197 | return EXIT_FAILURE; 198 | } 199 | if (test_read(">=0.0.0 1.2.3-alpha.2+77", STRNSIZE("* 1.2.3-alpha.2+77"))) { 200 | return EXIT_FAILURE; 201 | } 202 | if (test_read(">=0.0.0 1.2.3-alpha.2+77.2", STRNSIZE("* 1.2.3-alpha.2+77.2"))) { 203 | return EXIT_FAILURE; 204 | } 205 | if (test_read(">=0.0.0 1.2.3-al-pha.2+77", STRNSIZE("* 1.2.3-al-pha.2+77"))) { 206 | return EXIT_FAILURE; 207 | } 208 | if (test_read(">=0.0.0 1.2.3-al-pha.2+77.2", STRNSIZE("* 1.2.3-al-pha.2+77.2"))) { 209 | return EXIT_FAILURE; 210 | } 211 | 212 | puts("\nx-range:"); 213 | if (test_read(">=0.0.0", STRNSIZE("*"))) { 214 | return EXIT_FAILURE; 215 | } 216 | if (test_read(">=1.0.0 <2.0.0", STRNSIZE("1.x"))) { 217 | return EXIT_FAILURE; 218 | } 219 | if (test_read(">=1.2.0 <1.3.0", STRNSIZE("1.2.x"))) { 220 | return EXIT_FAILURE; 221 | } 222 | if (test_read(">=0.0.0", STRNSIZE(""))) { 223 | return EXIT_FAILURE; 224 | } 225 | if (test_read(">=1.0.0 <2.0.0", STRNSIZE("1"))) { 226 | return EXIT_FAILURE; 227 | } 228 | if (test_read(">=1.2.0 <1.3.0", STRNSIZE("1.2"))) { 229 | return EXIT_FAILURE; 230 | } 231 | 232 | puts("\nhyphen:"); 233 | if (test_read(">=1.2.3 <=2.3.4", STRNSIZE("1.2.3 - 2.3.4"))) { 234 | return EXIT_FAILURE; 235 | } 236 | if (test_read(">=1.2.0 <=2.3.4", STRNSIZE("1.2 - 2.3.4"))) { 237 | return EXIT_FAILURE; 238 | } 239 | if (test_read(">=1.2.3 <2.4.0", STRNSIZE("1.2.3 - 2.3"))) { 240 | return EXIT_FAILURE; 241 | } 242 | if (test_read(">=1.2.3 <3.0.0", STRNSIZE("1.2.3 - 2"))) { 243 | return EXIT_FAILURE; 244 | } 245 | 246 | puts("\ntilde:"); 247 | if (test_read(">=1.2.3 <1.3.0", STRNSIZE("~1.2.3"))) { 248 | return EXIT_FAILURE; 249 | } 250 | if (test_read(">=1.2.0 <1.3.0", STRNSIZE("~1.2"))) { 251 | return EXIT_FAILURE; 252 | } 253 | if (test_read(">=1.0.0 <2.0.0", STRNSIZE("~1"))) { 254 | return EXIT_FAILURE; 255 | } 256 | if (test_read(">=0.2.3 <0.3.0", STRNSIZE("~0.2.3"))) { 257 | return EXIT_FAILURE; 258 | } 259 | if (test_read(">=0.2.0 <0.3.0", STRNSIZE("~0.2"))) { 260 | return EXIT_FAILURE; 261 | } 262 | if (test_read(">=0.0.0 <1.0.0", STRNSIZE("~0"))) { 263 | return EXIT_FAILURE; 264 | } 265 | 266 | puts("\ncaret:"); 267 | if (test_read(">=1.2.3 <2.0.0", STRNSIZE("^1.2.3"))) { 268 | return EXIT_FAILURE; 269 | } 270 | if (test_read(">=0.2.3 <0.3.0", STRNSIZE("^0.2.3"))) { 271 | return EXIT_FAILURE; 272 | } 273 | if (test_read(">=0.0.3 <0.0.4", STRNSIZE("^0.0.3"))) { 274 | return EXIT_FAILURE; 275 | } 276 | 277 | puts("\nprimitive:"); 278 | if (test_read(">=1.2.3 <2.0.0", STRNSIZE(">=1.2.3 <2.0"))) { 279 | return EXIT_FAILURE; 280 | } 281 | if (test_read(">=0.2.3 <0.3.0", STRNSIZE(">=0.2.3 <0.3"))) { 282 | return EXIT_FAILURE; 283 | } 284 | if (test_read(">=0.5.0 <0.0.4", STRNSIZE(">=0.5 <0.0.4"))) { 285 | return EXIT_FAILURE; 286 | } 287 | if (test_read(">0.0.3", STRNSIZE(">0.0.3"))) { 288 | return EXIT_FAILURE; 289 | } 290 | if (test_read("0.0.3", STRNSIZE("=0.0.3"))) { 291 | return EXIT_FAILURE; 292 | } 293 | if (test_read("9.0.0", STRNSIZE("=9"))) { 294 | return EXIT_FAILURE; 295 | } 296 | 297 | puts("\nand:"); 298 | if (test_and(">=0.0.0 >=0.0.3 <0.0.4", STRNSIZE("*"), STRNSIZE("^0.0.3"))) { 299 | return EXIT_FAILURE; 300 | } 301 | if (test_and(">=1.0.0 <2.0.0 >=0.0.3 <0.0.4", STRNSIZE("1.x"), STRNSIZE("^0.0.3"))) { 302 | return EXIT_FAILURE; 303 | } 304 | if (test_and(">=1.2.0 <1.3.0 >=0.0.3 <0.0.4", STRNSIZE("1.2.x"), STRNSIZE("^0.0.3"))) { 305 | return EXIT_FAILURE; 306 | } 307 | 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"))) { 308 | return EXIT_FAILURE; 309 | } 310 | if (test_and(">=1.0.0 <2.0.0 >=0.0.3 <0.0.4", STRNSIZE("1"), STRNSIZE("^0.0.3"))) { 311 | return EXIT_FAILURE; 312 | } 313 | if (test_and(">=1.2.0 <1.3.0 >=0.0.3 <0.0.4", STRNSIZE("1.2"), STRNSIZE("^0.0.3"))) { 314 | return EXIT_FAILURE; 315 | } 316 | if (test_and("", STRNSIZE("1.2"), STRNSIZE("")) == 0) { 317 | return EXIT_FAILURE; 318 | } 319 | if (test_and("", STRNSIZE("1.2"), STRNSIZE("a")) == 0) { 320 | return EXIT_FAILURE; 321 | } 322 | if (test_and("", STRNSIZE("1.2"), STRNSIZE("1.2.x abc")) == 0) { 323 | return EXIT_FAILURE; 324 | } 325 | if (test_read("", STRNSIZE("Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget " 326 | "dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascet" 327 | "ur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, s")) 328 | == 0) { 329 | return EXIT_FAILURE; 330 | } 331 | 332 | return EXIT_SUCCESS; 333 | } 334 | -------------------------------------------------------------------------------- /src/comp.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This is free and unencumbered software released into the public domain. 3 | * 4 | * Anyone is free to copy, modify, publish, use, compile, sell, or 5 | * distribute this software, either in source code form or as a compiled 6 | * binary, for any purpose, commercial or non-commercial, and by any 7 | * means. 8 | * 9 | * In jurisdictions that recognize copyright laws, the author or authors 10 | * of this software dedicate any and all copyright interest in the 11 | * software to the public domain. We make this dedication for the benefit 12 | * of the public at large and to the detriment of our heirs and 13 | * successors. We intend this dedication to be an overt act of 14 | * relinquishment in perpetuity of all present and future rights to this 15 | * software under copyright law. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | * OTHER DEALINGS IN THE SOFTWARE. 24 | * 25 | * For more information, please refer to 26 | */ 27 | 28 | #include 29 | #include 30 | #include 31 | 32 | #include "comp.h" 33 | #include "num.h" 34 | #include "id.h" 35 | #include "utils.h" 36 | 37 | static void semver_xrevert(semver_t *semver) { 38 | if (semver->major == SEMVER_NUM_X) { 39 | semver->major = semver->minor = semver->patch = 0; 40 | } else if (semver->minor == SEMVER_NUM_X) { 41 | semver->minor = semver->patch = 0; 42 | } else if (semver->patch == SEMVER_NUM_X) { 43 | semver->patch = 0; 44 | } 45 | } 46 | 47 | static semver_comp_t *semver_xconvert(semver_comp_t *self) { 48 | if (self->version.major == SEMVER_NUM_X) { 49 | self->op = SEMVER_OP_GE; 50 | semver_xrevert(&self->version); 51 | return self; 52 | } 53 | if (self->version.minor == SEMVER_NUM_X) { 54 | semver_xrevert(&self->version); 55 | self->op = SEMVER_OP_GE; 56 | self->next = (semver_comp_t *) sv_malloc(sizeof(semver_comp_t)); 57 | if (self->next == NULL) { 58 | return NULL; 59 | } 60 | semver_comp_ctor(self->next); 61 | self->next->op = SEMVER_OP_LT; 62 | self->next->version = self->version; 63 | ++self->next->version.major; 64 | return self->next; 65 | } 66 | if (self->version.patch == SEMVER_NUM_X) { 67 | semver_xrevert(&self->version); 68 | self->op = SEMVER_OP_GE; 69 | self->next = (semver_comp_t *) sv_malloc(sizeof(semver_comp_t)); 70 | if (self->next == NULL) { 71 | return NULL; 72 | } 73 | semver_comp_ctor(self->next); 74 | self->next->op = SEMVER_OP_LT; 75 | self->next->version = self->version; 76 | ++self->next->version.minor; 77 | return self->next; 78 | } 79 | self->op = SEMVER_OP_EQ; 80 | return self; 81 | } 82 | 83 | static char parse_partial(semver_t *self, const char *str, size_t len, size_t *offset) { 84 | semver_ctor(self); 85 | self->major = self->minor = self->patch = SEMVER_NUM_X; 86 | if (*offset < len) { 87 | self->raw = str + *offset; 88 | if (semver_num_read(&self->major, str, len, offset)) { 89 | return 0; 90 | } 91 | if (*offset >= len || str[*offset] != '.') { 92 | return 0; 93 | } 94 | ++*offset; 95 | if (semver_num_read(&self->minor, str, len, offset)) { 96 | return 1; 97 | } 98 | if (*offset >= len || str[*offset] != '.') { 99 | return 0; 100 | } 101 | ++*offset; 102 | if (semver_num_read(&self->patch, str, len, offset)) { 103 | return 1; 104 | } 105 | if ((str[*offset] == '-' && semver_id_read_prerelease(&self->prerelease, str, len, (++*offset, offset))) 106 | || (str[*offset] == '+' && semver_id_read_build(&self->build, str, len, (++*offset, offset)))) { 107 | return 1; 108 | } 109 | self->len = str + *offset - self->raw; 110 | return 0; 111 | } 112 | return 0; 113 | } 114 | 115 | static char parse_hiphen(semver_comp_t *self, const char *str, size_t len, size_t *offset) { 116 | semver_t partial; 117 | 118 | if (parse_partial(&partial, str, len, offset)) { 119 | return 1; 120 | } 121 | self->op = SEMVER_OP_GE; 122 | semver_xrevert(&self->version); 123 | self->next = (semver_comp_t *) sv_malloc(sizeof(semver_comp_t)); 124 | if (self->next == NULL) { 125 | return 1; 126 | } 127 | semver_comp_ctor(self->next); 128 | self->next->op = SEMVER_OP_LT; 129 | if (partial.minor == SEMVER_NUM_X) { 130 | self->next->version.major = partial.major + 1; 131 | } else if (partial.patch == SEMVER_NUM_X) { 132 | self->next->version.major = partial.major; 133 | self->next->version.minor = partial.minor + 1; 134 | } else { 135 | self->next->op = SEMVER_OP_LE; 136 | self->next->version = partial; 137 | } 138 | 139 | return 0; 140 | } 141 | 142 | static char parse_caret(semver_comp_t *self, const char *str, size_t len, size_t *offset) { 143 | semver_t partial; 144 | 145 | if (parse_partial(&self->version, str, len, offset)) { 146 | return 1; 147 | } 148 | semver_xrevert(&self->version); 149 | self->op = SEMVER_OP_GE; 150 | partial = self->version; 151 | if (partial.major != 0) { 152 | ++partial.major; 153 | partial.minor = partial.patch = 0; 154 | } else if (partial.minor != 0) { 155 | ++partial.minor; 156 | partial.patch = 0; 157 | } else { 158 | ++partial.patch; 159 | } 160 | self->next = (semver_comp_t *) sv_malloc(sizeof(semver_comp_t)); 161 | if (self->next == NULL) { 162 | return 1; 163 | } 164 | semver_comp_ctor(self->next); 165 | self->next->op = SEMVER_OP_LT; 166 | self->next->version = partial; 167 | return 0; 168 | } 169 | 170 | static char parse_tilde(semver_comp_t *self, const char *str, size_t len, size_t *offset) { 171 | semver_t partial; 172 | 173 | if (parse_partial(&self->version, str, len, offset)) { 174 | return 1; 175 | } 176 | semver_xrevert(&self->version); 177 | self->op = SEMVER_OP_GE; 178 | partial = self->version; 179 | if (partial.minor || partial.patch) { 180 | ++partial.minor; 181 | partial.patch = 0; 182 | } else { 183 | ++partial.major; 184 | partial.minor = partial.patch = 0; 185 | } 186 | self->next = (semver_comp_t *) sv_malloc(sizeof(semver_comp_t)); 187 | if (self->next == NULL) { 188 | return 1; 189 | } 190 | semver_comp_ctor(self->next); 191 | self->next->op = SEMVER_OP_LT; 192 | self->next->version = partial; 193 | return 0; 194 | } 195 | 196 | void semver_comp_ctor(semver_comp_t *self) { 197 | #ifndef _MSC_VER 198 | *self = (semver_comp_t) {0}; 199 | #else 200 | self->next = NULL; 201 | self->op = SEMVER_OP_EQ; 202 | semver_ctor(&self->version); 203 | #endif 204 | } 205 | 206 | void semver_comp_dtor(semver_comp_t *self) { 207 | if (self && self->next) { 208 | semver_comp_dtor(self->next); 209 | free(self->next); 210 | self->next = NULL; 211 | } 212 | } 213 | 214 | char semver_compn(semver_comp_t *self, const char *str, size_t len) { 215 | size_t offset = 0; 216 | 217 | if (len > SV_COMP_MAX_LEN) { 218 | return 1; 219 | } 220 | if (semver_comp_read(self, str, len, &offset) || offset < len) { 221 | semver_comp_dtor(self); 222 | return 1; 223 | } 224 | return 0; 225 | } 226 | 227 | char semver_comp_read(semver_comp_t *self, const char *str, size_t len, size_t *offset) { 228 | semver_comp_ctor(self); 229 | while (*offset < len) { 230 | switch (str[*offset]) { 231 | case '^': 232 | ++*offset; 233 | if (parse_caret(self, str, len, offset)) { 234 | return 1; 235 | } 236 | self = self->next; 237 | goto next; 238 | case '~': 239 | ++*offset; 240 | if (parse_tilde(self, str, len, offset)) { 241 | return 1; 242 | } 243 | self = self->next; 244 | goto next; 245 | case '>': 246 | ++*offset; 247 | if (*offset < len && str[*offset] == '=') { 248 | ++*offset; 249 | self->op = SEMVER_OP_GE; 250 | } else { 251 | self->op = SEMVER_OP_GT; 252 | } 253 | if (parse_partial(&self->version, str, len, offset)) { 254 | return 1; 255 | } 256 | semver_xrevert(&self->version); 257 | goto next; 258 | case '<': 259 | ++*offset; 260 | if (*offset < len && str[*offset] == '=') { 261 | ++*offset; 262 | self->op = SEMVER_OP_LE; 263 | } else { 264 | self->op = SEMVER_OP_LT; 265 | } 266 | if (parse_partial(&self->version, str, len, offset)) { 267 | return 1; 268 | } 269 | semver_xrevert(&self->version); 270 | goto next; 271 | case '=': 272 | ++*offset; 273 | self->op = SEMVER_OP_EQ; 274 | if (parse_partial(&self->version, str, len, offset)) { 275 | return 1; 276 | } 277 | semver_xrevert(&self->version); 278 | goto next; 279 | default: 280 | goto range; 281 | } 282 | } 283 | range: 284 | if (parse_partial(&self->version, str, len, offset)) { 285 | return 1; 286 | } 287 | if (*offset < len && str[*offset] == ' ' 288 | && *offset + 1 < len && str[*offset + 1] == '-' 289 | && *offset + 2 < len && str[*offset + 2] == ' ') { 290 | *offset += 3; 291 | if (parse_hiphen(self, str, len, offset)) { 292 | return 1; 293 | } 294 | self = self->next; 295 | } else { 296 | self = semver_xconvert(self); 297 | if (self == NULL) { 298 | return 1; 299 | } 300 | } 301 | next: 302 | if (*offset < len && str[*offset] == ' ' 303 | && *offset + 1 < len && str[*offset + 1] != ' ' && str[*offset + 1] != '|') { 304 | ++*offset; 305 | if (*offset < len) { 306 | self->next = (semver_comp_t *) sv_malloc(sizeof(semver_comp_t)); 307 | if (self->next == NULL) { 308 | return 1; 309 | } 310 | return semver_comp_read(self->next, str, len, offset); 311 | } 312 | return 1; 313 | } 314 | return 0; 315 | } 316 | 317 | char semver_and(semver_comp_t *left, const char *str, size_t len) { 318 | semver_comp_t *comp, *tail; 319 | 320 | if (len > 0) { 321 | comp = (semver_comp_t *) sv_malloc(sizeof(semver_comp_t)); 322 | if (NULL == comp) { 323 | return 1; 324 | } 325 | if (semver_compn(comp, str, len)) { 326 | sv_free(comp); 327 | return 1; 328 | } 329 | if (NULL == left->next) { 330 | left->next = comp; 331 | } else { 332 | tail = left->next; 333 | while (tail->next) tail = tail->next; 334 | tail->next = comp; 335 | } 336 | return 0; 337 | } 338 | return 1; 339 | } 340 | 341 | bool semver_comp_pmatch(const semver_t *self, const semver_comp_t *comp) { 342 | int result = semver_pcmp(self, &comp->version); 343 | 344 | if (result < 0 && comp->op != SEMVER_OP_LT && comp->op != SEMVER_OP_LE) { 345 | return false; 346 | } 347 | if (result > 0 && comp->op != SEMVER_OP_GT && comp->op != SEMVER_OP_GE) { 348 | return false; 349 | } 350 | if (result == 0 && comp->op != SEMVER_OP_EQ && comp->op != SEMVER_OP_LE && comp->op != SEMVER_OP_GE) { 351 | return false; 352 | } 353 | if (comp->next) { 354 | return semver_comp_pmatch(self, comp->next); 355 | } 356 | return true; 357 | } 358 | 359 | bool semver_comp_matchn(const semver_t *self, const char *comp_str, size_t comp_len) { 360 | semver_comp_t comp; 361 | bool result; 362 | 363 | if (semver_compn(&comp, comp_str, comp_len)) { 364 | return false; 365 | } 366 | result = semver_comp_pmatch(self, &comp); 367 | semver_comp_dtor(&comp); 368 | return result; 369 | } 370 | 371 | int semver_comp_pwrite(const semver_comp_t *self, char *buffer, size_t len) { 372 | char semver[SV_COMP_MAX_LEN]; 373 | 374 | semver_write(self->version, semver, SV_COMP_MAX_LEN); 375 | if (self->next) { 376 | char next[SV_COMP_MAX_LEN]; 377 | return snprintf(buffer, len, "%s%s %.*s", 378 | semver_op_string(self->op), semver, semver_comp_pwrite(self->next, next, SV_COMP_MAX_LEN), next 379 | ); 380 | } 381 | return snprintf(buffer, len, "%s%s", semver_op_string(self->op), semver); 382 | } 383 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # libsv 2 | libsv - Public domain cross-platform semantic versioning in c99 3 | 4 | [![codecov](https://codecov.io/gh/uael/sv/branch/master/graph/badge.svg)](https://codecov.io/gh/uael/sv) 5 | 6 | # Topics 7 | - [Introduction](#introduction) 8 | - [License](#license) 9 | - [Install](#install) 10 | - [xmake](#xmake) 11 | - [cmake](#cmake) 12 | - [autotools](#autotools) 13 | - [Usage](#usage) 14 | - [Credits](#credits) 15 | - [Bugs, vulnerabilities and contributions](#bugs-vulnerabilities-and-contributions) 16 | - [Resources](#resources) 17 | - [Badges and static analysis](#badges-and-static-analysis) 18 | - [Travis CI](#travis-ci) 19 | - [Clang's Static Analyzer](#clangs-static-analyzer) 20 | 21 | ## Introduction 22 | 23 | This is free and unencumbered software released into the public domain. 24 | This package installs a C language library implementing semantic versioning for the C language. 25 | 26 | ## License 27 | 28 | See the [UNLICENSE](https://github.com/uael/sv/blob/master/UNLICENSE) file. 29 | 30 | ## Install 31 | 32 | ### xmake 33 | 34 | [Install xmake build system (A make-like build utility based on Lua)](http://xmake.io) 35 | 36 | ```bash 37 | $ xmake 38 | $ xmake check 39 | $ xmake install 40 | ``` 41 | 42 | ### cmake 43 | 44 | ```bash 45 | $ mkdir build && cd build 46 | $ cmake .. 47 | $ make 48 | $ make test 49 | $ make install 50 | ``` 51 | 52 | ### autotools 53 | 54 | To install from a proper release tarball, do this: 55 | ```bash 56 | $ cd libsv-3.1 57 | $ mkdir build 58 | $ cd build 59 | $ ../configure 60 | $ make 61 | $ make check 62 | $ make install 63 | ``` 64 | to inspect the available configuration options: 65 | ```bash 66 | $ ../configure --help 67 | ``` 68 | The Makefile is designed to allow parallel builds, so we can do: 69 | ```bash 70 | $ make -j4 all && make -j4 check 71 | ``` 72 | which, on a 4-core CPU, should speed up building and checking significantly. 73 | The Makefile supports the DESTDIR environment variable to install files in a temporary location, example: to see what will happen: 74 | ```bash 75 | $ make -n install DESTDIR=/tmp/libsv 76 | ``` 77 | to really do it: 78 | ```bash 79 | $ make install DESTDIR=/tmp/libsv 80 | ``` 81 | After the installation it is possible to verify the installed library against the test suite with: 82 | ```bash 83 | $ make installcheck 84 | ``` 85 | 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: 86 | ```bash 87 | $ cd libsv 88 | $ sh autogen.sh 89 | ``` 90 | 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: 91 | ```bash 92 | $ LIBTOOLIZE=glibtoolize sh autogen.sh 93 | ``` 94 | After this the procedure is the same as the one for building from a proper release tarball, but we have to enable maintainer mode: 95 | ```bash 96 | $ ../configure --enable-maintainer-mode [options] 97 | $ make 98 | $ make check 99 | $ make install 100 | ``` 101 | 102 | ## Usage 103 | 104 | ```c 105 | ... 106 | semver_t semver = {0}; 107 | 108 | semver(&semver, "v1.2.3-alpha.1"); 109 | 110 | assert(1 == semver.major); 111 | assert(2 == semver.minor); 112 | assert(3 == semver.patch); 113 | assert(0 == memcmp("alpha", semver.prerelease.raw, sizeof("alpha")-1)); 114 | assert(0 == memcmp("1", semver.prerelease.next->raw, sizeof("1")-1)); 115 | assert(true == semver_rmatch(semver, "1.2.1 || >=1.2.3-alpha <1.2.5")); 116 | 117 | semver_dtor(&semver); 118 | ... 119 | ``` 120 | 121 | ### Versions 122 | 123 | A "version" is described by the `v2.0.0` specification found at 124 | . 125 | 126 | A leading `"v"` character is stripped off and ignored. 127 | 128 | ### Ranges 129 | 130 | A `version range` is a set of `comparators` which specify versions 131 | that satisfy the range. 132 | 133 | A `comparator` is composed of an `operator` and a `version`. The set 134 | of primitive `operators` is: 135 | 136 | * `<` Less than 137 | * `<=` Less than or equal to 138 | * `>` Greater than 139 | * `>=` Greater than or equal to 140 | * `=` Equal. If no operator is specified, then equality is assumed, 141 | so this operator is optional, but MAY be included. 142 | 143 | For example, the comparator `>=1.2.7` would match the versions 144 | `1.2.7`, `1.2.8`, `2.5.3`, and `1.3.9`, but not the versions `1.2.6` 145 | or `1.1.0`. 146 | 147 | Comparators can be joined by whitespace to form a `comparator set`, 148 | which is satisfied by the **intersection** of all of the comparators 149 | it includes. 150 | 151 | A range is composed of one or more comparator sets, joined by `||`. A 152 | version matches a range if and only if every comparator in at least 153 | one of the `||`-separated comparator sets is satisfied by the version. 154 | 155 | For example, the range `>=1.2.7 <1.3.0` would match the versions 156 | `1.2.7`, `1.2.8`, and `1.2.99`, but not the versions `1.2.6`, `1.3.0`, 157 | or `1.1.0`. 158 | 159 | The range `1.2.7 || >=1.2.9 <2.0.0` would match the versions `1.2.7`, 160 | `1.2.9`, and `1.4.6`, but not the versions `1.2.8` or `2.0.0`. 161 | 162 | #### Prerelease Tags 163 | 164 | If a version has a prerelease tag (for example, `1.2.3-alpha.3`) then 165 | it will only be allowed to satisfy comparator sets if at least one 166 | comparator with the same `[major, minor, patch]` tuple also has a 167 | prerelease tag. 168 | 169 | For example, the range `>1.2.3-alpha.3` would be allowed to match the 170 | version `1.2.3-alpha.7`, but it would *not* be satisfied by 171 | `3.4.5-alpha.9`, even though `3.4.5-alpha.9` is technically "greater 172 | than" `1.2.3-alpha.3` according to the SemVer sort rules. The version 173 | range only accepts prerelease tags on the `1.2.3` version. The 174 | version `3.4.5` *would* satisfy the range, because it does not have a 175 | prerelease flag, and `3.4.5` is greater than `1.2.3-alpha.7`. 176 | 177 | The purpose for this behavior is twofold. First, prerelease versions 178 | frequently are updated very quickly, and contain many breaking changes 179 | that are (by the author's design) not yet fit for public consumption. 180 | Therefore, by default, they are excluded from range matching 181 | semantics. 182 | 183 | Second, a user who has opted into using a prerelease version has 184 | clearly indicated the intent to use *that specific* set of 185 | alpha/beta/rc versions. By including a prerelease tag in the range, 186 | the user is indicating that they are aware of the risk. However, it 187 | is still not appropriate to assume that they have opted into taking a 188 | similar risk on the *next* set of prerelease versions. 189 | 190 | #### Advanced Range Syntax 191 | 192 | Advanced range syntax desugars to primitive comparators in 193 | deterministic ways. 194 | 195 | Advanced ranges may be combined in the same way as primitive 196 | comparators using white space or `||`. 197 | 198 | ##### Hyphen Ranges `X.Y.Z - A.B.C` 199 | 200 | Specifies an inclusive set. 201 | 202 | * `1.2.3 - 2.3.4` := `>=1.2.3 <=2.3.4` 203 | 204 | If a partial version is provided as the first version in the inclusive 205 | range, then the missing pieces are replaced with zeroes. 206 | 207 | * `1.2 - 2.3.4` := `>=1.2.0 <=2.3.4` 208 | 209 | If a partial version is provided as the second version in the 210 | inclusive range, then all versions that start with the supplied parts 211 | of the tuple are accepted, but nothing that would be greater than the 212 | provided tuple parts. 213 | 214 | * `1.2.3 - 2.3` := `>=1.2.3 <2.4.0` 215 | * `1.2.3 - 2` := `>=1.2.3 <3.0.0` 216 | 217 | ##### X-Ranges `1.2.x` `1.X` `1.2.*` `*` 218 | 219 | Any of `X`, `x`, or `*` may be used to "stand in" for one of the 220 | numeric values in the `[major, minor, patch]` tuple. 221 | 222 | * `*` := `>=0.0.0` (Any version satisfies) 223 | * `1.x` := `>=1.0.0 <2.0.0` (Matching major version) 224 | * `1.2.x` := `>=1.2.0 <1.3.0` (Matching major and minor versions) 225 | 226 | A partial version range is treated as an X-Range, so the special 227 | character is in fact optional. 228 | 229 | * `""` (empty string) := `*` := `>=0.0.0` 230 | * `1` := `1.x.x` := `>=1.0.0 <2.0.0` 231 | * `1.2` := `1.2.x` := `>=1.2.0 <1.3.0` 232 | 233 | ##### Tilde Ranges `~1.2.3` `~1.2` `~1` 234 | 235 | Allows patch-level changes if a minor version is specified on the 236 | comparator. Allows minor-level changes if not. 237 | 238 | * `~1.2.3` := `>=1.2.3 <1.(2+1).0` := `>=1.2.3 <1.3.0` 239 | * `~1.2` := `>=1.2.0 <1.(2+1).0` := `>=1.2.0 <1.3.0` (Same as `1.2.x`) 240 | * `~1` := `>=1.0.0 <(1+1).0.0` := `>=1.0.0 <2.0.0` (Same as `1.x`) 241 | * `~0.2.3` := `>=0.2.3 <0.(2+1).0` := `>=0.2.3 <0.3.0` 242 | * `~0.2` := `>=0.2.0 <0.(2+1).0` := `>=0.2.0 <0.3.0` (Same as `0.2.x`) 243 | * `~0` := `>=0.0.0 <(0+1).0.0` := `>=0.0.0 <1.0.0` (Same as `0.x`) 244 | * `~1.2.3-beta.2` := `>=1.2.3-beta.2 <1.3.0` Note that prereleases in 245 | the `1.2.3` version will be allowed, if they are greater than or 246 | equal to `beta.2`. So, `1.2.3-beta.4` would be allowed, but 247 | `1.2.4-beta.2` would not, because it is a prerelease of a 248 | different `[major, minor, patch]` tuple. 249 | 250 | #### Caret Ranges `^1.2.3` `^0.2.5` `^0.0.4` 251 | 252 | Allows changes that do not modify the left-most non-zero digit in the 253 | `[major, minor, patch]` tuple. In other words, this allows patch and 254 | minor updates for versions `1.0.0` and above, patch updates for 255 | versions `0.X >=0.1.0`, and *no* updates for versions `0.0.X`. 256 | 257 | Many authors treat a `0.x` version as if the `x` were the major 258 | "breaking-change" indicator. 259 | 260 | Caret ranges are ideal when an author may make breaking changes 261 | between `0.2.4` and `0.3.0` releases, which is a common practice. 262 | However, it presumes that there will *not* be breaking changes between 263 | `0.2.4` and `0.2.5`. It allows for changes that are presumed to be 264 | additive (but non-breaking), according to commonly observed practices. 265 | 266 | * `^1.2.3` := `>=1.2.3 <2.0.0` 267 | * `^0.2.3` := `>=0.2.3 <0.3.0` 268 | * `^0.0.3` := `>=0.0.3 <0.0.4` 269 | * `^1.2.3-beta.2` := `>=1.2.3-beta.2 <2.0.0` Note that prereleases in 270 | the `1.2.3` version will be allowed, if they are greater than or 271 | equal to `beta.2`. So, `1.2.3-beta.4` would be allowed, but 272 | `1.2.4-beta.2` would not, because it is a prerelease of a 273 | different `[major, minor, patch]` tuple. 274 | * `^0.0.3-beta` := `>=0.0.3-beta <0.0.4` Note that prereleases in the 275 | `0.0.3` version *only* will be allowed, if they are greater than or 276 | equal to `beta`. So, `0.0.3-pr.2` would be allowed. 277 | 278 | When parsing caret ranges, a missing `patch` value desugars to the 279 | number `0`, but will allow flexibility within that value, even if the 280 | major and minor versions are both `0`. 281 | 282 | * `^1.2.x` := `>=1.2.0 <2.0.0` 283 | * `^0.0.x` := `>=0.0.0 <0.1.0` 284 | * `^0.0` := `>=0.0.0 <0.1.0` 285 | 286 | A missing `minor` and `patch` values will desugar to zero, but also 287 | allow flexibility within those values, even if the major version is 288 | zero. 289 | 290 | * `^1.x` := `>=1.0.0 <2.0.0` 291 | * `^0.x` := `>=0.0.0 <1.0.0` 292 | 293 | ## Credits 294 | 295 | The stuff was written by Lucas Abel and contributors 296 | - Marco Maggi 297 | 298 | ## Bugs, vulnerabilities and contributions 299 | 300 | 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. 301 | 302 | Reports about the original code must be registered at: 303 | 304 | 305 | ## Resources 306 | 307 | Development of the original projects takes place at: 308 | 309 | 310 | the GNU Project software can be found here: 311 | 312 | 313 | ## Badges and static analysis 314 | 315 | ### Travis CI 316 | 317 | 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: 318 | 319 | 320 | Usage of this service is configured through the file ".travis.yml". 321 | 322 | ### Clang's Static Analyzer 323 | 324 | 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: 325 | 326 | 327 | Usage of this service is implemented with make rules; see the relevant section in the file "Makefile.am". 328 | -------------------------------------------------------------------------------- /test/match.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This is free and unencumbered software released into the public domain. 3 | * 4 | * Anyone is free to copy, modify, publish, use, compile, sell, or 5 | * distribute this software, either in source code form or as a compiled 6 | * binary, for any purpose, commercial or non-commercial, and by any 7 | * means. 8 | * 9 | * In jurisdictions that recognize copyright laws, the author or authors 10 | * of this software dedicate any and all copyright interest in the 11 | * software to the public domain. We make this dedication for the benefit 12 | * of the public at large and to the detriment of our heirs and 13 | * successors. We intend this dedication to be an overt act of 14 | * relinquishment in perpetuity of all present and future rights to this 15 | * software under copyright law. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | * OTHER DEALINGS IN THE SOFTWARE. 24 | * 25 | * For more information, please refer to 26 | */ 27 | 28 | #include 29 | #include 30 | 31 | #include "semver.h" 32 | 33 | #define STRNSIZE(s) (s), sizeof(s)-1 34 | 35 | int test_matchn(bool expected, const char *semver_str, size_t semver_len, const char *comp_str, size_t comp_len) { 36 | bool result; 37 | semver_t semver = {0}; 38 | 39 | printf("test: `%.*s` ^ `%.*s`", (int) semver_len, semver_str, (int) comp_len, comp_str); 40 | if (semvern(&semver, semver_str, semver_len)) { 41 | puts(" \tcouldn't parse semver"); 42 | return 1; 43 | } 44 | result = semver_comp_matchn(&semver, comp_str, comp_len); 45 | printf(" \t=> %d\t", result); 46 | if (result != expected) { 47 | printf(" != `%d`\n", expected); 48 | semver_dtor(&semver); 49 | return 1; 50 | } 51 | printf(" == `%d`\n", expected); 52 | semver_dtor(&semver); 53 | return 0; 54 | } 55 | 56 | int test_rmatchn(bool expected, const char *semver_str, size_t semver_len, const char *range_str, size_t range_len) { 57 | bool result; 58 | semver_t semver = {0}; 59 | 60 | printf("test: `%.*s` ^ `%.*s`", (int) semver_len, semver_str, (int) range_len, range_str); 61 | if (semvern(&semver, semver_str, semver_len)) { 62 | puts(" \tcouldn't parse semver"); 63 | return 1; 64 | } 65 | result = semver_range_matchn(&semver, range_str, range_len); 66 | printf(" \t=> %d\t", result); 67 | if (result != expected) { 68 | printf(" != `%d`\n", expected); 69 | semver_dtor(&semver); 70 | return 1; 71 | } 72 | printf(" == `%d`\n", expected); 73 | semver_dtor(&semver); 74 | return 0; 75 | } 76 | 77 | int main(void) { 78 | if (test_matchn(true, STRNSIZE("v1.2.3"), STRNSIZE("1.2.3"))) { 79 | return EXIT_FAILURE; 80 | } 81 | if (test_matchn(true, STRNSIZE("v1.2.3"), STRNSIZE("1.2.x"))) { 82 | return EXIT_FAILURE; 83 | } 84 | if (test_matchn(true, STRNSIZE("v1.2.3"), STRNSIZE("1.x.x"))) { 85 | return EXIT_FAILURE; 86 | } 87 | if (test_matchn(true, STRNSIZE("v1.2.3"), STRNSIZE("1.x"))) { 88 | return EXIT_FAILURE; 89 | } 90 | if (test_matchn(true, STRNSIZE("v1.2.3"), STRNSIZE("1"))) { 91 | return EXIT_FAILURE; 92 | } 93 | if (test_matchn(true, STRNSIZE("v1.2.3"), STRNSIZE("*"))) { 94 | return EXIT_FAILURE; 95 | } 96 | if (test_matchn(true, STRNSIZE("v1.2.3"), STRNSIZE(">1"))) { 97 | return EXIT_FAILURE; 98 | } 99 | if (test_matchn(false, STRNSIZE("v1.2.3"), STRNSIZE(">2"))) { 100 | return EXIT_FAILURE; 101 | } 102 | if (test_matchn(false, STRNSIZE("v1.2.3"), STRNSIZE(">=2"))) { 103 | return EXIT_FAILURE; 104 | } 105 | if (test_matchn(false, STRNSIZE("v1.2.3"), STRNSIZE("<1"))) { 106 | return EXIT_FAILURE; 107 | } 108 | if (test_matchn(false, STRNSIZE("v1.2.3"), STRNSIZE("<=1"))) { 109 | return EXIT_FAILURE; 110 | } 111 | if (test_matchn(true, STRNSIZE("v1.2.3"), STRNSIZE(">=1.2.3"))) { 112 | return EXIT_FAILURE; 113 | } 114 | if (test_matchn(false, STRNSIZE("v1.2.3"), STRNSIZE(">1.2.3"))) { 115 | return EXIT_FAILURE; 116 | } 117 | if (test_matchn(false, STRNSIZE("v1.2.3"), STRNSIZE("<1.2.3"))) { 118 | return EXIT_FAILURE; 119 | } 120 | if (test_matchn(true, STRNSIZE("v1.2.3"), STRNSIZE("<=1.2.3"))) { 121 | return EXIT_FAILURE; 122 | } 123 | if (test_matchn(false, STRNSIZE("v1.2.3"), STRNSIZE("2.x"))) { 124 | return EXIT_FAILURE; 125 | } 126 | if (test_matchn(true, STRNSIZE("0.0.1-98"), STRNSIZE("<0.0.1-99"))) { 127 | return EXIT_FAILURE; 128 | } 129 | if (test_matchn(true, STRNSIZE("0.0.1-98"), STRNSIZE("<=0.0.1-99"))) { 130 | return EXIT_FAILURE; 131 | } 132 | if (test_matchn(true, STRNSIZE("0.0.1-98"), STRNSIZE("<=0.0.1-98"))) { 133 | return EXIT_FAILURE; 134 | } 135 | if (test_matchn(true, STRNSIZE("0.0.1-98"), STRNSIZE("=0.0.1-98"))) { 136 | return EXIT_FAILURE; 137 | } 138 | if (test_matchn(true, STRNSIZE("0.0.1-98"), STRNSIZE(">=0.0.1-98"))) { 139 | return EXIT_FAILURE; 140 | } 141 | if (test_matchn(true, STRNSIZE("0.0.1-98"), STRNSIZE(">=0.0.1-97"))) { 142 | return EXIT_FAILURE; 143 | } 144 | if (test_matchn(true, STRNSIZE("0.0.1-98"), STRNSIZE(">0.0.1-97"))) { 145 | return EXIT_FAILURE; 146 | } 147 | if (test_matchn(true, STRNSIZE("0.0.1-alpha"), STRNSIZE("0.0.1-alpha"))) { 148 | return EXIT_FAILURE; 149 | } 150 | if (test_matchn(true, STRNSIZE("0.0.1-98"), STRNSIZE("<0.0.1-99"))) { 151 | return EXIT_FAILURE; 152 | } 153 | if (test_matchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("<0.0.1-alpha.99"))) { 154 | return EXIT_FAILURE; 155 | } 156 | if (test_matchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("<=0.0.1-alpha.99"))) { 157 | return EXIT_FAILURE; 158 | } 159 | if (test_matchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("<=0.0.1-alpha.98"))) { 160 | return EXIT_FAILURE; 161 | } 162 | if (test_matchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("=0.0.1-alpha.98"))) { 163 | return EXIT_FAILURE; 164 | } 165 | if (test_matchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE(">=0.0.1-alpha.98"))) { 166 | return EXIT_FAILURE; 167 | } 168 | if (test_matchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE(">=0.0.1-alpha.97"))) { 169 | return EXIT_FAILURE; 170 | } 171 | if (test_matchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE(">0.0.1-alpha.97"))) { 172 | return EXIT_FAILURE; 173 | } 174 | if (test_matchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("<0.0.1-alpha.99.1"))) { 175 | return EXIT_FAILURE; 176 | } 177 | if (test_matchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("<=0.0.1-alpha.99.1"))) { 178 | return EXIT_FAILURE; 179 | } 180 | if (test_matchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("<=0.0.1-alpha.98.1"))) { 181 | return EXIT_FAILURE; 182 | } 183 | if (test_matchn(false, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("=0.0.1-alpha.98.1"))) { 184 | return EXIT_FAILURE; 185 | } 186 | if (test_matchn(false, STRNSIZE("0.0.1-alpha.98"), STRNSIZE(">=0.0.1-alpha.98.1"))) { 187 | return EXIT_FAILURE; 188 | } 189 | if (test_matchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE(">=0.0.1-alpha.97.1"))) { 190 | return EXIT_FAILURE; 191 | } 192 | if (test_matchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE(">0.0.1-alpha.97.1"))) { 193 | return EXIT_FAILURE; 194 | } 195 | if (test_matchn(true, STRNSIZE("0.0.1-alpha.98.1.3"), STRNSIZE("<0.0.1-alpha.99.1"))) { 196 | return EXIT_FAILURE; 197 | } 198 | if (test_matchn(true, STRNSIZE("0.0.1-alpha.98.1.3"), STRNSIZE("<=0.0.1-alpha.99.1"))) { 199 | return EXIT_FAILURE; 200 | } 201 | if (test_matchn(false, STRNSIZE("0.0.1-alpha.98.1.3"), STRNSIZE("<=0.0.1-alpha.98.1"))) { 202 | return EXIT_FAILURE; 203 | } 204 | if (test_matchn(false, STRNSIZE("0.0.1-alpha.98.1.3"), STRNSIZE("=0.0.1-alpha.98.1"))) { 205 | return EXIT_FAILURE; 206 | } 207 | if (test_matchn(true, STRNSIZE("0.0.1-alpha.98.1.3"), STRNSIZE(">=0.0.1-alpha.98.1"))) { 208 | return EXIT_FAILURE; 209 | } 210 | if (test_matchn(true, STRNSIZE("0.0.1-alpha.98.1.3"), STRNSIZE(">=0.0.1-alpha.97.1"))) { 211 | return EXIT_FAILURE; 212 | } 213 | if (test_matchn(true, STRNSIZE("0.0.1-alpha.98.1.3"), STRNSIZE(">0.0.1-alpha.97.1"))) { 214 | return EXIT_FAILURE; 215 | } 216 | 217 | if (test_rmatchn(true, STRNSIZE("v1.2.3"), STRNSIZE("9.x || 1.2.3"))) { 218 | return EXIT_FAILURE; 219 | } 220 | if (test_rmatchn(true, STRNSIZE("v1.2.3"), STRNSIZE("9.x || 1.2.x"))) { 221 | return EXIT_FAILURE; 222 | } 223 | if (test_rmatchn(true, STRNSIZE("v1.2.3"), STRNSIZE("9.x || 1.x.x"))) { 224 | return EXIT_FAILURE; 225 | } 226 | if (test_rmatchn(true, STRNSIZE("v1.2.3"), STRNSIZE("9.x || 1.x"))) { 227 | return EXIT_FAILURE; 228 | } 229 | if (test_rmatchn(true, STRNSIZE("v1.2.3"), STRNSIZE("9.x || 1"))) { 230 | return EXIT_FAILURE; 231 | } 232 | if (test_rmatchn(true, STRNSIZE("v1.2.3"), STRNSIZE("9.x || *"))) { 233 | return EXIT_FAILURE; 234 | } 235 | if (test_rmatchn(true, STRNSIZE("v1.2.3"), STRNSIZE("9.x || >1"))) { 236 | return EXIT_FAILURE; 237 | } 238 | if (test_rmatchn(false, STRNSIZE("v1.2.3"), STRNSIZE("9.x || >2"))) { 239 | return EXIT_FAILURE; 240 | } 241 | if (test_rmatchn(false, STRNSIZE("v1.2.3"), STRNSIZE("9.x || >=2"))) { 242 | return EXIT_FAILURE; 243 | } 244 | if (test_rmatchn(false, STRNSIZE("v1.2.3"), STRNSIZE("9.x || <1"))) { 245 | return EXIT_FAILURE; 246 | } 247 | if (test_rmatchn(false, STRNSIZE("v1.2.3"), STRNSIZE("9.x || <=1"))) { 248 | return EXIT_FAILURE; 249 | } 250 | if (test_rmatchn(true, STRNSIZE("v1.2.3"), STRNSIZE("9.x || >=1.2.3"))) { 251 | return EXIT_FAILURE; 252 | } 253 | if (test_rmatchn(false, STRNSIZE("v1.2.3"), STRNSIZE("9.x || >1.2.3"))) { 254 | return EXIT_FAILURE; 255 | } 256 | if (test_rmatchn(false, STRNSIZE("v1.2.3"), STRNSIZE("9.x || <1.2.3"))) { 257 | return EXIT_FAILURE; 258 | } 259 | if (test_rmatchn(true, STRNSIZE("v1.2.3"), STRNSIZE("9.x || <=1.2.3"))) { 260 | return EXIT_FAILURE; 261 | } 262 | if (test_rmatchn(false, STRNSIZE("v1.2.3"), STRNSIZE("9.x || 2.x"))) { 263 | return EXIT_FAILURE; 264 | } 265 | if (test_rmatchn(true, STRNSIZE("0.0.1-98"), STRNSIZE("9.x || <0.0.1-99"))) { 266 | return EXIT_FAILURE; 267 | } 268 | if (test_rmatchn(true, STRNSIZE("0.0.1-98"), STRNSIZE("9.x || <=0.0.1-99"))) { 269 | return EXIT_FAILURE; 270 | } 271 | if (test_rmatchn(true, STRNSIZE("0.0.1-98"), STRNSIZE("9.x || <=0.0.1-98"))) { 272 | return EXIT_FAILURE; 273 | } 274 | if (test_rmatchn(true, STRNSIZE("0.0.1-98"), STRNSIZE("9.x || =0.0.1-98"))) { 275 | return EXIT_FAILURE; 276 | } 277 | if (test_rmatchn(true, STRNSIZE("0.0.1-98"), STRNSIZE("9.x || >=0.0.1-98"))) { 278 | return EXIT_FAILURE; 279 | } 280 | if (test_rmatchn(true, STRNSIZE("0.0.1-98"), STRNSIZE("9.x || >=0.0.1-97"))) { 281 | return EXIT_FAILURE; 282 | } 283 | if (test_rmatchn(true, STRNSIZE("0.0.1-98"), STRNSIZE("9.x || >0.0.1-97"))) { 284 | return EXIT_FAILURE; 285 | } 286 | if (test_rmatchn(true, STRNSIZE("0.0.1-alpha"), STRNSIZE("9.x || 0.0.1-alpha"))) { 287 | return EXIT_FAILURE; 288 | } 289 | if (test_rmatchn(true, STRNSIZE("0.0.1-98"), STRNSIZE("9.x || <0.0.1-99"))) { 290 | return EXIT_FAILURE; 291 | } 292 | if (test_rmatchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("9.x || <0.0.1-alpha.99"))) { 293 | return EXIT_FAILURE; 294 | } 295 | if (test_rmatchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("9.x || <=0.0.1-alpha.99"))) { 296 | return EXIT_FAILURE; 297 | } 298 | if (test_rmatchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("9.x || <=0.0.1-alpha.98"))) { 299 | return EXIT_FAILURE; 300 | } 301 | if (test_rmatchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("9.x || =0.0.1-alpha.98"))) { 302 | return EXIT_FAILURE; 303 | } 304 | if (test_rmatchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("9.x || >=0.0.1-alpha.98"))) { 305 | return EXIT_FAILURE; 306 | } 307 | if (test_rmatchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("9.x || >=0.0.1-alpha.97"))) { 308 | return EXIT_FAILURE; 309 | } 310 | if (test_rmatchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("9.x || >0.0.1-alpha.97"))) { 311 | return EXIT_FAILURE; 312 | } 313 | if (test_rmatchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("9.x || <0.0.1-alpha.99.1"))) { 314 | return EXIT_FAILURE; 315 | } 316 | if (test_rmatchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("9.x || <=0.0.1-alpha.99.1"))) { 317 | return EXIT_FAILURE; 318 | } 319 | if (test_rmatchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("9.x || <=0.0.1-alpha.98.1"))) { 320 | return EXIT_FAILURE; 321 | } 322 | if (test_rmatchn(false, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("9.x || =0.0.1-alpha.98.1"))) { 323 | return EXIT_FAILURE; 324 | } 325 | if (test_rmatchn(false, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("9.x || >=0.0.1-alpha.98.1"))) { 326 | return EXIT_FAILURE; 327 | } 328 | if (test_rmatchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("9.x || >=0.0.1-alpha.97.1"))) { 329 | return EXIT_FAILURE; 330 | } 331 | if (test_rmatchn(true, STRNSIZE("0.0.1-alpha.98"), STRNSIZE("9.x || >0.0.1-alpha.97.1"))) { 332 | return EXIT_FAILURE; 333 | } 334 | if (test_rmatchn(true, STRNSIZE("0.0.1-alpha.98.1.3"), STRNSIZE("9.x || <0.0.1-alpha.99.1"))) { 335 | return EXIT_FAILURE; 336 | } 337 | if (test_rmatchn(true, STRNSIZE("0.0.1-alpha.98.1.3"), STRNSIZE("9.x || <=0.0.1-alpha.99.1"))) { 338 | return EXIT_FAILURE; 339 | } 340 | if (test_rmatchn(false, STRNSIZE("0.0.1-alpha.98.1.3"), STRNSIZE("9.x || <=0.0.1-alpha.98.1"))) { 341 | return EXIT_FAILURE; 342 | } 343 | if (test_rmatchn(false, STRNSIZE("0.0.1-alpha.98.1.3"), STRNSIZE("9.x || =0.0.1-alpha.98.1"))) { 344 | return EXIT_FAILURE; 345 | } 346 | if (test_rmatchn(true, STRNSIZE("0.0.1-alpha.98.1.3"), STRNSIZE("9.x || >=0.0.1-alpha.98.1"))) { 347 | return EXIT_FAILURE; 348 | } 349 | if (test_rmatchn(true, STRNSIZE("0.0.1-alpha.98.1.3"), STRNSIZE("9.x || >=0.0.1-alpha.97.1"))) { 350 | return EXIT_FAILURE; 351 | } 352 | if (test_rmatchn(true, STRNSIZE("0.0.1-alpha.98.1.3"), STRNSIZE("9.x || >0.0.1-alpha.97.1"))) { 353 | return EXIT_FAILURE; 354 | } 355 | 356 | return EXIT_SUCCESS; 357 | } 358 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | Installation Instructions 2 | ************************* 3 | 4 | Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005, 5 | 2006, 2007, 2008, 2009 Free Software Foundation, Inc. 6 | 7 | Copying and distribution of this file, with or without modification, 8 | are permitted in any medium without royalty provided the copyright 9 | notice and this notice are preserved. This file is offered as-is, 10 | without warranty of any kind. 11 | 12 | Basic Installation 13 | ================== 14 | 15 | Briefly, the shell commands `./configure; make; make install' should 16 | configure, build, and install this package. The following 17 | more-detailed instructions are generic; see the `README' file for 18 | instructions specific to this package. Some packages provide this 19 | `INSTALL' file but do not implement all of the features documented 20 | below. The lack of an optional feature in a given package is not 21 | necessarily a bug. More recommendations for GNU packages can be found 22 | in *note Makefile Conventions: (standards)Makefile Conventions. 23 | 24 | The `configure' shell script attempts to guess correct values for 25 | various system-dependent variables used during compilation. It uses 26 | those values to create a `Makefile' in each directory of the package. 27 | It may also create one or more `.h' files containing system-dependent 28 | definitions. Finally, it creates a shell script `config.status' that 29 | you can run in the future to recreate the current configuration, and a 30 | file `config.log' containing compiler output (useful mainly for 31 | debugging `configure'). 32 | 33 | It can also use an optional file (typically called `config.cache' 34 | and enabled with `--cache-file=config.cache' or simply `-C') that saves 35 | the results of its tests to speed up reconfiguring. Caching is 36 | disabled by default to prevent problems with accidental use of stale 37 | cache files. 38 | 39 | If you need to do unusual things to compile the package, please try 40 | to figure out how `configure' could check whether to do them, and mail 41 | diffs or instructions to the address given in the `README' so they can 42 | be considered for the next release. If you are using the cache, and at 43 | some point `config.cache' contains results you don't want to keep, you 44 | may remove or edit it. 45 | 46 | The file `configure.ac' (or `configure.in') is used to create 47 | `configure' by a program called `autoconf'. You need `configure.ac' if 48 | you want to change it or regenerate `configure' using a newer version 49 | of `autoconf'. 50 | 51 | The simplest way to compile this package is: 52 | 53 | 1. `cd' to the directory containing the package's source code and type 54 | `./configure' to configure the package for your system. 55 | 56 | Running `configure' might take a while. While running, it prints 57 | some messages telling which features it is checking for. 58 | 59 | 2. Type `make' to compile the package. 60 | 61 | 3. Optionally, type `make check' to run any self-tests that come with 62 | the package, generally using the just-built uninstalled binaries. 63 | 64 | 4. Type `make install' to install the programs and any data files and 65 | documentation. When installing into a prefix owned by root, it is 66 | recommended that the package be configured and built as a regular 67 | user, and only the `make install' phase executed with root 68 | privileges. 69 | 70 | 5. Optionally, type `make installcheck' to repeat any self-tests, but 71 | this time using the binaries in their final installed location. 72 | This target does not install anything. Running this target as a 73 | regular user, particularly if the prior `make install' required 74 | root privileges, verifies that the installation completed 75 | correctly. 76 | 77 | 6. You can remove the program binaries and object files from the 78 | source code directory by typing `make clean'. To also remove the 79 | files that `configure' created (so you can compile the package for 80 | a different kind of computer), type `make distclean'. There is 81 | also a `make maintainer-clean' target, but that is intended mainly 82 | for the package's developers. If you use it, you may have to get 83 | all sorts of other programs in order to regenerate files that came 84 | with the distribution. 85 | 86 | 7. Often, you can also type `make uninstall' to remove the installed 87 | files again. In practice, not all packages have tested that 88 | uninstallation works correctly, even though it is required by the 89 | GNU Coding Standards. 90 | 91 | 8. Some packages, particularly those that use Automake, provide `make 92 | distcheck', which can by used by developers to test that all other 93 | targets like `make install' and `make uninstall' work correctly. 94 | This target is generally not run by end users. 95 | 96 | Compilers and Options 97 | ===================== 98 | 99 | Some systems require unusual options for compilation or linking that 100 | the `configure' script does not know about. Run `./configure --help' 101 | for details on some of the pertinent environment variables. 102 | 103 | You can give `configure' initial values for configuration parameters 104 | by setting variables in the command line or in the environment. Here 105 | is an example: 106 | 107 | ./configure CC=c99 CFLAGS=-g LIBS=-lposix 108 | 109 | *Note Defining Variables::, for more details. 110 | 111 | Compiling For Multiple Architectures 112 | ==================================== 113 | 114 | You can compile the package for more than one kind of computer at the 115 | same time, by placing the object files for each architecture in their 116 | own directory. To do this, you can use GNU `make'. `cd' to the 117 | directory where you want the object files and executables to go and run 118 | the `configure' script. `configure' automatically checks for the 119 | source code in the directory that `configure' is in and in `..'. This 120 | is known as a "VPATH" build. 121 | 122 | With a non-GNU `make', it is safer to compile the package for one 123 | architecture at a time in the source code directory. After you have 124 | installed the package for one architecture, use `make distclean' before 125 | reconfiguring for another architecture. 126 | 127 | On MacOS X 10.5 and later systems, you can create libraries and 128 | executables that work on multiple system types--known as "fat" or 129 | "universal" binaries--by specifying multiple `-arch' options to the 130 | compiler but only a single `-arch' option to the preprocessor. Like 131 | this: 132 | 133 | ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ 134 | CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ 135 | CPP="gcc -E" CXXCPP="g++ -E" 136 | 137 | This is not guaranteed to produce working output in all cases, you 138 | may have to build one architecture at a time and combine the results 139 | using the `lipo' tool if you have problems. 140 | 141 | Installation Names 142 | ================== 143 | 144 | By default, `make install' installs the package's commands under 145 | `/usr/local/bin', include files under `/usr/local/include', etc. You 146 | can specify an installation prefix other than `/usr/local' by giving 147 | `configure' the option `--prefix=PREFIX', where PREFIX must be an 148 | absolute file name. 149 | 150 | You can specify separate installation prefixes for 151 | architecture-specific files and architecture-independent files. If you 152 | pass the option `--exec-prefix=PREFIX' to `configure', the package uses 153 | PREFIX as the prefix for installing programs and libraries. 154 | Documentation and other data files still use the regular prefix. 155 | 156 | In addition, if you use an unusual directory layout you can give 157 | options like `--bindir=DIR' to specify different values for particular 158 | kinds of files. Run `configure --help' for a list of the directories 159 | you can set and what kinds of files go in them. In general, the 160 | default for these options is expressed in terms of `${prefix}', so that 161 | specifying just `--prefix' will affect all of the other directory 162 | specifications that were not explicitly provided. 163 | 164 | The most portable way to affect installation locations is to pass the 165 | correct locations to `configure'; however, many packages provide one or 166 | both of the following shortcuts of passing variable assignments to the 167 | `make install' command line to change installation locations without 168 | having to reconfigure or recompile. 169 | 170 | The first method involves providing an override variable for each 171 | affected directory. For example, `make install 172 | prefix=/alternate/directory' will choose an alternate location for all 173 | directory configuration variables that were expressed in terms of 174 | `${prefix}'. Any directories that were specified during `configure', 175 | but not in terms of `${prefix}', must each be overridden at install 176 | time for the entire installation to be relocated. The approach of 177 | makefile variable overrides for each directory variable is required by 178 | the GNU Coding Standards, and ideally causes no recompilation. 179 | However, some platforms have known limitations with the semantics of 180 | shared libraries that end up requiring recompilation when using this 181 | method, particularly noticeable in packages that use GNU Libtool. 182 | 183 | The second method involves providing the `DESTDIR' variable. For 184 | example, `make install DESTDIR=/alternate/directory' will prepend 185 | `/alternate/directory' before all installation names. The approach of 186 | `DESTDIR' overrides is not required by the GNU Coding Standards, and 187 | does not work on platforms that have drive letters. On the other hand, 188 | it does better at avoiding recompilation issues, and works well even 189 | when some directory options were not specified in terms of `${prefix}' 190 | at `configure' time. 191 | 192 | Optional Features 193 | ================= 194 | 195 | If the package supports it, you can cause programs to be installed 196 | with an extra prefix or suffix on their names by giving `configure' the 197 | option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. 198 | 199 | Some packages pay attention to `--enable-FEATURE' options to 200 | `configure', where FEATURE indicates an optional part of the package. 201 | They may also pay attention to `--with-PACKAGE' options, where PACKAGE 202 | is something like `gnu-as' or `x' (for the X Window System). The 203 | `README' should mention any `--enable-' and `--with-' options that the 204 | package recognizes. 205 | 206 | For packages that use the X Window System, `configure' can usually 207 | find the X include and library files automatically, but if it doesn't, 208 | you can use the `configure' options `--x-includes=DIR' and 209 | `--x-libraries=DIR' to specify their locations. 210 | 211 | Some packages offer the ability to configure how verbose the 212 | execution of `make' will be. For these packages, running `./configure 213 | --enable-silent-rules' sets the default to minimal output, which can be 214 | overridden with `make V=1'; while running `./configure 215 | --disable-silent-rules' sets the default to verbose, which can be 216 | overridden with `make V=0'. 217 | 218 | Particular systems 219 | ================== 220 | 221 | On HP-UX, the default C compiler is not ANSI C compatible. If GNU 222 | CC is not installed, it is recommended to use the following options in 223 | order to use an ANSI C compiler: 224 | 225 | ./configure CC="cc -Ae -D_XOPEN_SOURCE=500" 226 | 227 | and if that doesn't work, install pre-built binaries of GCC for HP-UX. 228 | 229 | On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot 230 | parse its `' header file. The option `-nodtk' can be used as 231 | a workaround. If GNU CC is not installed, it is therefore recommended 232 | to try 233 | 234 | ./configure CC="cc" 235 | 236 | and if that doesn't work, try 237 | 238 | ./configure CC="cc -nodtk" 239 | 240 | On Solaris, don't put `/usr/ucb' early in your `PATH'. This 241 | directory contains several dysfunctional programs; working variants of 242 | these programs are available in `/usr/bin'. So, if you need `/usr/ucb' 243 | in your `PATH', put it _after_ `/usr/bin'. 244 | 245 | On Haiku, software installed for all users goes in `/boot/common', 246 | not `/usr/local'. It is recommended to use the following options: 247 | 248 | ./configure --prefix=/boot/common 249 | 250 | Specifying the System Type 251 | ========================== 252 | 253 | There may be some features `configure' cannot figure out 254 | automatically, but needs to determine by the type of machine the package 255 | will run on. Usually, assuming the package is built to be run on the 256 | _same_ architectures, `configure' can figure that out, but if it prints 257 | a message saying it cannot guess the machine type, give it the 258 | `--build=TYPE' option. TYPE can either be a short name for the system 259 | type, such as `sun4', or a canonical name which has the form: 260 | 261 | CPU-COMPANY-SYSTEM 262 | 263 | where SYSTEM can have one of these forms: 264 | 265 | OS 266 | KERNEL-OS 267 | 268 | See the file `config.sub' for the possible values of each field. If 269 | `config.sub' isn't included in this package, then this package doesn't 270 | need to know the machine type. 271 | 272 | If you are _building_ compiler tools for cross-compiling, you should 273 | use the option `--target=TYPE' to select the type of system they will 274 | produce code for. 275 | 276 | If you want to _use_ a cross compiler, that generates code for a 277 | platform different from the build platform, you should specify the 278 | "host" platform (i.e., that on which the generated programs will 279 | eventually be run) with `--host=TYPE'. 280 | 281 | Sharing Defaults 282 | ================ 283 | 284 | If you want to set default values for `configure' scripts to share, 285 | you can create a site shell script called `config.site' that gives 286 | default values for variables like `CC', `cache_file', and `prefix'. 287 | `configure' looks for `PREFIX/share/config.site' if it exists, then 288 | `PREFIX/etc/config.site' if it exists. Or, you can set the 289 | `CONFIG_SITE' environment variable to the location of the site script. 290 | A warning: not all `configure' scripts look for a site script. 291 | 292 | Defining Variables 293 | ================== 294 | 295 | Variables not defined in a site shell script can be set in the 296 | environment passed to `configure'. However, some packages may run 297 | configure again during the build, and the customized values of these 298 | variables may be lost. In order to avoid this problem, you should set 299 | them in the `configure' command line, using `VAR=value'. For example: 300 | 301 | ./configure CC=/usr/local2/bin/gcc 302 | 303 | causes the specified `gcc' to be used as the C compiler (unless it is 304 | overridden in the site shell script). 305 | 306 | Unfortunately, this technique does not work for `CONFIG_SHELL' due to 307 | an Autoconf bug. Until the bug is fixed you can use this workaround: 308 | 309 | CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash 310 | 311 | `configure' Invocation 312 | ====================== 313 | 314 | `configure' recognizes the following options to control how it 315 | operates. 316 | 317 | `--help' 318 | `-h' 319 | Print a summary of all of the options to `configure', and exit. 320 | 321 | `--help=short' 322 | `--help=recursive' 323 | Print a summary of the options unique to this package's 324 | `configure', and exit. The `short' variant lists options used 325 | only in the top level, while the `recursive' variant lists options 326 | also present in any nested packages. 327 | 328 | `--version' 329 | `-V' 330 | Print the version of Autoconf used to generate the `configure' 331 | script, and exit. 332 | 333 | `--cache-file=FILE' 334 | Enable the cache: use and save the results of the tests in FILE, 335 | traditionally `config.cache'. FILE defaults to `/dev/null' to 336 | disable caching. 337 | 338 | `--config-cache' 339 | `-C' 340 | Alias for `--cache-file=config.cache'. 341 | 342 | `--quiet' 343 | `--silent' 344 | `-q' 345 | Do not print messages saying which checks are being made. To 346 | suppress all normal output, redirect it to `/dev/null' (any error 347 | messages will still be shown). 348 | 349 | `--srcdir=DIR' 350 | Look for the package's source code in directory DIR. Usually 351 | `configure' can determine that directory automatically. 352 | 353 | `--prefix=DIR' 354 | Use DIR as the installation prefix. *note Installation Names:: 355 | for more details, including other options available for fine-tuning 356 | the installation locations. 357 | 358 | `--no-create' 359 | `-n' 360 | Run the configure checks, but stop before creating any output 361 | files. 362 | 363 | `configure' also accepts some other, not widely useful, options. Run 364 | `configure --help' for more details. 365 | --------------------------------------------------------------------------------