├── .github └── workflows │ ├── release.yml │ └── tests.yml ├── .gitignore ├── .npmrc ├── BEST_PRACTICE.md ├── History.md ├── LICENSE ├── Makefile ├── Readme.md ├── clib.json ├── deps ├── asprintf │ ├── asprintf.c │ ├── asprintf.h │ └── package.json ├── assertion-macros │ ├── assertion-macros.h │ └── package.json ├── case │ ├── case.c │ ├── case.h │ └── package.json ├── commander │ ├── clib.json │ ├── commander.c │ ├── commander.h │ └── package.json ├── console-colors │ ├── console-colors.c │ ├── console-colors.h │ └── package.json ├── copy │ ├── clib.json │ ├── copy.c │ ├── copy.h │ └── package.json ├── debug │ ├── debug.c │ ├── debug.h │ └── package.json ├── describe │ ├── describe.h │ └── package.json ├── fs │ ├── clib.json │ ├── fs.c │ ├── fs.h │ └── package.json ├── gumbo-get-element-by-id │ ├── get-element-by-id.c │ ├── get-element-by-id.h │ └── package.json ├── gumbo-get-elements-by-tag-name │ ├── get-elements-by-tag-name.c │ ├── get-elements-by-tag-name.h │ └── package.json ├── gumbo-parser │ ├── attribute.c │ ├── attribute.h │ ├── char_ref.c │ ├── char_ref.h │ ├── error.c │ ├── error.h │ ├── gumbo.h │ ├── insertion_mode.h │ ├── package.json │ ├── parser.c │ ├── parser.h │ ├── string_buffer.c │ ├── string_buffer.h │ ├── string_piece.c │ ├── string_piece.h │ ├── tag.c │ ├── token_type.h │ ├── tokenizer.c │ ├── tokenizer.h │ ├── tokenizer_states.h │ ├── utf8.c │ ├── utf8.h │ ├── util.c │ ├── util.h │ ├── vector.c │ └── vector.h ├── gumbo-text-content │ ├── gumbo-text-content.c │ ├── gumbo-text-content.h │ └── package.json ├── hash │ ├── clib.json │ ├── hash.c │ ├── hash.h │ ├── khash.h │ └── package.json ├── http-get │ ├── clib.json │ ├── http-get.c │ └── http-get.h ├── list │ ├── list.c │ ├── list.h │ ├── list_iterator.c │ ├── list_node.c │ └── package.json ├── logger │ ├── clib.json │ ├── logger.h │ └── package.json ├── mkdirp │ ├── mkdirp.c │ ├── mkdirp.h │ └── package.json ├── occurrences │ ├── occurrences.c │ ├── occurrences.h │ └── package.json ├── parse-repo │ ├── package.json │ ├── parse-repo.c │ └── parse-repo.h ├── parson │ ├── clib.json │ ├── package.json │ ├── parson.c │ └── parson.h ├── path-join │ ├── package.json │ ├── path-join.c │ └── path-join.h ├── path-normalize │ ├── package.json │ ├── path-normalize.c │ └── path-normalize.h ├── rimraf │ ├── package.json │ ├── rimraf.c │ └── rimraf.h ├── semver │ ├── package.json │ ├── semver.c │ └── semver.h ├── str-ends-with │ ├── package.json │ ├── str-ends-with.c │ └── str-ends-with.h ├── str-flatten │ ├── package.json │ ├── str-flatten.c │ └── str-flatten.h ├── str-replace │ ├── package.json │ ├── str-replace.c │ └── str-replace.h ├── str-starts-with │ ├── package.json │ ├── str-starts-with.c │ └── str-starts-with.h ├── strdup │ ├── clib.json │ ├── package.json │ ├── strdup.c │ └── strdup.h ├── substr │ ├── package.json │ ├── substr.c │ └── substr.h ├── tempdir │ ├── package.json │ ├── tempdir.c │ └── tempdir.h ├── tinydir │ ├── package.json │ └── tinydir.h ├── trim │ ├── package.json │ ├── trim.c │ └── trim.h ├── which │ ├── clib.json │ ├── package.json │ ├── which.c │ └── which.h ├── wiki-registry │ ├── package.json │ ├── wiki-registry.c │ └── wiki-registry.h └── wildcardcmp │ ├── clib.json │ ├── package.json │ ├── wildcardcmp.c │ └── wildcardcmp.h ├── package.json ├── scripts ├── ccan2clib.py ├── convert_all_ccan2clib.sh ├── feature-test-pthreads ├── pre-commit-hook.sh └── update-clib-json ├── src ├── clib-build.c ├── clib-configure.c ├── clib-init.c ├── clib-install.c ├── clib-search.c ├── clib-uninstall.c ├── clib-update.c ├── clib-upgrade.c ├── clib.c ├── common │ ├── clib-cache.c │ ├── clib-cache.h │ ├── clib-package.c │ ├── clib-package.h │ ├── clib-release-info.c │ ├── clib-release-info.h │ ├── clib-settings.c │ ├── clib-settings.h │ ├── clib-validate.c │ └── clib-validate.h └── version.h ├── test.sh └── test ├── cache ├── Makefile └── cache-test.c ├── data └── test-save-package.json ├── fuzzing └── fuzz_manifest.c ├── gh-35-exit-codes.sh ├── help.sh ├── install-binary-dependencies.sh ├── install-brace-expansion.sh ├── install-deps-from-package-json.sh ├── install-multiple-clibs-libs.sh ├── install-multiple-libs.sh ├── install-no-save.sh ├── install-save.sh ├── package ├── Makefile ├── clib.json ├── package-dependency-new.c ├── package-install-dependencies.c ├── package-install-dev-dependencies.c ├── package-install.c ├── package-load-from-manifest.c ├── package-load-manifest-file.c ├── package-new-from-slug.c ├── package-new.c ├── package-parse-author.c ├── package-parse-name.c ├── package-parse-version.c └── package-url.c ├── search-basic.sh ├── search-no-color.sh └── uninstall.sh /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | linux: 7 | name: Linux 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v4 11 | - name: System Setup 12 | shell: bash 13 | run: | 14 | sudo apt update -y 15 | sudo apt install -qq libcurl4-gnutls-dev 16 | - name: Run Tests 17 | run: | 18 | make 19 | sudo make test 20 | 21 | macos: 22 | name: macOS 23 | runs-on: macos-latest 24 | steps: 25 | - uses: actions/checkout@v4 26 | - name: System Setup 27 | shell: bash 28 | run: brew install curl 29 | - name: Run Tests 30 | run: | 31 | make 32 | sudo make test 33 | 34 | windows: 35 | name: Windows 36 | runs-on: ubuntu-latest 37 | steps: 38 | - uses: actions/checkout@v4 39 | - name: System Setup 40 | shell: bash 41 | run: | 42 | mkdir -p dockcross 43 | sudo docker run --rm dockcross/windows-x64 > dockcross-windows-x64 44 | cat dockcross-windows-x64 45 | chmod +x dockcross-windows-x64 46 | wget https://curl.haxx.se/download/curl-7.80.0.tar.gz 47 | tar xzf curl-* 48 | CURL_SRC=curl-* 49 | ./dockcross-windows-x64 bash -c 'cd '"$CURL_SRC"' && ./configure --prefix="/work/deps/curl" --host=x86_64-w64-mingw32.static --disable-shared --with-schannel --disable-dependency-tracking --enable-threaded-resolver --disable-imap --disable-pop3 --disable-smtp --disable-ldap --disable-mqtt --disable-smb' 50 | ./dockcross-windows-x64 bash -c 'cd '"$CURL_SRC"' && make' 51 | ./dockcross-windows-x64 bash -c 'cd '"$CURL_SRC"' && make install' 52 | - name: Run Tests 53 | run: | 54 | ## if builds pass then its passing for now 55 | ./dockcross-windows-x64 make all STATIC=true EXE=true 56 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | clib 3 | clib-install 4 | clib-search 5 | *.exe 6 | *.o 7 | *.d 8 | tmp/ 9 | /clib-init 10 | /clib-configure 11 | package-lock.json 12 | clib-build 13 | clib-update 14 | clib-upgrade 15 | clib-uninstall 16 | 17 | test/package/package-* 18 | !test/package/package-*.c 19 | 20 | test/cache/* 21 | !test/cache/*.c 22 | !test/cache/Makefile 23 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | tag-version-prefix="" 2 | message="chore(release): %s" 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2012-2020 clib authors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC ?= cc 2 | PREFIX ?= /usr/local 3 | 4 | BINS = clib clib-install clib-search clib-init clib-configure clib-build clib-update clib-upgrade clib-uninstall 5 | 6 | ifdef EXE 7 | BINS := $(addsuffix .exe,$(BINS)) 8 | endif 9 | 10 | CP = cp -f 11 | RM = rm -f 12 | MKDIR = mkdir -p 13 | INSTALL = install 14 | 15 | SRC = $(wildcard src/*.c) 16 | COMMON_SRC = $(wildcard src/common/*.c) 17 | ALL_SRC = $(wildcard src/*.c src/*.h src/common/*.c src/common/*.h test/package/*.c test/cache/*.c) 18 | SDEPS = $(wildcard deps/*/*.c) 19 | ODEPS = $(SDEPS:.c=.o) 20 | DEPS = $(filter-out $(ODEPS), $(SDEPS)) 21 | OBJS = $(DEPS:.c=.o) 22 | MAKEFILES = $(wildcard deps/*/Makefile) 23 | HEADERS_BINS = src/common/*.h src/version.h deps/logger/logger.h 24 | 25 | export CC 26 | 27 | CFLAGS += -std=c99 -Ideps -Wall -Wno-unused-function -U__STRICT_ANSI__ 28 | 29 | ifdef STATIC 30 | CFLAGS += -DCURL_STATICLIB $(shell deps/curl/bin/curl-config --cflags) 31 | LDFLAGS += -static $(shell deps/curl/bin/curl-config --static-libs) 32 | else 33 | CFLAGS += $(shell curl-config --cflags) 34 | LDFLAGS += $(shell curl-config --libs) 35 | endif 36 | 37 | ifneq (0,$(PTHREADS)) 38 | ifndef NO_PTHREADS 39 | CFLAGS += $(shell ./scripts/feature-test-pthreads && echo "-DHAVE_PTHREADS=1 -pthread") 40 | endif 41 | endif 42 | 43 | ifdef DEBUG 44 | CFLAGS += -g -D CLIB_DEBUG=1 -D DEBUG="$(DEBUG)" 45 | endif 46 | 47 | default: all 48 | 49 | all: $(BINS) 50 | 51 | build: $(BINS) 52 | 53 | $(BINS): $(SRC) $(COMMON_SRC) $(MAKEFILES) $(OBJS) $(HEADERS_BINS) 54 | $(CC) $(CFLAGS) -o $@ $(COMMON_SRC) src/$(@:.exe=).c $(OBJS) $(LDFLAGS) 55 | 56 | $(MAKEFILES): 57 | $(MAKE) -C $@ 58 | 59 | %.o: %.c 60 | $(CC) $< -c -o $@ $(CFLAGS) -MMD 61 | 62 | clean: 63 | $(foreach c, $(BINS), $(RM) $(c);) 64 | $(RM) $(OBJS) 65 | $(RM) $(AUTODEPS) 66 | cd test/cache && make clean 67 | cd test/package && make clean 68 | 69 | install: $(BINS) 70 | $(MKDIR) $(PREFIX)/bin 71 | $(foreach c, $(BINS), $(INSTALL) $(c) $(PREFIX)/bin/$(c);) 72 | 73 | uninstall: 74 | $(foreach c, $(BINS), $(RM) $(PREFIX)/bin/$(c);) 75 | 76 | test: $(BINS) 77 | @./test.sh 78 | 79 | # create a list of auto dependencies 80 | AUTODEPS:= $(patsubst %.c,%.d, $(DEPS)) $(patsubst %.c,%.d, $(SRC)) 81 | 82 | # include by auto dependencies 83 | -include $(AUTODEPS) 84 | 85 | # Format all source files in the repository. 86 | fmt: 87 | @if ! command -v clang-format &> /dev/null; then \ 88 | echo "clang-format not found"; \ 89 | exit; \ 90 | fi 91 | clang-format -i -style=LLVM $(ALL_SRC) 92 | 93 | # Install the commit hook. 94 | commit-hook: scripts/pre-commit-hook.sh 95 | cp -f scripts/pre-commit-hook.sh .git/hooks/pre-commit 96 | 97 | .PHONY: test all clean install uninstall fmt 98 | -------------------------------------------------------------------------------- /clib.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "clib", 3 | "version": "2.8.7", 4 | "repo": "clibs/clib", 5 | "install": "make clean uninstall build install", 6 | "makefile": "Makefile", 7 | "dependencies": { 8 | "stephenmathieson/trim.c": "0.0.2", 9 | "which": "0.1.3", 10 | "stephenmathieson/str-flatten.c": "0.0.4", 11 | "commander": "1.3.2", 12 | "clibs/wiki-registry.c": "0.1.2", 13 | "stephenmathieson/case.c": "0.1.3", 14 | "jwerle/fs.c": "0.2.0", 15 | "stephenmathieson/str-replace.c": "0.0.6", 16 | "strdup": "*", 17 | "Constellation/console-colors.c": "1.0.1", 18 | "littlstar/asprintf.c": "0.0.3", 19 | "logger": "0.0.1", 20 | "clibs/parson": "1.0.2", 21 | "clibs/http-get.c": "*", 22 | "hash": "0.0.1", 23 | "list": "*", 24 | "stephenmathieson/substr.c": "0.1.2", 25 | "stephenmathieson/mkdirp.c": "0.1.5", 26 | "stephenmathieson/path-join.c": "0.0.6", 27 | "stephenmathieson/parse-repo.c": "1.1.1", 28 | "stephenmathieson/debug.c": "0.0.0", 29 | "stephenmathieson/tempdir.c": "0.0.2", 30 | "isty001/copy": "0.0.0", 31 | "stephenmathieson/rimraf.c": "0.1.0", 32 | "h2non/semver.c@v1.0.0": "v1.0.0" 33 | }, 34 | "development": { 35 | "stephenmathieson/describe.h": "2.0.1" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /deps/asprintf/asprintf.c: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * `asprintf.c' - asprintf 4 | * 5 | * copyright (c) 2014 joseph werle 6 | */ 7 | 8 | #ifndef HAVE_ASPRINTF 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | #include "asprintf.h" 15 | 16 | int 17 | asprintf (char **str, const char *fmt, ...) { 18 | int size = 0; 19 | va_list args; 20 | 21 | // init variadic argumens 22 | va_start(args, fmt); 23 | 24 | // format and get size 25 | size = vasprintf(str, fmt, args); 26 | 27 | // toss args 28 | va_end(args); 29 | 30 | return size; 31 | } 32 | 33 | int 34 | vasprintf (char **str, const char *fmt, va_list args) { 35 | int size = 0; 36 | va_list tmpa; 37 | 38 | // copy 39 | va_copy(tmpa, args); 40 | 41 | // apply variadic arguments to 42 | // sprintf with format to get size 43 | size = vsnprintf(NULL, size, fmt, tmpa); 44 | 45 | // toss args 46 | va_end(tmpa); 47 | 48 | // return -1 to be compliant if 49 | // size is less than 0 50 | if (size < 0) { return -1; } 51 | 52 | // alloc with size plus 1 for `\0' 53 | *str = (char *) malloc(size + 1); 54 | 55 | // return -1 to be compliant 56 | // if pointer is `NULL' 57 | if (NULL == *str) { return -1; } 58 | 59 | // format string with original 60 | // variadic arguments and set new size 61 | size = vsprintf(*str, fmt, args); 62 | return size; 63 | } 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /deps/asprintf/asprintf.h: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * `asprintf.h' - asprintf.c 4 | * 5 | * copyright (c) 2014 joseph werle 6 | */ 7 | 8 | #ifndef HAVE_ASPRINTF 9 | #ifndef ASPRINTF_H 10 | #define ASPRINTF_H 1 11 | 12 | #include 13 | 14 | /** 15 | * Sets `char **' pointer to be a buffer 16 | * large enough to hold the formatted string 17 | * accepting a `va_list' args of variadic 18 | * arguments. 19 | */ 20 | 21 | int 22 | vasprintf (char **, const char *, va_list); 23 | 24 | /** 25 | * Sets `char **' pointer to be a buffer 26 | * large enough to hold the formatted 27 | * string accepting `n' arguments of 28 | * variadic arguments. 29 | */ 30 | 31 | int 32 | asprintf (char **, const char *, ...); 33 | 34 | #endif 35 | #endif 36 | -------------------------------------------------------------------------------- /deps/asprintf/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "asprintf", 3 | "version": "0.0.3", 4 | "repo": "littlstar/asprintf.c", 5 | "description": "asprintf() implementation", 6 | "keywords": ["asprintf", "sprintf", "alloc", "string"], 7 | "src": ["asprintf.h", "asprintf.c"] 8 | } 9 | 10 | -------------------------------------------------------------------------------- /deps/assertion-macros/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "assertion-macros", 3 | "version": "0.2.1", 4 | "repo": "stephenmathieson/assertion-macros.h", 5 | "description": "Simple assertion macros", 6 | "keywords": [ "assert", "assertions" ], 7 | "license": "MIT", 8 | "src": [ "assertion-macros.h" ] 9 | } 10 | -------------------------------------------------------------------------------- /deps/case/case.c: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // case.c 4 | // 5 | // Copyright (c) 2014 Stephen Mathieson 6 | // MIT licensed 7 | // 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include "case.h" 14 | 15 | #define CASE_MODIFIER 0x20 16 | #define CASE_IS_SEP(c) c == '-' || c == '_' || c == ' ' 17 | 18 | char * 19 | case_upper(char *str) { 20 | for (int i = 0, len = strlen(str); i < len; i++) { 21 | if (islower(str[i])) { 22 | str[i] &= ~CASE_MODIFIER; 23 | } 24 | } 25 | return str; 26 | } 27 | 28 | char * 29 | case_lower(char *str) { 30 | for (int i = 0, len = strlen(str); i < len; i++) { 31 | if (isupper(str[i])) { 32 | str[i] |= CASE_MODIFIER; 33 | } 34 | } 35 | return str; 36 | } 37 | 38 | char * 39 | case_camel(char *str) { 40 | for (int i = 0, len = strlen(str); i < len; i++) { 41 | if (CASE_IS_SEP(str[i])) { 42 | memmove(&str[i], &str[i + 1], len - i); 43 | // never cap the first char 44 | if (i && islower(str[i])) { 45 | str[i] &= ~CASE_MODIFIER; 46 | } 47 | // account for removing seperator 48 | i--; 49 | len--; 50 | } 51 | } 52 | 53 | return str; 54 | } 55 | -------------------------------------------------------------------------------- /deps/case/case.h: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // case.h 4 | // 5 | // Copyright (c) 2014 Stephen Mathieson 6 | // MIT licensed 7 | // 8 | 9 | 10 | #ifndef CASE_H 11 | #define CASE_H 12 | 13 | char * 14 | case_upper(char *); 15 | 16 | char * 17 | case_lower(char *); 18 | 19 | char * 20 | case_camel(char *); 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /deps/case/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "case", 3 | "version": "0.1.3", 4 | "repo": "stephenmathieson/case.c", 5 | "description": "String case conversion utility", 6 | "keywords": [ 7 | "string", 8 | "uppercase", 9 | "lowercase" 10 | ], 11 | "license": "MIT", 12 | "src": [ 13 | "src/case.c", 14 | "src/case.h" 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /deps/commander/clib.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "commander", 3 | "version": "1.3.2", 4 | "repo": "clibs/commander", 5 | "description": "Command-line argument parser", 6 | "keywords": ["cli", "command", "parser", "argv", "args", "options"], 7 | "license": "MIT", 8 | "src": ["src/commander.h", "src/commander.c"] 9 | } 10 | -------------------------------------------------------------------------------- /deps/commander/commander.h: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // commander.h 4 | // 5 | // Copyright (c) 2012 TJ Holowaychuk 6 | // 7 | 8 | #ifndef COMMANDER_H 9 | #define COMMANDER_H 10 | 11 | /* 12 | * Max options that can be defined. 13 | */ 14 | 15 | #ifndef COMMANDER_MAX_OPTIONS 16 | #define COMMANDER_MAX_OPTIONS 32 17 | #endif 18 | 19 | /* 20 | * Max arguments that can be passed. 21 | */ 22 | 23 | #ifndef COMMANDER_MAX_ARGS 24 | #define COMMANDER_MAX_ARGS 32 25 | #endif 26 | 27 | /* 28 | * Command struct. 29 | */ 30 | 31 | struct command; 32 | 33 | /* 34 | * Option callback. 35 | */ 36 | 37 | typedef void (* command_callback_t)(struct command *self); 38 | 39 | /* 40 | * Command option. 41 | */ 42 | 43 | typedef struct { 44 | int optional_arg; 45 | int required_arg; 46 | char *argname; 47 | char *large; 48 | const char *small; 49 | const char *large_with_arg; 50 | const char *description; 51 | command_callback_t cb; 52 | } command_option_t; 53 | 54 | /* 55 | * Command. 56 | */ 57 | 58 | typedef struct command { 59 | void *data; 60 | const char *usage; 61 | const char *arg; 62 | const char *name; 63 | const char *version; 64 | int option_count; 65 | command_option_t options[COMMANDER_MAX_OPTIONS]; 66 | int argc; 67 | char *argv[COMMANDER_MAX_ARGS]; 68 | char **nargv; 69 | } command_t; 70 | 71 | // prototypes 72 | 73 | void 74 | command_init(command_t *self, const char *name, const char *version); 75 | 76 | void 77 | command_free(command_t *self); 78 | 79 | void 80 | command_help(command_t *self); 81 | 82 | void 83 | command_option(command_t *self, const char *small, const char *large, const char *desc, command_callback_t cb); 84 | 85 | void 86 | command_parse(command_t *self, int argc, char **argv); 87 | 88 | #endif /* COMMANDER_H */ 89 | -------------------------------------------------------------------------------- /deps/commander/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "commander", 3 | "version": "1.3.2", 4 | "repo": "clibs/commander", 5 | "description": "Command-line argument parser", 6 | "keywords": ["cli", "command", "parser", "argv", "args", "options"], 7 | "license": "MIT", 8 | "src": ["src/commander.h", "src/commander.c"] 9 | } 10 | -------------------------------------------------------------------------------- /deps/console-colors/console-colors.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2014 Yusuke Suzuki 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 14 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 | ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 17 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | */ 24 | #ifndef CONSOLE_COLORS_CONSOLE_COLORS_H_ 25 | #define CONSOLE_COLORS_CONSOLE_COLORS_H_ 26 | #include 27 | 28 | #define CC_COLOR_BITS 5 29 | 30 | typedef enum { 31 | CC_FG_NONE = 0 << 0, 32 | CC_FG_BLACK = 1 << 0, 33 | CC_FG_DARK_RED = 2 << 0, 34 | CC_FG_DARK_GREEN = 3 << 0, 35 | CC_FG_DARK_YELLOW = 4 << 0, 36 | CC_FG_DARK_BLUE = 5 << 0, 37 | CC_FG_DARK_MAGENTA = 6 << 0, 38 | CC_FG_DARK_CYAN = 7 << 0, 39 | CC_FG_GRAY = 8 << 0, 40 | CC_FG_DARK_GRAY = 9 << 0, 41 | CC_FG_RED = 10 << 0, 42 | CC_FG_GREEN = 11 << 0, 43 | CC_FG_YELLOW = 12 << 0, 44 | CC_FG_BLUE = 13 << 0, 45 | CC_FG_MAGENTA = 14 << 0, 46 | CC_FG_CYAN = 15 << 0, 47 | CC_FG_WHITE = 16 << 0, 48 | 49 | CC_BG_NONE = 0 << CC_COLOR_BITS, 50 | CC_BG_BLACK = 1 << CC_COLOR_BITS, 51 | CC_BG_DARK_RED = 2 << CC_COLOR_BITS, 52 | CC_BG_DARK_GREEN = 3 << CC_COLOR_BITS, 53 | CC_BG_DARK_YELLOW = 4 << CC_COLOR_BITS, 54 | CC_BG_DARK_BLUE = 5 << CC_COLOR_BITS, 55 | CC_BG_DARK_MAGENTA = 6 << CC_COLOR_BITS, 56 | CC_BG_DARK_CYAN = 7 << CC_COLOR_BITS, 57 | CC_BG_GRAY = 8 << CC_COLOR_BITS, 58 | CC_BG_DARK_GRAY = 9 << CC_COLOR_BITS, 59 | CC_BG_RED = 10 << CC_COLOR_BITS, 60 | CC_BG_GREEN = 11 << CC_COLOR_BITS, 61 | CC_BG_YELLOW = 12 << CC_COLOR_BITS, 62 | CC_BG_BLUE = 13 << CC_COLOR_BITS, 63 | CC_BG_MAGENTA = 14 << CC_COLOR_BITS, 64 | CC_BG_CYAN = 15 << CC_COLOR_BITS, 65 | CC_BG_WHITE = 16 << CC_COLOR_BITS 66 | } cc_color_t; 67 | 68 | #ifndef COMMON_LVB_LEADING_BYTE 69 | #define COMMON_LVB_LEADING_BYTE 0x0100 70 | #endif 71 | 72 | #ifndef COMMON_LVB_TRAILING_BYTE 73 | #define COMMON_LVB_TRAILING_BYTE 0x0200 74 | #endif 75 | 76 | #ifndef COMMON_LVB_GRID_HORIZONTAL 77 | #define COMMON_LVB_GRID_HORIZONTAL 0x0400 78 | #endif 79 | 80 | #ifndef COMMON_LVB_GRID_LVERTICAL 81 | #define COMMON_LVB_GRID_LVERTICAL 0x0800 82 | #endif 83 | 84 | #ifndef COMMON_LVB_GRID_RVERTICAL 85 | #define COMMON_LVB_GRID_RVERTICAL 0x1000 86 | #endif 87 | 88 | #ifndef COMMON_LVB_REVERSE_VIDEO 89 | #define COMMON_LVB_REVERSE_VIDEO 0x4000 90 | #endif 91 | 92 | #ifndef COMMON_LVB_UNDERSCORE 93 | #define COMMON_LVB_UNDERSCORE 0x8000 94 | #endif 95 | 96 | /** 97 | * @param color {console_color_t} Console color. We can pass (FG | BG) as color. 98 | * @param stream {FILE*} `stdout` or `stderr`. Others will be passed to fprintf 99 | * without colors. 100 | * @param format {const char*} Format string fprintf will take. 101 | * @return {int} fprintf returned value. 102 | * 103 | * CAUTION(Yusuke Suzuki): bright FG & dark BG combination doesn't works 104 | * correctly on some terminals, but this is an well-known issue. 105 | */ 106 | int cc_fprintf(cc_color_t color, FILE* stream, const char* format, ...); 107 | 108 | #endif /* CONSOLE_COLORS_CONSOLE_COLORS_H_ */ 109 | /* vim: set sw=4 ts=4 et tw=80 : */ 110 | -------------------------------------------------------------------------------- /deps/console-colors/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "console-colors", 3 | "version": "1.0.1", 4 | "repo": "Constellation/console-colors.c", 5 | "description": "Write formatted string to console with colors", 6 | "keywords": [ "console", "color" ], 7 | "license": "BSD", 8 | "src": [ 9 | "console-colors.c", 10 | "console-colors.h" 11 | ], 12 | "dependencies": { } 13 | } 14 | -------------------------------------------------------------------------------- /deps/copy/clib.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "copy", 3 | "description": "Copies files, directories recursively", 4 | "version": "0.0.0", 5 | "repo": "Isty001/copy", 6 | "dependencies": { 7 | "cxong/tinydir": "*", 8 | "jwerle/fs.c": "0.1.2" 9 | }, 10 | "development": { 11 | "jlcordeiro/minunit": "*", 12 | "stephenmathieson/rimraf.c": "0.1.0" 13 | }, 14 | "keywords": [ 15 | "dir", 16 | "directory", 17 | "file", 18 | "copy", 19 | "recursive" 20 | ], 21 | "license": "MIT", 22 | "src": [ 23 | "src/copy.c", 24 | "src/copy.h" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /deps/copy/copy.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "fs/fs.h" 3 | #include "tinydir/tinydir.h" 4 | #include "copy.h" 5 | 6 | 7 | #define is_dot_file(file) 0 == strcmp(".", file.name) || 0 == strcmp("..", file.name) 8 | #define check_err(x) if (0 != (err = x)) break; 9 | 10 | 11 | int copy_file(char *from, char *to) 12 | { 13 | char *content = fs_read(from); 14 | if (!content) { 15 | return -1; 16 | } 17 | fs_write(to, content); 18 | free(content); 19 | 20 | return 0; 21 | } 22 | 23 | static void check_dir(char *dir) 24 | { 25 | if (0 != fs_exists(dir)) { 26 | fs_mkdir(dir, 0700); 27 | } 28 | } 29 | 30 | static int copy(tinydir_file file, char *target_dir) 31 | { 32 | char target_path[strlen(target_dir) + strlen(file.name) + 2]; 33 | 34 | sprintf(target_path, "%s/%s", target_dir, file.name); 35 | 36 | if (file.is_dir) { 37 | return copy_dir(file.path, target_path); 38 | } 39 | 40 | return copy_file(file.path, target_path); 41 | } 42 | 43 | int copy_dir(char *dir_path, char *target_dir) 44 | { 45 | int err = 0; 46 | tinydir_dir dir; 47 | tinydir_file file; 48 | tinydir_open(&dir, dir_path); 49 | check_dir(target_dir); 50 | 51 | while (dir.has_next) { 52 | check_err(tinydir_readfile(&dir, &file)); 53 | 54 | if (is_dot_file(file)) { 55 | goto next; 56 | } 57 | check_err(copy(file, target_dir)); 58 | 59 | next: 60 | check_err(tinydir_next(&dir)); 61 | } 62 | tinydir_close(&dir); 63 | 64 | return err; 65 | } 66 | -------------------------------------------------------------------------------- /deps/copy/copy.h: -------------------------------------------------------------------------------- 1 | #ifndef COPY_DIR_H 2 | #define COPY_DIR_H 3 | 4 | 5 | /** 6 | * Copies one file 7 | * 8 | * @example copy_file("./dir/file.txt", "./target_dir/file.txt"); 9 | * "./target_dir/file.txt" will be created if it doesn't exist 10 | * 11 | * @return 0 on success, -1 otherwise 12 | */ 13 | int copy_file(char *from_path, char *to_path); 14 | 15 | /** 16 | * Copies directory recursively to the given target 17 | * 18 | * @example copy_dir("./dir/sub_dir", "./target_dir/sub_dir") 19 | * "target_dir/sub_dir" will be created if it doesn't exist 20 | * 21 | * @return 0 on success, -1 otherwise 22 | */ 23 | int copy_dir(char *dir, char *target_dir); 24 | 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /deps/copy/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "copy", 3 | "description": "Copies files, directories recursively", 4 | "version": "0.0.0", 5 | "repo": "Isty001/copy", 6 | "dependencies": { 7 | "cxong/tinydir": "*", 8 | "jwerle/fs.c": "0.1.2" 9 | }, 10 | "development": { 11 | "jlcordeiro/minunit": "*", 12 | "stephenmathieson/rimraf.c": "0.1.0" 13 | }, 14 | "keywords": [ 15 | "dir", 16 | "directory", 17 | "file", 18 | "copy", 19 | "recursive" 20 | ], 21 | "license": "MIT", 22 | "src": [ 23 | "src/copy.c", 24 | "src/copy.h" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /deps/debug/debug.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "strdup/strdup.h" 8 | #include "asprintf/asprintf.h" 9 | #include "wildcardcmp/wildcardcmp.h" 10 | #include "debug.h" 11 | 12 | /** 13 | * Have we seeded `rand()`? 14 | */ 15 | 16 | static int seeded = 0; 17 | 18 | /** 19 | * Log format. 20 | */ 21 | 22 | #define FMT "\x1B[3%dm%s\033[0m" 23 | 24 | /** 25 | * ENV var delimiter. 26 | */ 27 | 28 | #define DELIMITER "," 29 | 30 | /** 31 | * Check if the given `stream` is a TTY, and/or if 32 | * the environment variable `DEBUG_COLORS` has been 33 | * disabled. 34 | */ 35 | 36 | static int 37 | use_colors(FILE *stream) { 38 | // only use color for a TTY 39 | int tty = isatty(fileno(stream)); 40 | if (0 == tty) return 0; 41 | // check env 42 | char *colors = getenv("DEBUG_COLORS"); 43 | if (!colors) return 1; 44 | // see: https://github.com/visionmedia/debug/blob/2.1.0/node.js#L49-L52 45 | if (0 == strcmp("0", colors)) return 0; 46 | if (0 == strncmp("no", colors, 2)) return 0; 47 | if (0 == strncmp("false", colors, 5)) return 0; 48 | if (0 == strncmp("disabled", colors, 8)) return 0; 49 | return 1; 50 | } 51 | 52 | int 53 | debug_is_enabled(const char *name) { 54 | char *env = NULL; 55 | char *tmp = NULL; 56 | char *debugger = NULL; 57 | int enabled = 0; 58 | 59 | // get DEBUG env var 60 | if (!(env = getenv("DEBUG"))) return 0; 61 | if (!(tmp = strdup(env))) return 0; 62 | 63 | debugger = strtok(tmp, DELIMITER); 64 | while (debugger) { 65 | // support DEBUG=foo* 66 | if (1 == wildcardcmp(debugger, name)) { 67 | enabled = 1; 68 | break; 69 | } 70 | debugger = strtok(NULL, DELIMITER); 71 | } 72 | 73 | free(tmp); 74 | return enabled; 75 | } 76 | 77 | int 78 | debug_init(debug_t *debugger, const char *name) { 79 | // seed, if necessary 80 | if (0 == seeded) { 81 | srand(clock()); 82 | seeded = 1; 83 | } 84 | 85 | // random color 86 | debugger->color = 1 + (rand() % 6); 87 | // set enabled flag 88 | debugger->enabled = debug_is_enabled(name); 89 | // name, stream 90 | debugger->name = name; 91 | debugger->stream = stderr; 92 | return 0; 93 | } 94 | 95 | void 96 | debug(debug_t *debugger, const char *fmt, ...) { 97 | // noop when disabled 98 | if (0 == debugger->enabled) return; 99 | 100 | char *pre = NULL; 101 | char *post = NULL; 102 | va_list args; 103 | 104 | va_start(args, fmt); 105 | 106 | if (use_colors(debugger->stream)) { 107 | // [color][name][/color] 108 | if (-1 == asprintf(&pre, FMT, debugger->color, debugger->name)) { 109 | va_end(args); 110 | return; 111 | } 112 | } else { 113 | // [name] 114 | if (!(pre = strdup(debugger->name))) { 115 | va_end(args); 116 | return; 117 | } 118 | } 119 | 120 | // format args 121 | if (-1 == vasprintf(&post, fmt, args)) { 122 | free(pre); 123 | va_end(args); 124 | return; 125 | } 126 | 127 | // print to stream 128 | fprintf(debugger->stream, " %s : %s\n", pre, post); 129 | 130 | // release memory 131 | free(pre); 132 | free(post); 133 | } 134 | -------------------------------------------------------------------------------- /deps/debug/debug.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef DEBUG_H 3 | #define DEBUG_H 1 4 | 5 | #include 6 | 7 | /** 8 | * Debug type. 9 | */ 10 | 11 | typedef struct { 12 | const char *name; 13 | int color; 14 | int enabled; 15 | FILE *stream; 16 | } debug_t; 17 | 18 | /** 19 | * Output a debugging message from the given `debugger`. 20 | */ 21 | 22 | void 23 | debug(debug_t *debugger, const char *fmt, ...); 24 | 25 | /** 26 | * Check if a debugger is enabled. 27 | */ 28 | 29 | int 30 | debug_is_enabled(const char *name); 31 | 32 | /** 33 | * Initialize the given `debugger` with `name`. 34 | */ 35 | 36 | int 37 | debug_init(debug_t *debugger, const char *name); 38 | 39 | #endif // DEBUG_H 40 | -------------------------------------------------------------------------------- /deps/debug/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "debug", 3 | "version": "0.0.0", 4 | "src": ["debug.h", "debug.c"], 5 | "repo": "stephenmathieson/debug.c", 6 | "license": "mit", 7 | "dependencies": { 8 | "strdup": "0.0.0", 9 | "littlstar/asprintf.c": "0.0.3", 10 | "wildcardcmp": "0.0.0" 11 | }, 12 | "development": { 13 | "ms": "*" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /deps/describe/describe.h: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // describe.h 4 | // 5 | // Copyright (c) 2013 Stephen Mathieson 6 | // Copyright (c) 2015 Michael Phan-Ba 7 | // MIT licensed 8 | // 9 | 10 | 11 | #ifndef DESCRIBE_H 12 | #define DESCRIBE_H 1 13 | 14 | #include "console-colors/console-colors.h" 15 | #include "assertion-macros/assertion-macros.h" 16 | 17 | #define DESCRIBE_VERSION "1.1.0" 18 | #define DESCRIBE_OK "✓" 19 | #define DESCRIBE_FAIL "✖" 20 | 21 | void __describe_after_spec(const char *specification, int before) { 22 | if (assert_failures() == before) { 23 | cc_fprintf( 24 | CC_FG_DARK_GREEN 25 | , stdout 26 | , " %s" 27 | , DESCRIBE_OK 28 | ); 29 | } else { 30 | cc_fprintf( 31 | CC_FG_DARK_RED 32 | , stdout 33 | , " %s" 34 | , DESCRIBE_FAIL 35 | ); 36 | } 37 | cc_fprintf( 38 | CC_FG_GRAY 39 | , stdout 40 | , " %s\n" 41 | , specification 42 | ); 43 | } 44 | 45 | /* 46 | * Describe `suite` with `title` 47 | */ 48 | 49 | #define describe(title) for ( \ 50 | int __run = 0; \ 51 | __run++ == 0 && printf("\n %s\n", title); \ 52 | printf("\n") \ 53 | ) 54 | 55 | /* 56 | * Describe `fn` with `specification` 57 | */ 58 | 59 | #define it(specification) for ( \ 60 | int __before = assert_failures(), __run = 0; \ 61 | __run++ == 0; \ 62 | __describe_after_spec(specification, __before) \ 63 | ) 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /deps/describe/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "describe", 3 | "version": "2.0.1", 4 | "repo": "stephenmathieson/describe.h", 5 | "description": "Simple BDD describe test thingy", 6 | "keywords": [ "testing", "bdd", "assert", "describe" ], 7 | "license": "MIT", 8 | "src": [ "describe.h" ], 9 | "dependencies": { 10 | "stephenmathieson/assertion-macros.h": "0.2.1", 11 | "Constellation/console-colors.c": "1.0.1" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /deps/fs/clib.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fs", 3 | "version": "0.2.0", 4 | "description": "File system API much like Node's fs module", 5 | "repo": "jwerle/fs.c", 6 | "src": [ 7 | "fs.h", 8 | "fs.c" 9 | ], 10 | "scripts": { 11 | "test": "make test" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git@github.com:jwerle/fs.c.git" 16 | }, 17 | "keywords": [ 18 | "fs", 19 | "filesystem", 20 | "file", 21 | "system" 22 | ], 23 | "author": "Joseph Werle", 24 | "license": "MIT", 25 | "bugs": { 26 | "url": "https://github.com/jwerle/fs.c/issues" 27 | } 28 | } -------------------------------------------------------------------------------- /deps/fs/fs.h: -------------------------------------------------------------------------------- 1 | #ifndef FS_H 2 | #define FS_H 1 3 | 4 | 5 | /** 6 | * fs.h 7 | * 8 | * copyright 2013 - joseph werle 9 | */ 10 | 11 | 12 | #include 13 | #include 14 | 15 | #ifdef _WIN32 16 | #define FS_OPEN_READ "rb" 17 | #define FS_OPEN_WRITE "wb" 18 | #define FS_OPEN_READWRITE "rwb" 19 | #else 20 | #define FS_OPEN_READ "r" 21 | #define FS_OPEN_WRITE "w" 22 | #define FS_OPEN_READWRITE "rw" 23 | #endif 24 | 25 | typedef struct stat fs_stats; 26 | 27 | 28 | 29 | /** 30 | * Prints the last error to stderr 31 | */ 32 | 33 | void 34 | fs_error (const char *prefix); 35 | 36 | 37 | /** 38 | * Opens a file with given flags 39 | * and returns a file descriptor 40 | */ 41 | 42 | FILE * 43 | fs_open (const char *path, const char *flags); 44 | 45 | 46 | /** 47 | * Closes a given file descriptor 48 | */ 49 | 50 | int 51 | fs_close (FILE *file); 52 | 53 | 54 | /** 55 | * Moves a path to a new destination 56 | */ 57 | 58 | int 59 | fs_rename (const char *from, const char *to); 60 | 61 | 62 | /** 63 | * Stats a given path and returns 64 | * a `struct stat` 65 | */ 66 | 67 | fs_stats * 68 | fs_stat (const char *path); 69 | 70 | 71 | /** 72 | * Stats a given file descriptor 73 | */ 74 | 75 | fs_stats * 76 | fs_fstat (FILE *file); 77 | 78 | 79 | /** 80 | * Stats a given link path 81 | */ 82 | 83 | fs_stats * 84 | fs_lstat (const char *path); 85 | 86 | 87 | /** 88 | * Truncates a file to a specified 89 | * length from a given file descriptor 90 | */ 91 | 92 | int 93 | fs_ftruncate (FILE *file, int len); 94 | 95 | 96 | /** 97 | * Truncates a file to a specified 98 | * len from a given file path 99 | */ 100 | 101 | int 102 | fs_truncate (const char *path, int len); 103 | 104 | 105 | /** 106 | * Changes ownership of a given 107 | * file path to a given owner 108 | * and group 109 | */ 110 | 111 | int 112 | fs_chown (const char *path, int uid, int gid); 113 | 114 | 115 | /** 116 | * Change ownership of a given 117 | * file descriptor to a given owner 118 | * and group 119 | */ 120 | 121 | int 122 | fs_fchown (FILE *file, int uid, int gid); 123 | 124 | 125 | /** 126 | * Returns the size of a file from 127 | * a given file path 128 | */ 129 | 130 | size_t 131 | fs_size (const char *path); 132 | 133 | 134 | /** 135 | * Returns the size of a file 136 | * from a given file descriptor 137 | */ 138 | 139 | size_t 140 | fs_fsize (FILE *file); 141 | 142 | 143 | /** 144 | * Change ownership of a given 145 | * link path to a given owner 146 | * and group 147 | */ 148 | 149 | int 150 | fs_lchown (const char *path, int uid, int gid); 151 | 152 | 153 | /** 154 | * Reads a file by a given file 155 | * path 156 | */ 157 | 158 | char * 159 | fs_read (const char *path); 160 | 161 | 162 | /** 163 | * Reads a file by a given 164 | * file path by a given `n` 165 | * number of bytes 166 | */ 167 | 168 | char * 169 | fs_nread (const char *path, int len); 170 | 171 | 172 | /** 173 | * Reads a file by a given 174 | * file descriptor 175 | */ 176 | 177 | char * 178 | fs_fread (FILE *file); 179 | 180 | 181 | /** 182 | * Reads a file by a given 183 | * file descriptor by a given 184 | * `n` number of bytes 185 | */ 186 | 187 | char * 188 | fs_fnread (FILE *file, int len); 189 | 190 | 191 | /** 192 | * Writes a buffer 193 | * to a given file path 194 | */ 195 | 196 | int 197 | fs_write (const char *path, const char *buffer); 198 | 199 | 200 | /** 201 | * Writes `n` bytes of a buffer to a given 202 | * file path 203 | */ 204 | 205 | int 206 | fs_nwrite (const char *path, const char *buffer, int len); 207 | 208 | 209 | /** 210 | * Writes a buffer to a given 211 | * file stream 212 | */ 213 | 214 | int 215 | fs_fwrite (FILE *file, const char *buffer); 216 | 217 | 218 | /** 219 | * Writes `n` bytes of a buffer 220 | * to a given file stream 221 | */ 222 | 223 | int 224 | fs_fnwrite (FILE *file, const char *buffer, int len); 225 | 226 | 227 | /** 228 | * Makes a directory and returns 0 229 | * on success or -1 on failure 230 | */ 231 | 232 | int 233 | fs_mkdir (const char *path, int mode); 234 | 235 | 236 | /** 237 | * Removes a directory and returns 238 | * 0 on success and -1 on failure 239 | */ 240 | 241 | int 242 | fs_rmdir (const char *path); 243 | 244 | /** 245 | * Check if the given `path` exists 246 | */ 247 | 248 | int 249 | fs_exists (const char *path); 250 | 251 | 252 | #endif 253 | -------------------------------------------------------------------------------- /deps/fs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fs", 3 | "version": "0.1.2", 4 | "description": "File system API much like Node's fs module", 5 | "repo": "jwerle/fs.c", 6 | "src": ["fs.h", "fs.c"], 7 | "scripts": { 8 | "test": "make test" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git@github.com:jwerle/fs.c.git" 13 | }, 14 | "keywords": [ 15 | "fs" 16 | ], 17 | "author": "Joseph Werle", 18 | "license": "MIT", 19 | "bugs": { 20 | "url": "https://github.com/jwerle/fs.c/issues" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /deps/gumbo-get-element-by-id/get-element-by-id.c: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // get-element-by-id.c 4 | // 5 | // Copyright (c) 2014 Stephen Mathieson 6 | // MIT licensed 7 | // 8 | 9 | #include 10 | #include "get-element-by-id.h" 11 | 12 | /** 13 | * Get the first `GumboNode` with the given `id` 14 | * contained with the `document`. 15 | */ 16 | 17 | GumboNode * 18 | gumbo_get_element_by_id(const char *id, GumboNode *document) { 19 | 20 | if (GUMBO_NODE_DOCUMENT != document->type 21 | && GUMBO_NODE_ELEMENT != document->type) { 22 | return NULL; 23 | } 24 | 25 | GumboAttribute *node_id = 26 | gumbo_get_attribute(&document->v.element.attributes, "id"); 27 | if (node_id && 0 == strcmp(id, node_id->value)) { 28 | return document; 29 | } 30 | 31 | // iterate all children 32 | GumboVector *children = &document->v.element.children; 33 | for (unsigned int i = 0; i < children->length; i++) { 34 | GumboNode *node = gumbo_get_element_by_id(id, children->data[i]); 35 | if (node) return node; 36 | } 37 | 38 | return NULL; 39 | } 40 | -------------------------------------------------------------------------------- /deps/gumbo-get-element-by-id/get-element-by-id.h: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // get-element-by-id.h 4 | // 5 | // Copyright (c) 2014 Stephen Mathieson 6 | // MIT licensed 7 | // 8 | 9 | #ifndef GUMBO_GET_ELEMENT_BY_ID 10 | #define GUMBO_GET_ELEMENT_BY_ID 1 11 | 12 | #include "gumbo-parser/gumbo.h" 13 | 14 | GumboNode * 15 | gumbo_get_element_by_id(const char *, GumboNode *); 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /deps/gumbo-get-element-by-id/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gumbo-get-element-by-id", 3 | "version": "1.0.1", 4 | "repo": "stephenmathieson/gumbo-get-element-by-id.c", 5 | "license": "MIT", 6 | "src": [ 7 | "src/get-element-by-id.c", 8 | "src/get-element-by-id.h" 9 | ], 10 | "dependencies": {}, 11 | "development": { 12 | "thlorenz/gumbo-parser.c": "*" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /deps/gumbo-get-elements-by-tag-name/get-elements-by-tag-name.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include "gumbo-parser/gumbo.h" 5 | #include "list/list.h" 6 | #include "trim/trim.h" 7 | #include "case/case.h" 8 | 9 | #define NODE_TYPE_CHECK(node) \ 10 | if (GUMBO_NODE_DOCUMENT != node->type \ 11 | && GUMBO_NODE_ELEMENT != node->type) \ 12 | return 13 | 14 | /** 15 | * Crawl all children of the given `node`, 16 | * adding `tag` elements to the given `list_t`. 17 | */ 18 | 19 | static void 20 | crawl(GumboTag tag, list_t *elements, GumboNode *node) { 21 | NODE_TYPE_CHECK(node); 22 | 23 | if (tag == node->v.element.tag) 24 | list_rpush(elements, list_node_new(node)); 25 | 26 | GumboVector *children = &node->v.element.children; 27 | for (unsigned int i = 0; i < children->length; i++) { 28 | crawl(tag, elements, children->data[i]); 29 | } 30 | } 31 | 32 | /** 33 | * Get all elements of `tag_name` contained 34 | * with the given `root` node. 35 | */ 36 | 37 | list_t * 38 | gumbo_get_elements_by_tag_name(const char *tag_name, GumboNode *root) { 39 | GumboTag tag; 40 | list_t *elements = NULL; 41 | 42 | if (!tag_name || GUMBO_TAG_UNKNOWN == (tag = gumbo_tag_enum(tag_name))) 43 | return NULL; 44 | 45 | if (!(elements = list_new())) 46 | return NULL; 47 | 48 | crawl(tag, elements, root); 49 | 50 | return elements; 51 | } 52 | -------------------------------------------------------------------------------- /deps/gumbo-get-elements-by-tag-name/get-elements-by-tag-name.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef GUMBO_GET_ELEMENTS_BY_TAG_NAME_H 3 | #define GUMBO_GET_ELEMENTS_BY_TAG_NAME_H 1 4 | 5 | #include "list/list.h" 6 | #include "gumbo-parser/gumbo.h" 7 | 8 | list_t * 9 | gumbo_get_elements_by_tag_name(const char *, GumboNode *); 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /deps/gumbo-get-elements-by-tag-name/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gumbo-get-elements-by-tag-name", 3 | "version": "1.0.1", 4 | "repo": "stephenmathieson/gumbo-get-elements-by-tag-name.c", 5 | "license": "MIT", 6 | "src": [ 7 | "src/get-elements-by-tag-name.c", 8 | "src/get-elements-by-tag-name.h" 9 | ], 10 | "dependencies": { 11 | "list": "*", 12 | "stephenmathieson/case.c": "*", 13 | "stephenmathieson/trim.c": "*" 14 | }, 15 | "development": { 16 | "thlorenz/gumbo-parser.c": "*", 17 | "stephenmathieson/gumbo-get-element-by-id.c": "*" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /deps/gumbo-parser/attribute.c: -------------------------------------------------------------------------------- 1 | // Copyright 2010 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | // Author: jdtang@google.com (Jonathan Tang) 16 | 17 | #include "attribute.h" 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include "util.h" 25 | 26 | struct GumboInternalParser; 27 | 28 | GumboAttribute* gumbo_get_attribute( 29 | const GumboVector* attributes, const char* name) { 30 | for (int i = 0; i < attributes->length; ++i) { 31 | GumboAttribute* attr = attributes->data[i]; 32 | if (!strcasecmp(attr->name, name)) { 33 | return attr; 34 | } 35 | } 36 | return NULL; 37 | } 38 | 39 | void gumbo_destroy_attribute( 40 | struct GumboInternalParser* parser, GumboAttribute* attribute) { 41 | gumbo_parser_deallocate(parser, (void*) attribute->name); 42 | gumbo_parser_deallocate(parser, (void*) attribute->value); 43 | gumbo_parser_deallocate(parser, (void*) attribute); 44 | } 45 | -------------------------------------------------------------------------------- /deps/gumbo-parser/attribute.h: -------------------------------------------------------------------------------- 1 | // Copyright 2010 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | // Author: jdtang@google.com (Jonathan Tang) 16 | 17 | #ifndef GUMBO_ATTRIBUTE_H_ 18 | #define GUMBO_ATTRIBUTE_H_ 19 | 20 | #include "gumbo.h" 21 | 22 | #ifdef __cplusplus 23 | extern "C" { 24 | #endif 25 | 26 | struct GumboInternalParser; 27 | 28 | // Release the memory used for an GumboAttribute, including the attribute 29 | // itself. 30 | void gumbo_destroy_attribute( 31 | struct GumboInternalParser* parser, GumboAttribute* attribute); 32 | 33 | #ifdef __cplusplus 34 | } 35 | #endif 36 | 37 | #endif // GUMBO_ATTRIBUTE_H_ 38 | -------------------------------------------------------------------------------- /deps/gumbo-parser/char_ref.h: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | // Author: jdtang@google.com (Jonathan Tang) 16 | // 17 | // Internal header for character reference handling; this should not be exposed 18 | // transitively by any public API header. This is why the functions aren't 19 | // namespaced. 20 | 21 | #ifndef GUMBO_CHAR_REF_H_ 22 | #define GUMBO_CHAR_REF_H_ 23 | 24 | #include 25 | 26 | #ifdef __cplusplus 27 | extern "C" { 28 | #endif 29 | 30 | struct GumboInternalParser; 31 | struct GumboInternalUtf8Iterator; 32 | 33 | // Value that indicates no character was produced. 34 | extern const int kGumboNoChar; 35 | 36 | // Certain named character references generate two codepoints, not one, and so 37 | // the consume_char_ref subroutine needs to return this instead of an int. The 38 | // first field will be kGumboNoChar if no character reference was found; the 39 | // second field will be kGumboNoChar if that is the case or if the character 40 | // reference returns only a single codepoint. 41 | typedef struct { 42 | int first; 43 | int second; 44 | } OneOrTwoCodepoints; 45 | 46 | // Implements the "consume a character reference" section of the spec. 47 | // This reads in characters from the input as necessary, and fills in a 48 | // OneOrTwoCodepoints struct containing the characters read. It may add parse 49 | // errors to the GumboParser's errors vector, if the spec calls for it. Pass a 50 | // space for the "additional allowed char" when the spec says "with no 51 | // additional allowed char". Returns false on parse error, true otherwise. 52 | bool consume_char_ref( 53 | struct GumboInternalParser* parser, struct GumboInternalUtf8Iterator* input, 54 | int additional_allowed_char, bool is_in_attribute, 55 | OneOrTwoCodepoints* output); 56 | 57 | #ifdef __cplusplus 58 | } 59 | #endif 60 | 61 | #endif // GUMBO_CHAR_REF_H_ 62 | -------------------------------------------------------------------------------- /deps/gumbo-parser/insertion_mode.h: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | // Author: jdtang@google.com (Jonathan Tang) 16 | 17 | #ifndef GUMBO_INSERTION_MODE_H_ 18 | #define GUMBO_INSERTION_MODE_H_ 19 | 20 | #ifdef __cplusplus 21 | extern "C" { 22 | #endif 23 | 24 | // http://www.whatwg.org/specs/web-apps/current-work/complete/parsing.html#insertion-mode 25 | // If new enum values are added, be sure to update the kTokenHandlers dispatch 26 | // table in parser.c. 27 | typedef enum { 28 | GUMBO_INSERTION_MODE_INITIAL, 29 | GUMBO_INSERTION_MODE_BEFORE_HTML, 30 | GUMBO_INSERTION_MODE_BEFORE_HEAD, 31 | GUMBO_INSERTION_MODE_IN_HEAD, 32 | GUMBO_INSERTION_MODE_IN_HEAD_NOSCRIPT, 33 | GUMBO_INSERTION_MODE_AFTER_HEAD, 34 | GUMBO_INSERTION_MODE_IN_BODY, 35 | GUMBO_INSERTION_MODE_TEXT, 36 | GUMBO_INSERTION_MODE_IN_TABLE, 37 | GUMBO_INSERTION_MODE_IN_TABLE_TEXT, 38 | GUMBO_INSERTION_MODE_IN_CAPTION, 39 | GUMBO_INSERTION_MODE_IN_COLUMN_GROUP, 40 | GUMBO_INSERTION_MODE_IN_TABLE_BODY, 41 | GUMBO_INSERTION_MODE_IN_ROW, 42 | GUMBO_INSERTION_MODE_IN_CELL, 43 | GUMBO_INSERTION_MODE_IN_SELECT, 44 | GUMBO_INSERTION_MODE_IN_SELECT_IN_TABLE, 45 | GUMBO_INSERTION_MODE_IN_TEMPLATE, 46 | GUMBO_INSERTION_MODE_AFTER_BODY, 47 | GUMBO_INSERTION_MODE_IN_FRAMESET, 48 | GUMBO_INSERTION_MODE_AFTER_FRAMESET, 49 | GUMBO_INSERTION_MODE_AFTER_AFTER_BODY, 50 | GUMBO_INSERTION_MODE_AFTER_AFTER_FRAMESET 51 | } GumboInsertionMode; 52 | 53 | #ifdef __cplusplus 54 | } // extern C 55 | #endif 56 | 57 | #endif // GUMBO_INSERTION_MODE_H_ 58 | -------------------------------------------------------------------------------- /deps/gumbo-parser/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gumbo-parser", 3 | "version": "0.1.0", 4 | "description": "Gumbo - A pure-C HTML5 parser, adapted to be installable via clib.", 5 | "directories": { 6 | "src": "src" 7 | }, 8 | "src": [ 9 | "src/attribute.c", 10 | "src/attribute.h", 11 | "src/char_ref.c", 12 | "src/char_ref.h", 13 | "src/error.c", 14 | "src/error.h", 15 | "src/gumbo.h", 16 | "src/insertion_mode.h", 17 | "src/parser.c", 18 | "src/parser.h", 19 | "src/string_buffer.c", 20 | "src/string_buffer.h", 21 | "src/string_piece.c", 22 | "src/string_piece.h", 23 | "src/tag.c", 24 | "src/token_type.h", 25 | "src/tokenizer.c", 26 | "src/tokenizer.h", 27 | "src/tokenizer_states.h", 28 | "src/utf8.c", 29 | "src/utf8.h", 30 | "src/util.c", 31 | "src/util.h", 32 | "src/vector.c", 33 | "src/vector.h" 34 | ], 35 | "scripts": {}, 36 | "repository": { 37 | "type": "git", 38 | "url": "git://github.com/thlorenz/gumbo-parser.c.git" 39 | }, 40 | "keywords": [ 41 | "parse", 42 | "html", 43 | "html5", 44 | "clib" 45 | ], 46 | "author": "Thorsten Lorenz (http://thlorenz.com/)", 47 | "license": "Apache License, Version 2.0", 48 | "gypfile": true, 49 | "bugs": { 50 | "url": "https://github.com/thlorenz/gumbo-parser.c/issues" 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /deps/gumbo-parser/parser.h: -------------------------------------------------------------------------------- 1 | // Copyright 2010 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | // Author: jdtang@google.com (Jonathan Tang) 16 | // 17 | // Contains the definition of the top-level GumboParser structure that's 18 | // threaded through basically every internal function in the library. 19 | 20 | #ifndef GUMBO_PARSER_H_ 21 | #define GUMBO_PARSER_H_ 22 | 23 | #ifdef __cplusplus 24 | extern "C" { 25 | #endif 26 | 27 | struct GumboInternalParserState; 28 | struct GumboInternalOutput; 29 | struct GumboInternalOptions; 30 | struct GumboInternalTokenizerState; 31 | 32 | // An overarching struct that's threaded through (nearly) all functions in the 33 | // library, OOP-style. This gives each function access to the options and 34 | // output, along with any internal state needed for the parse. 35 | typedef struct GumboInternalParser { 36 | // Settings for this parse run. 37 | const struct GumboInternalOptions* _options; 38 | 39 | // Output for the parse. 40 | struct GumboInternalOutput* _output; 41 | 42 | // The internal tokenizer state, defined as a pointer to avoid a cyclic 43 | // dependency on html5tokenizer.h. The main parse routine is responsible for 44 | // initializing this on parse start, and destroying it on parse end. 45 | // End-users will never see a non-garbage value in this pointer. 46 | struct GumboInternalTokenizerState* _tokenizer_state; 47 | 48 | // The internal parser state. Initialized on parse start and destroyed on 49 | // parse end; end-users will never see a non-garbage value in this pointer. 50 | struct GumboInternalParserState* _parser_state; 51 | } GumboParser; 52 | 53 | #ifdef __cplusplus 54 | } 55 | #endif 56 | 57 | #endif // GUMBO_PARSER_H_ 58 | -------------------------------------------------------------------------------- /deps/gumbo-parser/string_buffer.c: -------------------------------------------------------------------------------- 1 | // Copyright 2010 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | // Author: jdtang@google.com (Jonathan Tang) 16 | 17 | #include "string_buffer.h" 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include "string_piece.h" 25 | #include "util.h" 26 | 27 | struct GumboInternalParser; 28 | 29 | static const size_t kDefaultStringBufferSize = 10; 30 | 31 | static void maybe_resize_string_buffer( 32 | struct GumboInternalParser* parser, size_t additional_chars, 33 | GumboStringBuffer* buffer) { 34 | size_t new_length = buffer->length + additional_chars; 35 | size_t new_capacity = buffer->capacity; 36 | while (new_capacity < new_length) { 37 | new_capacity *= 2; 38 | } 39 | if (new_capacity != buffer->capacity) { 40 | char* new_data = gumbo_parser_allocate(parser, new_capacity); 41 | memcpy(new_data, buffer->data, buffer->length); 42 | gumbo_parser_deallocate(parser, buffer->data); 43 | buffer->data = new_data; 44 | buffer->capacity = new_capacity; 45 | } 46 | } 47 | 48 | void gumbo_string_buffer_init( 49 | struct GumboInternalParser* parser, GumboStringBuffer* output) { 50 | output->data = gumbo_parser_allocate(parser, kDefaultStringBufferSize); 51 | output->length = 0; 52 | output->capacity = kDefaultStringBufferSize; 53 | } 54 | 55 | void gumbo_string_buffer_reserve( 56 | struct GumboInternalParser* parser, size_t min_capacity, 57 | GumboStringBuffer* output) { 58 | maybe_resize_string_buffer(parser, min_capacity - output->length, output); 59 | } 60 | 61 | void gumbo_string_buffer_append_codepoint( 62 | struct GumboInternalParser* parser, int c, GumboStringBuffer* output) { 63 | // num_bytes is actually the number of continuation bytes, 1 less than the 64 | // total number of bytes. This is done to keep the loop below simple and 65 | // should probably change if we unroll it. 66 | int num_bytes, prefix; 67 | if (c <= 0x7f) { 68 | num_bytes = 0; 69 | prefix = 0; 70 | } else if (c <= 0x7ff) { 71 | num_bytes = 1; 72 | prefix = 0xc0; 73 | } else if (c <= 0xffff) { 74 | num_bytes = 2; 75 | prefix = 0xe0; 76 | } else { 77 | num_bytes = 3; 78 | prefix = 0xf0; 79 | } 80 | maybe_resize_string_buffer(parser, num_bytes + 1, output); 81 | output->data[output->length++] = prefix | (c >> (num_bytes * 6)); 82 | for (int i = num_bytes - 1; i >= 0; --i) { 83 | output->data[output->length++] = 0x80 | (0x3f & (c >> (i * 6))); 84 | } 85 | } 86 | 87 | void gumbo_string_buffer_append_string( 88 | struct GumboInternalParser* parser, GumboStringPiece* str, 89 | GumboStringBuffer* output) { 90 | maybe_resize_string_buffer(parser, str->length, output); 91 | memcpy(output->data + output->length, str->data, str->length); 92 | output->length += str->length; 93 | } 94 | 95 | char* gumbo_string_buffer_to_string( 96 | struct GumboInternalParser* parser, GumboStringBuffer* input) { 97 | char* buffer = gumbo_parser_allocate(parser, input->length + 1); 98 | memcpy(buffer, input->data, input->length); 99 | buffer[input->length] = '\0'; 100 | return buffer; 101 | } 102 | 103 | void gumbo_string_buffer_destroy( 104 | struct GumboInternalParser* parser, GumboStringBuffer* buffer) { 105 | gumbo_parser_deallocate(parser, buffer->data); 106 | } 107 | -------------------------------------------------------------------------------- /deps/gumbo-parser/string_buffer.h: -------------------------------------------------------------------------------- 1 | // Copyright 2010 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | // Author: jdtang@google.com (Jonathan Tang) 16 | // 17 | #ifndef GUMBO_STRING_BUFFER_H_ 18 | #define GUMBO_STRING_BUFFER_H_ 19 | 20 | #include 21 | #include 22 | 23 | #include "gumbo.h" 24 | 25 | #ifdef __cplusplus 26 | extern "C" { 27 | #endif 28 | 29 | struct GumboInternalParser; 30 | 31 | // A struct representing a mutable, growable string. This consists of a 32 | // heap-allocated buffer that may grow (by doubling) as necessary. When 33 | // converting to a string, this allocates a new buffer that is only as long as 34 | // it needs to be. Note that the internal buffer here is *not* nul-terminated, 35 | // so be sure not to use ordinary string manipulation functions on it. 36 | typedef struct { 37 | // A pointer to the beginning of the string. NULL iff length == 0. 38 | char* data; 39 | 40 | // The length of the string fragment, in bytes. May be zero. 41 | size_t length; 42 | 43 | // The capacity of the buffer, in bytes. 44 | size_t capacity; 45 | } GumboStringBuffer; 46 | 47 | // Initializes a new GumboStringBuffer. 48 | void gumbo_string_buffer_init( 49 | struct GumboInternalParser* parser, GumboStringBuffer* output); 50 | 51 | // Ensures that the buffer contains at least a certain amount of space. Most 52 | // useful with snprintf and the other length-delimited string functions, which 53 | // may want to write directly into the buffer. 54 | void gumbo_string_buffer_reserve( 55 | struct GumboInternalParser* parser, size_t min_capacity, 56 | GumboStringBuffer* output); 57 | 58 | // Appends a single Unicode codepoint onto the end of the GumboStringBuffer. 59 | // This is essentially a UTF-8 encoder, and may add 1-4 bytes depending on the 60 | // value of the codepoint. 61 | void gumbo_string_buffer_append_codepoint( 62 | struct GumboInternalParser* parser, int c, GumboStringBuffer* output); 63 | 64 | // Appends a string onto the end of the GumboStringBuffer. 65 | void gumbo_string_buffer_append_string( 66 | struct GumboInternalParser* parser, GumboStringPiece* str, 67 | GumboStringBuffer* output); 68 | 69 | // Converts this string buffer to const char*, alloctaing a new buffer for it. 70 | char* gumbo_string_buffer_to_string( 71 | struct GumboInternalParser* parser, GumboStringBuffer* input); 72 | 73 | // Deallocates this GumboStringBuffer. 74 | void gumbo_string_buffer_destroy( 75 | struct GumboInternalParser* parser, GumboStringBuffer* buffer); 76 | 77 | #ifdef __cplusplus 78 | } 79 | #endif 80 | 81 | #endif // GUMBO_STRING_BUFFER_H_ 82 | -------------------------------------------------------------------------------- /deps/gumbo-parser/string_piece.c: -------------------------------------------------------------------------------- 1 | // Copyright 2010 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | // Author: jdtang@google.com (Jonathan Tang) 16 | 17 | #include "string_piece.h" 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include "util.h" 25 | 26 | struct GumboInternalParser; 27 | 28 | const GumboStringPiece kGumboEmptyString = { NULL, 0 }; 29 | 30 | bool gumbo_string_equals( 31 | const GumboStringPiece* str1, const GumboStringPiece* str2) { 32 | return str1->length == str2->length && 33 | !memcmp(str1->data, str2->data, str1->length); 34 | } 35 | 36 | bool gumbo_string_equals_ignore_case( 37 | const GumboStringPiece* str1, const GumboStringPiece* str2) { 38 | return str1->length == str2->length && 39 | !strncasecmp(str1->data, str2->data, str1->length); 40 | } 41 | 42 | void gumbo_string_copy( 43 | struct GumboInternalParser* parser, GumboStringPiece* dest, 44 | const GumboStringPiece* source) { 45 | dest->length = source->length; 46 | char* buffer = gumbo_parser_allocate(parser, source->length); 47 | memcpy(buffer, source->data, source->length); 48 | dest->data = buffer; 49 | } 50 | -------------------------------------------------------------------------------- /deps/gumbo-parser/string_piece.h: -------------------------------------------------------------------------------- 1 | // Copyright 2010 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | // Author: jdtang@google.com (Jonathan Tang) 16 | 17 | #ifndef GUMBO_STRING_PIECE_H_ 18 | #define GUMBO_STRING_PIECE_H_ 19 | 20 | #include "gumbo.h" 21 | 22 | #ifdef __cplusplus 23 | extern "C" { 24 | #endif 25 | 26 | struct GumboInternalParser; 27 | 28 | // Performs a deep-copy of an GumboStringPiece, allocating a fresh buffer in the 29 | // destination and copying over the characters from source. Dest should be 30 | // empty, with no buffer allocated; otherwise, this leaks it. 31 | void gumbo_string_copy( 32 | struct GumboInternalParser* parser, GumboStringPiece* dest, 33 | const GumboStringPiece* source); 34 | 35 | #ifdef __cplusplus 36 | } 37 | #endif 38 | 39 | #endif // GUMBO_STRING_PIECE_H_ 40 | -------------------------------------------------------------------------------- /deps/gumbo-parser/token_type.h: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | // Author: jdtang@google.com (Jonathan Tang) 16 | 17 | #ifndef GUMBO_TOKEN_TYPE_H_ 18 | #define GUMBO_TOKEN_TYPE_H_ 19 | 20 | #ifdef __cplusplus 21 | extern "C" { 22 | #endif 23 | 24 | // An enum representing the type of token. 25 | typedef enum { 26 | GUMBO_TOKEN_DOCTYPE, 27 | GUMBO_TOKEN_START_TAG, 28 | GUMBO_TOKEN_END_TAG, 29 | GUMBO_TOKEN_COMMENT, 30 | GUMBO_TOKEN_WHITESPACE, 31 | GUMBO_TOKEN_CHARACTER, 32 | GUMBO_TOKEN_NULL, 33 | GUMBO_TOKEN_EOF 34 | } GumboTokenType; 35 | 36 | #ifdef __cplusplus 37 | } // extern C 38 | #endif 39 | 40 | #endif // GUMBO_TOKEN_TYPE_H_ 41 | -------------------------------------------------------------------------------- /deps/gumbo-parser/tokenizer_states.h: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | // Author: jdtang@google.com (Jonathan Tang) 16 | // 17 | // This contains the list of states used in the tokenizer. Although at first 18 | // glance it seems like these could be kept internal to the tokenizer, several 19 | // of the actions in the parser require that it reach into the tokenizer and 20 | // reset the tokenizer state. For that to work, it needs to have the 21 | // definitions of individual states available. 22 | // 23 | // This may also be useful for providing more detailed error messages for parse 24 | // errors, as we can match up states and inputs in a table without having to 25 | // clutter the tokenizer code with lots of precise error messages. 26 | 27 | #ifndef GUMBO_TOKENIZER_STATES_H_ 28 | #define GUMBO_TOKENIZER_STATES_H_ 29 | 30 | // The ordering of this enum is also used to build the dispatch table for the 31 | // tokenizer state machine, so if it is changed, be sure to update that too. 32 | typedef enum { 33 | GUMBO_LEX_DATA, 34 | GUMBO_LEX_CHAR_REF_IN_DATA, 35 | GUMBO_LEX_RCDATA, 36 | GUMBO_LEX_CHAR_REF_IN_RCDATA, 37 | GUMBO_LEX_RAWTEXT, 38 | GUMBO_LEX_SCRIPT, 39 | GUMBO_LEX_PLAINTEXT, 40 | GUMBO_LEX_TAG_OPEN, 41 | GUMBO_LEX_END_TAG_OPEN, 42 | GUMBO_LEX_TAG_NAME, 43 | GUMBO_LEX_RCDATA_LT, 44 | GUMBO_LEX_RCDATA_END_TAG_OPEN, 45 | GUMBO_LEX_RCDATA_END_TAG_NAME, 46 | GUMBO_LEX_RAWTEXT_LT, 47 | GUMBO_LEX_RAWTEXT_END_TAG_OPEN, 48 | GUMBO_LEX_RAWTEXT_END_TAG_NAME, 49 | GUMBO_LEX_SCRIPT_LT, 50 | GUMBO_LEX_SCRIPT_END_TAG_OPEN, 51 | GUMBO_LEX_SCRIPT_END_TAG_NAME, 52 | GUMBO_LEX_SCRIPT_ESCAPED_START, 53 | GUMBO_LEX_SCRIPT_ESCAPED_START_DASH, 54 | GUMBO_LEX_SCRIPT_ESCAPED, 55 | GUMBO_LEX_SCRIPT_ESCAPED_DASH, 56 | GUMBO_LEX_SCRIPT_ESCAPED_DASH_DASH, 57 | GUMBO_LEX_SCRIPT_ESCAPED_LT, 58 | GUMBO_LEX_SCRIPT_ESCAPED_END_TAG_OPEN, 59 | GUMBO_LEX_SCRIPT_ESCAPED_END_TAG_NAME, 60 | GUMBO_LEX_SCRIPT_DOUBLE_ESCAPED_START, 61 | GUMBO_LEX_SCRIPT_DOUBLE_ESCAPED, 62 | GUMBO_LEX_SCRIPT_DOUBLE_ESCAPED_DASH, 63 | GUMBO_LEX_SCRIPT_DOUBLE_ESCAPED_DASH_DASH, 64 | GUMBO_LEX_SCRIPT_DOUBLE_ESCAPED_LT, 65 | GUMBO_LEX_SCRIPT_DOUBLE_ESCAPED_END, 66 | GUMBO_LEX_BEFORE_ATTR_NAME, 67 | GUMBO_LEX_ATTR_NAME, 68 | GUMBO_LEX_AFTER_ATTR_NAME, 69 | GUMBO_LEX_BEFORE_ATTR_VALUE, 70 | GUMBO_LEX_ATTR_VALUE_DOUBLE_QUOTED, 71 | GUMBO_LEX_ATTR_VALUE_SINGLE_QUOTED, 72 | GUMBO_LEX_ATTR_VALUE_UNQUOTED, 73 | GUMBO_LEX_CHAR_REF_IN_ATTR_VALUE, 74 | GUMBO_LEX_AFTER_ATTR_VALUE_QUOTED, 75 | GUMBO_LEX_SELF_CLOSING_START_TAG, 76 | GUMBO_LEX_BOGUS_COMMENT, 77 | GUMBO_LEX_MARKUP_DECLARATION, 78 | GUMBO_LEX_COMMENT_START, 79 | GUMBO_LEX_COMMENT_START_DASH, 80 | GUMBO_LEX_COMMENT, 81 | GUMBO_LEX_COMMENT_END_DASH, 82 | GUMBO_LEX_COMMENT_END, 83 | GUMBO_LEX_COMMENT_END_BANG, 84 | GUMBO_LEX_DOCTYPE, 85 | GUMBO_LEX_BEFORE_DOCTYPE_NAME, 86 | GUMBO_LEX_DOCTYPE_NAME, 87 | GUMBO_LEX_AFTER_DOCTYPE_NAME, 88 | GUMBO_LEX_AFTER_DOCTYPE_PUBLIC_KEYWORD, 89 | GUMBO_LEX_BEFORE_DOCTYPE_PUBLIC_ID, 90 | GUMBO_LEX_DOCTYPE_PUBLIC_ID_DOUBLE_QUOTED, 91 | GUMBO_LEX_DOCTYPE_PUBLIC_ID_SINGLE_QUOTED, 92 | GUMBO_LEX_AFTER_DOCTYPE_PUBLIC_ID, 93 | GUMBO_LEX_BETWEEN_DOCTYPE_PUBLIC_SYSTEM_ID, 94 | GUMBO_LEX_AFTER_DOCTYPE_SYSTEM_KEYWORD, 95 | GUMBO_LEX_BEFORE_DOCTYPE_SYSTEM_ID, 96 | GUMBO_LEX_DOCTYPE_SYSTEM_ID_DOUBLE_QUOTED, 97 | GUMBO_LEX_DOCTYPE_SYSTEM_ID_SINGLE_QUOTED, 98 | GUMBO_LEX_AFTER_DOCTYPE_SYSTEM_ID, 99 | GUMBO_LEX_BOGUS_DOCTYPE, 100 | GUMBO_LEX_CDATA 101 | } GumboTokenizerEnum; 102 | 103 | #endif // GUMBO_TOKENIZER_STATES_H_ 104 | -------------------------------------------------------------------------------- /deps/gumbo-parser/util.c: -------------------------------------------------------------------------------- 1 | // Copyright 2010 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | // Author: jdtang@google.com (Jonathan Tang) 16 | 17 | #include "util.h" 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "gumbo.h" 27 | #include "parser.h" 28 | 29 | // TODO(jdtang): This should be elsewhere, but there's no .c file for 30 | // SourcePositions and yet the constant needs some linkage, so this is as good 31 | // as any. 32 | const GumboSourcePosition kGumboEmptySourcePosition = { 0, 0, 0 }; 33 | 34 | void* gumbo_parser_allocate(GumboParser* parser, size_t num_bytes) { 35 | return parser->_options->allocator(parser->_options->userdata, num_bytes); 36 | } 37 | 38 | void gumbo_parser_deallocate(GumboParser* parser, void* ptr) { 39 | return parser->_options->deallocator(parser->_options->userdata, ptr); 40 | } 41 | 42 | char* gumbo_copy_stringz(GumboParser* parser, const char* str) { 43 | char* buffer = gumbo_parser_allocate(parser, strlen(str) + 1); 44 | strcpy(buffer, str); 45 | return buffer; 46 | } 47 | 48 | // Debug function to trace operation of the parser. Pass --copts=-DGUMBO_DEBUG 49 | // to use. 50 | void gumbo_debug(const char* format, ...) { 51 | #ifdef GUMBO_DEBUG 52 | va_list args; 53 | va_start(args, format); 54 | vprintf(format, args); 55 | va_end(args); 56 | fflush(stdout); 57 | #endif 58 | } 59 | -------------------------------------------------------------------------------- /deps/gumbo-parser/util.h: -------------------------------------------------------------------------------- 1 | // Copyright 2010 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | // Author: jdtang@google.com (Jonathan Tang) 16 | // 17 | // This contains some utility functions that didn't fit into any of the other 18 | // headers. 19 | 20 | #ifndef GUMBO_UTIL_H_ 21 | #define GUMBO_UTIL_H_ 22 | 23 | #include 24 | #include 25 | 26 | #ifdef __cplusplus 27 | extern "C" { 28 | #endif 29 | 30 | // Forward declaration since it's passed into some of the functions in this 31 | // header. 32 | struct GumboInternalParser; 33 | 34 | // Utility function for allocating & copying a null-terminated string into a 35 | // freshly-allocated buffer. This is necessary for proper memory management; we 36 | // have the convention that all const char* in parse tree structures are 37 | // freshly-allocated, so if we didn't copy, we'd try to delete a literal string 38 | // when the parse tree is destroyed. 39 | char* gumbo_copy_stringz(struct GumboInternalParser* parser, const char* str); 40 | 41 | // Allocate a chunk of memory, using the allocator specified in the Parser's 42 | // config options. 43 | void* gumbo_parser_allocate( 44 | struct GumboInternalParser* parser, size_t num_bytes); 45 | 46 | // Deallocate a chunk of memory, using the deallocator specified in the Parser's 47 | // config options. 48 | void gumbo_parser_deallocate(struct GumboInternalParser* parser, void* ptr); 49 | 50 | // Debug wrapper for printf, to make it easier to turn off debugging info when 51 | // required. 52 | void gumbo_debug(const char* format, ...); 53 | 54 | #ifdef __cplusplus 55 | } 56 | #endif 57 | 58 | #endif // GUMBO_UTIL_H_ 59 | -------------------------------------------------------------------------------- /deps/gumbo-parser/vector.c: -------------------------------------------------------------------------------- 1 | // Copyright 2010 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | // Author: jdtang@google.com (Jonathan Tang) 16 | 17 | #include "vector.h" 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include "util.h" 25 | 26 | struct GumboInternalParser; 27 | 28 | const GumboVector kGumboEmptyVector = { NULL, 0, 0 }; 29 | 30 | void gumbo_vector_init( 31 | struct GumboInternalParser* parser, size_t initial_capacity, GumboVector* vector) { 32 | vector->length = 0; 33 | vector->capacity = initial_capacity; 34 | if (initial_capacity > 0) { 35 | vector->data = gumbo_parser_allocate( 36 | parser, sizeof(void*) * initial_capacity); 37 | } else { 38 | vector->data = NULL; 39 | } 40 | } 41 | 42 | void gumbo_vector_destroy(struct GumboInternalParser* parser, GumboVector* vector) { 43 | if (vector->capacity > 0) { 44 | gumbo_parser_deallocate(parser, vector->data); 45 | } 46 | } 47 | 48 | static void enlarge_vector_if_full( 49 | struct GumboInternalParser* parser, GumboVector* vector) { 50 | if (vector->length >= vector->capacity) { 51 | if (vector->capacity) { 52 | size_t old_num_bytes = sizeof(void*) * vector->capacity; 53 | vector->capacity *= 2; 54 | size_t num_bytes = sizeof(void*) * vector->capacity; 55 | void** temp = gumbo_parser_allocate(parser, num_bytes); 56 | memcpy(temp, vector->data, old_num_bytes); 57 | gumbo_parser_deallocate(parser, vector->data); 58 | vector->data = temp; 59 | } else { 60 | // 0-capacity vector; no previous array to deallocate. 61 | vector->capacity = 2; 62 | vector->data = gumbo_parser_allocate( 63 | parser, sizeof(void*) * vector->capacity); 64 | } 65 | } 66 | } 67 | 68 | void gumbo_vector_add( 69 | struct GumboInternalParser* parser, void* element, GumboVector* vector) { 70 | enlarge_vector_if_full(parser, vector); 71 | assert(vector->data); 72 | assert(vector->length < vector->capacity); 73 | vector->data[vector->length++] = element; 74 | } 75 | 76 | void* gumbo_vector_pop( 77 | struct GumboInternalParser* parser, GumboVector* vector) { 78 | if (vector->length == 0) { 79 | return NULL; 80 | } 81 | return vector->data[--vector->length]; 82 | } 83 | 84 | int gumbo_vector_index_of(GumboVector* vector, void* element) { 85 | for (int i = 0; i < vector->length; ++i) { 86 | if (vector->data[i] == element) { 87 | return i; 88 | } 89 | } 90 | return -1; 91 | } 92 | 93 | void gumbo_vector_insert_at( 94 | struct GumboInternalParser* parser, void* element, int index, 95 | GumboVector* vector) { 96 | assert(index >= 0); 97 | assert(index <= vector->length); 98 | enlarge_vector_if_full(parser, vector); 99 | ++vector->length; 100 | memmove(&vector->data[index + 1], &vector->data[index], 101 | sizeof(void*) * (vector->length - index - 1)); 102 | vector->data[index] = element; 103 | } 104 | 105 | void gumbo_vector_remove( 106 | struct GumboInternalParser* parser, void* node, GumboVector* vector) { 107 | int index = gumbo_vector_index_of(vector, node); 108 | if (index == -1) { 109 | return; 110 | } 111 | gumbo_vector_remove_at(parser, index, vector); 112 | } 113 | 114 | void* gumbo_vector_remove_at( 115 | struct GumboInternalParser* parser, int index, GumboVector* vector) { 116 | assert(index >= 0); 117 | assert(index < vector->length); 118 | void* result = vector->data[index]; 119 | memmove(&vector->data[index], &vector->data[index + 1], 120 | sizeof(void*) * (vector->length - index - 1)); 121 | --vector->length; 122 | return result; 123 | } 124 | -------------------------------------------------------------------------------- /deps/gumbo-parser/vector.h: -------------------------------------------------------------------------------- 1 | // Copyright 2010 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | // Author: jdtang@google.com (Jonathan Tang) 16 | 17 | #ifndef GUMBO_VECTOR_H_ 18 | #define GUMBO_VECTOR_H_ 19 | 20 | #include "gumbo.h" 21 | 22 | #ifdef __cplusplus 23 | extern "C" { 24 | #endif 25 | 26 | // Forward declaration since it's passed into some of the functions in this 27 | // header. 28 | struct GumboInternalParser; 29 | 30 | // Initializes a new GumboVector with the specified initial capacity. 31 | void gumbo_vector_init( 32 | struct GumboInternalParser* parser, size_t initial_capacity, 33 | GumboVector* vector); 34 | 35 | // Frees the memory used by an GumboVector. Does not free the contained 36 | // pointers. 37 | void gumbo_vector_destroy( 38 | struct GumboInternalParser* parser, GumboVector* vector); 39 | 40 | // Adds a new element to an GumboVector. 41 | void gumbo_vector_add( 42 | struct GumboInternalParser* parser, void* element, GumboVector* vector); 43 | 44 | // Removes and returns the element most recently added to the GumboVector. 45 | // Ownership is transferred to caller. Capacity is unchanged. If the vector is 46 | // empty, NULL is returned. 47 | void* gumbo_vector_pop(struct GumboInternalParser* parser, GumboVector* vector); 48 | 49 | // Inserts an element at a specific index. This is potentially O(N) time, but 50 | // is necessary for some of the spec's behavior. 51 | void gumbo_vector_insert_at( 52 | struct GumboInternalParser* parser, void* element, int index, 53 | GumboVector* vector); 54 | 55 | // Removes an element from the vector, or does nothing if the element is not in 56 | // the vector. 57 | void gumbo_vector_remove( 58 | struct GumboInternalParser* parser, void* element, GumboVector* vector); 59 | 60 | // Removes and returns an element at a specific index. Note that this is 61 | // potentially O(N) time and should be used sparingly. 62 | void* gumbo_vector_remove_at( 63 | struct GumboInternalParser* parser, int index, GumboVector* vector); 64 | 65 | #ifdef __cplusplus 66 | } 67 | #endif 68 | 69 | #endif // GUMBO_VECTOR_H_ 70 | -------------------------------------------------------------------------------- /deps/gumbo-text-content/gumbo-text-content.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include "gumbo-parser/gumbo.h" 5 | #include "gumbo-text-content.h" 6 | 7 | /** 8 | * Maximum number of text nodes. 9 | */ 10 | 11 | #define GUMBO_TEXT_CONTENT_MAX 1024 12 | 13 | typedef struct { 14 | const char *nodes[GUMBO_TEXT_CONTENT_MAX]; 15 | size_t length; 16 | } text_nodes_t; 17 | 18 | /** 19 | * Get a `text_nodes_t` instance of all text nodes 20 | * contained in given `root` node. 21 | */ 22 | 23 | static text_nodes_t * 24 | get_text_nodes(GumboNode *root) { 25 | text_nodes_t *nodes = malloc(sizeof(text_nodes_t)); 26 | if (!nodes) return NULL; 27 | nodes->length = 0; 28 | 29 | GumboVector *children = &root->v.element.children; 30 | 31 | for (size_t i = 0; i < children->length; i++) { 32 | GumboNode *child = children->data[i]; 33 | if (GUMBO_NODE_TEXT == child->type) { 34 | nodes->nodes[nodes->length++] = child->v.text.text; 35 | } else if (GUMBO_NODE_ELEMENT == child->type) { 36 | text_nodes_t *child_nodes = get_text_nodes(child); 37 | // exit loop on malloc failure 38 | if (!child_nodes) break; 39 | // join children with our node 40 | if (child_nodes->length) { 41 | for (size_t j = 0; j < child_nodes->length; j++) { 42 | nodes->nodes[nodes->length++] = child_nodes->nodes[j]; 43 | } 44 | } 45 | free(child_nodes); 46 | } 47 | } 48 | return nodes; 49 | } 50 | 51 | 52 | /** 53 | * Get all text contained in the given `root` node, much 54 | * like `Node#textContent`. 55 | */ 56 | 57 | char * 58 | gumbo_text_content(GumboNode *node) { 59 | text_nodes_t *text_nodes = NULL; 60 | char *text_content = NULL; 61 | size_t length = 1; 62 | int pos = 0; 63 | 64 | text_nodes = get_text_nodes(node); 65 | if (!text_nodes) goto cleanup; 66 | 67 | // calculate total length of all text 68 | for (size_t i = 0; i < text_nodes->length; i++) { 69 | length += strlen(text_nodes->nodes[i]); 70 | } 71 | 72 | text_content = malloc(length); 73 | if (!text_content) goto cleanup; 74 | *text_content = '\0'; 75 | // join all text nodes 76 | for (size_t i = 0; i < text_nodes->length; i++) { 77 | size_t l = strlen(text_nodes->nodes[i]); 78 | strncat(&text_content[pos], text_nodes->nodes[i], l); 79 | pos += l; 80 | text_content[pos] = '\0'; 81 | } 82 | 83 | cleanup: 84 | free(text_nodes); 85 | return text_content; 86 | } 87 | -------------------------------------------------------------------------------- /deps/gumbo-text-content/gumbo-text-content.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef GUMBO_TEXT_CONTENT_H 3 | #define GUMBO_TEXT_CONTENT_H 1 4 | 5 | #include "gumbo-parser/gumbo.h" 6 | 7 | char * 8 | gumbo_text_content(GumboNode *); 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /deps/gumbo-text-content/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gumbo-text-content", 3 | "version": "1.0.3", 4 | "repo": "stephenmathieson/gumbo-text-content.c", 5 | "license": "MIT", 6 | "src": [ 7 | "src/gumbo-text-content.c", 8 | "src/gumbo-text-content.h" 9 | ], 10 | "development": { 11 | "thlorenz/gumbo-parser.c": "*" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /deps/hash/clib.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hash", 3 | "version": "0.0.1", 4 | "repo": "clibs/hash", 5 | "description": "Hash wrapper around khash", 6 | "keywords": ["hash", "khash", "container"], 7 | "license": "MIT", 8 | "src": ["hash.c", "hash.h", "khash.h"] 9 | } -------------------------------------------------------------------------------- /deps/hash/hash.c: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // hash.c 4 | // 5 | // Copyright (c) 2012 TJ Holowaychuk 6 | // 7 | 8 | #include "hash.h" 9 | 10 | /* 11 | * Set hash `key` to `val`. 12 | */ 13 | 14 | inline void 15 | hash_set(hash_t *self, char *key, void *val) { 16 | int ret; 17 | khiter_t k = kh_put(ptr, self, key, &ret); 18 | kh_value(self, k) = val; 19 | } 20 | 21 | /* 22 | * Get hash `key`, or NULL. 23 | */ 24 | 25 | inline void * 26 | hash_get(hash_t *self, char *key) { 27 | khiter_t k = kh_get(ptr, self, key); 28 | return k == kh_end(self) ? NULL : kh_value(self, k); 29 | } 30 | 31 | /* 32 | * Check if hash `key` exists. 33 | */ 34 | 35 | inline int 36 | hash_has(hash_t *self, char *key) { 37 | khiter_t k = kh_get(ptr, self, key); 38 | return kh_exist(self, k); 39 | } 40 | 41 | /* 42 | * Remove hash `key`. 43 | */ 44 | 45 | void 46 | hash_del(hash_t *self, char *key) { 47 | khiter_t k = kh_get(ptr, self, key); 48 | kh_del(ptr, self, k); 49 | } 50 | 51 | // tests 52 | 53 | #ifdef TEST_HASH 54 | 55 | #include 56 | #include 57 | #include 58 | 59 | void 60 | test_hash_set() { 61 | hash_t *hash = hash_new(); 62 | assert(0 == hash_size(hash)); 63 | 64 | hash_set(hash, "name", "tobi"); 65 | hash_set(hash, "species", "ferret"); 66 | assert(2 == hash_size(hash)); 67 | 68 | assert(0 == strcmp("tobi", hash_get(hash, "name"))); 69 | assert(0 == strcmp("ferret", hash_get(hash, "species"))); 70 | } 71 | 72 | void 73 | test_hash_get() { 74 | hash_t *hash = hash_new(); 75 | hash_set(hash, "foo", "bar"); 76 | assert(0 == strcmp("bar", hash_get(hash, "foo"))); 77 | assert(NULL == hash_get(hash, "bar")); 78 | } 79 | 80 | void 81 | test_hash_has() { 82 | hash_t *hash = hash_new(); 83 | hash_set(hash, "foo", "bar"); 84 | assert(1 == hash_has(hash, "foo")); 85 | assert(0 == hash_has(hash, "bar")); 86 | } 87 | 88 | void 89 | test_hash_size() { 90 | hash_t *hash = hash_new(); 91 | assert(0 == hash_size(hash)); 92 | hash_set(hash, "foo", "bar"); 93 | assert(1 == hash_size(hash)); 94 | hash_set(hash, "bar", "baz"); 95 | assert(2 == hash_size(hash)); 96 | } 97 | 98 | void 99 | test_hash_del() { 100 | hash_t *hash = hash_new(); 101 | hash_set(hash, "foo", "bar"); 102 | assert(1 == hash_has(hash, "foo")); 103 | assert(0 == hash_has(hash, "bar")); 104 | hash_del(hash, "foo"); 105 | hash_del(hash, "bar"); 106 | assert(0 == hash_has(hash, "foo")); 107 | } 108 | 109 | void 110 | test_hash_clear() { 111 | hash_t *hash = hash_new(); 112 | hash_set(hash, "foo", "bar"); 113 | hash_set(hash, "bar", "baz"); 114 | hash_set(hash, "raz", "jaz"); 115 | assert(3 == hash_size(hash)); 116 | hash_clear(hash); 117 | assert(0 == hash_size(hash)); 118 | } 119 | 120 | void 121 | test_hash_each() { 122 | hash_t *hash = hash_new(); 123 | hash_set(hash, "name", "tj"); 124 | hash_set(hash, "age", "25"); 125 | 126 | const char *keys[2]; 127 | void *vals[2]; 128 | int n = 0; 129 | 130 | hash_each(hash, { 131 | keys[n] = key; 132 | vals[n] = val; 133 | n++; 134 | }); 135 | 136 | assert(0 == strcmp("age", keys[0]) || 0 == strcmp("name", keys[0])); 137 | assert(0 == strcmp("age", keys[1]) || 0 == strcmp("name", keys[1])); 138 | assert(0 == strcmp("25", vals[0]) || 0 == strcmp("tj", vals[0])); 139 | assert(0 == strcmp("25", vals[1]) || 0 == strcmp("tj", vals[1])); 140 | } 141 | 142 | void 143 | test_hash_each_key() { 144 | hash_t *hash = hash_new(); 145 | hash_set(hash, "name", "tj"); 146 | hash_set(hash, "age", "25"); 147 | 148 | const char *keys[2]; 149 | int n = 0; 150 | 151 | hash_each_key(hash, { 152 | keys[n++] = key; 153 | }); 154 | 155 | assert(0 == strcmp("age", keys[0]) || 0 == strcmp("name", keys[0])); 156 | assert(0 == strcmp("age", keys[1]) || 0 == strcmp("name", keys[1])); 157 | } 158 | 159 | void 160 | test_hash_each_val() { 161 | hash_t *hash = hash_new(); 162 | hash_set(hash, "name", "tj"); 163 | hash_set(hash, "age", "25"); 164 | 165 | void *vals[2]; 166 | int n = 0; 167 | 168 | hash_each_val(hash, { 169 | vals[n++] = val; 170 | }); 171 | 172 | assert(0 == strcmp("25", vals[0]) || 0 == strcmp("tj", vals[0])); 173 | assert(0 == strcmp("25", vals[1]) || 0 == strcmp("tj", vals[1])); 174 | } 175 | 176 | int 177 | main(){ 178 | test_hash_set(); 179 | test_hash_get(); 180 | test_hash_has(); 181 | test_hash_del(); 182 | test_hash_size(); 183 | test_hash_clear(); 184 | test_hash_each(); 185 | test_hash_each_key(); 186 | test_hash_each_val(); 187 | printf("\n \e[32m\u2713 \e[90mok\e[0m\n\n"); 188 | return 0; 189 | } 190 | 191 | #endif -------------------------------------------------------------------------------- /deps/hash/hash.h: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // hash.h 4 | // 5 | // Copyright (c) 2012 TJ Holowaychuk 6 | // 7 | 8 | #ifndef HASH 9 | #define HASH 10 | 11 | #include "khash.h" 12 | 13 | // pointer hash 14 | 15 | KHASH_MAP_INIT_STR(ptr, void *); 16 | 17 | /* 18 | * Hash type. 19 | */ 20 | 21 | typedef khash_t(ptr) hash_t; 22 | 23 | /* 24 | * Allocate a new hash. 25 | */ 26 | 27 | #define hash_new() kh_init(ptr) 28 | 29 | /* 30 | * Destroy the hash. 31 | */ 32 | 33 | #define hash_free(self) kh_destroy(ptr, self) 34 | 35 | /* 36 | * Hash size. 37 | */ 38 | 39 | #define hash_size kh_size 40 | 41 | /* 42 | * Remove all pairs in the hash. 43 | */ 44 | 45 | #define hash_clear(self) kh_clear(ptr, self) 46 | 47 | /* 48 | * Iterate hash keys and ptrs, populating 49 | * `key` and `val`. 50 | */ 51 | 52 | #define hash_each(self, block) { \ 53 | const char *key; \ 54 | void *val; \ 55 | for (khiter_t k = kh_begin(self); k < kh_end(self); ++k) { \ 56 | if (!kh_exist(self, k)) continue; \ 57 | key = kh_key(self, k); \ 58 | val = kh_value(self, k); \ 59 | block; \ 60 | } \ 61 | } 62 | 63 | /* 64 | * Iterate hash keys, populating `key`. 65 | */ 66 | 67 | #define hash_each_key(self, block) { \ 68 | const char *key; \ 69 | for (khiter_t k = kh_begin(self); k < kh_end(self); ++k) { \ 70 | if (!kh_exist(self, k)) continue; \ 71 | key = kh_key(self, k); \ 72 | block; \ 73 | } \ 74 | } 75 | 76 | /* 77 | * Iterate hash ptrs, populating `val`. 78 | */ 79 | 80 | #define hash_each_val(self, block) { \ 81 | void *val; \ 82 | for (khiter_t k = kh_begin(self); k < kh_end(self); ++k) { \ 83 | if (!kh_exist(self, k)) continue; \ 84 | val = kh_value(self, k); \ 85 | block; \ 86 | } \ 87 | } 88 | 89 | // protos 90 | 91 | void 92 | hash_set(hash_t *self, char *key, void *val); 93 | 94 | void * 95 | hash_get(hash_t *self, char *key); 96 | 97 | int 98 | hash_has(hash_t *self, char *key); 99 | 100 | void 101 | hash_del(hash_t *self, char *key); 102 | 103 | void 104 | hash_clear(hash_t *self); 105 | 106 | #endif /* HASH */ -------------------------------------------------------------------------------- /deps/hash/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hash", 3 | "version": "0.0.1", 4 | "repo": "clibs/hash", 5 | "description": "Hash wrapper around khash", 6 | "keywords": ["hash", "khash", "container"], 7 | "license": "MIT", 8 | "src": ["hash.c", "hash.h", "khash.h"] 9 | } -------------------------------------------------------------------------------- /deps/http-get/clib.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "http-get", 3 | "version": "0.4.0", 4 | "repo": "clibs/http-get.c", 5 | "description": "Simple HTTP GET requests backed by libcurl", 6 | "keywords": [ 7 | "http", 8 | "curl", 9 | "get", 10 | "download" 11 | ], 12 | "license": "MIT", 13 | "src": [ 14 | "src/http-get.c", 15 | "src/http-get.h" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /deps/http-get/http-get.c: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // http-get.c 4 | // 5 | // Copyright (c) 2013 Stephen Mathieson 6 | // MIT licensed 7 | // 8 | 9 | #include 10 | #include 11 | #include 12 | #include "http-get.h" 13 | 14 | /** 15 | * HTTP GET write callback 16 | */ 17 | 18 | static size_t http_get_cb(void *contents, size_t size, size_t nmemb, void *userp) { 19 | size_t realsize = size * nmemb; 20 | http_get_response_t *res = userp; 21 | 22 | if (0 == res->data) { 23 | res->data = malloc(realsize + 1); 24 | } else { 25 | void *ptr = realloc(res->data, res->size + realsize + 1); 26 | 27 | if (NULL == ptr) { 28 | fprintf(stderr, "not enough memory!"); 29 | return 0; 30 | } 31 | 32 | res->data = ptr; 33 | } 34 | 35 | memset(res->data + res->size, 0, realsize); 36 | memcpy(res->data + res->size, contents, realsize); 37 | res->size += realsize; 38 | res->data[res->size] = 0; 39 | 40 | return realsize; 41 | } 42 | 43 | http_get_response_t *http_get_shared(const char *url, CURLSH *share) { 44 | CURL *req = curl_easy_init(); 45 | 46 | http_get_response_t *res = malloc(sizeof(http_get_response_t)); 47 | memset(res, 0, sizeof(http_get_response_t)); 48 | 49 | if (share) { 50 | curl_easy_setopt(req, CURLOPT_SHARE, share); 51 | } 52 | 53 | curl_easy_setopt(req, CURLOPT_URL, url); 54 | curl_easy_setopt(req, CURLOPT_HTTPGET, 1); 55 | curl_easy_setopt(req, CURLOPT_FOLLOWLOCATION, 1); 56 | curl_easy_setopt(req, CURLOPT_WRITEFUNCTION, http_get_cb); 57 | curl_easy_setopt(req, CURLOPT_WRITEDATA, (void *) res); 58 | curl_easy_setopt(req, CURLOPT_USERAGENT, "http-get.c/"HTTP_GET_VERSION); 59 | 60 | int c = curl_easy_perform(req); 61 | 62 | curl_easy_getinfo(req, CURLINFO_RESPONSE_CODE, &res->status); 63 | res->ok = (200 == res->status && CURLE_ABORTED_BY_CALLBACK != c) ? 1 : 0; 64 | curl_easy_cleanup(req); 65 | 66 | return res; 67 | } 68 | 69 | /** 70 | * Perform an HTTP(S) GET on `url` 71 | */ 72 | 73 | http_get_response_t *http_get(const char *url) { 74 | return http_get_shared(url, NULL); 75 | } 76 | 77 | /** 78 | * HTTP GET file write callback 79 | */ 80 | 81 | static size_t http_get_file_cb(void *ptr, size_t size, size_t nmemb, void *stream) { 82 | fflush(stream); 83 | size_t n = fwrite(ptr, size, nmemb, stream); 84 | return n; 85 | } 86 | 87 | /** 88 | * Request `url` and save to `file` 89 | */ 90 | 91 | int http_get_file_shared(const char *url, const char *file, CURLSH *share) { 92 | CURL *req = curl_easy_init(); 93 | if (!req) return -1; 94 | 95 | FILE *fp = fopen(file, "wb"); 96 | if (!fp) return -1; 97 | 98 | if (share) { 99 | curl_easy_setopt(req, CURLOPT_SHARE, share); 100 | } 101 | 102 | curl_easy_setopt(req, CURLOPT_URL, url); 103 | curl_easy_setopt(req, CURLOPT_HTTPGET, 1); 104 | curl_easy_setopt(req, CURLOPT_FOLLOWLOCATION, 1); 105 | curl_easy_setopt(req, CURLOPT_WRITEFUNCTION, http_get_file_cb); 106 | curl_easy_setopt(req, CURLOPT_WRITEDATA, fp); 107 | int res = curl_easy_perform(req); 108 | 109 | long status; 110 | curl_easy_getinfo(req, CURLINFO_RESPONSE_CODE, &status); 111 | 112 | curl_easy_cleanup(req); 113 | fclose(fp); 114 | 115 | return (200 == status && CURLE_ABORTED_BY_CALLBACK != res) ? 0 : -1; 116 | } 117 | 118 | int http_get_file(const char *url, const char *file) { 119 | return http_get_file_shared(url, file, NULL); 120 | } 121 | 122 | /** 123 | * Free the given `res` 124 | */ 125 | 126 | void http_get_free(http_get_response_t *res) { 127 | if (NULL == res) return; 128 | if (NULL != res->data) free(res->data); 129 | res->data = NULL; 130 | res->size = 0; 131 | free(res); 132 | } 133 | -------------------------------------------------------------------------------- /deps/http-get/http-get.h: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // http-get.h 4 | // 5 | // Copyright (c) 2013 Stephen Mathieson 6 | // MIT licensed 7 | // 8 | 9 | 10 | #ifndef HTTP_GET_H 11 | #define HTTP_GET_H 1 12 | 13 | #include 14 | 15 | #define HTTP_GET_VERSION "0.4.0" 16 | 17 | typedef struct { 18 | char *data; 19 | size_t size; 20 | long status; 21 | int ok; 22 | } http_get_response_t; 23 | 24 | http_get_response_t *http_get(const char *); 25 | http_get_response_t *http_get_shared(const char *, void *); 26 | 27 | int http_get_file(const char *, const char *); 28 | int http_get_file_shared(const char *, const char *, void *); 29 | 30 | void http_get_free(http_get_response_t *); 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /deps/list/list.c: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // list.c 4 | // 5 | // Copyright (c) 2010 TJ Holowaychuk 6 | // 7 | 8 | #include "list.h" 9 | 10 | /* 11 | * Allocate a new list_t. NULL on failure. 12 | */ 13 | 14 | list_t * 15 | list_new(void) { 16 | list_t *self; 17 | if (!(self = LIST_MALLOC(sizeof(list_t)))) 18 | return NULL; 19 | self->head = NULL; 20 | self->tail = NULL; 21 | self->free = NULL; 22 | self->match = NULL; 23 | self->len = 0; 24 | return self; 25 | } 26 | 27 | /* 28 | * Free the list. 29 | */ 30 | 31 | void 32 | list_destroy(list_t *self) { 33 | unsigned int len = self->len; 34 | list_node_t *next; 35 | list_node_t *curr = self->head; 36 | 37 | while (len--) { 38 | next = curr->next; 39 | if (self->free) self->free(curr->val); 40 | LIST_FREE(curr); 41 | curr = next; 42 | } 43 | 44 | LIST_FREE(self); 45 | } 46 | 47 | /* 48 | * Append the given node to the list 49 | * and return the node, NULL on failure. 50 | */ 51 | 52 | list_node_t * 53 | list_rpush(list_t *self, list_node_t *node) { 54 | if (!node) return NULL; 55 | 56 | if (self->len) { 57 | node->prev = self->tail; 58 | node->next = NULL; 59 | self->tail->next = node; 60 | self->tail = node; 61 | } else { 62 | self->head = self->tail = node; 63 | node->prev = node->next = NULL; 64 | } 65 | 66 | ++self->len; 67 | return node; 68 | } 69 | 70 | /* 71 | * Return / detach the last node in the list, or NULL. 72 | */ 73 | 74 | list_node_t * 75 | list_rpop(list_t *self) { 76 | if (!self->len) return NULL; 77 | 78 | list_node_t *node = self->tail; 79 | 80 | if (--self->len) { 81 | (self->tail = node->prev)->next = NULL; 82 | } else { 83 | self->tail = self->head = NULL; 84 | } 85 | 86 | node->next = node->prev = NULL; 87 | return node; 88 | } 89 | 90 | /* 91 | * Return / detach the first node in the list, or NULL. 92 | */ 93 | 94 | list_node_t * 95 | list_lpop(list_t *self) { 96 | if (!self->len) return NULL; 97 | 98 | list_node_t *node = self->head; 99 | 100 | if (--self->len) { 101 | (self->head = node->next)->prev = NULL; 102 | } else { 103 | self->head = self->tail = NULL; 104 | } 105 | 106 | node->next = node->prev = NULL; 107 | return node; 108 | } 109 | 110 | /* 111 | * Prepend the given node to the list 112 | * and return the node, NULL on failure. 113 | */ 114 | 115 | list_node_t * 116 | list_lpush(list_t *self, list_node_t *node) { 117 | if (!node) return NULL; 118 | 119 | if (self->len) { 120 | node->next = self->head; 121 | node->prev = NULL; 122 | self->head->prev = node; 123 | self->head = node; 124 | } else { 125 | self->head = self->tail = node; 126 | node->prev = node->next = NULL; 127 | } 128 | 129 | ++self->len; 130 | return node; 131 | } 132 | 133 | /* 134 | * Return the node associated to val or NULL. 135 | */ 136 | 137 | list_node_t * 138 | list_find(list_t *self, void *val) { 139 | list_iterator_t *it = list_iterator_new(self, LIST_HEAD); 140 | list_node_t *node; 141 | 142 | while ((node = list_iterator_next(it))) { 143 | if (self->match) { 144 | if (self->match(val, node->val)) { 145 | list_iterator_destroy(it); 146 | return node; 147 | } 148 | } else { 149 | if (val == node->val) { 150 | list_iterator_destroy(it); 151 | return node; 152 | } 153 | } 154 | } 155 | 156 | list_iterator_destroy(it); 157 | return NULL; 158 | } 159 | 160 | /* 161 | * Return the node at the given index or NULL. 162 | */ 163 | 164 | list_node_t * 165 | list_at(list_t *self, int index) { 166 | list_direction_t direction = LIST_HEAD; 167 | 168 | if (index < 0) { 169 | direction = LIST_TAIL; 170 | index = ~index; 171 | } 172 | 173 | if ((unsigned)index < self->len) { 174 | list_iterator_t *it = list_iterator_new(self, direction); 175 | list_node_t *node = list_iterator_next(it); 176 | while (index--) node = list_iterator_next(it); 177 | list_iterator_destroy(it); 178 | return node; 179 | } 180 | 181 | return NULL; 182 | } 183 | 184 | /* 185 | * Remove the given node from the list, freeing it and it's value. 186 | */ 187 | 188 | void 189 | list_remove(list_t *self, list_node_t *node) { 190 | node->prev 191 | ? (node->prev->next = node->next) 192 | : (self->head = node->next); 193 | 194 | node->next 195 | ? (node->next->prev = node->prev) 196 | : (self->tail = node->prev); 197 | 198 | if (self->free) self->free(node->val); 199 | 200 | LIST_FREE(node); 201 | --self->len; 202 | } 203 | -------------------------------------------------------------------------------- /deps/list/list.h: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // list.h 4 | // 5 | // Copyright (c) 2010 TJ Holowaychuk 6 | // 7 | 8 | #ifndef __CLIBS_LIST_H__ 9 | #define __CLIBS_LIST_H__ 10 | 11 | #ifdef __cplusplus 12 | extern "C" { 13 | #endif 14 | 15 | #include 16 | 17 | // Library version 18 | 19 | #define LIST_VERSION "0.0.5" 20 | 21 | // Memory management macros 22 | #ifdef LIST_CONFIG_H 23 | #define _STR(x) #x 24 | #define STR(x) _STR(x) 25 | #include STR(LIST_CONFIG_H) 26 | #undef _STR 27 | #undef STR 28 | #endif 29 | 30 | #ifndef LIST_MALLOC 31 | #define LIST_MALLOC malloc 32 | #endif 33 | 34 | #ifndef LIST_FREE 35 | #define LIST_FREE free 36 | #endif 37 | 38 | /* 39 | * list_t iterator direction. 40 | */ 41 | 42 | typedef enum { 43 | LIST_HEAD 44 | , LIST_TAIL 45 | } list_direction_t; 46 | 47 | /* 48 | * list_t node struct. 49 | */ 50 | 51 | typedef struct list_node { 52 | struct list_node *prev; 53 | struct list_node *next; 54 | void *val; 55 | } list_node_t; 56 | 57 | /* 58 | * list_t struct. 59 | */ 60 | 61 | typedef struct { 62 | list_node_t *head; 63 | list_node_t *tail; 64 | unsigned int len; 65 | void (*free)(void *val); 66 | int (*match)(void *a, void *b); 67 | } list_t; 68 | 69 | /* 70 | * list_t iterator struct. 71 | */ 72 | 73 | typedef struct { 74 | list_node_t *next; 75 | list_direction_t direction; 76 | } list_iterator_t; 77 | 78 | // Node prototypes. 79 | 80 | list_node_t * 81 | list_node_new(void *val); 82 | 83 | // list_t prototypes. 84 | 85 | list_t * 86 | list_new(void); 87 | 88 | list_node_t * 89 | list_rpush(list_t *self, list_node_t *node); 90 | 91 | list_node_t * 92 | list_lpush(list_t *self, list_node_t *node); 93 | 94 | list_node_t * 95 | list_find(list_t *self, void *val); 96 | 97 | list_node_t * 98 | list_at(list_t *self, int index); 99 | 100 | list_node_t * 101 | list_rpop(list_t *self); 102 | 103 | list_node_t * 104 | list_lpop(list_t *self); 105 | 106 | void 107 | list_remove(list_t *self, list_node_t *node); 108 | 109 | void 110 | list_destroy(list_t *self); 111 | 112 | // list_t iterator prototypes. 113 | 114 | list_iterator_t * 115 | list_iterator_new(list_t *list, list_direction_t direction); 116 | 117 | list_iterator_t * 118 | list_iterator_new_from_node(list_node_t *node, list_direction_t direction); 119 | 120 | list_node_t * 121 | list_iterator_next(list_iterator_t *self); 122 | 123 | void 124 | list_iterator_destroy(list_iterator_t *self); 125 | 126 | #ifdef __cplusplus 127 | } 128 | #endif 129 | 130 | #endif /* __CLIBS_LIST_H__ */ 131 | -------------------------------------------------------------------------------- /deps/list/list_iterator.c: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // iterator.c 4 | // 5 | // Copyright (c) 2010 TJ Holowaychuk 6 | // 7 | 8 | #include "list.h" 9 | 10 | /* 11 | * Allocate a new list_iterator_t. NULL on failure. 12 | * Accepts a direction, which may be LIST_HEAD or LIST_TAIL. 13 | */ 14 | 15 | list_iterator_t * 16 | list_iterator_new(list_t *list, list_direction_t direction) { 17 | list_node_t *node = direction == LIST_HEAD 18 | ? list->head 19 | : list->tail; 20 | return list_iterator_new_from_node(node, direction); 21 | } 22 | 23 | /* 24 | * Allocate a new list_iterator_t with the given start 25 | * node. NULL on failure. 26 | */ 27 | 28 | list_iterator_t * 29 | list_iterator_new_from_node(list_node_t *node, list_direction_t direction) { 30 | list_iterator_t *self; 31 | if (!(self = LIST_MALLOC(sizeof(list_iterator_t)))) 32 | return NULL; 33 | self->next = node; 34 | self->direction = direction; 35 | return self; 36 | } 37 | 38 | /* 39 | * Return the next list_node_t or NULL when no more 40 | * nodes remain in the list. 41 | */ 42 | 43 | list_node_t * 44 | list_iterator_next(list_iterator_t *self) { 45 | list_node_t *curr = self->next; 46 | if (curr) { 47 | self->next = self->direction == LIST_HEAD 48 | ? curr->next 49 | : curr->prev; 50 | } 51 | return curr; 52 | } 53 | 54 | /* 55 | * Free the list iterator. 56 | */ 57 | 58 | void 59 | list_iterator_destroy(list_iterator_t *self) { 60 | LIST_FREE(self); 61 | self = NULL; 62 | } 63 | -------------------------------------------------------------------------------- /deps/list/list_node.c: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // node.c 4 | // 5 | // Copyright (c) 2010 TJ Holowaychuk 6 | // 7 | 8 | #include "list.h" 9 | 10 | /* 11 | * Allocates a new list_node_t. NULL on failure. 12 | */ 13 | 14 | list_node_t * 15 | list_node_new(void *val) { 16 | list_node_t *self; 17 | if (!(self = LIST_MALLOC(sizeof(list_node_t)))) 18 | return NULL; 19 | self->prev = NULL; 20 | self->next = NULL; 21 | self->val = val; 22 | return self; 23 | } -------------------------------------------------------------------------------- /deps/list/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "list", 3 | "version": "0.1.0", 4 | "repo": "clibs/list", 5 | "description": "Simple linked list", 6 | "keywords": ["list", "structure"], 7 | "license": "MIT", 8 | "src": [ 9 | "src/list_iterator.c", 10 | "src/list.c", 11 | "src/list_node.c", 12 | "src/list.h" 13 | ], 14 | "development": { 15 | "bench": "*" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /deps/logger/clib.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "logger", 3 | "version": "0.0.1", 4 | "repo": "clibs/logger", 5 | "src": ["logger.h"], 6 | "dependencies": { 7 | "Constellation/console-colors.c": "1.0.1" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /deps/logger/logger.h: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // logger.h 4 | // 5 | // Copyright (c) 2014 Stephen Mathieson 6 | // MIT licensed 7 | // 8 | 9 | #ifndef CLIB_LOGGER_H 10 | #define CLIB_LOGGER_H 1 11 | 12 | #include 13 | #include "console-colors/console-colors.h" 14 | 15 | #ifndef CLIB_LOGGER_FMT 16 | # define CLIB_LOGGER_FMT " %10s" 17 | #endif 18 | 19 | /** 20 | * Log an info message to stdout. 21 | */ 22 | 23 | #define logger_info(type, ...) ({ \ 24 | cc_fprintf(CC_FG_CYAN, stdout, CLIB_LOGGER_FMT, type); \ 25 | fprintf(stdout, " : "); \ 26 | cc_fprintf(CC_FG_DARK_GRAY, stdout, __VA_ARGS__); \ 27 | fprintf(stdout, "\n"); \ 28 | }); 29 | 30 | /** 31 | * Log a warning to stdout. 32 | */ 33 | 34 | #define logger_warn(type, ...) ({ \ 35 | cc_fprintf(CC_FG_DARK_YELLOW, stdout, CLIB_LOGGER_FMT, type); \ 36 | fprintf(stdout, " : "); \ 37 | cc_fprintf(CC_FG_DARK_GRAY, stdout, __VA_ARGS__); \ 38 | fprintf(stdout, "\n"); \ 39 | }); 40 | 41 | /** 42 | * Log an error message to stderr. 43 | */ 44 | 45 | #define logger_error(type, ...) ({ \ 46 | cc_fprintf(CC_FG_DARK_RED, stderr, CLIB_LOGGER_FMT, type); \ 47 | fprintf(stderr, " : "); \ 48 | cc_fprintf(CC_FG_DARK_GRAY, stderr, __VA_ARGS__); \ 49 | fprintf(stderr, "\n"); \ 50 | }); 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /deps/logger/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "logger", 3 | "version": "0.0.1", 4 | "repo": "clibs/logger", 5 | "src": ["logger.h"], 6 | "dependencies": { 7 | "Constellation/console-colors.c": "1.0.1" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /deps/mkdirp/mkdirp.c: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // mkdirp.c 4 | // 5 | // Copyright (c) 2013 Stephen Mathieson 6 | // MIT licensed 7 | // 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include "strdup/strdup.h" 14 | #include "path-normalize/path-normalize.h" 15 | #include "mkdirp.h" 16 | 17 | #ifdef _WIN32 18 | #define PATH_SEPARATOR '\\' 19 | #else 20 | #define PATH_SEPARATOR '/' 21 | #endif 22 | 23 | /* 24 | * Recursively `mkdir(path, mode)` 25 | */ 26 | 27 | int 28 | mkdirp(const char *path, mode_t mode) { 29 | char *pathname = NULL; 30 | char *parent = NULL; 31 | 32 | if (NULL == path) return -1; 33 | 34 | pathname = path_normalize(path); 35 | if (NULL == pathname) goto fail; 36 | 37 | parent = strdup(pathname); 38 | if (NULL == parent) goto fail; 39 | 40 | char *p = parent + strlen(parent); 41 | while (PATH_SEPARATOR != *p && p != parent) { 42 | p--; 43 | } 44 | *p = '\0'; 45 | 46 | // make parent dir 47 | if (p != parent && 0 != mkdirp(parent, mode)) goto fail; 48 | free(parent); 49 | 50 | // make this one if parent has been made 51 | #ifdef _WIN32 52 | // http://msdn.microsoft.com/en-us/library/2fkk4dzw.aspx 53 | int rc = mkdir(pathname); 54 | #else 55 | int rc = mkdir(pathname, mode); 56 | #endif 57 | 58 | free(pathname); 59 | 60 | return 0 == rc || EEXIST == errno 61 | ? 0 62 | : -1; 63 | 64 | fail: 65 | free(pathname); 66 | free(parent); 67 | return -1; 68 | } 69 | -------------------------------------------------------------------------------- /deps/mkdirp/mkdirp.h: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // mkdirp.h 4 | // 5 | // Copyright (c) 2013 Stephen Mathieson 6 | // MIT licensed 7 | // 8 | 9 | #ifndef MKDIRP 10 | #define MKDIRP 11 | 12 | #include 13 | #include 14 | 15 | /* 16 | * Recursively `mkdir(path, mode)` 17 | */ 18 | 19 | int mkdirp(const char *, mode_t ); 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /deps/mkdirp/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mkdirp", 3 | "version": "0.1.5", 4 | "repo": "stephenmathieson/mkdirp.c", 5 | "description": "mkdir -p", 6 | "keywords": [ 7 | "mkdir", 8 | "mkdirp" 9 | ], 10 | "license": "MIT", 11 | "src": [ 12 | "src/mkdirp.c", 13 | "src/mkdirp.h" 14 | ], 15 | "dependencies": { 16 | "stephenmathieson/path-normalize.c": "*", 17 | "strdup": "0.0.0" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /deps/occurrences/occurrences.c: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // occurrences.c 4 | // 5 | // Copyright (c) 2013 Stephen Mathieson 6 | // MIT licensed 7 | // 8 | 9 | #include 10 | #include 11 | #include "occurrences.h" 12 | 13 | /* 14 | * Get the number of occurrences of `needle` in `haystack` 15 | */ 16 | 17 | size_t 18 | occurrences(const char *needle, const char *haystack) { 19 | if (NULL == needle || NULL == haystack) return -1; 20 | 21 | char *pos = (char *)haystack; 22 | size_t i = 0; 23 | size_t l = strlen(needle); 24 | 25 | while ((pos = strstr(pos, needle))) { 26 | pos += l; 27 | i++; 28 | } 29 | 30 | return i; 31 | } 32 | -------------------------------------------------------------------------------- /deps/occurrences/occurrences.h: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // occurrences.h 4 | // 5 | // Copyright (c) 2013 Stephen Mathieson 6 | // MIT licensed 7 | // 8 | 9 | 10 | #ifndef OCCURRENCES_H 11 | #define OCCURRENCES_H 1 12 | 13 | size_t 14 | occurrences(const char *, const char *); 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /deps/occurrences/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "occurrences", 3 | "version": "1.0.0", 4 | "repo": "stephenmathieson/occurrences.c", 5 | "description": "Get the number of occurrences of `needle` in `haystack`", 6 | "keywords": [ "string", "occurrences", "count" ], 7 | "license": "MIT", 8 | "src": [ 9 | "occurrences.c", 10 | "occurrences.h" 11 | ], 12 | "development": { 13 | "stephenmathieson/describe.h": "2.0.1" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /deps/parse-repo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "parse-repo", 3 | "version": "1.1.1", 4 | "repo": "stephenmathieson/parse-repo.c", 5 | "description": "Parse GitHub style repos", 6 | "keywords": [ "parse", "GitHub", "repo" ], 7 | "license": "MIT", 8 | "src": [ 9 | "src/parse-repo.c", 10 | "src/parse-repo.h" 11 | ], 12 | "dependencies": { 13 | "stephenmathieson/substr.c": "0.1.2", 14 | "strdup": "0.0.0" 15 | }, 16 | "development": { 17 | "stephenmathieson/describe.h": "*" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /deps/parse-repo/parse-repo.c: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // parse-repo.c 4 | // 5 | // Copyright (c) 2014 Stephen Mathieson 6 | // MIT licensed 7 | // 8 | 9 | #include 10 | #include 11 | #include 12 | #include "strdup/strdup.h" 13 | #include "substr/substr.h" 14 | #include "parse-repo.h" 15 | 16 | char * 17 | parse_repo_owner(const char *slug, const char *fallback) { 18 | char *copy = NULL; 19 | char *owner = NULL; 20 | 21 | if (NULL == slug) return NULL; 22 | if (0 == strlen(slug)) return NULL; 23 | if (!(copy = strdup(slug))) return NULL; 24 | 25 | if ((owner = strchr(copy, '/'))) { 26 | int delta = owner - copy; 27 | if (!delta) { 28 | free(copy); 29 | return NULL; 30 | } 31 | 32 | char *tmp = substr(copy, 0, delta); 33 | free(copy); 34 | return tmp; 35 | } 36 | 37 | if (fallback && 0 < strlen(copy) && '@' != copy[0]) { 38 | owner = strdup(fallback); 39 | } 40 | 41 | free(copy); 42 | return owner; 43 | } 44 | 45 | char * 46 | parse_repo_name(const char *slug) { 47 | char *owner = NULL; 48 | char *copy = NULL; 49 | char *name = NULL; 50 | char *version = NULL; 51 | 52 | if (NULL == slug) return NULL; 53 | if (0 == strlen(slug)) return NULL; 54 | if (!(copy = strdup(slug))) return NULL; 55 | 56 | if ((version = strchr(copy, '@'))) { 57 | int delta = version - copy; 58 | char *tmp = substr(copy, 0, delta); 59 | free(copy); 60 | if (!tmp) return NULL; 61 | copy = tmp; 62 | } 63 | 64 | if ((owner = strchr(copy, '/'))) { 65 | int delta = owner - copy; 66 | if (!delta) { 67 | free(copy); 68 | return NULL; 69 | } 70 | 71 | char *tmp = substr(copy, delta + 1, -1); 72 | free(copy); 73 | copy = tmp; 74 | } 75 | 76 | if (copy) name = strdup(copy); 77 | free(copy); 78 | return name; 79 | } 80 | 81 | char * 82 | parse_repo_version(const char *slug, const char *fallback) { 83 | // malformed slugs 84 | if (NULL == slug) return NULL; 85 | if (0 == strlen(slug)) return NULL; 86 | char *name = parse_repo_name(slug); 87 | if (NULL == name) return NULL; 88 | free(name); 89 | 90 | char *version = strchr(slug, '@'); 91 | if (version) { 92 | version++; 93 | // malformed 94 | if (0 == strlen(version)) return NULL; 95 | // * <-> master 96 | if ('*' == version[0]) return strdup("master"); 97 | return strdup(version); 98 | } 99 | 100 | version = NULL; 101 | if (fallback) version = strdup(fallback); 102 | return version; 103 | } 104 | -------------------------------------------------------------------------------- /deps/parse-repo/parse-repo.h: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // parse-repo.h 4 | // 5 | // Copyright (c) 2014 Stephen Mathieson 6 | // MIT licensed 7 | // 8 | 9 | #ifndef PARSE_REPO_H 10 | #define PARSE_REPO_H 1 11 | 12 | /** 13 | * Parse the repo owner from the given slug. If 14 | * no owner is provided and `fallback != NULL`, 15 | * will return a copy of `fallback`. 16 | * 17 | * Free the result when you're done with it. 18 | */ 19 | 20 | char * 21 | parse_repo_owner(const char *, const char *); 22 | 23 | /** 24 | * Parse the repo name from the given slug. 25 | * 26 | * Free the result when you're done with it. 27 | */ 28 | 29 | char * 30 | parse_repo_name(const char *); 31 | 32 | /** 33 | * Parse the repo version from the given slug. If 34 | * no version is present and `fallback != NULL`, 35 | * will return a copy of `fallback`. 36 | * 37 | * Free the result when you're done with it. 38 | */ 39 | 40 | char * 41 | parse_repo_version(const char *, const char *); 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /deps/parson/clib.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "parson", 3 | "version": "1.0.2", 4 | "repo": "clibs/parson", 5 | "description": "Small json parser and reader", 6 | "keywords": [ "json", "parser" ], 7 | "license": "MIT", 8 | "src": [ 9 | "parson.c", 10 | "parson.h" 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /deps/parson/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "parson", 3 | "version": "1.0.2", 4 | "repo": "clibs/parson", 5 | "description": "Small json parser and reader", 6 | "keywords": [ "json", "parser" ], 7 | "license": "MIT", 8 | "src": [ 9 | "parson.c", 10 | "parson.h" 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /deps/path-join/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "path-join", 3 | "version": "0.0.6", 4 | "repo": "stephenmathieson/path-join.c", 5 | "description": "Join a path", 6 | "keywords": [ 7 | "path", 8 | "join", 9 | "directory", 10 | "file" 11 | ], 12 | "license": "MIT", 13 | "src": [ 14 | "src/path-join.c", 15 | "src/path-join.h" 16 | ], 17 | "dependencies": { 18 | "stephenmathieson/str-starts-with.c": "*", 19 | "stephenmathieson/str-ends-with.c": "*", 20 | "strdup": "0.0.0" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /deps/path-join/path-join.c: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // path-join.c 4 | // 5 | // Copyright (c) 2013 Stephen Mathieson 6 | // MIT licensed 7 | // 8 | 9 | #include 10 | #include 11 | #include "strdup/strdup.h" 12 | #include "str-ends-with/str-ends-with.h" 13 | #include "str-starts-with/str-starts-with.h" 14 | #include "path-join.h" 15 | 16 | #ifdef _WIN32 17 | #define PATH_JOIN_SEPERATOR "\\" 18 | #else 19 | #define PATH_JOIN_SEPERATOR "/" 20 | #endif 21 | 22 | /* 23 | * Join `dir` with `file` 24 | */ 25 | 26 | char * 27 | path_join(const char *dir, const char *file) { 28 | int size = strlen(dir) + strlen(file) + 2; 29 | char *buf = malloc(size * sizeof(char)); 30 | if (NULL == buf) return NULL; 31 | 32 | strcpy(buf, dir); 33 | 34 | // add the sep if necessary 35 | if (!str_ends_with(dir, PATH_JOIN_SEPERATOR)) { 36 | strcat(buf, PATH_JOIN_SEPERATOR); 37 | } 38 | 39 | // remove the sep if necessary 40 | if (str_starts_with(file, PATH_JOIN_SEPERATOR)) { 41 | char *filecopy = strdup(file); 42 | if (NULL == filecopy) { 43 | free(buf); 44 | return NULL; 45 | } 46 | strcat(buf, ++filecopy); 47 | free(--filecopy); 48 | } else { 49 | strcat(buf, file); 50 | } 51 | 52 | return buf; 53 | } 54 | -------------------------------------------------------------------------------- /deps/path-join/path-join.h: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // path-join.h 4 | // 5 | // Copyright (c) 2013 Stephen Mathieson 6 | // MIT licensed 7 | // 8 | 9 | 10 | #ifndef PATH_JOIN_H 11 | #define PATH_JOIN_H 1 12 | 13 | char * 14 | path_join(const char *, const char *); 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /deps/path-normalize/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "path-normalize", 3 | "version": "0.0.6", 4 | "repo": "stephenmathieson/path-normalize.c", 5 | "description": "Normalize a path", 6 | "keywords": [ 7 | "path", 8 | "directory", 9 | "normalize" 10 | ], 11 | "license": "MIT", 12 | "src": [ 13 | "src/path-normalize.c", 14 | "src/path-normalize.h" 15 | ], 16 | "dependencies": { 17 | "strdup": "0.0.0" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /deps/path-normalize/path-normalize.c: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // path-normalize.c 4 | // 5 | // Copyright (c) 2013 Stephen Mathieson 6 | // MIT licensed 7 | // 8 | 9 | #include 10 | #include "strdup/strdup.h" 11 | #include "path-normalize.h" 12 | 13 | /* 14 | * Normalize the given `path` 15 | */ 16 | 17 | char * 18 | path_normalize(const char *path) { 19 | if (!path) return NULL; 20 | 21 | char *copy = strdup(path); 22 | if (NULL == copy) return NULL; 23 | char *ptr = copy; 24 | 25 | for (int i = 0; copy[i]; i++) { 26 | *ptr++ = path[i]; 27 | if ('/' == path[i]) { 28 | i++; 29 | while ('/' == path[i]) i++; 30 | i--; 31 | } 32 | } 33 | 34 | *ptr = '\0'; 35 | 36 | return copy; 37 | } 38 | -------------------------------------------------------------------------------- /deps/path-normalize/path-normalize.h: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // path-normalize.h 4 | // 5 | // Copyright (c) 2013 Stephen Mathieson 6 | // MIT licensed 7 | // 8 | 9 | 10 | #ifndef PATH_NORMALIZE_H 11 | #define PATH_NORMALIZE_H 1 12 | 13 | /* 14 | * Normalize the given `path` 15 | */ 16 | 17 | char * 18 | path_normalize(const char *); 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /deps/rimraf/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rimraf", 3 | "version": "0.1.0", 4 | "repo": "stephenmathieson/rimraf.c", 5 | "description": "rm -rf", 6 | "keywords": [ "rm", "rimraf", "unlink" ], 7 | "license": "MIT", 8 | "src": [ 9 | "src/rimraf.c", 10 | "src/rimraf.h" 11 | ], 12 | "dependencies": { 13 | "stephenmathieson/path-join.c": "master" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /deps/rimraf/rimraf.c: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // rimraf.c 4 | // 5 | // Copyright (c) 2013 Stephen Mathieson 6 | // MIT licensed 7 | // 8 | 9 | #define _POSIX_C_SOURCE 200809L 10 | 11 | // hack 12 | #ifndef S_IFDIR 13 | #define S_IFDIR 0040000 14 | #endif 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include "path-join/path-join.h" 22 | #include "rimraf.h" 23 | 24 | /* 25 | * rm -rf $path 26 | */ 27 | 28 | int 29 | rimraf(const char *path) { 30 | DIR *dir = opendir(path); 31 | if (NULL == dir) return -1; 32 | 33 | struct dirent *dp = NULL; 34 | while (NULL != (dp = readdir(dir))) { 35 | if (0 == strcmp(".", dp->d_name) 36 | || 0 == strcmp("..", dp->d_name)) continue; 37 | 38 | char *f = path_join(path, dp->d_name); 39 | if (NULL == f) return -1; 40 | 41 | struct stat s; 42 | if (0 != stat(f, &s)) return -1; 43 | if (s.st_mode & S_IFDIR) { 44 | // rimraf dirs 45 | if (-1 == rimraf(f)) return -1; 46 | } else { 47 | // unlink files 48 | if (-1 == unlink(f)) return -1; 49 | } 50 | free(f); 51 | } 52 | free(dp); 53 | closedir(dir); 54 | 55 | return rmdir(path); 56 | } 57 | -------------------------------------------------------------------------------- /deps/rimraf/rimraf.h: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // rimraf.h 4 | // 5 | // Copyright (c) 2013 Stephen Mathieson 6 | // MIT licensed 7 | // 8 | 9 | #ifndef RIMRAF_H 10 | #define RIMRAF_H 11 | 12 | #define RIMRAF_VERSION "0.0.1" 13 | 14 | int 15 | rimraf(const char *); 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /deps/semver/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "semver", 3 | "version": "1.0.0", 4 | "repo": "h2non/semver.c", 5 | "author": "Tomas Aparicio", 6 | "license": "MIT", 7 | "description": "Semantic version parser and render written in ANSI C", 8 | "keywords": ["semver", "semantic", "versioning", "version", "parser", "dependencies", "matcher", "ansi"], 9 | "src": ["semver.c", "semver.h"] 10 | } 11 | -------------------------------------------------------------------------------- /deps/semver/semver.h: -------------------------------------------------------------------------------- 1 | /* 2 | * semver.h 3 | * 4 | * Copyright (c) 2015-2017 Tomas Aparicio 5 | * MIT licensed 6 | */ 7 | 8 | #ifndef __SEMVER_H 9 | #define __SEMVER_H 10 | 11 | #ifdef __cplusplus 12 | extern "C" { 13 | #endif 14 | 15 | #ifndef SEMVER_VERSION 16 | #define SEMVER_VERSION "0.2.0" 17 | #endif 18 | 19 | /** 20 | * semver_t struct 21 | */ 22 | 23 | typedef struct semver_version_s { 24 | int major; 25 | int minor; 26 | int patch; 27 | char * metadata; 28 | char * prerelease; 29 | } semver_t; 30 | 31 | /** 32 | * Set prototypes 33 | */ 34 | 35 | int 36 | semver_satisfies (semver_t x, semver_t y, const char *op); 37 | 38 | int 39 | semver_satisfies_caret (semver_t x, semver_t y); 40 | 41 | int 42 | semver_satisfies_patch (semver_t x, semver_t y); 43 | 44 | int 45 | semver_compare (semver_t x, semver_t y); 46 | 47 | int 48 | semver_compare_version (semver_t x, semver_t y); 49 | 50 | int 51 | semver_compare_prerelease (semver_t x, semver_t y); 52 | 53 | int 54 | semver_gt (semver_t x, semver_t y); 55 | 56 | int 57 | semver_gte (semver_t x, semver_t y); 58 | 59 | int 60 | semver_lt (semver_t x, semver_t y); 61 | 62 | int 63 | semver_lte (semver_t x, semver_t y); 64 | 65 | int 66 | semver_eq (semver_t x, semver_t y); 67 | 68 | int 69 | semver_neq (semver_t x, semver_t y); 70 | 71 | int 72 | semver_parse (const char *str, semver_t *ver); 73 | 74 | int 75 | semver_parse_version (const char *str, semver_t *ver); 76 | 77 | void 78 | semver_render (semver_t *x, char *dest); 79 | 80 | int 81 | semver_numeric (semver_t *x); 82 | 83 | void 84 | semver_bump (semver_t *x); 85 | 86 | void 87 | semver_bump_minor (semver_t *x); 88 | 89 | void 90 | semver_bump_patch (semver_t *x); 91 | 92 | void 93 | semver_free (semver_t *x); 94 | 95 | int 96 | semver_is_valid (const char *s); 97 | 98 | int 99 | semver_clean (char *s); 100 | 101 | #ifdef __cplusplus 102 | } 103 | #endif 104 | 105 | #endif 106 | -------------------------------------------------------------------------------- /deps/str-ends-with/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "str-ends-with", 3 | "version": "0.0.3", 4 | "repo": "stephenmathieson/str-ends-with.c", 5 | "description": "Check if a string ends with another string", 6 | "keywords": [ "string" ], 7 | "license": "MIT", 8 | "src": [ 9 | "src/str-ends-with.c", 10 | "src/str-ends-with.h" 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /deps/str-ends-with/str-ends-with.c: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // str-ends-with.c 4 | // 5 | // Copyright (c) 2013 Stephen Mathieson 6 | // MIT licensed 7 | // 8 | 9 | #include 10 | #include 11 | #include "str-ends-with.h" 12 | 13 | bool str_ends_with(const char *str, const char *end) { 14 | int end_len; 15 | int str_len; 16 | 17 | if (NULL == str || NULL == end) return false; 18 | 19 | end_len = strlen(end); 20 | str_len = strlen(str); 21 | 22 | return str_len < end_len 23 | ? false 24 | : !strcmp(str + str_len - end_len, end); 25 | } 26 | -------------------------------------------------------------------------------- /deps/str-ends-with/str-ends-with.h: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // str-ends-with.h 4 | // 5 | // Copyright (c) 2013 Stephen Mathieson 6 | // MIT licensed 7 | // 8 | 9 | 10 | #ifndef STR_ENDS_WITH 11 | #define STR_ENDS_WITH 12 | 13 | #include 14 | #include 15 | 16 | bool str_ends_with(const char *str, const char *end); 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /deps/str-flatten/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "str-flatten", 3 | "version": "0.0.4", 4 | "repo": "stephenmathieson/str-flatten.c", 5 | "description": "Flatten a char array, ripped out of sphia(1)", 6 | "keywords": [ "string", "flatten", "join" ], 7 | "license": "MIT", 8 | "src": [ 9 | "src/str-flatten.c", 10 | "src/str-flatten.h" 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /deps/str-flatten/str-flatten.c: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // str-flatten.c 4 | // 5 | // Copyright (c) 2014 Stephen Mathieson 6 | // MIT licensed 7 | // 8 | 9 | #include 10 | #include 11 | #include "str-flatten.h" 12 | 13 | char * 14 | str_flatten(const char *array[], int start, int end) { 15 | int count = end - start; 16 | size_t lengths[count]; 17 | size_t size = 0; 18 | size_t pos = 0; 19 | 20 | for (int i = start, j = 0; i < end; ++i, ++j) { 21 | lengths[j] = strlen(array[i]); 22 | size += lengths[j]; 23 | } 24 | 25 | char *str = malloc(size + count); 26 | str[size + count - 1] = '\0'; 27 | 28 | for (int i = start, j = 0; i < (end - 1); ++i, ++j) { 29 | memcpy(str + pos + j 30 | // current index 31 | , array[i] 32 | // current index length 33 | , lengths[j]); 34 | // add space 35 | str[pos + lengths[j] + j] = ' '; 36 | // bump `pos` 37 | pos += lengths[j]; 38 | } 39 | 40 | memcpy(str + pos + count - 1 41 | , array[end - 1] 42 | , lengths[count - 1]); 43 | 44 | return str; 45 | } 46 | -------------------------------------------------------------------------------- /deps/str-flatten/str-flatten.h: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // str-flatten.h 4 | // 5 | // Copyright (c) 2014 Stephen Mathieson 6 | // MIT licensed 7 | // 8 | 9 | 10 | #ifndef STR_FLATTEN_H 11 | #define STR_FLATTEN_H 1 12 | 13 | char * 14 | str_flatten(const char *[], int, int); 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /deps/str-replace/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "str-replace", 3 | "version": "0.0.6", 4 | "repo": "stephenmathieson/str-replace.c", 5 | "description": "String replacement in C", 6 | "keywords": [ "string", "replace" ], 7 | "license": "MIT", 8 | "src": [ 9 | "src/str-replace.c", 10 | "src/str-replace.h" 11 | ], 12 | "dependencies": { 13 | "stephenmathieson/occurrences.c": "*", 14 | "clibs/strdup": "0.0.2" 15 | }, 16 | "development": { 17 | "stephenmathieson/describe.h": "2.0.2" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /deps/str-replace/str-replace.c: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // str-replace.c 4 | // 5 | // Copyright (c) 2013 Stephen Mathieson 6 | // MIT licensed 7 | // 8 | 9 | #include 10 | #include 11 | #include "occurrences/occurrences.h" 12 | #include "strdup/strdup.h" 13 | #include "str-replace.h" 14 | 15 | /* 16 | * Replace all occurrences of `sub` with `replace` in `str` 17 | */ 18 | 19 | char * 20 | str_replace(const char *str, const char *sub, const char *replace) { 21 | char *pos = (char *) str; 22 | int count = occurrences(sub, str); 23 | 24 | if (0 >= count) return strdup(str); 25 | 26 | int size = ( 27 | strlen(str) 28 | - (strlen(sub) * count) 29 | + strlen(replace) * count 30 | ) + 1; 31 | 32 | char *result = (char *) malloc(size); 33 | if (NULL == result) return NULL; 34 | memset(result, '\0', size); 35 | char *current; 36 | while ((current = strstr(pos, sub))) { 37 | int len = current - pos; 38 | strncat(result, pos, len); 39 | strncat(result, replace, strlen(replace)); 40 | pos = current + strlen(sub); 41 | } 42 | 43 | if (pos != (str + strlen(str))) { 44 | strncat(result, pos, (str - pos)); 45 | } 46 | 47 | return result; 48 | } 49 | -------------------------------------------------------------------------------- /deps/str-replace/str-replace.h: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // str-replace.h 4 | // 5 | // Copyright (c) 2013 Stephen Mathieson 6 | // MIT licensed 7 | // 8 | 9 | 10 | #ifndef STR_REPLACE_H 11 | #define STR_REPLACE_H 12 | 13 | char *str_replace(const char *str, const char *sub, const char *replace); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /deps/str-starts-with/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "str-starts-with", 3 | "version": "0.0.3", 4 | "repo": "stephenmathieson/str-starts-with.c", 5 | "description": "Check if a string starts with another string", 6 | "keywords": [ "string" ], 7 | "license": "MIT", 8 | "src": [ 9 | "src/str-starts-with.c", 10 | "src/str-starts-with.h" 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /deps/str-starts-with/str-starts-with.c: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // str-starts-with.c 4 | // 5 | // Copyright (c) 2013 Stephen Mathieson 6 | // MIT licensed 7 | // 8 | 9 | #include 10 | #include 11 | #include "str-starts-with.h" 12 | 13 | bool str_starts_with(const char *str, const char *start) { 14 | for (; ; str++, start++) 15 | if (!*start) 16 | return true; 17 | else if (*str != *start) 18 | return false; 19 | } 20 | -------------------------------------------------------------------------------- /deps/str-starts-with/str-starts-with.h: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // str-starts-with.h 4 | // 5 | // Copyright (c) 2013 Stephen Mathieson 6 | // MIT licensed 7 | // 8 | 9 | 10 | #ifndef STR_STARTS_WITH 11 | #define STR_STARTS_WITH 12 | 13 | #include 14 | 15 | bool str_starts_with(const char *str, const char *start); 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /deps/strdup/clib.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "strdup", 3 | "version": "0.1.5", 4 | "repo": "clibs/strdup", 5 | "description": "drop-in replacement for strdup(3) from libc", 6 | "keywords": [ "string", "copy" ], 7 | "license": "Expat", 8 | "src": [ 9 | "strdup.c", 10 | "strdup.h" 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /deps/strdup/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "strdup", 3 | "version": "0.0.0", 4 | "repo": "clibs/strdup", 5 | "description": "drop-in replacement for strdup(3) from libc", 6 | "keywords": [ "string", "copy" ], 7 | "license": "MIT", 8 | "src": [ 9 | "strdup.c", 10 | "strdup.h" 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /deps/strdup/strdup.c: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // strdup.c 4 | // 5 | // Copyright (c) 2014 Stephen Mathieson 6 | // MIT licensed 7 | // 8 | 9 | #ifndef HAVE_STRDUP 10 | 11 | #include 12 | #include 13 | #include "strdup.h" 14 | 15 | #ifndef strdup 16 | 17 | char * 18 | strdup(const char *str) { 19 | if (NULL == (char *) str) { 20 | return NULL; 21 | } 22 | 23 | int len = strlen(str) + 1; 24 | char *buf = malloc(len); 25 | 26 | if (buf) { 27 | memset(buf, 0, len); 28 | memcpy(buf, str, len - 1); 29 | } 30 | return buf; 31 | } 32 | 33 | #endif 34 | 35 | #endif /* HAVE_STRDUP */ 36 | -------------------------------------------------------------------------------- /deps/strdup/strdup.h: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // strdup.h 4 | // 5 | // Copyright (c) 2014 Stephen Mathieson 6 | // MIT licensed 7 | // 8 | 9 | #ifndef HAVE_STRDUP 10 | #define HAVE_STRDUP 11 | 12 | /** 13 | * Drop-in replacement for strdup(3) from libc. 14 | * 15 | * Creates a copy of `str`. Free when done. 16 | * 17 | * Returns a pointer to the newly allocated 18 | * copy of `str`, or `NULL` on failure. 19 | */ 20 | 21 | #ifndef strdup 22 | char * 23 | strdup(const char *str); 24 | #endif 25 | 26 | #endif /* HAVE_STRDUP */ 27 | -------------------------------------------------------------------------------- /deps/substr/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "substr", 3 | "version": "0.1.2", 4 | "repo": "stephenmathieson/substr.c", 5 | "description": "Get a substring of a string", 6 | "keywords": [ "substr", "substring", "string" ], 7 | "license": "MIT", 8 | "src": [ 9 | "src/substr.c", 10 | "src/substr.h" 11 | ], 12 | "dependencies": { 13 | "strdup": "0.0.0" 14 | }, 15 | "development": { 16 | "stephenmathieson/describe.h": "*" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /deps/substr/substr.c: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // substr.c 4 | // 5 | // Copyright (c) 2013 Stephen Mathieson 6 | // MIT licensed 7 | // 8 | 9 | #include 10 | #include 11 | #include "strdup/strdup.h" 12 | #include "substr.h" 13 | 14 | /* 15 | * Get a substring of `str` from `start` to `end` 16 | */ 17 | 18 | char * 19 | substr(const char *str, int start, int end) { 20 | if (0 > start) return NULL; 21 | int len = strlen(str); 22 | // -1 == length of string 23 | if (-1 == end) end = len; 24 | if (end <= start) return NULL; 25 | int diff = end - start; 26 | if (len == diff) return strdup(str); 27 | if (len < start) return NULL; 28 | if (len + 1 < end) return NULL; 29 | 30 | char *res = malloc(sizeof(char) * diff + 1); 31 | if (NULL == res) return NULL; 32 | memset(res, '\0', diff + 1); 33 | strncpy(res, str + start, diff); 34 | return res; 35 | } 36 | -------------------------------------------------------------------------------- /deps/substr/substr.h: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // substr.h 4 | // 5 | // Copyright (c) 2013 Stephen Mathieson 6 | // MIT licensed 7 | // 8 | 9 | 10 | #ifndef SUBSTR_H 11 | #define SUBSTR_H 1 12 | 13 | char *substr(const char *, int, int); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /deps/tempdir/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tempdir", 3 | "version": "0.0.2", 4 | "repo": "stephenmathieson/tempdir.c", 5 | "description": "implementation of Python's tempfile.tempdir", 6 | "keywords": ["temp", "tempdir"], 7 | "src": ["tempdir.h", "tempdir.c"], 8 | "dependencies": { 9 | "strdup": "0.0.0" 10 | }, 11 | "development": { 12 | "jwerle/fs.c": "*" 13 | } 14 | } 15 | 16 | -------------------------------------------------------------------------------- /deps/tempdir/tempdir.c: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // tempdir.c 4 | // 5 | // Copyright (c) 2014 Stephen Mathieson 6 | // MIT licensed 7 | // 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include "strdup/strdup.h" 14 | #include "tempdir.h" 15 | 16 | // 1. The directory named by the TMPDIR environment variable. 17 | // 2. The directory named by the TEMP environment variable. 18 | // 3. The directory named by the TMP environment variable. 19 | // 4. A platform-specific location: 20 | // 4.1 On RiscOS, the directory named by the Wimp$ScrapDir 21 | // environment variable. 22 | // 4.2 On Windows, the directories C:\TEMP, C:\TMP, \TEMP, 23 | // and \TMP, in that order. 24 | // 4.3 On all other platforms, the directories /tmp, 25 | // /var/tmp, and /usr/tmp, in that order. 26 | // 5. As a last resort, the current working directory. 27 | 28 | static const char *env_vars[] = { 29 | "TMPDIR", 30 | "TEMP", 31 | "TMP", 32 | // RiscOS (4.1) 33 | "Wimp$ScrapDir", 34 | NULL, 35 | }; 36 | 37 | 38 | #ifdef _WIN32 39 | // 4.2 40 | static const char *platform_dirs[] = { 41 | "C:\\TEMP", 42 | "C:\\TMP", 43 | "\\TEMP", 44 | "\\TMP", 45 | NULL, 46 | }; 47 | #else 48 | // 4.3 49 | static const char *platform_dirs[] = { 50 | "/tmp", 51 | "/var/tmp", 52 | "/usr/tmp", 53 | NULL, 54 | }; 55 | #endif 56 | 57 | /** 58 | * Check if the file at `path` exists and is a directory. 59 | * 60 | * Returns `0` if both checks pass, and `-1` if either fail. 61 | */ 62 | 63 | static int 64 | is_directory(const char *path) { 65 | struct stat s; 66 | if (-1 == stat(path, &s)) return -1; 67 | return 1 == S_ISDIR(s.st_mode) ? 0 : -1; 68 | } 69 | 70 | char * 71 | gettempdir(void) { 72 | // check ENV vars (1, 2, 3) 73 | for (int i = 0; env_vars[i]; i++) { 74 | char *dir = getenv(env_vars[i]); 75 | if (dir && 0 == is_directory(dir)) { 76 | return strdup(dir); 77 | } 78 | } 79 | 80 | // platform-specific checks (4) 81 | for (int i = 0; platform_dirs[i]; i++) { 82 | if (0 == is_directory(platform_dirs[i])) { 83 | return strdup(platform_dirs[i]); 84 | } 85 | } 86 | 87 | // fallback to cwd (5) 88 | char cwd[256]; 89 | if (NULL != getcwd(cwd, sizeof(cwd))) { 90 | return strdup(cwd); 91 | } 92 | 93 | return NULL; 94 | } 95 | -------------------------------------------------------------------------------- /deps/tempdir/tempdir.h: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // tempdir.h 4 | // 5 | // Copyright (c) 2014 Stephen Mathieson 6 | // MIT licensed 7 | // 8 | 9 | #ifndef TEMPDIR_H 10 | #define TEMPDIR_H 1 11 | 12 | /** 13 | * Get the system's temporary directory using Python's 14 | * `tempfile.tempdir` algorithm. Free the result when 15 | * done. 16 | * 17 | * Returns `NULL` on failure. 18 | */ 19 | 20 | char * 21 | gettempdir(void); 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /deps/tinydir/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tinydir", 3 | "description": "Lightweight, portable and easy to integrate C directory and file reader", 4 | "license": "BSD-2-Clause", 5 | "keywords": [ 6 | "dir", 7 | "directory", 8 | "file", 9 | "reader", 10 | "filesystem" 11 | ], 12 | "src": [ 13 | "tinydir.h" 14 | ], 15 | "version": "1.2.4", 16 | "repo": "cxong/tinydir" 17 | } 18 | -------------------------------------------------------------------------------- /deps/trim/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "trim", 3 | "version": "0.0.2", 4 | "repo": "stephenmathieson/trim.c", 5 | "description": "String trim utility", 6 | "keywords": [ 7 | "string", 8 | "trim", 9 | "trim left", 10 | "trim right" 11 | ], 12 | "license": "MIT", 13 | "src": [ 14 | "src/trim.c", 15 | "src/trim.h" 16 | ], 17 | "development": { 18 | "stephenmathieson/describe.h": "master" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /deps/trim/trim.c: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // trim.c 4 | // 5 | // Copyright (c) 2013 Stephen Mathieson 6 | // MIT licensed 7 | // 8 | 9 | 10 | #include 11 | #include 12 | #include "trim.h" 13 | 14 | char *trim_left(char *str) { 15 | int len = strlen(str); 16 | char *cur = str; 17 | 18 | while (*cur && isspace(*cur)) { 19 | ++cur; 20 | --len; 21 | } 22 | 23 | if (str != cur) { 24 | memmove(str, cur, len + 1); 25 | } 26 | 27 | return str; 28 | } 29 | 30 | char *trim_right(char *str) { 31 | int len = strlen(str); 32 | char *cur = str + len - 1; 33 | 34 | while (cur != str && isspace(*cur)) { 35 | --cur; 36 | --len; 37 | } 38 | 39 | cur[isspace(*cur) ? 0 : 1] = '\0'; 40 | 41 | return str; 42 | } 43 | 44 | char *trim(char *str) { 45 | trim_right(str); 46 | trim_left(str); 47 | return str; 48 | } 49 | -------------------------------------------------------------------------------- /deps/trim/trim.h: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // trim.h 4 | // 5 | // Copyright (c) 2013 Stephen Mathieson 6 | // MIT licensed 7 | // 8 | 9 | 10 | #ifndef __TRIM__ 11 | #define __TRIM__ 1 12 | 13 | char *trim(char *str); 14 | char *trim_right(char *str); 15 | char *trim_left(char *str); 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /deps/which/clib.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "which", 3 | "version": "0.1.3", 4 | "repo": "clibs/which", 5 | "description": "Locate executable via PATH or given string", 6 | "keywords": ["lookup", "which", "locate", "find", "path", "bin", "executable"], 7 | "license": "MIT", 8 | "src": ["src/which.c", "src/which.h"], 9 | "dependencies": { 10 | "strdup": "0.0.0" 11 | }, 12 | "development": { 13 | "stephenmathieson/describe.h": "1.0.0" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /deps/which/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "which", 3 | "version": "0.1.3", 4 | "repo": "clibs/which", 5 | "description": "Locate executable via PATH or given string", 6 | "keywords": ["lookup", "which", "locate", "find", "path", "bin", "executable"], 7 | "license": "MIT", 8 | "src": ["src/which.c", "src/which.h"], 9 | "dependencies": { 10 | "strdup": "0.0.0" 11 | }, 12 | "development": { 13 | "stephenmathieson/describe.h": "1.0.0" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /deps/which/which.c: -------------------------------------------------------------------------------- 1 | // 2 | // which.c 3 | // 4 | // Copyright (c) 2013 TJ Holowaychuk 5 | // 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "strdup/strdup.h" 12 | #include "which.h" 13 | 14 | // delimiter 15 | 16 | #ifdef _WIN32 17 | #define WHICH_DELIMITER ";" 18 | #else 19 | #define WHICH_DELIMITER ":" 20 | #endif 21 | 22 | /* 23 | * Lookup executable `name` within the PATH environment variable. 24 | */ 25 | 26 | char * 27 | which(const char *name) { 28 | return which_path(name, getenv("PATH")); 29 | } 30 | 31 | /* 32 | * Lookup executable `name` within `path`. 33 | */ 34 | 35 | char * 36 | which_path(const char *name, const char *_path) { 37 | char *path = strdup(_path); 38 | if (NULL == path) return NULL; 39 | char *tok = strtok(path, WHICH_DELIMITER); 40 | 41 | while (tok) { 42 | // path 43 | int len = strlen(tok) + 2 + strlen(name); 44 | char *file = malloc(len); 45 | if (!file) { 46 | free(path); 47 | return NULL; 48 | } 49 | sprintf(file, "%s/%s", tok, name); 50 | 51 | // executable 52 | if (0 == access(file, X_OK)) { 53 | free(path); 54 | return file; 55 | } 56 | 57 | // next token 58 | tok = strtok(NULL, WHICH_DELIMITER); 59 | free(file); 60 | } 61 | 62 | free(path); 63 | 64 | return NULL; 65 | } 66 | -------------------------------------------------------------------------------- /deps/which/which.h: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // which.h 4 | // 5 | // Copyright (c) 2013 TJ Holowaychuk 6 | // 7 | 8 | #ifndef WHICH_H 9 | #define WHICH_H 10 | 11 | char * 12 | which(const char *name); 13 | 14 | char * 15 | which_path(const char *name, const char *path); 16 | 17 | #endif /* WHICH_H */ 18 | -------------------------------------------------------------------------------- /deps/wiki-registry/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wiki-registry", 3 | "version": "0.1.2", 4 | "repo": "clibs/wiki-registry.c", 5 | "description": "Turn a GitHub Wiki page into a package registry", 6 | "keywords": [ "registry", "github", "wiki" ], 7 | "license": "MIT", 8 | "src": [ 9 | "src/wiki-registry.c", 10 | "src/wiki-registry.h" 11 | ], 12 | "dependencies": { 13 | "thlorenz/gumbo-parser.c": "*", 14 | "stephenmathieson/substr.c": "*", 15 | "strdup": "0.0.0", 16 | "stephenmathieson/http-get.c": "*", 17 | "stephenmathieson/case.c": "*", 18 | "stephenmathieson/trim.c": "*", 19 | "stephenmathieson/gumbo-text-content.c": "*", 20 | "stephenmathieson/gumbo-get-element-by-id.c": "*", 21 | "stephenmathieson/gumbo-get-elements-by-tag-name.c": "*", 22 | "clibs/list": "*" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /deps/wiki-registry/wiki-registry.c: -------------------------------------------------------------------------------- 1 | // 2 | // wiki-registry.c 3 | // 4 | // Copyright (c) 2014 Stephen Mathieson 5 | // MIT licensed 6 | // 7 | 8 | #include 9 | #include 10 | #include 11 | #include "gumbo-parser/gumbo.h" 12 | #include "gumbo-text-content/gumbo-text-content.h" 13 | #include "gumbo-get-element-by-id/get-element-by-id.h" 14 | #include "gumbo-get-elements-by-tag-name/get-elements-by-tag-name.h" 15 | #include "http-get/http-get.h" 16 | #include "list/list.h" 17 | #include "substr/substr.h" 18 | #include "strdup/strdup.h" 19 | #include "case/case.h" 20 | #include "trim/trim.h" 21 | #include "wiki-registry.h" 22 | 23 | // 24 | // TODO find dox on gumbo so the node iteration isn't so ugly 25 | // 26 | 27 | /** 28 | * Create a new wiki package. 29 | */ 30 | 31 | static wiki_package_t * 32 | wiki_package_new() { 33 | wiki_package_t *pkg = malloc(sizeof(wiki_package_t)); 34 | if (pkg) { 35 | pkg->repo = NULL; 36 | pkg->href = NULL; 37 | pkg->description = NULL; 38 | pkg->category = NULL; 39 | } 40 | return pkg; 41 | } 42 | 43 | /** 44 | * Add `href` to the given `package`. 45 | */ 46 | 47 | static void 48 | add_package_href(wiki_package_t *self) { 49 | size_t len = strlen(self->repo) + 20; // https://github.com/ \0 50 | self->href = malloc(len); 51 | if (self->href) 52 | sprintf(self->href, "https://github.com/%s", self->repo); 53 | } 54 | 55 | /** 56 | * Parse the given wiki `li` into a package. 57 | */ 58 | 59 | static wiki_package_t * 60 | parse_li(GumboNode *li) { 61 | wiki_package_t *self = wiki_package_new(); 62 | char *text = NULL; 63 | 64 | if (!self) goto cleanup; 65 | 66 | text = gumbo_text_content(li); 67 | if (!text) goto cleanup; 68 | 69 | // TODO support unicode dashes 70 | char *tok = strstr(text, " - "); 71 | if (!tok) goto cleanup; 72 | 73 | int pos = tok - text; 74 | self->repo = substr(text, 0, pos); 75 | self->description = substr(text, pos + 3, -1); 76 | if (!self->repo || !self->description) goto cleanup; 77 | trim(self->description); 78 | trim(self->repo); 79 | 80 | add_package_href(self); 81 | 82 | cleanup: 83 | free(text); 84 | return self; 85 | } 86 | 87 | /** 88 | * Parse a list of packages from the given `html` 89 | */ 90 | 91 | list_t * 92 | wiki_registry_parse(const char *html) { 93 | GumboOutput *output = gumbo_parse(html); 94 | list_t *pkgs = list_new(); 95 | 96 | GumboNode *body = gumbo_get_element_by_id("wiki-body", output->root); 97 | if (body) { 98 | GumboNode* markdown_body = ((GumboNode*)((GumboVector)body->v.element.children).data[1]); 99 | GumboVector children = (GumboVector)markdown_body->v.element.children; 100 | 101 | size_t count = children.length - 1; 102 | 103 | for (size_t index = 0; index < count; index++) { 104 | GumboNode *heading = (GumboNode *)children.data[index]; 105 | GumboNode *ul = NULL; 106 | 107 | if (heading->v.element.tag != GUMBO_TAG_DIV) { 108 | continue; 109 | } 110 | 111 | GumboAttribute *node_id = gumbo_get_attribute(&heading->v.element.attributes, "class"); 112 | if (node_id == NULL || strncmp(node_id->value, "markdown-heading", 16) != 0) { 113 | continue; 114 | } 115 | 116 | for (; index < count; index++) { 117 | ul = (GumboNode *)children.data[index]; 118 | 119 | if (ul->v.element.tag == GUMBO_TAG_UL) { 120 | break; 121 | } 122 | } 123 | 124 | list_t *h2 = gumbo_get_elements_by_tag_name("h2", heading); 125 | char *category = gumbo_text_content(h2->head->val); 126 | if (!category) break; 127 | trim(case_lower(category)); 128 | 129 | list_t *lis = gumbo_get_elements_by_tag_name("li", ul); 130 | list_iterator_t *li_iterator = list_iterator_new(lis, LIST_HEAD); 131 | list_node_t *li_node; 132 | while ((li_node = list_iterator_next(li_iterator))) { 133 | wiki_package_t *package = parse_li(li_node->val); 134 | if (package && package->description) { 135 | package->category = strdup(category); 136 | list_rpush(pkgs, list_node_new(package)); 137 | } else { 138 | // failed to parse package 139 | if (package) wiki_package_free(package); 140 | } 141 | } 142 | list_iterator_destroy(li_iterator); 143 | list_destroy(lis); 144 | free(category); 145 | } 146 | } 147 | 148 | gumbo_destroy_output(&kGumboDefaultOptions, output); 149 | return pkgs; 150 | } 151 | 152 | /** 153 | * Get a list of packages from the given GitHub wiki `url`. 154 | */ 155 | 156 | list_t * 157 | wiki_registry(const char *url) { 158 | http_get_response_t *res = http_get(url); 159 | if (!res->ok) return NULL; 160 | 161 | list_t *list = wiki_registry_parse(res->data); 162 | http_get_free(res); 163 | return list; 164 | } 165 | 166 | /** 167 | * Free a wiki_package_t. 168 | */ 169 | 170 | void 171 | wiki_package_free(wiki_package_t *pkg) { 172 | free(pkg->repo); 173 | free(pkg->href); 174 | free(pkg->description); 175 | free(pkg->category); 176 | free(pkg); 177 | } 178 | -------------------------------------------------------------------------------- /deps/wiki-registry/wiki-registry.h: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // wiki-registry.h 4 | // 5 | // Copyright (c) 2013 Stephen Mathieson 6 | // MIT licensed 7 | // 8 | 9 | 10 | #ifndef WIKI_REGISTRY_H 11 | #define WIKI_REGISTRY_H 1 12 | 13 | #include "list/list.h" 14 | 15 | typedef struct { 16 | char *repo; 17 | char *href; 18 | char *description; 19 | char *category; 20 | } wiki_package_t; 21 | 22 | list_t * 23 | wiki_registry(const char *); 24 | 25 | list_t * 26 | wiki_registry_parse(const char *); 27 | 28 | void 29 | wiki_package_free(wiki_package_t *); 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /deps/wildcardcmp/clib.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wildcardcmp", 3 | "version": "0.0.0", 4 | "repo": "clibs/wildcardcmp", 5 | "description": "simple wildcard string comparison", 6 | "keywords": ["wildcard", "string", "comparison"], 7 | "license": "MIT", 8 | "src": ["wildcardcmp.c", "wildcardcmp.h"] 9 | } 10 | -------------------------------------------------------------------------------- /deps/wildcardcmp/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wildcardcmp", 3 | "version": "0.0.0", 4 | "repo": "clibs/wildcardcmp", 5 | "description": "simple wildcard string comparison", 6 | "keywords": ["wildcard", "string", "comparison"], 7 | "license": "MIT", 8 | "src": ["wildcardcmp.c", "wildcardcmp.h"] 9 | } 10 | -------------------------------------------------------------------------------- /deps/wildcardcmp/wildcardcmp.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include "wildcardcmp.h" 4 | 5 | int 6 | wildcardcmp(const char *pattern, const char *string) { 7 | const char *w = NULL; // last `*` 8 | const char *s = NULL; // last checked char 9 | 10 | // malformed 11 | if (!pattern || !string) return 0; 12 | 13 | // loop 1 char at a time 14 | while (1) { 15 | if (!*string) { 16 | if (!*pattern) return 1; 17 | if ('*' == *pattern) { 18 | pattern++; 19 | continue; 20 | } 21 | if (!*s) return 0; 22 | string = s++; 23 | pattern = w; 24 | continue; 25 | } else { 26 | if (*pattern != *string) { 27 | if ('*' == *pattern) { 28 | w = ++pattern; 29 | s = string; 30 | // "*" -> "foobar" 31 | if (*pattern) continue; 32 | return 1; 33 | } else if (w) { 34 | string++; 35 | // "*ooba*" -> "foobar" 36 | continue; 37 | } 38 | return 0; 39 | } 40 | } 41 | 42 | string++; 43 | pattern++; 44 | } 45 | 46 | return 1; 47 | } 48 | -------------------------------------------------------------------------------- /deps/wildcardcmp/wildcardcmp.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef WILDCARDCMP_H 3 | #define WILDCARDCMP_H 1 4 | 5 | /** 6 | * Check if the given `string` matches `pattern`, 7 | * using `*` as a wildcard. Will return `1` if 8 | * the two match. 9 | */ 10 | 11 | int 12 | wildcardcmp(const char *pattern, const char *string); 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "clib", 3 | "version": "2.8.7", 4 | "repo": "clibs/clib", 5 | "install": "make clean install", 6 | "scripts": { 7 | "install": "clib install -fc $($npm_config_dev && echo '--dev')", 8 | "version": "which node >/dev/null && ./scripts/update-clib-json && git add clib.json" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /scripts/ccan2clib.py: -------------------------------------------------------------------------------- 1 | import glob 2 | import json 3 | import os 4 | import os.path 5 | import subprocess 6 | import sys 7 | 8 | doc_sections = [ 9 | 'summary', 10 | 'description', 11 | # 'functions', 12 | 'example', 13 | 'author', 14 | 'maintainer', 15 | 'license', 16 | 'see_also', 17 | ] 18 | 19 | doc_extract_bin = 'tools/doc_extract' 20 | depends_bin = 'tools/ccan_depends' 21 | 22 | 23 | def get_source_path(module): 24 | return 'ccan/{module}'.format(module=module) 25 | 26 | 27 | def get_dependencies(module): 28 | args = [depends_bin, get_source_path(module)] 29 | try: 30 | dependencies = subprocess.check_output(args) 31 | except subprocess.CalledProcessError: 32 | return {} 33 | else: 34 | return {d.replace('ccan/', 'clibs/'): '*' 35 | for d in dependencies.split('\n') 36 | if d != ''} 37 | 38 | 39 | def get_src(module): 40 | src_path = get_source_path(module) 41 | files = glob.glob('{src_path}/*.c'.format(src_path=src_path)) 42 | files.extend(glob.glob('{src_path}/*.h'.format(src_path=src_path))) 43 | return files 44 | 45 | 46 | def get_summary(module): 47 | args = [doc_extract_bin, 'summary', "{src_path}/_info".format(src_path=get_source_path(module))] 48 | try: 49 | return subprocess.check_output(args).strip() 50 | except subprocess.CalledProcessError: 51 | return None 52 | 53 | 54 | def ccan2repo(module, dst_path): 55 | dst_path = dst_path + '/' + module 56 | src_path = 'ccan/{module}'.format(module=module) 57 | 58 | if not os.path.isfile('{src_path}/_info'.format(src_path=src_path)): 59 | print "WARNING: {module} does not have a _info file".format(module=module) 60 | return 61 | 62 | try: 63 | os.mkdir(dst_path) 64 | except OSError: 65 | pass 66 | 67 | # Create package.json 68 | package = { 69 | "name": module, 70 | "version": "master", 71 | "repo": "rustyrussell/ccan", 72 | "src": get_src(module), 73 | } 74 | 75 | summary = get_summary(module) 76 | if summary: 77 | package['description'] = summary 78 | else: 79 | print "WARNING: {module} does not have a summary".format(module=module) 80 | 81 | dependencies = get_dependencies(module) 82 | if dependencies: 83 | package['dependencies'] = dependencies 84 | 85 | packagejson = open(dst_path + "/package.json", "w") 86 | packagejson.write(json.dumps(package, indent=2, sort_keys=True)) 87 | packagejson.close() 88 | 89 | # Create source files 90 | # for src_fname in get_src(module): 91 | # dst_fname = src_fname.replace(src_path, module) 92 | # open(dst_fname, 'w').write(open(src_fname, 'r').read()) 93 | 94 | # Create README.rst 95 | readme = open(dst_path + "/README.rst", "w") 96 | readme.write('This repository is a mirror of www.github.com/rustyrussell/ccan/tree/master/ccan/{module}\n\n'.format(module=module)) 97 | for section in doc_sections: 98 | args = [doc_extract_bin, section, "{src_path}/_info".format(src_path=src_path)] 99 | 100 | try: 101 | text = subprocess.check_output(args).strip() 102 | except subprocess.CalledProcessError: 103 | continue 104 | 105 | if text == '': continue 106 | 107 | if section == 'example': 108 | indent = ' ' * 4 109 | text = ".. code-block:: c\n\n" + indent + ('\n' + indent).join(text.split('\n')) 110 | 111 | readme.writelines([ 112 | section.title() + '\n', 113 | len(section) * '-' + '\n', 114 | text + '\n' * 2, 115 | ]) 116 | readme.close() 117 | 118 | 119 | ccan2repo(sys.argv[1], sys.argv[2]) 120 | -------------------------------------------------------------------------------- /scripts/convert_all_ccan2clib.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | git clone https://github.com/rustyrussell/ccan 4 | 5 | # Output directory 6 | mkdir clibs 7 | 8 | cd ccan || exit 9 | 10 | make 11 | make tools 12 | 13 | # Convert ccan modules into Clib repos 14 | for file in ccan/*; do 15 | if [ -d "$file" ]; then 16 | python ../ccan2clib.py "${file#ccan/}" ../clibs 17 | fi 18 | done 19 | -------------------------------------------------------------------------------- /scripts/feature-test-pthreads: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | { 4 | echo '#include ' && 5 | echo 'void *f(void *a) { return 0; }' && 6 | echo 'int main(void) { pthread_t t; int ret = pthread_create(&t, 0, f, 0); ret |= pthread_cancel(t); return ret; }'; 7 | } | ${CC:-cc} -o pthread_test -xc -pthread - 2>/dev/null && rm pthread_test 8 | exit $? 9 | -------------------------------------------------------------------------------- /scripts/pre-commit-hook.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | function format_and_restage_file { 4 | local file="$1" 5 | # Ensure the file exists, otherwise clang-format gets very angry. 6 | if [ -f "$file" ]; then 7 | clang-format -i -style=LLVM "$file" 8 | git add "$file" 9 | fi 10 | } 11 | 12 | if ! command -v clang-format &> /dev/null; then 13 | echo "Unable to format staged changes: clang-format not found." 14 | exit 15 | fi 16 | 17 | # Format each staged file (ending in `.c` or `.h`). 18 | for file in `git diff-index --cached --name-only HEAD | grep -iE '\.(c|h)$' ` ; do 19 | format_and_restage_file "$file" 20 | done 21 | -------------------------------------------------------------------------------- /scripts/update-clib-json: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const clib = require('../clib.json') 4 | const pkg = require('../package.json') 5 | const fs = require('fs') 6 | 7 | fs.writeFileSync(require.resolve('../clib.json'), 8 | JSON.stringify(Object.assign(clib, { version: pkg.version }), null, ' ')) 9 | -------------------------------------------------------------------------------- /src/clib-init.c: -------------------------------------------------------------------------------- 1 | // 2 | // clib-init.c 3 | // 4 | // Copyright (c) 2012-2020 clib authors 5 | // MIT licensed 6 | // 7 | 8 | #include "asprintf/asprintf.h" 9 | #include "commander/commander.h" 10 | #include "common/clib-package.h" 11 | #include "debug/debug.h" 12 | #include "fs/fs.h" 13 | #include "logger/logger.h" 14 | #include "parson/parson.h" 15 | #include "version.h" 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #if defined(_WIN32) || defined(WIN32) || defined(__MINGW32__) || \ 22 | defined(__MINGW64__) 23 | #define setenv(k, v, _) _putenv_s(k, v) 24 | #define realpath(a, b) _fullpath(a, b, strlen(a)) 25 | #define PATH_SEPARATOR '\\' 26 | #else 27 | #define PATH_SEPARATOR '/' 28 | #endif 29 | 30 | debug_t debugger; 31 | 32 | struct options { 33 | char *manifest; 34 | int verbose; 35 | }; 36 | 37 | static struct options opts; 38 | 39 | /** 40 | * Option setters. 41 | */ 42 | 43 | static void setopt_quiet(command_t *self) { 44 | opts.verbose = 0; 45 | debug(&debugger, "set quiet flag"); 46 | } 47 | 48 | static void setopt_manifest_file(command_t *self) { 49 | opts.manifest = (char *)self->arg; 50 | debug(&debugger, "set manifest: %s", opts.manifest); 51 | } 52 | 53 | /** 54 | * Program. 55 | */ 56 | 57 | static char *find_basepath() { 58 | char cwd[4096] = {0}; 59 | getcwd(cwd, 4096); 60 | 61 | char* last_part = strrchr(cwd, PATH_SEPARATOR); 62 | char* base_path = (last_part != NULL) ? last_part + 1 : cwd; 63 | return strdup( base_path); 64 | } 65 | 66 | static void getinput(char *buffer, size_t s) { 67 | char *walk = buffer; 68 | int c = 0; 69 | while ((walk - s) != buffer && (c = fgetc(stdin)) && c != '\n' && c != 0) { 70 | *(walk++) = c; 71 | } 72 | } 73 | 74 | static void ask_for(JSON_Object *root, const char *key, 75 | const char *default_value, const char *question) { 76 | static char buffer[512] = {0}; 77 | memset(buffer, '\0', 512); 78 | printf("%s", question); 79 | getinput(buffer, 512); 80 | char *value = (char *)(strlen(buffer) > 0 ? buffer : default_value); 81 | json_object_set_string(root, key, value); 82 | } 83 | 84 | static inline size_t write_to_file(const char *manifest, const char *str, 85 | size_t length) { 86 | size_t wrote = 0; 87 | 88 | FILE *file = fopen(manifest, "w+"); 89 | if (!file) { 90 | debug(&debugger, "Cannot open %s file.", manifest); 91 | return 0; 92 | } 93 | 94 | wrote = fwrite(str, sizeof(char), length, file); 95 | fclose(file); 96 | 97 | return length - wrote; 98 | } 99 | 100 | static int write_package_file(const char *manifest, JSON_Value *pkg) { 101 | int rc = 0; 102 | char *package = json_serialize_to_string_pretty(pkg); 103 | 104 | if (0 != write_to_file(manifest, package, strlen(package))) { 105 | logger_error("Failed to write to %s", manifest); 106 | rc = 1; 107 | goto e1; 108 | } 109 | 110 | debug(&debugger, "Wrote %s file.", manifest); 111 | 112 | e1: 113 | json_free_serialized_string(package); 114 | 115 | return rc; 116 | } 117 | 118 | /** 119 | * Entry point. 120 | */ 121 | 122 | int main(int argc, char *argv[]) { 123 | int exit_code = 0; 124 | opts.verbose = 1; 125 | opts.manifest = "clib.json"; 126 | 127 | debug_init(&debugger, "clib-init"); 128 | 129 | command_t program; 130 | 131 | command_init(&program, "clib-init", CLIB_VERSION); 132 | 133 | program.usage = "[options]"; 134 | 135 | command_option(&program, "-q", "--quiet", "disable verbose output", 136 | setopt_quiet); 137 | command_option(&program, "-M", "--manifest ", 138 | "give a manifest of the manifest file. (default: clib.json)", 139 | setopt_manifest_file); 140 | command_parse(&program, argc, argv); 141 | 142 | debug(&debugger, "%d arguments", program.argc); 143 | 144 | JSON_Value *json = json_value_init_object(); 145 | JSON_Object *root = json_object(json); 146 | 147 | char *basepath = find_basepath(); 148 | char *package_name = NULL; 149 | 150 | int rc = asprintf(&package_name, "package name (%s): ", basepath); 151 | if (-1 == rc) { 152 | logger_error("error", "asprintf() out of memory"); 153 | goto end; 154 | } 155 | 156 | ask_for(root, "name", basepath, package_name); 157 | ask_for(root, "version", "0.1.0", "version (default: 0.1.0): "); 158 | 159 | exit_code = write_package_file(opts.manifest, json); 160 | 161 | end: 162 | free(package_name); 163 | free(basepath); 164 | 165 | json_value_free(json); 166 | command_free(&program); 167 | 168 | return exit_code; 169 | } 170 | -------------------------------------------------------------------------------- /src/common/clib-cache.h: -------------------------------------------------------------------------------- 1 | // 2 | // clib-cache.h 3 | // 4 | // Copyright (c) 2016-2020 clib authors 5 | // MIT licensed 6 | // 7 | 8 | #ifndef CLIB_CACHE_H 9 | #define CLIB_CACHE_H 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | /** 16 | * Internal setup, creates the base cache dir if necessary 17 | * 18 | * @param expiration Cache expiration in seconds 19 | * 20 | * @return 0 on success, -1 otherwise 21 | */ 22 | int clib_cache_init(time_t expiration); 23 | 24 | /** 25 | * Initializes the internal cache directory 26 | * 27 | * @return 0 on success, -1 otherwise 28 | */ 29 | int clib_cache_meta_init(void); 30 | 31 | /** 32 | * @return directory of internally cached data 33 | */ 34 | const char *clib_cache_meta_dir(void); 35 | 36 | /** 37 | * @return The base base dir 38 | */ 39 | const char *clib_cache_dir(void); 40 | 41 | /** 42 | * At this point the package object is not built yet, and can't rely on it 43 | * 44 | * @return 0/1 if the package.json is cached 45 | */ 46 | int clib_cache_has_json(char *author, char *name, char *version); 47 | 48 | /** 49 | * @return The content of the cached package.json, or NULL on error, if not 50 | * found, or expired 51 | */ 52 | char *clib_cache_read_json(char *author, char *name, char *version); 53 | 54 | /** 55 | * @return Number of written bytes, or -1 on error 56 | */ 57 | int clib_cache_save_json(char *author, char *name, char *version, 58 | char *content); 59 | 60 | /** 61 | * @return Number of written bytes, or -1 on error 62 | */ 63 | int clib_cache_delete_json(char *author, char *name, char *version); 64 | 65 | /** 66 | * @return 0/1 if the search cache exists 67 | */ 68 | int clib_cache_has_search(void); 69 | 70 | /** 71 | * @return The content of the search cache, NULL on error, if not found, or 72 | * expired 73 | */ 74 | char *clib_cache_read_search(void); 75 | 76 | /** 77 | * @return Number of written bytes, or -1 on error, or if there is no search 78 | * cahce 79 | */ 80 | int clib_cache_save_search(char *content); 81 | 82 | /** 83 | * @return 0 on success, -1 otherwise 84 | */ 85 | int clib_cache_delete_search(void); 86 | 87 | /** 88 | * @return 0/1 if the packe is cached 89 | */ 90 | int clib_cache_has_package(char *author, char *name, char *version); 91 | 92 | /** 93 | * @return 0/1 if the cached package modified date is more or less then the 94 | * given expiration. -1 if the package is not cached 95 | */ 96 | int clib_cache_is_expired_package(char *author, char *name, char *version); 97 | 98 | /** 99 | * @param target_dir Where the cached package should be copied 100 | * 101 | * @return 0 on success, -1 on error, if the package is not found in the cache. 102 | * If the cached package is expired, it will be deleted, and -2 returned 103 | */ 104 | int clib_cache_load_package(char *author, char *name, char *version, 105 | char *target_dir); 106 | 107 | /** 108 | * @param pkg_dir The downloaded package (e.g. ./deps/my_package). 109 | * If the package was already cached, it will be deleted first, 110 | * then saved 111 | * 112 | * @return 0 on success, -1 on error 113 | */ 114 | int clib_cache_save_package(char *author, char *name, char *version, 115 | char *pkg_dir); 116 | 117 | /** 118 | * @return 0 on success, -1 on error 119 | */ 120 | int clib_cache_delete_package(char *author, char *name, char *version); 121 | 122 | #endif 123 | -------------------------------------------------------------------------------- /src/common/clib-package.h: -------------------------------------------------------------------------------- 1 | // 2 | // clib-package.h 3 | // 4 | // Copyright (c) 2014 Stephen Mathieson 5 | // Copyright (c) 2014-2020 clib authors 6 | // MIT license 7 | // 8 | 9 | #ifndef CLIB_PACKAGE_H 10 | #define CLIB_PACKAGE_H 1 11 | 12 | #include "list/list.h" 13 | #include 14 | 15 | typedef struct { 16 | char *name; 17 | char *author; 18 | char *version; 19 | } clib_package_dependency_t; 20 | 21 | typedef struct { 22 | char *author; 23 | char *description; 24 | char *install; 25 | char *configure; 26 | char *json; 27 | char *license; 28 | char *name; 29 | char *repo; 30 | char *repo_name; 31 | char *url; 32 | char *version; 33 | char *makefile; 34 | char *filename; // `package.json` or `clib.json` 35 | char *flags; 36 | char *prefix; 37 | list_t *dependencies; 38 | list_t *development; 39 | list_t *src; 40 | void *data; // user data 41 | unsigned int refs; 42 | } clib_package_t; 43 | 44 | typedef struct { 45 | int skip_cache; 46 | int force; 47 | int global; 48 | char *prefix; 49 | int concurrency; 50 | char *token; 51 | } clib_package_opts_t; 52 | 53 | extern CURLSH *clib_package_curl_share; 54 | 55 | void clib_package_set_opts(clib_package_opts_t opts); 56 | 57 | clib_package_t *clib_package_new(const char *, int); 58 | 59 | clib_package_t *clib_package_new_from_slug(const char *, int); 60 | 61 | clib_package_t *clib_package_load_from_manifest(const char *, int); 62 | 63 | clib_package_t *clib_package_load_local_manifest(int); 64 | 65 | char *clib_package_url(const char *, const char *, const char *); 66 | 67 | char *clib_package_url_from_repo(const char *repo, const char *version); 68 | 69 | char *clib_package_parse_version(const char *); 70 | 71 | char *clib_package_parse_author(const char *); 72 | 73 | char *clib_package_parse_name(const char *); 74 | 75 | clib_package_dependency_t *clib_package_dependency_new(const char *, 76 | const char *); 77 | 78 | int clib_package_install_executable(clib_package_t *pkg, const char *dir, 79 | int verbose); 80 | 81 | int clib_package_install(clib_package_t *, const char *, int); 82 | 83 | int clib_package_install_dependencies(clib_package_t *, const char *, int); 84 | 85 | int clib_package_install_development(clib_package_t *, const char *, int); 86 | 87 | void clib_package_free(clib_package_t *); 88 | 89 | void clib_package_dependency_free(void *); 90 | 91 | void clib_package_cleanup(); 92 | 93 | #endif 94 | -------------------------------------------------------------------------------- /src/common/clib-release-info.c: -------------------------------------------------------------------------------- 1 | // 2 | // clib-release-info.c 3 | // 4 | // Copyright (c) 2016-2021 clib authors 5 | // MIT licensed 6 | // 7 | 8 | #include "debug/debug.h" 9 | #include "http-get/http-get.h" 10 | #include "parson/parson.h" 11 | #include "strdup/strdup.h" 12 | 13 | #define LATEST_RELEASE_ENDPOINT \ 14 | "https://api.github.com/repos/clibs/clib/releases/latest" 15 | 16 | static debug_t debugger; 17 | 18 | const char *clib_release_get_latest_tag(void) { 19 | debug_init(&debugger, "clib-release-info"); 20 | 21 | http_get_response_t *res = http_get(LATEST_RELEASE_ENDPOINT); 22 | 23 | JSON_Value *root_json = NULL; 24 | JSON_Object *json_object = NULL; 25 | char *tag_name = NULL; 26 | 27 | if (!res->ok) { 28 | debug(&debugger, "Couldn't lookup latest release"); 29 | goto cleanup; 30 | } 31 | 32 | if (!(root_json = json_parse_string(res->data))) { 33 | debug(&debugger, "Unable to parse release JSON response"); 34 | goto cleanup; 35 | } 36 | 37 | if (!(json_object = json_value_get_object(root_json))) { 38 | debug(&debugger, "Unable to parse release JSON response object"); 39 | goto cleanup; 40 | } 41 | 42 | tag_name = strdup(json_object_get_string(json_object, "tag_name")); 43 | 44 | if (!tag_name) { 45 | debug(&debugger, "strudp(tag_name) failed"); 46 | goto cleanup; 47 | } 48 | 49 | cleanup: 50 | if (root_json) 51 | json_value_free(root_json); 52 | 53 | http_get_free(res); 54 | 55 | return tag_name; 56 | } 57 | -------------------------------------------------------------------------------- /src/common/clib-release-info.h: -------------------------------------------------------------------------------- 1 | // 2 | // clib-release-info.h 3 | // 4 | // Copyright (c) 2016-2021 clib authors 5 | // MIT licensed 6 | // 7 | 8 | #ifndef CLIB_RELEASE_INFO_H 9 | #define CLIB_RELEASE_INFO_H 10 | 11 | /** 12 | * @return NULL on failure, char * otherwise that must be freed 13 | */ 14 | const char *clib_release_get_latest_tag(void); 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /src/common/clib-settings.c: -------------------------------------------------------------------------------- 1 | #include "clib-settings.h" 2 | 3 | const char *manifest_names[] = {"clib.json", "package.json", 0}; 4 | -------------------------------------------------------------------------------- /src/common/clib-settings.h: -------------------------------------------------------------------------------- 1 | #ifndef CLIB_SETTINGS_H 2 | #define CLIB_SETTINGS_H 3 | 4 | // Shared settings 5 | #define CLIB_PACKAGE_CACHE_TIME 30 * 24 * 60 * 60 6 | #define CLIB_SEARCH_CACHE_TIME 1 * 24 * 60 * 60 7 | 8 | #ifdef HAVE_PTHREADS 9 | #define MAX_THREADS 12 10 | #endif 11 | 12 | extern const char *manifest_names[]; 13 | 14 | #endif // CLIB_SRC_COMMON_CLIB_SETTINGS_H 15 | -------------------------------------------------------------------------------- /src/common/clib-validate.c: -------------------------------------------------------------------------------- 1 | // 2 | // clib-validate: `clib-validate.c` 3 | // 4 | // Copyright (c) 2014 Stephen Mathieson 5 | // Copyright (c) 2021 clib authors 6 | // MIT licensed 7 | // 8 | 9 | #include "fs/fs.h" 10 | #include "logger/logger.h" 11 | #include "parse-repo/parse-repo.h" 12 | #include "parson/parson.h" 13 | #include "path-join/path-join.h" 14 | #include "strdup/strdup.h" 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #define ERROR_FORMAT(err, ...) \ 21 | ({ \ 22 | rc = 1; \ 23 | logger_error("error", err, __VA_ARGS__); \ 24 | goto done; \ 25 | }) 26 | 27 | #define WARN(warning) ({ logger_warn("warning", warning); }); 28 | 29 | #define WARN_FORMAT(warning, ...) \ 30 | ({ logger_warn("warning", warning, __VA_ARGS__); }); 31 | 32 | #define WARN_MISSING(key, file) \ 33 | ({ WARN_FORMAT("missing " #key " in %s", file); }) 34 | 35 | #define require_string(name, file) \ 36 | ({ \ 37 | const char *__##name = json_object_get_string(obj, #name); \ 38 | if (!(__##name)) \ 39 | WARN_MISSING(#name, file); \ 40 | }) 41 | 42 | int clib_validate(const char *file) { 43 | const char *repo = NULL; 44 | char *repo_owner = NULL; 45 | char *repo_name = NULL; 46 | int rc = 0; 47 | JSON_Value *root = NULL; 48 | JSON_Object *obj = NULL; 49 | JSON_Value *src = NULL; 50 | 51 | if (-1 == fs_exists(file)) 52 | ERROR_FORMAT("no such file: %s", file); 53 | if (!(root = json_parse_file(file))) 54 | ERROR_FORMAT("malformed file: %s", file); 55 | if (!(obj = json_value_get_object(root))) 56 | ERROR_FORMAT("malformed file: %s", file); 57 | 58 | require_string(name, file); 59 | require_string(version, file); 60 | // TODO: validate semver 61 | 62 | repo = json_object_get_string(obj, "repo"); 63 | if (!repo) { 64 | WARN_MISSING("repo", file); 65 | } else { 66 | if (!(repo_name = parse_repo_name(repo))) 67 | WARN("invalid repo"); 68 | if (!(repo_owner = parse_repo_owner(repo, NULL))) 69 | WARN("invalid repo"); 70 | } 71 | 72 | require_string(description, file); 73 | require_string(license, file); 74 | 75 | if (!json_object_get_array(obj, "keywords")) { 76 | WARN_MISSING("keywords", file); 77 | } 78 | 79 | src = json_object_get_value(obj, "src"); 80 | if (!src) { 81 | 82 | if (!json_object_get_string(obj, "install")) 83 | ERROR_FORMAT("Must have either src or install defined in %s", file); 84 | 85 | } else if (json_value_get_type(src) != JSONArray) { 86 | WARN("src should be an array") 87 | } 88 | 89 | done: 90 | if (root) 91 | json_value_free(root); 92 | return rc; 93 | } 94 | -------------------------------------------------------------------------------- /src/common/clib-validate.h: -------------------------------------------------------------------------------- 1 | // 2 | // clib-validate.h 3 | // 4 | // Copyright (c) 2014-2021 clib authors 5 | // MIT licensed 6 | // 7 | 8 | #ifndef CLIB_VALIDATE_H 9 | #define CLIB_VALIDATE_H 10 | 11 | /** 12 | * @return 0 if the file is valid 13 | */ 14 | int clib_validate(const char *file); 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /src/version.h: -------------------------------------------------------------------------------- 1 | // 2 | // version.h 3 | // 4 | // Copyright (c) 2012-2014 clib authors 5 | // MIT licensed 6 | // 7 | 8 | #ifndef CLIB_VERSION 9 | #define CLIB_VERSION "2.8.7" 10 | #endif 11 | -------------------------------------------------------------------------------- /test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ctrl_c () { 4 | echo "Ctrl+c detected. Exiting..." 5 | exit 1 6 | } 7 | 8 | trap ctrl_c INT 9 | 10 | TESTS=$(find test/*.sh -type f -perm -111) 11 | EXIT_CODE=0 12 | export PATH="$PWD:$PATH" 13 | 14 | printf "\nRunning clib(1) tests\n\n" 15 | 16 | for t in $TESTS; do 17 | if ! ./"$t"; then 18 | echo >&2 " (✖) $t" 19 | EXIT_CODE=1 20 | else 21 | echo " (✓) $t" 22 | fi 23 | done 24 | echo 25 | 26 | printf "\nRunning clib package tests\n\n" 27 | cd test/package && make clean 28 | 29 | if ! make test; then 30 | EXIT_CODE=1 31 | fi 32 | 33 | cd ../../ 34 | 35 | printf "\nRunning clib cache tests\n\n" 36 | cd test/cache && make clean 37 | 38 | if ! make test; then 39 | EXIT_CODE=1 40 | fi 41 | 42 | cd ../../ 43 | 44 | exit $EXIT_CODE 45 | -------------------------------------------------------------------------------- /test/cache/Makefile: -------------------------------------------------------------------------------- 1 | CC ?= cc 2 | VALGRIND ?= valgrind 3 | TEST_RUNNER ?= 4 | 5 | SRC = ../../src/common/clib-cache.c 6 | DEPS += $(wildcard ../../deps/*/*.c) 7 | OBJS = $(SRC:.c=.o) $(DEPS:.c=.o) 8 | TEST_SRC = $(wildcard *.c) 9 | TEST_OBJ = $(TEST_SRC:.c=.o) 10 | TEST_BIN = $(TEST_SRC:.c=) 11 | 12 | CFLAGS += -std=c99 -Wall -I../../src/common -I../../deps -g 13 | LDFLAGS = -lcurl 14 | VALGRIND_OPTS ?= --leak-check=full --error-exitcode=3 15 | 16 | .DEFAULT_GOAL := test 17 | 18 | test: $(TEST_BIN) 19 | $(foreach t, $^, $(TEST_RUNNER) ./$(t) || exit 1;) 20 | 21 | valgrind: TEST_RUNNER=$(VALGRIND) $(VALGRIND_OPTS) 22 | valgrind: test 23 | 24 | example: example.o $(OBJS) 25 | 26 | cache-%: cache-%.o $(OBJS) 27 | $(CC) $(CFLAGS) $^ -o $@ $(LDFLAGS) 28 | 29 | clean: 30 | rm -f $(OBJS) 31 | rm -f $(TEST_OBJ) 32 | rm -f $(TEST_BIN) 33 | rm -rf test/fixtures 34 | 35 | .PHONY: test valgrind clean 36 | -------------------------------------------------------------------------------- /test/cache/cache-test.c: -------------------------------------------------------------------------------- 1 | #include "../../src/common/clib-cache.h" 2 | #include "fs/fs.h" 3 | #include "rimraf/rimraf.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define assert_exists(f) assert_equal(0, fs_exists(f)); 11 | 12 | static void assert_cached_dir(char *pkg_dir, int exists) { 13 | assert_equal(exists, fs_exists(pkg_dir)); 14 | } 15 | 16 | static void assert_cached_file(char *pkg_dir, char *file) { 17 | char path[BUFSIZ]; 18 | sprintf(path, "%s/%s", pkg_dir, file); 19 | 20 | assert_exists(path); 21 | } 22 | 23 | static void assert_cached_files(char *pkg_dir) { 24 | assert_cached_file(pkg_dir, "copy.c"); 25 | assert_cached_file(pkg_dir, "copy.h"); 26 | assert_cached_file(pkg_dir, "package.json"); 27 | } 28 | 29 | int main() { 30 | 31 | rimraf(clib_cache_dir()); 32 | 33 | describe("clib-cache operations") { 34 | 35 | char *author = "author"; 36 | char *name = "pkg"; 37 | char *version = "1.2.0"; 38 | char pkg_dir[BUFSIZ]; 39 | 40 | int expiraton = 1; 41 | 42 | it("should initialize succesfully") { 43 | assert_equal(0, clib_cache_init(expiraton)); 44 | } 45 | 46 | sprintf(pkg_dir, "%s/author_pkg_1.2.0", clib_cache_dir()); 47 | 48 | it("should manage the package cache") { 49 | assert_equal( 50 | 0, clib_cache_save_package(author, name, version, "../../deps/copy")); 51 | assert_equal(1, clib_cache_has_package(author, name, version)); 52 | assert_equal(0, clib_cache_is_expired_package(author, name, version)); 53 | 54 | assert_cached_dir(pkg_dir, 0); 55 | assert_cached_files(pkg_dir); 56 | } 57 | 58 | it("should manage the json cache") { 59 | char *cached_json; 60 | 61 | assert_equal(0, clib_cache_has_json("a", "n", "v")); 62 | assert_null(clib_cache_read_json("a", "n", "v")); 63 | 64 | assert_equal(2, clib_cache_save_json("a", "n", "v", "{}")); 65 | assert_equal( 66 | 0, strcmp("{}", cached_json = clib_cache_read_json("a", "n", "v"))); 67 | free(cached_json); 68 | assert_equal(1, clib_cache_has_json("a", "n", "v")); 69 | 70 | assert_equal(0, clib_cache_delete_json("a", "n", "v")); 71 | assert_equal(0, clib_cache_has_json("a", "n", "v")); 72 | assert_null(clib_cache_read_json("a", "n", "v")); 73 | } 74 | 75 | it("should manage the search cache") { 76 | char *cached_search; 77 | 78 | clib_cache_delete_search(); 79 | 80 | assert_equal(0, clib_cache_has_search()); 81 | assert_null(clib_cache_read_search()); 82 | 83 | assert_equal(13, clib_cache_save_search("")); 84 | assert_equal(1, clib_cache_has_search()); 85 | assert_equal( 86 | 0, strcmp("", cached_search = clib_cache_read_search())); 87 | free(cached_search); 88 | 89 | assert_equal(0, clib_cache_delete_search()); 90 | assert_equal(0, clib_cache_has_search()); 91 | assert_null(clib_cache_read_search()); 92 | } 93 | 94 | it("should expire the search cache") { 95 | clib_cache_delete_search(); 96 | 97 | assert_equal(13, clib_cache_save_search("")); 98 | assert_equal(1, clib_cache_has_search()); 99 | 100 | sleep(expiraton + 1); 101 | 102 | assert_equal(0, clib_cache_has_search()); 103 | } 104 | 105 | clib_cache_delete_search(); 106 | } 107 | 108 | return assert_failures(); 109 | } 110 | -------------------------------------------------------------------------------- /test/data/test-save-package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test-package" 3 | } 4 | -------------------------------------------------------------------------------- /test/fuzzing/fuzz_manifest.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "../../src/common/clib-package.h" 7 | 8 | int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 9 | if(size<3){ 10 | return 0; 11 | } 12 | char filename[256]; 13 | sprintf(filename, "libfuzzer.json"); 14 | 15 | FILE *fp = fopen(filename, "wb"); 16 | if (!fp) 17 | return 0; 18 | fwrite(data, size, 1, fp); 19 | fclose(fp); 20 | 21 | clib_package_t *pkg = 22 | clib_package_load_from_manifest(filename, 0); 23 | if(pkg) { 24 | clib_package_free(pkg); 25 | } 26 | unlink(filename); 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /test/gh-35-exit-codes.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # see #35 4 | 5 | clib install stephenmathieson/rot132.c > /dev/null 2>&1 && { 6 | echo >&2 "Failed installations should exit with a non-zero exit code" 7 | exit 1 8 | } 9 | exit 0 10 | -------------------------------------------------------------------------------- /test/help.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | clib help 2> /dev/null 4 | [ $? -eq 1 ] || { 5 | echo >&2 "Expected \`clib help\` to fail" 6 | exit 1 7 | } 8 | 9 | ACTUAL=$(clib help install) 10 | EXPECTED=$(clib install --help) 11 | 12 | [ "$ACTUAL" = "$EXPECTED" ] || { 13 | echo >&2 "\`help install\` should ouput clib-install --help" 14 | exit 1 15 | } 16 | 17 | ACTUAL=$(clib help search) 18 | EXPECTED=$(clib search --help) 19 | 20 | [ "$ACTUAL" = "$EXPECTED" ] || { 21 | echo >&2 "\`help search\` should ouput clib-search --help" 22 | exit 1 23 | } 24 | 25 | -------------------------------------------------------------------------------- /test/install-binary-dependencies.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | mkdir -p tmp/bin 4 | trap 'rm -rf tmp' EXIT 5 | 6 | clib install -c -N stephenmathieson/tabs-to-spaces@1.0.0 -P tmp > /dev/null || { 7 | echo >&2 "Failed to install stephenmathieson/tabs-to-spaces" 8 | exit 1 9 | } 10 | 11 | command -v tmp/bin/t2s >/dev/null 2>&1 || { 12 | echo >&2 "Failed to put t2s on path" 13 | exit 1 14 | } 15 | -------------------------------------------------------------------------------- /test/install-brace-expansion.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | throw() { 4 | echo >&2 "$1" 5 | exit 1 6 | } 7 | 8 | trap 'rm -rf tmp' EXIT 9 | 10 | clib install -c -N -o tmp stephenmathieson/trim.c stephenmathieson/case.c > /dev/null || 11 | throw "expecting successful exit code" 12 | 13 | [ -d ./tmp/case ] && [ -f ./tmp/case/package.json ] || 14 | throw "failed to install case.c" 15 | 16 | [ -d ./tmp/trim ] && [ -f ./tmp/trim/package.json ] || 17 | throw "failed to install trim.c" 18 | -------------------------------------------------------------------------------- /test/install-deps-from-package-json.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | throw() { 4 | echo >&2 "$1" 5 | exit 1 6 | } 7 | 8 | mkdir -p tmp 9 | trap 'rm -rf tmp' EXIT 10 | 11 | cd tmp || exit 12 | 13 | # see https://github.com/clibs/clib/issues/45 14 | cat > package.json << EOF 15 | { 16 | "dependencies": { 17 | "linenoise": "*", 18 | "stephenmathieson/substr.c": "*", 19 | "stephenmathieson/emtter.c": "*" 20 | } 21 | } 22 | EOF 23 | 24 | clib install > /dev/null 2>&1 25 | 26 | [ $? -eq 1 ] || throw "expecting exit code of 1"; 27 | 28 | cd - > /dev/null || exit 29 | -------------------------------------------------------------------------------- /test/install-multiple-clibs-libs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | throw() { 4 | echo >&2 "$1" 5 | exit 1 6 | } 7 | 8 | trap 'rm -rf tmp' EXIT 9 | 10 | clib install -c -N -o tmp ms file hash > /dev/null || 11 | throw "expecting successful exit code" 12 | 13 | [ -d ./tmp/ms ] && [ -f ./tmp/ms/package.json ] || 14 | throw "failed to install ms" 15 | 16 | [ -d ./tmp/file ] && [ -f ./tmp/file/package.json ] || 17 | throw "failed to install file" 18 | 19 | [ -d ./tmp/hash ] && [ -f ./tmp/hash/package.json ] || 20 | throw "failed to install hash" 21 | -------------------------------------------------------------------------------- /test/install-multiple-libs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | throw() { 4 | echo >&2 "$1" 5 | exit 1 6 | } 7 | 8 | trap 'rm -rf tmp' EXIT 9 | 10 | clib install -c -N -o tmp \ 11 | stephenmathieson/case.c stephenmathieson/trim.c > /dev/null || 12 | throw "expecting successful exit code" 13 | 14 | [ -d ./tmp/case ] && [ -f ./tmp/case/package.json ] || 15 | throw "failed to install case.c" 16 | 17 | [ -d ./tmp/trim ] && [ -f ./tmp/trim/package.json ] || 18 | throw "failed to install trim.c" 19 | -------------------------------------------------------------------------------- /test/install-no-save.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | mkdir -p tmp/test-save/bin 3 | RUNDIR="$PWD" 4 | trap 'rm -rf "$RUNDIR/tmp"' EXIT 5 | 6 | cp test/data/test-save-package.json tmp/test-save/package.json 7 | 8 | cd tmp/test-save || exit 9 | ../../clib-install -c --no-save stephenmathieson/tabs-to-spaces@1.0.0 -P . >/dev/null 10 | ../../clib-install -c -N darthtrevino/str-concat@0.0.2 >/dev/null 11 | ../../clib-install -c --dev --no-save jwerle/fs.c@0.1.1 >/dev/null 12 | ../../clib-install -c -d --no-save clibs/parson@1.0.2 >/dev/null 13 | cd - || exit 14 | 15 | if grep --quiet "stephenmathieson/tabs-to-spaces" tmp/test-save/package.json; then 16 | echo >&2 "Found stephenmathieson/tabs-to-spaces saved in package.json but --no-save was used" 17 | exit 1 18 | fi 19 | 20 | if grep --quiet "darthtrevino/str-concat" tmp/test-save/package.json; then 21 | echo >&2 "Found darthtrevino/strconcat saved in package.json but --no-save was used" 22 | exit 1 23 | fi 24 | 25 | if grep --quiet "jwerle/fs.c" tmp/test-save/package.json; then 26 | echo >&2 "Found jwerle/fs.c saved in package.json but --no-save was used" 27 | exit 1 28 | fi 29 | 30 | if grep --quiet "clibs/parson" tmp/test-save/package.json; then 31 | echo >&2 "Found clibs/parson saved in package.json but --no-save was used" 32 | exit 1 33 | fi 34 | -------------------------------------------------------------------------------- /test/install-save.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | mkdir -p tmp/test-save/bin 3 | RUNDIR="$PWD" 4 | trap 'rm -rf "$RUNDIR/tmp"' EXIT 5 | 6 | cp test/data/test-save-package.json tmp/test-save/package.json 7 | 8 | cd tmp/test-save || exit 9 | ../../clib-install -c stephenmathieson/tabs-to-spaces@1.0.0 -P . >/dev/null 10 | ../../clib-install -c darthtrevino/str-concat@0.0.2 >/dev/null 11 | ../../clib-install -c --dev jwerle/fs.c@0.1.1 >/dev/null 12 | ../../clib-install -c -D clibs/parson@1.0.2 >/dev/null 13 | cd - || exit 14 | 15 | if ! grep --quiet "stephenmathieson/tabs-to-spaces" tmp/test-save/package.json; then 16 | echo >&2 "Failed to find stephenmathieson/tabs-to-spaces saved in package.json" 17 | exit 1 18 | fi 19 | 20 | if ! grep --quiet "darthtrevino/str-concat" tmp/test-save/package.json; then 21 | echo >&2 "Failed to find darthtrevino/strconcat saved in package.json" 22 | exit 1 23 | fi 24 | 25 | if ! grep --quiet "jwerle/fs.c" tmp/test-save/package.json; then 26 | echo >&2 "Failed to find jwerle/fs.c saved in package.json" 27 | exit 1 28 | fi 29 | 30 | if ! grep --quiet "clibs/parson" tmp/test-save/package.json; then 31 | echo >&2 "Failed to find clibs/parson saved in package.json" 32 | exit 1 33 | fi 34 | -------------------------------------------------------------------------------- /test/package/Makefile: -------------------------------------------------------------------------------- 1 | CC ?= cc 2 | VALGRIND ?= valgrind 3 | TEST_RUNNER ?= 4 | 5 | SRC = ../../src/common/clib-package.c ../../src/common/clib-cache.c ../../src/common/clib-release-info.c ../../src/common/clib-settings.c 6 | DEPS += $(wildcard ../../deps/*/*.c) 7 | OBJS = $(SRC:.c=.o) $(DEPS:.c=.o) 8 | TEST_SRC = $(wildcard *.c) 9 | TEST_OBJ = $(TEST_SRC:.c=.o) 10 | TEST_BIN = $(TEST_SRC:.c=) 11 | 12 | CFLAGS += -std=c99 -Wall -I../../src/common -I../../deps -DHAVE_PTHREADS -pthread -g 13 | LDFLAGS = -lcurl 14 | VALGRIND_OPTS ?= --leak-check=full --error-exitcode=3 15 | 16 | .DEFAULT_GOAL := test 17 | 18 | test: $(TEST_BIN) 19 | $(foreach t, $^, $(TEST_RUNNER) ./$(t) || exit 1;) 20 | 21 | valgrind: TEST_RUNNER=$(VALGRIND) $(VALGRIND_OPTS) 22 | valgrind: test 23 | 24 | example: example.o $(OBJS) 25 | 26 | package-%: package-%.o $(OBJS) 27 | $(CC) $(CFLAGS) $^ -o $@ $(LDFLAGS) 28 | 29 | clean: 30 | rm -f $(OBJS) 31 | rm -f $(TEST_OBJ) 32 | rm -f $(TEST_BIN) 33 | rm -rf test/fixtures 34 | 35 | .PHONY: test valgrind clean 36 | -------------------------------------------------------------------------------- /test/package/clib.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "clib-package-test-fixture", 3 | "version": "0.0.0", 4 | "repo": "clibs/no-such-repo", 5 | "dependencies": { 6 | "list": "*" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /test/package/package-dependency-new.c: -------------------------------------------------------------------------------- 1 | #include "clib-cache.h" 2 | #include "clib-package.h" 3 | #include "rimraf/rimraf.h" 4 | #include "describe/describe.h" 5 | 6 | int main() { 7 | curl_global_init(CURL_GLOBAL_ALL); 8 | 9 | clib_cache_init(100); 10 | rimraf(clib_cache_dir()); 11 | 12 | describe("clib_package_dependency_new") { 13 | it("should return NULL when given bad input") { 14 | assert(NULL == clib_package_dependency_new("foo/bar", NULL)); 15 | assert(NULL == clib_package_dependency_new(NULL, "foo/bar")); 16 | } 17 | 18 | it("should return a clib-dependency when given valid input") { 19 | clib_package_dependency_t *dep = 20 | clib_package_dependency_new("foo/bar", "1.2.3"); 21 | assert(dep); 22 | assert_str_equal("foo", dep->author); 23 | assert_str_equal("bar", dep->name); 24 | assert_str_equal("1.2.3", dep->version); 25 | clib_package_dependency_free(dep); 26 | } 27 | 28 | it("should transform \"*\" to \"master\"") { 29 | clib_package_dependency_t *dep = 30 | clib_package_dependency_new("foo/bar", "*"); 31 | assert(dep); 32 | assert_str_equal("master", dep->version); 33 | clib_package_dependency_free(dep); 34 | } 35 | 36 | it("should default to \"clibs\" when no repo author is given") { 37 | clib_package_dependency_t *dep = 38 | clib_package_dependency_new("foo", "master"); 39 | assert(dep); 40 | assert_str_equal("clibs", dep->author); 41 | assert_str_equal("master", dep->version); 42 | clib_package_dependency_free(dep); 43 | } 44 | } 45 | 46 | curl_global_cleanup(); 47 | 48 | return assert_failures(); 49 | } 50 | -------------------------------------------------------------------------------- /test/package/package-install-dependencies.c: -------------------------------------------------------------------------------- 1 | #include "clib-package.h" 2 | #include "clib-cache.h" 3 | #include "describe/describe.h" 4 | #include "fs/fs.h" 5 | #include "rimraf/rimraf.h" 6 | 7 | int main() { 8 | curl_global_init(CURL_GLOBAL_ALL); 9 | clib_package_set_opts((clib_package_opts_t){ 10 | .skip_cache = 1, 11 | .prefix = 0, 12 | .force = 1, 13 | }); 14 | 15 | clib_cache_init(100); 16 | rimraf(clib_cache_dir()); 17 | 18 | describe("clib_package_install_dependencies") { 19 | it("should return -1 when given a bad package") { 20 | assert(-1 == clib_package_install_dependencies(NULL, "./deps", 0)); 21 | } 22 | 23 | it("should install the dep in its own directory") { 24 | clib_package_t *dep = 25 | clib_package_new_from_slug("stephenmathieson/mkdirp.c", 0); 26 | assert(dep); 27 | assert(0 == 28 | clib_package_install_dependencies(dep, "./test/fixtures/", 0)); 29 | assert(0 == fs_exists("./test/fixtures/")); 30 | assert(0 == fs_exists("./test/fixtures/path-normalize")); 31 | clib_package_free(dep); 32 | rimraf("./test/fixtures/"); 33 | } 34 | 35 | it("should install the dependency's package.json") { 36 | clib_package_t *pkg = 37 | clib_package_new_from_slug("stephenmathieson/mkdirp.c", 0); 38 | assert(pkg); 39 | assert(0 == 40 | clib_package_install_dependencies(pkg, "./test/fixtures/", 0)); 41 | assert(0 == fs_exists("./test/fixtures/path-normalize/package.json")); 42 | clib_package_free(pkg); 43 | rimraf("./test/fixtures/"); 44 | } 45 | 46 | it("should install the dependency's sources") { 47 | clib_package_t *pkg = 48 | clib_package_new_from_slug("stephenmathieson/mkdirp.c", 0); 49 | assert(pkg); 50 | assert(0 == 51 | clib_package_install_dependencies(pkg, "./test/fixtures/", 0)); 52 | assert(0 == fs_exists("./test/fixtures/path-normalize/path-normalize.c")); 53 | assert(0 == fs_exists("./test/fixtures/path-normalize/path-normalize.h")); 54 | clib_package_free(pkg); 55 | rimraf("./test/fixtures"); 56 | } 57 | 58 | it("should install the dependency's dependencies") { 59 | clib_package_t *pkg = 60 | clib_package_new_from_slug("stephenmathieson/rimraf.c", 0); 61 | assert(pkg); 62 | assert(0 == 63 | clib_package_install_dependencies(pkg, "./test/fixtures/", 0)); 64 | // deps 65 | assert(0 == fs_exists("./test/fixtures/path-join/")); 66 | assert(0 == fs_exists("./test/fixtures/path-join/package.json")); 67 | assert(0 == fs_exists("./test/fixtures/path-join/path-join.c")); 68 | assert(0 == fs_exists("./test/fixtures/path-join/path-join.h")); 69 | // deps' deps 70 | assert(0 == fs_exists("./test/fixtures/str-ends-with/")); 71 | assert(0 == fs_exists("./test/fixtures/str-ends-with/package.json")); 72 | assert(0 == fs_exists("./test/fixtures/str-ends-with/str-ends-with.h")); 73 | assert(0 == fs_exists("./test/fixtures/str-ends-with/str-ends-with.c")); 74 | assert(0 == fs_exists("./test/fixtures/str-starts-with/")); 75 | assert(0 == fs_exists("./test/fixtures/str-starts-with/package.json")); 76 | assert(0 == 77 | fs_exists("./test/fixtures/str-starts-with/str-starts-with.h")); 78 | assert(0 == 79 | fs_exists("./test/fixtures/str-starts-with/str-starts-with.c")); 80 | clib_package_free(pkg); 81 | rimraf("./test/fixtures"); 82 | } 83 | 84 | it("should handle unresolved packages") { 85 | char json[] = "{" 86 | " \"dependencies\": {" 87 | " \"linenoise\": \"*\"," 88 | " \"stephenmathieson/substr.c\": \"*\"," 89 | " \"stephenmathieson/emtter.c\": \"*\"" 90 | " }" 91 | "}"; 92 | 93 | clib_package_t *pkg = clib_package_new(json, 0); 94 | assert(pkg); 95 | 96 | int r = clib_package_install_dependencies(pkg, "./test/fixtures/", 0); 97 | // should fail 98 | assert(-1 == r); 99 | 100 | assert(0 == fs_exists("./test/fixtures/linenoise/package.json")); 101 | assert(0 == fs_exists("./test/fixtures/substr/package.json")); 102 | assert(-1 == fs_exists("./test/fixtures/emtter/")); 103 | 104 | clib_package_free(pkg); 105 | rimraf("./test/fixtures"); 106 | } 107 | } 108 | 109 | curl_global_cleanup(); 110 | clib_package_cleanup(); 111 | 112 | return assert_failures(); 113 | } 114 | -------------------------------------------------------------------------------- /test/package/package-install-dev-dependencies.c: -------------------------------------------------------------------------------- 1 | #include "clib-package.h" 2 | #include "clib-cache.h" 3 | #include "describe/describe.h" 4 | #include "fs/fs.h" 5 | #include "rimraf/rimraf.h" 6 | 7 | int main() { 8 | curl_global_init(CURL_GLOBAL_ALL); 9 | clib_package_set_opts((clib_package_opts_t){ 10 | .skip_cache = 1, 11 | .prefix = 0, 12 | .force = 1, 13 | }); 14 | 15 | clib_cache_init(100); 16 | rimraf(clib_cache_dir()); 17 | 18 | describe("clib_package_install_development") { 19 | it("should return -1 when given a bad package") { 20 | assert(-1 == clib_package_install_development(NULL, "./deps", 0)); 21 | } 22 | 23 | it("should return -1 when given a bad dir") { 24 | clib_package_t *pkg = 25 | clib_package_new_from_slug("stephenmathieson/mkdirp.c", 0); 26 | assert(pkg); 27 | assert(-1 == clib_package_install_development(pkg, NULL, 0)); 28 | clib_package_free(pkg); 29 | } 30 | 31 | it("should install the package's development dependencies") { 32 | clib_package_t *pkg = 33 | clib_package_new_from_slug("stephenmathieson/trim.c@0.0.2", 0); 34 | assert(pkg); 35 | assert(0 == clib_package_install_development(pkg, "./test/fixtures", 0)); 36 | assert(0 == fs_exists("./test/fixtures/describe")); 37 | assert(0 == fs_exists("./test/fixtures/describe/describe.h")); 38 | assert(0 == fs_exists("./test/fixtures/describe/package.json")); 39 | assert(0 == 40 | fs_exists("./test/fixtures/assertion-macros/assertion-macros.h")); 41 | assert(0 == fs_exists("./test/fixtures/assertion-macros/package.json")); 42 | rimraf("./test/fixtures"); 43 | clib_package_free(pkg); 44 | } 45 | } 46 | 47 | curl_global_cleanup(); 48 | clib_package_cleanup(); 49 | 50 | return assert_failures(); 51 | } 52 | -------------------------------------------------------------------------------- /test/package/package-load-from-manifest.c: -------------------------------------------------------------------------------- 1 | #include "clib-cache.h" 2 | #include "clib-package.h" 3 | #include "describe/describe.h" 4 | #include "rimraf/rimraf.h" 5 | 6 | int main() { 7 | clib_cache_init(100); 8 | rimraf(clib_cache_dir()); 9 | 10 | describe("clib_package_load_from_manifest") { 11 | it("should load a package from a file if available") { 12 | int verbose = 0; 13 | clib_package_t *pkg = 14 | clib_package_load_from_manifest("./clib.json", verbose); 15 | assert(NULL != pkg); 16 | if (pkg) { 17 | clib_package_free(pkg); 18 | } 19 | } 20 | } 21 | 22 | return assert_failures(); 23 | } 24 | -------------------------------------------------------------------------------- /test/package/package-load-manifest-file.c: -------------------------------------------------------------------------------- 1 | #include "clib-cache.h" 2 | #include "clib-package.h" 3 | #include "describe/describe.h" 4 | #include "rimraf/rimraf.h" 5 | 6 | int main() { 7 | clib_cache_init(100); 8 | rimraf(clib_cache_dir()); 9 | 10 | describe("clib_package_load_local_manifest") { 11 | it("should load a local package if available") { 12 | int verbose = 0; 13 | clib_package_t *pkg = clib_package_load_local_manifest(verbose); 14 | assert(NULL != pkg); 15 | if (pkg) { 16 | clib_package_free(pkg); 17 | } 18 | } 19 | } 20 | 21 | return assert_failures(); 22 | } 23 | -------------------------------------------------------------------------------- /test/package/package-new-from-slug.c: -------------------------------------------------------------------------------- 1 | #include "clib-cache.h" 2 | #include "clib-package.h" 3 | #include "describe/describe.h" 4 | #include "rimraf/rimraf.h" 5 | 6 | int main() { 7 | curl_global_init(CURL_GLOBAL_ALL); 8 | 9 | clib_cache_init(100); 10 | rimraf(clib_cache_dir()); 11 | 12 | describe("clib_package_new_from_slug") { 13 | it("should return NULL when given a bad slug") { 14 | assert(NULL == clib_package_new_from_slug(NULL, 0)); 15 | } 16 | 17 | it("should return NULL when given a slug missing a name") { 18 | assert(NULL == clib_package_new_from_slug("author/@version", 0)); 19 | } 20 | 21 | it("should return NULL when given slug which doesn't resolve") { 22 | assert(NULL == clib_package_new_from_slug("abc11234", 0)); 23 | } 24 | 25 | it("should build the correct package") { 26 | clib_package_t *pkg = 27 | clib_package_new_from_slug("stephenmathieson/case.c@0.1.0", 0); 28 | assert(pkg); 29 | assert_str_equal("case", pkg->name); 30 | assert_str_equal("0.1.0", pkg->version); 31 | assert_str_equal("stephenmathieson/case.c", pkg->repo); 32 | assert_str_equal("MIT", pkg->license); 33 | assert_str_equal("String case conversion utility", pkg->description); 34 | clib_package_free(pkg); 35 | } 36 | 37 | it("should force package version numbers") { 38 | clib_package_t *pkg = 39 | clib_package_new_from_slug("stephenmathieson/mkdirp.c@0.0.1", 0); 40 | assert(pkg); 41 | assert_str_equal("0.0.1", pkg->version); 42 | clib_package_free(pkg); 43 | } 44 | 45 | it("should use package version if version not provided") { 46 | clib_package_t *pkg = 47 | clib_package_new_from_slug("stephenmathieson/mkdirp.c", 0); 48 | assert(pkg); 49 | assert_str_equal("0.1.5", pkg->version); 50 | clib_package_free(pkg); 51 | } 52 | 53 | it("should save the package's json") { 54 | clib_package_t *pkg = clib_package_new_from_slug( 55 | "stephenmathieson/str-replace.c@8ca90fb", 0); 56 | assert(pkg); 57 | assert(pkg->json); 58 | 59 | char expected[] = "{\n" 60 | " \"name\": \"str-replace\",\n" 61 | " \"version\": \"0.0.3\",\n" 62 | " \"repo\": \"stephenmathieson/str-replace.c\",\n" 63 | " \"description\": \"String replacement in C\",\n" 64 | " \"keywords\": [ \"string\", \"replace\" ],\n" 65 | " \"license\": \"MIT\",\n" 66 | " \"src\": [\n" 67 | " \"src/str-replace.c\",\n" 68 | " \"src/str-replace.h\",\n" 69 | " \"deps/occurrences.c\",\n" 70 | " \"deps/occurrences.h\"\n" 71 | " ]\n" 72 | "}\n"; 73 | 74 | assert_str_equal(expected, pkg->json); 75 | clib_package_free(pkg); 76 | } 77 | } 78 | 79 | curl_global_cleanup(); 80 | clib_package_cleanup(); 81 | 82 | return assert_failures(); 83 | } 84 | -------------------------------------------------------------------------------- /test/package/package-new.c: -------------------------------------------------------------------------------- 1 | #include "clib-cache.h" 2 | #include "clib-package.h" 3 | #include "describe/describe.h" 4 | #include "rimraf/rimraf.h" 5 | 6 | int main() { 7 | clib_cache_init(100); 8 | rimraf(clib_cache_dir()); 9 | 10 | describe("clib_package_new") { 11 | char json[] = "{" 12 | " \"name\": \"foo\"," 13 | " \"version\": \"1.0.0\"," 14 | " \"repo\": \"foobar/foo\"," 15 | " \"license\": \"mit\"," 16 | " \"description\": \"lots of foo\"," 17 | " \"src\": [" 18 | " \"foo.h\"," 19 | " \"foo.c\"" 20 | " ]," 21 | " \"dependencies\": {" 22 | " \"blah/blah\": \"1.2.3\"," 23 | " \"bar\": \"*\"," 24 | " \"abc/def\": \"master\"" 25 | " }" 26 | "}"; 27 | 28 | it("should return NULL when given broken json") { 29 | assert(NULL == clib_package_new("{", 0)); 30 | } 31 | 32 | it("should return NULL when given a bad string") { 33 | assert(NULL == clib_package_new(NULL, 0)); 34 | } 35 | 36 | it("should return a clib_package when given valid json") { 37 | clib_package_t *pkg = clib_package_new(json, 0); 38 | assert(pkg); 39 | 40 | assert_str_equal(json, pkg->json); 41 | 42 | assert_str_equal("foo", pkg->name); 43 | assert_str_equal("foobar", pkg->author); 44 | assert_str_equal("1.0.0", pkg->version); 45 | assert_str_equal("foobar/foo", pkg->repo); 46 | assert_str_equal("mit", pkg->license); 47 | assert_str_equal("lots of foo", pkg->description); 48 | assert(NULL == pkg->install); 49 | 50 | assert(2 == pkg->src->len); 51 | assert_str_equal("foo.h", list_at(pkg->src, 0)->val); 52 | assert_str_equal("foo.c", list_at(pkg->src, 1)->val); 53 | 54 | assert(3 == pkg->dependencies->len); 55 | 56 | clib_package_dependency_t *dep0 = list_at(pkg->dependencies, 0)->val; 57 | assert_str_equal("blah", dep0->name); 58 | assert_str_equal("1.2.3", dep0->version); 59 | 60 | clib_package_dependency_t *dep1 = list_at(pkg->dependencies, 1)->val; 61 | assert_str_equal("bar", dep1->name); 62 | assert_str_equal("master", dep1->version); 63 | 64 | clib_package_dependency_t *dep2 = list_at(pkg->dependencies, 2)->val; 65 | assert_str_equal("def", dep2->name); 66 | assert_str_equal("master", dep2->version); 67 | 68 | clib_package_free(pkg); 69 | } 70 | 71 | it("should support missing src") { 72 | char json[] = "{" 73 | " \"name\": \"foo\"," 74 | " \"version\": \"1.0.0\"," 75 | " \"repo\": \"foobar/foo\"," 76 | " \"license\": \"mit\"," 77 | " \"description\": \"lots of foo\"" 78 | "}"; 79 | 80 | clib_package_t *pkg = clib_package_new(json, 0); 81 | assert(pkg); 82 | clib_package_free(pkg); 83 | } 84 | } 85 | 86 | return assert_failures(); 87 | } 88 | -------------------------------------------------------------------------------- /test/package/package-parse-author.c: -------------------------------------------------------------------------------- 1 | #include "clib-cache.h" 2 | #include "clib-package.h" 3 | #include "describe/describe.h" 4 | #include 5 | #include "rimraf/rimraf.h" 6 | 7 | int main() { 8 | clib_cache_init(100); 9 | rimraf(clib_cache_dir()); 10 | 11 | describe("clib_package_parse_author") { 12 | char *author = NULL; 13 | 14 | it("should return NULL when given a bad slug") { 15 | assert(NULL == clib_package_parse_author(NULL)); 16 | } 17 | 18 | it("should return NULL when unable to parse an author") { 19 | assert(NULL == clib_package_parse_author("/")); 20 | assert(NULL == clib_package_parse_author("/name")); 21 | assert(NULL == clib_package_parse_author("/name@version")); 22 | } 23 | 24 | it("should default to \"clibs\"") { 25 | author = clib_package_parse_author("foo"); 26 | assert_str_equal("clibs", author); 27 | free(author); 28 | } 29 | 30 | it("should support \"author/name\"-style slugs") { 31 | author = clib_package_parse_author("author/name"); 32 | assert_str_equal("author", author); 33 | free(author); 34 | } 35 | 36 | it("should support \"author/name@version\"-slugs slugs") { 37 | author = clib_package_parse_author("author/name@master"); 38 | assert_str_equal("author", author); 39 | free(author); 40 | author = clib_package_parse_author("author/name@*"); 41 | assert_str_equal("author", author); 42 | free(author); 43 | } 44 | 45 | // this was a bug in parse-repo.c... 46 | it("should not be affected after the slug is freed") { 47 | char *slug = malloc(48); 48 | assert(slug); 49 | strcpy(slug, "author/name@version"); 50 | 51 | author = clib_package_parse_author(slug); 52 | 53 | assert_str_equal("author", author); 54 | free(slug); 55 | assert_str_equal("author", author); 56 | free(author); 57 | } 58 | } 59 | 60 | return assert_failures(); 61 | } 62 | -------------------------------------------------------------------------------- /test/package/package-parse-name.c: -------------------------------------------------------------------------------- 1 | #include "clib-cache.h" 2 | #include "clib-package.h" 3 | #include "describe/describe.h" 4 | #include "rimraf/rimraf.h" 5 | 6 | int main() { 7 | clib_cache_init(100); 8 | rimraf(clib_cache_dir()); 9 | 10 | describe("clib_package_parse_name") { 11 | char *name = NULL; 12 | 13 | it("should return NULL when given a bad slug") { 14 | assert(NULL == clib_package_parse_name(NULL)); 15 | } 16 | 17 | it("should return NULL when unable to parse a name") { 18 | assert(NULL == clib_package_parse_name("/")); 19 | assert(NULL == clib_package_parse_name("author/")); 20 | } 21 | 22 | it("should support the \"name\"-style slugs") { 23 | name = clib_package_parse_name("name"); 24 | assert_str_equal("name", name); 25 | free(name); 26 | } 27 | 28 | it("should support \"author/name\"-style slugs") { 29 | name = clib_package_parse_name("author/name"); 30 | assert_str_equal("name", name); 31 | free(name); 32 | } 33 | 34 | it("should support \"author/name@version\"-slugs slugs") { 35 | name = clib_package_parse_name("author/name@master"); 36 | assert_str_equal("name", name); 37 | free(name); 38 | 39 | name = clib_package_parse_name("author/name@*"); 40 | assert_str_equal("name", name); 41 | free(name); 42 | } 43 | 44 | // this was a bug in parse-repo.c... 45 | it("should not be affected after the slug is freed") { 46 | char *slug = malloc(48); 47 | assert(slug); 48 | strcpy(slug, "author/name@version"); 49 | 50 | char *name = clib_package_parse_name(slug); 51 | 52 | assert_str_equal("name", name); 53 | free(slug); 54 | 55 | assert_str_equal("name", name); 56 | free(name); 57 | } 58 | } 59 | 60 | return assert_failures(); 61 | } 62 | -------------------------------------------------------------------------------- /test/package/package-parse-version.c: -------------------------------------------------------------------------------- 1 | #include "clib-cache.h" 2 | #include "clib-package.h" 3 | #include "describe/describe.h" 4 | #include "rimraf/rimraf.h" 5 | 6 | int main() { 7 | clib_cache_init(100); 8 | rimraf(clib_cache_dir()); 9 | 10 | describe("clib_package_parse_version") { 11 | char *version = NULL; 12 | 13 | it("should return NULL when given a bad slug") { 14 | assert(NULL == clib_package_parse_version(NULL)); 15 | assert(NULL == clib_package_parse_version("")); 16 | } 17 | 18 | it("should default to \"master\"") { 19 | version = clib_package_parse_version("foo"); 20 | assert_str_equal("master", version); 21 | free(version); 22 | 23 | version = clib_package_parse_version("foo/bar"); 24 | assert_str_equal("master", version); 25 | free(version); 26 | } 27 | 28 | it("should transform \"*\" to \"master\"") { 29 | version = clib_package_parse_version("*"); 30 | assert_str_equal("master", version); 31 | free(version); 32 | 33 | version = clib_package_parse_version("foo@*"); 34 | assert_str_equal("master", version); 35 | free(version); 36 | 37 | version = clib_package_parse_version("foo/bar@*"); 38 | assert_str_equal("master", version); 39 | free(version); 40 | } 41 | 42 | it("should support \"name\"-style slugs") { 43 | version = clib_package_parse_version("foo"); 44 | assert_str_equal("master", version); 45 | free(version); 46 | } 47 | 48 | it("should support \"name@version\"-style slugs") { 49 | version = clib_package_parse_version("foo@bar"); 50 | assert_str_equal("bar", version); 51 | free(version); 52 | 53 | version = clib_package_parse_version("foo@*"); 54 | assert_str_equal("master", version); 55 | free(version); 56 | 57 | version = clib_package_parse_version("foo@1.2.3"); 58 | assert_str_equal("1.2.3", version); 59 | free(version); 60 | } 61 | 62 | it("should support \"author/name@version\"-style slugs") { 63 | version = clib_package_parse_version("foo/bar@baz"); 64 | assert_str_equal("baz", version); 65 | free(version); 66 | 67 | version = clib_package_parse_version("foo/bar@*"); 68 | assert_str_equal("master", version); 69 | free(version); 70 | 71 | version = clib_package_parse_version("foo/bar@1.2.3"); 72 | assert_str_equal("1.2.3", version); 73 | free(version); 74 | } 75 | 76 | // this was a bug in parse-repo.c... 77 | it("should not be affected after the slug is freed") { 78 | char *slug = malloc(48); 79 | assert(slug); 80 | strcpy(slug, "author/name@version"); 81 | 82 | version = clib_package_parse_version(slug); 83 | 84 | assert_str_equal("version", version); 85 | free(slug); 86 | 87 | assert_str_equal("version", version); 88 | 89 | free(version); 90 | } 91 | } 92 | 93 | return assert_failures(); 94 | } 95 | -------------------------------------------------------------------------------- /test/package/package-url.c: -------------------------------------------------------------------------------- 1 | #include "clib-cache.h" 2 | #include "clib-package.h" 3 | #include "describe/describe.h" 4 | #include "rimraf/rimraf.h" 5 | 6 | int main() { 7 | clib_cache_init(100); 8 | rimraf(clib_cache_dir()); 9 | 10 | describe("clib_package_url") { 11 | it("should return NULL when given a bad author") { 12 | assert(NULL == clib_package_url(NULL, "name", "version")); 13 | } 14 | 15 | it("should return NULL when given a bad name") { 16 | assert(NULL == clib_package_url("author", NULL, "version")); 17 | } 18 | 19 | it("should return NULL when given a bad version") { 20 | assert(NULL == clib_package_url("author", "name", NULL)); 21 | } 22 | 23 | it("should build a GitHub url") { 24 | char *url = clib_package_url("author", "name", "version"); 25 | assert_str_equal("https://raw.githubusercontent.com/author/name/version", 26 | url); 27 | free(url); 28 | } 29 | } 30 | 31 | return assert_failures(); 32 | } 33 | -------------------------------------------------------------------------------- /test/search-basic.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | CACHE=$TMPDIR/clib-search.cache 4 | rm -f "$CACHE" 2> /dev/null 5 | 6 | N=$(./clib-search | wc -l) 7 | # lame check for more than 100 lines of output 8 | [ "$N" -lt 100 ] && { 9 | echo >&2 "Expected \`clib search\` to return at least 100 results" 10 | exit 1 11 | } 12 | 13 | TRIM=$(./clib-search trim) 14 | case "$TRIM" in 15 | *"stephenmathieson/trim.c"*) 16 | : 17 | ;; 18 | *) 19 | echo >&2 "Expected \`clib search trim\` to output stephenmathieson/trim.c" 20 | exit 1 21 | ;; 22 | esac 23 | -------------------------------------------------------------------------------- /test/search-no-color.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | color_tests() { 4 | cmd="./clib-search $1" 5 | stdout=$($cmd) 6 | # lame check for color 7 | case "$stdout" in 8 | *"[39;49;90;49"*) 9 | echo >&2 "Expected \`${cmd}\` to suppress all color" 10 | exit 1 11 | ;; 12 | esac 13 | } 14 | 15 | color_tests --no-color 16 | color_tests -n 17 | -------------------------------------------------------------------------------- /test/uninstall.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | mkdir -p tmp/bin 3 | trap 'rm -rf tmp' EXIT 4 | 5 | clib install -c -N stephenmathieson/tabs-to-spaces@1.0.0 -P tmp > /dev/null || { 6 | echo >&2 "Failed to install stephenmathieson/tabs-to-spaces" 7 | exit 1 8 | } 9 | 10 | clib uninstall stephenmathieson/tabs-to-spaces -P tmp 11 | 12 | # ensure the un-installation worked 13 | command -v tmp/bin/t2s >/dev/null 2>&1 && { 14 | exit 0 15 | } 16 | 17 | echo >&2 "Failed to uninstall stephenmathieson/tabs-to-spaces"; 18 | exit 1 19 | --------------------------------------------------------------------------------