diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/blogc-git-receiver.c | 502 | ||||
-rw-r--r-- | src/blogc-runserver.c | 389 | ||||
-rw-r--r-- | src/blogc.c (renamed from src/main.c) | 52 | ||||
-rw-r--r-- | src/content-parser.c | 349 | ||||
-rw-r--r-- | src/content-parser.h | 3 | ||||
-rw-r--r-- | src/datetime-parser.c | 4 | ||||
-rw-r--r-- | src/directives.c | 8 | ||||
-rw-r--r-- | src/directives.h | 4 | ||||
-rw-r--r-- | src/error.c | 12 | ||||
-rw-r--r-- | src/file.c | 8 | ||||
-rw-r--r-- | src/loader.c | 84 | ||||
-rw-r--r-- | src/loader.h | 8 | ||||
-rw-r--r-- | src/renderer.c | 68 | ||||
-rw-r--r-- | src/renderer.h | 16 | ||||
-rw-r--r-- | src/source-parser.c | 40 | ||||
-rw-r--r-- | src/source-parser.h | 4 | ||||
-rw-r--r-- | src/template-parser.c | 42 | ||||
-rw-r--r-- | src/template-parser.h | 6 | ||||
-rw-r--r-- | src/utils.c | 612 | ||||
-rw-r--r-- | src/utils.h | 102 | ||||
-rw-r--r-- | src/utils/mem.c | 42 | ||||
-rw-r--r-- | src/utils/slist.c | 68 | ||||
-rw-r--r-- | src/utils/strings.c | 314 | ||||
-rw-r--r-- | src/utils/trie.c | 199 | ||||
-rw-r--r-- | src/utils/utils.h | 79 |
25 files changed, 1981 insertions, 1034 deletions
diff --git a/src/blogc-git-receiver.c b/src/blogc-git-receiver.c new file mode 100644 index 0000000..ffeac61 --- /dev/null +++ b/src/blogc-git-receiver.c @@ -0,0 +1,502 @@ +/* + * blogc: A blog compiler. + * Copyright (C) 2015-2016 Rafael G. Martins <rafael@rafaelmartins.eng.br> + * + * This program can be distributed under the terms of the BSD License. + * See the file LICENSE. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif /* HAVE_CONFIG_H */ + +#include <stdarg.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <libgen.h> +#include <unistd.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <dirent.h> +#include <time.h> + +#include "utils.h" + +#ifndef BUFFER_SIZE +#define BUFFER_SIZE 4096 +#endif + + +static unsigned int +cpu_count(void) +{ +#ifdef _SC_NPROCESSORS_ONLN + long num = sysconf(_SC_NPROCESSORS_ONLN); + if (num >= 1) + return (unsigned int) num; +#endif + return 1; +} + + +static void +rmdir_recursive(const char *dir) +{ + struct stat buf; + if (0 != stat(dir, &buf)) { + fprintf(stderr, "warning: failed to remove directory (%s): %s\n", dir, + strerror(errno)); + return; + } + if (!S_ISDIR(buf.st_mode)) { + fprintf(stderr, "error: trying to remove invalid directory: %s\n", dir); + exit(2); + } + DIR *d = opendir(dir); + if (d == NULL) { + fprintf(stderr, "error: failed to open directory: %s\n", + strerror(errno)); + exit(2); + } + struct dirent *e; + while (NULL != (e = readdir(d))) { + if ((0 == strcmp(e->d_name, ".")) || (0 == strcmp(e->d_name, ".."))) + continue; + char *f = sb_strdup_printf("%s/%s", dir, e->d_name); + if (0 != stat(f, &buf)) { + fprintf(stderr, "error: failed to stat directory entry (%s): %s\n", + e->d_name, strerror(errno)); + free(f); + exit(2); + } + if (S_ISDIR(buf.st_mode)) { + rmdir_recursive(f); + } + else if (0 != unlink(f)) { + fprintf(stderr, "error: failed to remove file (%s): %s\n", f, + strerror(errno)); + free(f); + exit(2); + } + free(f); + } + if (0 != closedir(d)) { + fprintf(stderr, "error: failed to close directory: %s\n", + strerror(errno)); + exit(2); + } + if (0 != rmdir(dir)) { + fprintf(stderr, "error: failed to remove directory: %s\n", + strerror(errno)); + exit(2); + } +} + + +static int +git_shell(int argc, char *argv[]) +{ + int rv = 0; + + char *repo = NULL; + char *command_orig = NULL; + char *command_name = NULL; + char command_new[BUFFER_SIZE]; + + bool exec_git = false; + + // validate git command + size_t len = strlen(argv[2]); + if (!((len > 17 && (0 == strncmp(argv[2], "git-receive-pack ", 17))) || + (len > 16 && (0 == strncmp(argv[2], "git-upload-pack ", 16))) || + (len > 19 && (0 == strncmp(argv[2], "git-upload-archive ", 19))))) + { + fprintf(stderr, "error: unsupported git command: %s\n", argv[2]); + rv = 1; + goto cleanup; + } + + // get shell path + char *self = getenv("SHELL"); + if (self == NULL) { + fprintf(stderr, "error: failed to find blogc-git-receiver path\n"); + rv = 1; + goto cleanup; + } + + // get home path + char *home = getenv("HOME"); + if (home == NULL) { + fprintf(stderr, "error: failed to find user home path\n"); + rv = 1; + goto cleanup; + } + + // get git repository + command_orig = sb_strdup(argv[2]); + char *p, *r; + for (p = command_orig; *p != ' ' && *p != '\0'; p++); + if (*p == ' ') + p++; + if (*p == '\'' || *p == '"') + p++; + if (*p == '/') + p++; + for (r = p; *p != '\'' && *p != '"' && *p != '\0'; p++); + if (*p == '\'' || *p == '"') + *p = '\0'; + if (*--p == '/') + *p = '\0'; + + repo = sb_strdup_printf("repos/%s", r); + + // check if repository is sane + if (0 == strlen(repo)) { + fprintf(stderr, "error: invalid repository\n"); + rv = 1; + goto cleanup; + } + + if (0 == strncmp(argv[2], "git-upload-", 11)) // no need to check len here + goto git_exec; + + if (0 != chdir(home)) { + fprintf(stderr, "error: failed to chdir (%s): %s\n", home, + strerror(errno)); + rv = 1; + goto cleanup; + } + + if (0 != access(repo, F_OK)) { + char *git_init_cmd = sb_strdup_printf( + "git init --bare \"%s\" > /dev/null", repo); + if (0 != system(git_init_cmd)) { + fprintf(stderr, "error: failed to create git repository: %s\n", + repo); + rv = 1; + free(git_init_cmd); + goto cleanup; + } + free(git_init_cmd); + } + + if (0 != chdir(repo)) { + fprintf(stderr, "error: failed to chdir (%s/%s): %s\n", home, repo, + strerror(errno)); + rv = 1; + goto cleanup; + } + + if (0 != access("hooks", F_OK)) { + // openwrt git package won't install git templates, then the git + // repositories created with it won't have the hooks/ directory. + if (0 != mkdir("hooks", 0777)) { // mkdir honors umask for us. + fprintf(stderr, "error: failed to create directory (%s/%s/hooks): " + "%s\n", home, repo, strerror(errno)); + rv = 1; + goto cleanup; + } + } + + if (0 != chdir("hooks")) { + fprintf(stderr, "error: failed to chdir (%s/%s/hooks): %s\n", home, + repo, strerror(errno)); + rv = 1; + goto cleanup; + } + + if (0 == access("pre-receive", F_OK)) { + if (0 != unlink("pre-receive")) { + fprintf(stderr, "error: failed to remove old symlink " + "(%s/%s/hooks/pre-receive): %s\n", home, repo, strerror(errno)); + rv = 1; + goto cleanup; + } + } + + if (0 != symlink(self, "pre-receive")) { + fprintf(stderr, "error: failed to create symlink " + "(%s/%s/hooks/pre-receive): %s\n", home, repo, strerror(errno)); + rv = 1; + goto cleanup; + } + + if (0 == access("post-receive", F_OK)) { + if (0 != unlink("post-receive")) { + fprintf(stderr, "error: failed to remove old symlink " + "(%s/%s/hooks/post-receive): %s\n", home, repo, strerror(errno)); + rv = 1; + goto cleanup; + } + } + + if (0 != symlink(self, "post-receive")) { + fprintf(stderr, "error: failed to create symlink " + "(%s/%s/hooks/post-receive): %s\n", home, repo, strerror(errno)); + rv = 1; + goto cleanup; + } + + if (0 != chdir(home)) { + fprintf(stderr, "error: failed to chdir (%s): %s\n", home, + strerror(errno)); + rv = 1; + goto cleanup; + } + +git_exec: + command_name = sb_strdup(argv[2]); + for (p = command_name; *p != ' ' && *p != '\0'; p++); + if (*p == ' ') + *p = '\0'; + + if (BUFFER_SIZE < (strlen(command_name) + strlen(repo) + 4)) { + fprintf(stderr, "error: git-shell command is too big\n"); + rv = 1; + goto cleanup; + } + + if (snprintf(command_new, BUFFER_SIZE, "%s '%s'", command_name, repo)) + exec_git = true; + +cleanup: + free(repo); + free(command_orig); + free(command_name); + + if (exec_git) { + execlp("git-shell", "git-shell", "-c", command_new, NULL); + + // execlp only returns on error, then something bad happened + fprintf(stderr, "error: failed to execute git-shell\n"); + rv = 1; + } + + return rv; +} + + +static int +git_post_receive_hook(int argc, char *argv[]) +{ + if (0 != system("git remote get-url --push mirror &> /dev/null")) + return 0; + + // at this point we know that we have a remote called mirror, we can just + // push to it. + if (0 != system("git push --mirror mirror")) + fprintf(stderr, "warning: failed push to git mirror\n"); + + return 0; +} + + +typedef enum { + START_OLD = 1, + OLD, + START_NEW, + NEW, + START_REF, + REF +} input_state_t; + + +static int +git_pre_receive_hook(int argc, char *argv[]) +{ + int c; + char buffer[BUFFER_SIZE]; + + input_state_t state = START_OLD; + size_t i = 0; + size_t start = 0; + + int rv = 0; + char *new = NULL; + char *master = NULL; + + while (EOF != (c = getc(stdin))) { + + buffer[i] = (char) c; + + switch (state) { + case START_OLD: + start = i; + state = OLD; + break; + case OLD: + if (c != ' ') + break; + // no need to store old + state = START_NEW; + break; + case START_NEW: + start = i; + state = NEW; + break; + case NEW: + if (c != ' ') + break; + state = START_REF; + new = strndup(buffer + start, i - start); + break; + case START_REF: + start = i; + state = REF; + break; + case REF: + if (c != '\n') + break; + state = START_OLD; + // we just care about a ref (refs/heads/master), everything + // else is disposable :) + if (!((i - start == 17) && + (0 == strncmp("refs/heads/master", buffer + start, 17)))) + { + free(new); + new = NULL; + break; + } + master = new; + break; + } + + if (++i >= BUFFER_SIZE) { + fprintf(stderr, "error: pre-receive hook payload is too big.\n"); + rv = 1; + goto cleanup2; + } + } + + if (master == NULL) { + fprintf(stderr, "warning: no reference to master branch found. " + "nothing to deploy.\n"); + goto cleanup2; + } + + char *repo_dir = NULL; + char *output_dir = NULL; + + if (NULL == getcwd(buffer, BUFFER_SIZE)) { + fprintf(stderr, "error: failed to get repository remote path: %s\n", + strerror(errno)); + rv = 1; + goto cleanup; + } + + repo_dir = sb_strdup(buffer); + + char dir[] = "/tmp/blogc_XXXXXX"; + if (NULL == mkdtemp(dir)) { + rv = 1; + goto cleanup; + } + + char *git_archive_cmd = sb_strdup_printf( + "git archive \"%s\" | tar -x -C \"%s\" -f -", master, dir); + if (0 != system(git_archive_cmd)) { + fprintf(stderr, "error: failed to extract git content to temporary " + "directory: %s\n", dir); + rv = 1; + free(git_archive_cmd); + goto cleanup; + } + free(git_archive_cmd); + + if (0 != chdir(dir)) { + fprintf(stderr, "error: failed to chdir (%s): %s\n", dir, + strerror(errno)); + rv = 1; + goto cleanup; + } + + if ((0 != access("Makefile", F_OK)) && (0 != access("GNUMakefile", F_OK))) { + fprintf(stderr, "warning: no makefile found. skipping ...\n"); + goto cleanup; + } + + char *home = getenv("HOME"); + if (home == NULL) { + fprintf(stderr, "error: failed to find user home path\n"); + rv = 1; + goto cleanup; + } + + unsigned long epoch = time(NULL); + output_dir = sb_strdup_printf("%s/builds/%s-%lu", home, master, epoch); + char *gmake_cmd = sb_strdup_printf( + "gmake -j%d OUTPUT_DIR=\"%s\" BLOGC_GIT_RECEIVER=1", + cpu_count(), output_dir); + fprintf(stdout, "running command: %s\n\n", gmake_cmd); + fflush(stdout); + if (0 != system(gmake_cmd)) { + fprintf(stderr, "error: failed to build website ...\n"); + rmdir_recursive(output_dir); + free(gmake_cmd); + rv = 1; + goto cleanup; + } + free(gmake_cmd); + + if (0 != chdir(repo_dir)) { + fprintf(stderr, "error: failed to chdir (%s): %s\n", repo_dir, + strerror(errno)); + rmdir_recursive(output_dir); + rv = 1; + goto cleanup; + } + + char *htdocs_sym = NULL; + ssize_t htdocs_sym_len = readlink("htdocs", buffer, BUFFER_SIZE); + if (0 < htdocs_sym_len) { + if (0 != unlink("htdocs")) { + fprintf(stderr, "error: failed to remove symlink (%s/htdocs): %s\n", + repo_dir, strerror(errno)); + rmdir_recursive(output_dir); + rv = 1; + goto cleanup; + } + buffer[htdocs_sym_len] = '\0'; + htdocs_sym = buffer; + } + + if (0 != symlink(output_dir, "htdocs")) { + fprintf(stderr, "error: failed to create symlink (%s/htdocs): %s\n", + repo_dir, strerror(errno)); + rmdir_recursive(output_dir); + rv = 1; + goto cleanup; + } + + if (htdocs_sym != NULL) + rmdir_recursive(htdocs_sym); + +cleanup: + free(output_dir); + rmdir_recursive(dir); + free(repo_dir); +cleanup2: + free(new); + return rv; +} + + +int +main(int argc, char *argv[]) +{ + if (argc > 0) { + if (0 == strcmp(basename(argv[0]), "pre-receive")) + return git_pre_receive_hook(argc, argv); + if (0 == strcmp(basename(argv[0]), "post-receive")) + return git_post_receive_hook(argc, argv); + } + + if (argc == 3 && (0 == strcmp(argv[1], "-c"))) + return git_shell(argc, argv); + + fprintf(stderr, "error: this is a special shell, go away!\n"); + return 1; +} diff --git a/src/blogc-runserver.c b/src/blogc-runserver.c new file mode 100644 index 0000000..81bd5f9 --- /dev/null +++ b/src/blogc-runserver.c @@ -0,0 +1,389 @@ +/* + * blogc: A blog compiler. + * Copyright (C) 2015-2016 Rafael G. Martins <rafael@rafaelmartins.eng.br> + * + * This program can be distributed under the terms of the BSD License. + * See the file LICENSE. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif /* HAVE_CONFIG_H */ + +#include <event2/event.h> +#include <event2/http.h> +#include <event2/buffer.h> +#include <event2/keyvalq_struct.h> +#include <magic.h> +#include <signal.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> + +#include "utils.h" + + +/** + * this mapping is used to declare "supported" file types, that are forced over + * whatever detected by libmagic, but we will still use the charset provided by + * libmagic anyway. it also helps detecting index files when the client asks + * for a directory. + */ +static const struct content_type_map { + const char *mimetype; + const char *extension; + const char *index; +} content_types[] = { + {"text/html", "html", "index.html"}, + {"text/html", "htm", "index.htm"}, + {"text/xml", "xml", "index.xml"}, + {"text/plain", "txt", "index.txt"}, + {"text/css", "css", NULL}, + {"application/javascript", "js", NULL}, + {NULL, NULL, NULL} +}; + + +static magic_t magic_all = NULL; +static magic_t magic_charset = NULL; + + +static const char* +get_extension(const char *filename) +{ + const char *ext = NULL; + unsigned int i; + for (i = strlen(filename); i > 0; i--) { + if (filename[i] == '.') { + ext = filename + i + 1; + break; + } + } + if (i == 0) + return NULL; + return ext; +} + + +static char* +guess_content_type(const char *filename, int fd) +{ + int newfd; + + // try "supported" types first, and just use libmagic for charset + const char *extension = get_extension(filename); + if (extension == NULL) + goto libmagic; + const char *supported = NULL; + for (unsigned int i = 0; content_types[i].extension != NULL; i++) + if (0 == strcmp(content_types[i].extension, extension)) + supported = content_types[i].mimetype; + if (supported != NULL) { + newfd = dup(fd); + if (-1 != newfd) { + const char* charset = magic_descriptor(magic_charset, newfd); + close(newfd); + if (charset != NULL) + return sb_strdup_printf("%s; charset=%s", supported, charset); + } + return sb_strdup(supported); + } + +libmagic: + + // fallback to use libmagic for everything + newfd = dup(fd); + if (-1 != newfd) { + const char* content_type = magic_descriptor(magic_all, newfd); + close(newfd); + if (content_type != NULL) + return sb_strdup(content_type); + } + return sb_strdup("application/octet-stream"); +} + + +static void +handler(struct evhttp_request *request, void *ptr) +{ + const char *root = ptr; + const char *uri = evhttp_request_get_uri(request); + + struct evhttp_uri *decoded_uri = evhttp_uri_parse(uri); + if (decoded_uri == NULL) { + evhttp_send_error(request, 400, "Bad request"); + return; + } + + const char *path = evhttp_uri_get_path(decoded_uri); + if (path == NULL) + path = "/"; + + char *decoded_path = evhttp_uridecode(path, 0, NULL); + if (decoded_path == NULL) { + evhttp_send_error(request, 400, "Bad request"); + goto point1; + } + + char *abs_path = sb_strdup_printf("%s/%s", root, decoded_path); + char *real_path = realpath(abs_path, NULL); + free(abs_path); + + if (real_path == NULL) { + evhttp_send_error(request, 404, "Not found"); + goto point2; + } + + char *real_root = realpath(root, NULL); + if (real_root == NULL) { + evhttp_send_error(request, 500, "Internal server error"); + goto point3; + } + + if (0 != strncmp(real_root, real_path, strlen(real_root))) { + evhttp_send_error(request, 404, "Not found"); + goto point4; + } + + struct stat st; + if (0 > stat(real_path, &st)) { + evhttp_send_error(request, 404, "Not found"); + goto point4; + } + + bool add_slash = false; + + if (S_ISDIR(st.st_mode)) { + char *found = NULL; + + for (unsigned int i = 0; content_types[i].mimetype != NULL; i++) { + if (content_types[i].index == NULL) + continue; + char *f = sb_strdup_printf("%s/%s", real_path, + content_types[i].index); + if (0 == access(f, F_OK)) { + found = sb_strdup(f); + break; + } + free(f); + } + + if (found == NULL) { + evhttp_send_error(request, 403, "Forbidden"); + goto point4; + } + + size_t path_len = strlen(path); + if (path_len > 0 && path[path_len - 1] != '/') + add_slash = true; + + free(real_path); + real_path = found; + } + + int fd; + if ((fd = open(real_path, O_RDONLY)) < 0) { + evhttp_send_error(request, 500, "Internal server error"); + goto point4; + } + + char *type = guess_content_type(real_path, fd); + + if (fstat(fd, &st) < 0) { + evhttp_send_error(request, 500, "Internal server error"); + goto point5; + } + + struct evkeyvalq *headers = evhttp_request_get_output_headers(request); + + if (add_slash) { + char *tmp = sb_strdup_printf("%s/", path); + evhttp_add_header(headers, "Location", tmp); + free(tmp); + // production webservers usually returns 301 in such cases, but 302 is + // better for development/testing. + evhttp_send_reply(request, 302, "Found", NULL); + goto point5; + } + + evhttp_add_header(headers, "Content-Type", type); + char *content_length = sb_strdup_printf("%zu", st.st_size); + evhttp_add_header(headers, "Content-Length", content_length); + free(content_length); + + struct evbuffer *evb = evbuffer_new(); + evbuffer_add_file(evb, fd, 0, st.st_size); + evhttp_send_reply(request, 200, "OK", evb); + +point5: + free(type); +point4: + free(real_root); +point3: + free(real_path); +point2: + free(decoded_path); +point1: + evhttp_uri_free(decoded_uri); +} + + +static int +runserver(const char *address, unsigned short port, const char *root) +{ + struct event_base *base = event_base_new(); + if (base == NULL) { + fprintf(stderr, "error: failed to initialize event base\n"); + return 1; + } + + struct evhttp *http = evhttp_new(base); + if (http == NULL) { + fprintf(stderr, "error: failed to initialize HTTP server\n"); + return 1; + } + + evhttp_set_gencb(http, handler, (char*) root); + + evhttp_set_allowed_methods(http, EVHTTP_REQ_GET | EVHTTP_REQ_HEAD); + + if (0 != evhttp_bind_socket(http, address, port)) { + fprintf(stderr, "error: failed to bind socket to %s:%d\n", address, + port); + return 1; + } + + fprintf(stderr, " * Running on http://%s:%d/\n", address, port); + + event_base_dispatch(base); + + return 0; +} + + +static void +print_help(void) +{ + printf( + "usage:\n" + " blogc-runserver [-h] [-v] [-t HOST] [-p PORT] DOCROOT\n" + " - A simple HTTP server to test blogc websites.\n" + "\n" + "positional arguments:\n" + " DOCROOT document root directory\n" + "\n" + "optional arguments:\n" + " -h show this help message and exit\n" + " -v show version and exit\n" + " -t HOST set server listen address (default: 127.0.0.1)\n" + " -p PORT set server listen port (default: 8080)\n"); +} + + +static void +print_usage(void) +{ + printf("usage: blogc-runserver [-h] [-v] [-t HOST] [-p PORT] DOCROOT\n"); +} + + +int +main(int argc, char **argv) +{ + signal(SIGPIPE, SIG_IGN); + + int rv = 0; + char *host = NULL; + char *docroot = NULL; + unsigned short port = 8080; + + unsigned int args = 0; + + for (unsigned int i = 1; i < argc; i++) { + if (argv[i][0] == '-') { + switch (argv[i][1]) { + case 'h': + print_help(); + goto cleanup; + case 'v': + printf("%s\n", PACKAGE_STRING); + goto cleanup; + case 't': + if (argv[i][2] != '\0') + host = sb_strdup(argv[i] + 2); + else + host = sb_strdup(argv[++i]); + break; + case 'p': + if (argv[i][2] != '\0') + port = strtoul(argv[i] + 2, NULL, 10); + else + port = strtoul(argv[++i], NULL, 10); + break; + default: + print_usage(); + fprintf(stderr, "blogc-runserver: error: invalid " + "argument: -%c\n", argv[i][1]); + rv = 2; + goto cleanup; + } + } + else { + if (args > 0) { + print_usage(); + fprintf(stderr, "blogc-runserver: error: only one positional " + "argument allowed\n"); + rv = 2; + goto cleanup; + } + args++; + docroot = sb_strdup(argv[i]); + } + } + + if (docroot == NULL) { + print_usage(); + fprintf(stderr, "blogc-runserver: error: document root directory " + "required\n"); + rv = 2; + goto cleanup; + } + + if (host == NULL) + host = sb_strdup("127.0.0.1"); + + magic_all = magic_open(MAGIC_MIME); + magic_charset = magic_open(MAGIC_MIME_ENCODING); + if (magic_all == NULL || magic_charset == NULL) { + fprintf(stderr, "error: failed to initialize libmagic\n"); + rv = 1; + goto cleanup; + } + + if ((0 != magic_load(magic_all, NULL)) || + (0 != magic_load(magic_charset, NULL))) + { + fprintf(stderr, "error: failed to load libmagic data\n"); + magic_close(magic_all); + magic_close(magic_charset); + rv = 1; + goto cleanup; + } + + rv = runserver(host, port, docroot); + + magic_close(magic_all); + magic_close(magic_charset); + +cleanup: + free(host); + free(docroot); + + return rv; +} @@ -24,12 +24,12 @@ #include <stdio.h> #include <string.h> -#include "utils/utils.h" #include "source-parser.h" #include "template-parser.h" #include "loader.h" #include "renderer.h" #include "error.h" +#include "utils.h" #ifndef PACKAGE_VERSION #define PACKAGE_VERSION "Unknown" @@ -71,7 +71,7 @@ blogc_print_usage(void) static void blogc_mkdir_recursive(const char *filename) { - char *fname = b_strdup(filename); + char *fname = sb_strdup(filename); for (char *tmp = fname; *tmp != '\0'; tmp++) { if (*tmp != '/' && *tmp != '\\') continue; @@ -117,9 +117,9 @@ main(int argc, char **argv) char *tmp = NULL; char **pieces = NULL; - b_slist_t *sources = NULL; - b_trie_t *config = b_trie_new(free); - b_trie_insert(config, "BLOGC_VERSION", b_strdup(PACKAGE_VERSION)); + sb_slist_t *sources = NULL; + sb_trie_t *config = sb_trie_new(free); + sb_trie_insert(config, "BLOGC_VERSION", sb_strdup(PACKAGE_VERSION)); for (unsigned int i = 1; i < argc; i++) { tmp = NULL; @@ -136,21 +136,21 @@ main(int argc, char **argv) break; case 't': if (argv[i][2] != '\0') - template = b_strdup(argv[i] + 2); + template = sb_strdup(argv[i] + 2); else if (i + 1 < argc) - template = b_strdup(argv[++i]); + template = sb_strdup(argv[++i]); break; case 'o': if (argv[i][2] != '\0') - output = b_strdup(argv[i] + 2); + output = sb_strdup(argv[i] + 2); else if (i + 1 < argc) - output = b_strdup(argv[++i]); + output = sb_strdup(argv[++i]); break; case 'p': if (argv[i][2] != '\0') - print = b_strdup(argv[i] + 2); + print = sb_strdup(argv[i] + 2); else if (i + 1 < argc) - print = b_strdup(argv[++i]); + print = sb_strdup(argv[++i]); break; case 'D': if (argv[i][2] != '\0') @@ -158,11 +158,11 @@ main(int argc, char **argv) else if (i + 1 < argc) tmp = argv[++i]; if (tmp != NULL) { - pieces = b_str_split(tmp, '=', 2); - if (b_strv_length(pieces) != 2) { + pieces = sb_str_split(tmp, '=', 2); + if (sb_strv_length(pieces) != 2) { fprintf(stderr, "blogc: error: invalid value for " "-D (must have an '='): %s\n", tmp); - b_strv_free(pieces); + sb_strv_free(pieces); rv = 2; goto cleanup; } @@ -173,13 +173,13 @@ main(int argc, char **argv) fprintf(stderr, "blogc: error: invalid value " "for -D (configuration key must be uppercase " "with '_'): %s\n", pieces[0]); - b_strv_free(pieces); + sb_strv_free(pieces); rv = 2; goto cleanup; } } - b_trie_insert(config, pieces[0], b_strdup(pieces[1])); - b_strv_free(pieces); + sb_trie_insert(config, pieces[0], sb_strdup(pieces[1])); + sb_strv_free(pieces); pieces = NULL; } break; @@ -192,17 +192,17 @@ main(int argc, char **argv) } } else - sources = b_slist_append(sources, b_strdup(argv[i])); + sources = sb_slist_append(sources, sb_strdup(argv[i])); } - if (!listing && b_slist_length(sources) == 0) { + if (!listing && sb_slist_length(sources) == 0) { blogc_print_usage(); fprintf(stderr, "blogc: error: one source file is required\n"); rv = 2; goto cleanup; } - if (!listing && b_slist_length(sources) > 1) { + if (!listing && sb_slist_length(sources) > 1) { blogc_print_usage(); fprintf(stderr, "blogc: error: only one source file should be provided, " "if running without '-l'\n"); @@ -212,14 +212,14 @@ main(int argc, char **argv) blogc_error_t *err = NULL; - b_slist_t *s = blogc_source_parse_from_files(config, sources, &err); + sb_slist_t *s = blogc_source_parse_from_files(config, sources, &err); if (err != NULL) { blogc_error_print(err); rv = 2; goto cleanup2; } - b_slist_t* l = blogc_template_parse_from_file(template, &err); + sb_slist_t* l = blogc_template_parse_from_file(template, &err); if (err != NULL) { blogc_error_print(err); rv = 2; @@ -227,7 +227,7 @@ main(int argc, char **argv) } if (print != NULL) { - const char *val = b_trie_lookup(config, print); + const char *val = sb_trie_lookup(config, print); if (val == NULL) { fprintf(stderr, "blogc: error: configuration variable not found: %s\n", print); @@ -273,13 +273,13 @@ cleanup4: cleanup3: blogc_template_free_stmts(l); cleanup2: - b_slist_free_full(s, (b_free_func_t) b_trie_free); + sb_slist_free_full(s, (sb_free_func_t) sb_trie_free); blogc_error_free(err); cleanup: - b_trie_free(config); + sb_trie_free(config); free(template); free(output); free(print); - b_slist_free_full(sources, free); + sb_slist_free_full(sources, free); return rv; } diff --git a/src/content-parser.c b/src/content-parser.c index 8dceb8b..0561d20 100644 --- a/src/content-parser.c +++ b/src/content-parser.c @@ -13,9 +13,9 @@ #include <stdbool.h> #include <string.h> -#include "utils/utils.h" #include "content-parser.h" #include "directives.h" +#include "utils.h" // this is a half ass implementation of a markdown-like syntax. bugs are // expected. feel free to improve the parser and add new features. @@ -26,7 +26,7 @@ blogc_slugify(const char *str) { if (str == NULL) return NULL; - char *new_str = b_strdup(str); + char *new_str = sb_strdup(str); int diff = 'a' - 'A'; // just to avoid magic numbers for (size_t i = 0; new_str[i] != '\0'; i++) { if (new_str[i] >= 'a' && new_str[i] <= 'z') @@ -47,32 +47,32 @@ blogc_htmlentities(const char *str) { if (str == NULL) return NULL; - b_string_t *rv = b_string_new(); + sb_string_t *rv = sb_string_new(); for (size_t i = 0; str[i] != '\0'; i++) { switch (str[i]) { case '&': - b_string_append(rv, "&"); + sb_string_append(rv, "&"); break; case '<': - b_string_append(rv, "<"); + sb_string_append(rv, "<"); break; case '>': - b_string_append(rv, ">"); + sb_string_append(rv, ">"); break; case '"': - b_string_append(rv, """); + sb_string_append(rv, """); break; case '\'': - b_string_append(rv, "'"); + sb_string_append(rv, "'"); break; case '/': - b_string_append(rv, "/"); + sb_string_append(rv, "/"); break; default: - b_string_append_c(rv, str[i]); + sb_string_append_c(rv, str[i]); } } - return b_string_free(rv, false); + return sb_string_free(rv, false); } @@ -139,7 +139,7 @@ blogc_content_parse_inline(const char *src) size_t start_state = 0; size_t end = 0; - b_string_t *rv = b_string_new(); + sb_string_t *rv = sb_string_new(); bool open_em_ast = false; bool open_strong_ast = false; @@ -165,7 +165,7 @@ blogc_content_parse_inline(const char *src) if (escape) { if (state == LINK_CLOSED) - b_string_append_c(rv, c); + sb_string_append_c(rv, c); current++; escape = false; continue; @@ -174,11 +174,21 @@ blogc_content_parse_inline(const char *src) if (c != ' ' && c != '\n' && c != '\r') spaces = 0; + if (state == LINK_TEXT_CLOSE && c != ' ' && c != '\n' && c != '\r' && + c != '(') + { + sb_string_append_c(rv, src[start_state]); + tmp = blogc_content_parse_inline(src + start_state + 1); + sb_string_append(rv, tmp); + // no need to free here, we will exit the loop! + break; + } + switch (c) { case '\\': if (state == LINK_CLOSED && (open_code || open_code_double)) { - b_string_append_c(rv, c); + sb_string_append_c(rv, c); break; } if (!escape) @@ -188,7 +198,7 @@ blogc_content_parse_inline(const char *src) case '*': case '_': if (state == LINK_CLOSED && (open_code || open_code_double)) { - b_string_append_c(rv, c); + sb_string_append_c(rv, c); break; } if (!is_last && src[current + 1] == c) { @@ -197,7 +207,7 @@ blogc_content_parse_inline(const char *src) (c == '_' && open_strong_und)) { if (state == LINK_CLOSED) - b_string_append(rv, "</strong>"); + sb_string_append(rv, "</strong>"); if (c == '*') open_strong_ast = false; else @@ -205,7 +215,7 @@ blogc_content_parse_inline(const char *src) break; } if (state == LINK_CLOSED) - b_string_append(rv, "<strong>"); + sb_string_append(rv, "<strong>"); if (c == '*') open_strong_ast = true; else @@ -214,7 +224,7 @@ blogc_content_parse_inline(const char *src) } if ((c == '*' && open_em_ast) || (c == '_' && open_em_und)) { if (state == LINK_CLOSED) - b_string_append(rv, "</em>"); + sb_string_append(rv, "</em>"); if (c == '*') open_em_ast = false; else @@ -222,7 +232,7 @@ blogc_content_parse_inline(const char *src) break; } if (state == LINK_CLOSED) - b_string_append(rv, "<em>"); + sb_string_append(rv, "<em>"); if (c == '*') open_em_ast = true; else @@ -233,22 +243,26 @@ blogc_content_parse_inline(const char *src) if (!is_last && src[current + 1] == c) { current++; if (state == LINK_CLOSED) - b_string_append_printf(rv, "<%scode>", + sb_string_append_printf(rv, "<%scode>", open_code_double ? "/" : ""); open_code_double = !open_code_double; break; } if (state == LINK_CLOSED) - b_string_append_printf(rv, "<%scode>", open_code ? "/" : ""); + sb_string_append_printf(rv, "<%scode>", open_code ? "/" : ""); open_code = !open_code; break; case '!': - if (state == LINK_CLOSED && (open_code || open_code_double)) { - b_string_append_c(rv, c); - break; - } if (state == LINK_CLOSED) { + if (open_code || open_code_double) { + sb_string_append_c(rv, c); + break; + } + if (!is_last && src[current + 1] != '[') { + sb_string_append_c(rv, c); + break; + } state = LINK_IMAGE; is_image = true; start_state = current; @@ -257,7 +271,7 @@ blogc_content_parse_inline(const char *src) case '[': if (state == LINK_CLOSED && (open_code || open_code_double)) { - b_string_append_c(rv, c); + sb_string_append_c(rv, c); break; } if (state == LINK_CLOSED || state == LINK_IMAGE) { @@ -287,8 +301,8 @@ blogc_content_parse_inline(const char *src) } if (state == LINK_AUTO_CLOSE) { state = LINK_CLOSED; - tmp = b_strndup(src + start, end - start); - b_string_append_printf(rv, "<a href=\"%s\">%s</a>", tmp, tmp); + tmp = sb_strndup(src + start, end - start); + sb_string_append_printf(rv, "<a href=\"%s\">%s</a>", tmp, tmp); end = 0; free(tmp); tmp = NULL; @@ -298,7 +312,7 @@ blogc_content_parse_inline(const char *src) if (state == LINK_TEXT) { if (open_bracket-- == 0) { state = LINK_TEXT_CLOSE; - tmp = b_strndup(src + start, current - start); + tmp = sb_strndup(src + start, current - start); tmp2 = blogc_content_parse_inline(tmp); free(tmp); tmp = NULL; @@ -306,7 +320,7 @@ blogc_content_parse_inline(const char *src) break; } if (state == LINK_CLOSED) - b_string_append_c(rv, c); + sb_string_append_c(rv, c); break; case '(': @@ -316,18 +330,18 @@ blogc_content_parse_inline(const char *src) break; } if (state == LINK_CLOSED) - b_string_append_c(rv, c); + sb_string_append_c(rv, c); break; case ')': if (state == LINK_URL) { state = LINK_CLOSED; - tmp = b_strndup(src + start, current - start); + tmp = sb_strndup(src + start, current - start); if (is_image) - b_string_append_printf(rv, "<img src=\"%s\" alt=\"%s\">", + sb_string_append_printf(rv, "<img src=\"%s\" alt=\"%s\">", tmp, tmp2); else - b_string_append_printf(rv, "<a href=\"%s\">%s</a>", + sb_string_append_printf(rv, "<a href=\"%s\">%s</a>", tmp, tmp2); free(tmp); tmp = NULL; @@ -337,13 +351,13 @@ blogc_content_parse_inline(const char *src) break; } if (state == LINK_CLOSED) - b_string_append_c(rv, c); + sb_string_append_c(rv, c); break; case ' ': if (state == LINK_CLOSED) { spaces++; - b_string_append_c(rv, c); + sb_string_append_c(rv, c); } if (!is_last) break; @@ -352,55 +366,74 @@ blogc_content_parse_inline(const char *src) case '\r': if (state == LINK_CLOSED) { if (spaces >= 2) { - b_string_append(rv, "<br />"); + sb_string_append(rv, "<br />"); spaces = 0; } if (c == '\n' || c == '\r') - b_string_append_c(rv, c); + sb_string_append_c(rv, c); + } + break; + + case '-': + if (state != LINK_CLOSED) + break; + if ((current < (src_len - 1) && src[current + 1] == '-') && + !(open_code || open_code_double)) + { + if (current < (src_len - 2) && src[current + 2] == '-') { + sb_string_append(rv, "—"); + current += 2; + } + else { + sb_string_append(rv, "–"); + current += 1; + } + } + else { + sb_string_append_c(rv, c); } break; case '&': if (state == LINK_CLOSED) - b_string_append(rv, "&"); + sb_string_append(rv, "&"); break; case '<': if (state == LINK_CLOSED) - b_string_append(rv, "<"); + sb_string_append(rv, "<"); break; case '>': if (state == LINK_CLOSED) - b_string_append(rv, ">"); + sb_string_append(rv, ">"); break; case '"': if (state == LINK_CLOSED) - b_string_append(rv, """); + sb_string_append(rv, """); break; case '\'': if (state == LINK_CLOSED) - b_string_append(rv, "'"); + sb_string_append(rv, "'"); break; case '/': if (state == LINK_CLOSED) - b_string_append(rv, "/"); + sb_string_append(rv, "/"); break; default: if (state == LINK_CLOSED) - b_string_append_c(rv, c); + sb_string_append_c(rv, c); } if (is_last && state != LINK_CLOSED) { - b_string_append_c(rv, src[start_state]); + sb_string_append_c(rv, src[start_state]); tmp = blogc_content_parse_inline(src + start_state + 1); - b_string_append(rv, tmp); - free(tmp); - tmp = NULL; + sb_string_append(rv, tmp); + // no need to free here, its the last iteration } current++; } @@ -408,7 +441,7 @@ blogc_content_parse_inline(const char *src) free(tmp); free(tmp2); - return b_string_free(rv, false); + return sb_string_free(rv, false); } @@ -440,7 +473,7 @@ blogc_is_ordered_list_item(const char *str, size_t prefix_len) char* -blogc_content_parse(const char *src, size_t *end_excerpt) +blogc_content_parse(const char *src, size_t *end_excerpt, char **description) { // src is always nul-terminated. size_t src_len = strlen(src); @@ -463,7 +496,7 @@ blogc_content_parse(const char *src, size_t *end_excerpt) char *directive_name = NULL; char *directive_argument = NULL; char *directive_key = NULL; - b_trie_t *directive_params = NULL; + sb_trie_t *directive_params = NULL; // this isn't empty because we need some reasonable default value in the // unlikely case that we need to print some line ending before evaluating @@ -473,11 +506,11 @@ blogc_content_parse(const char *src, size_t *end_excerpt) char d = '\0'; - b_slist_t *lines = NULL; - b_slist_t *lines2 = NULL; + sb_slist_t *lines = NULL; + sb_slist_t *lines2 = NULL; - b_string_t *rv = b_string_new(); - b_string_t *tmp_str = NULL; + sb_string_t *rv = sb_string_new(); + sb_string_t *tmp_str = NULL; blogc_content_parser_state_t state = CONTENT_START_LINE; @@ -607,14 +640,14 @@ blogc_content_parse(const char *src, size_t *end_excerpt) if (c == '\n' || c == '\r' || is_last) { end = is_last && c != '\n' && c != '\r' ? src_len : (real_end != 0 ? real_end : current); - tmp = b_strndup(src + start, end - start); + tmp = sb_strndup(src + start, end - start); parsed = blogc_content_parse_inline(tmp); slug = blogc_slugify(tmp); if (slug == NULL) - b_string_append_printf(rv, "<h%d>%s</h%d>%s", + sb_string_append_printf(rv, "<h%d>%s</h%d>%s", header_level, parsed, header_level, line_ending); else - b_string_append_printf(rv, "<h%d id=\"%s\">%s</h%d>%s", + sb_string_append_printf(rv, "<h%d id=\"%s\">%s</h%d>%s", header_level, slug, parsed, header_level, line_ending); free(slug); @@ -638,8 +671,8 @@ blogc_content_parse(const char *src, size_t *end_excerpt) case CONTENT_HTML_END: if (c == '\n' || c == '\r' || is_last) { - tmp = b_strndup(src + start, end - start); - b_string_append_printf(rv, "%s%s", tmp, line_ending); + tmp = sb_strndup(src + start, end - start); + sb_string_append_printf(rv, "%s%s", tmp, line_ending); free(tmp); tmp = NULL; state = CONTENT_START_LINE; @@ -652,7 +685,7 @@ blogc_content_parse(const char *src, size_t *end_excerpt) case CONTENT_BLOCKQUOTE: if (c == ' ' || c == '\t') break; - prefix = b_strndup(src + start, current - start); + prefix = sb_strndup(src + start, current - start); state = CONTENT_BLOCKQUOTE_START; break; @@ -660,16 +693,16 @@ blogc_content_parse(const char *src, size_t *end_excerpt) if (c == '\n' || c == '\r' || is_last) { end = is_last && c != '\n' && c != '\r' ? src_len : (real_end != 0 ? real_end : current); - tmp = b_strndup(src + start2, end - start2); - if (b_str_starts_with(tmp, prefix)) { - lines = b_slist_append(lines, b_strdup(tmp + strlen(prefix))); + tmp = sb_strndup(src + start2, end - start2); + if (sb_str_starts_with(tmp, prefix)) { + lines = sb_slist_append(lines, sb_strdup(tmp + strlen(prefix))); state = CONTENT_BLOCKQUOTE_END; } else { state = CONTENT_PARAGRAPH; free(prefix); prefix = NULL; - b_slist_free_full(lines, free); + sb_slist_free_full(lines, free); lines = NULL; if (is_last) { free(tmp); @@ -685,22 +718,18 @@ blogc_content_parse(const char *src, size_t *end_excerpt) case CONTENT_BLOCKQUOTE_END: if (c == '\n' || c == '\r' || is_last) { - tmp_str = b_string_new(); - for (b_slist_t *l = lines; l != NULL; l = l->next) { - if (l->next == NULL) - b_string_append_printf(tmp_str, "%s", l->data); - else - b_string_append_printf(tmp_str, "%s%s", l->data, - line_ending); - } - tmp = blogc_content_parse(tmp_str->str, NULL); - b_string_append_printf(rv, "<blockquote>%s</blockquote>%s", + tmp_str = sb_string_new(); + for (sb_slist_t *l = lines; l != NULL; l = l->next) + sb_string_append_printf(tmp_str, "%s%s", l->data, + line_ending); + tmp = blogc_content_parse(tmp_str->str, NULL, description); + sb_string_append_printf(rv, "<blockquote>%s</blockquote>%s", tmp, line_ending); free(tmp); tmp = NULL; - b_string_free(tmp_str, true); + sb_string_free(tmp_str, true); tmp_str = NULL; - b_slist_free_full(lines, free); + sb_slist_free_full(lines, free); lines = NULL; free(prefix); prefix = NULL; @@ -716,7 +745,7 @@ blogc_content_parse(const char *src, size_t *end_excerpt) case CONTENT_CODE: if (c == ' ' || c == '\t') break; - prefix = b_strndup(src + start, current - start); + prefix = sb_strndup(src + start, current - start); state = CONTENT_CODE_START; break; @@ -724,16 +753,16 @@ blogc_content_parse(const char *src, size_t *end_excerpt) if (c == '\n' || c == '\r' || is_last) { end = is_last && c != '\n' && c != '\r' ? src_len : (real_end != 0 ? real_end : current); - tmp = b_strndup(src + start2, end - start2); - if (b_str_starts_with(tmp, prefix)) { - lines = b_slist_append(lines, b_strdup(tmp + strlen(prefix))); + tmp = sb_strndup(src + start2, end - start2); + if (sb_str_starts_with(tmp, prefix)) { + lines = sb_slist_append(lines, sb_strdup(tmp + strlen(prefix))); state = CONTENT_CODE_END; } else { state = CONTENT_PARAGRAPH; free(prefix); prefix = NULL; - b_slist_free_full(lines, free); + sb_slist_free_full(lines, free); lines = NULL; free(tmp); tmp = NULL; @@ -749,18 +778,18 @@ blogc_content_parse(const char *src, size_t *end_excerpt) case CONTENT_CODE_END: if (c == '\n' || c == '\r' || is_last) { - b_string_append(rv, "<pre><code>"); - for (b_slist_t *l = lines; l != NULL; l = l->next) { + sb_string_append(rv, "<pre><code>"); + for (sb_slist_t *l = lines; l != NULL; l = l->next) { char *tmp_line = blogc_htmlentities(l->data); if (l->next == NULL) - b_string_append_printf(rv, "%s", tmp_line); + sb_string_append_printf(rv, "%s", tmp_line); else - b_string_append_printf(rv, "%s%s", tmp_line, + sb_string_append_printf(rv, "%s%s", tmp_line, line_ending); free(tmp_line); } - b_string_append_printf(rv, "</code></pre>%s", line_ending); - b_slist_free_full(lines, free); + sb_string_append_printf(rv, "</code></pre>%s", line_ending); + sb_slist_free_full(lines, free); lines = NULL; free(prefix); prefix = NULL; @@ -782,7 +811,7 @@ blogc_content_parse(const char *src, size_t *end_excerpt) } if (c == ' ' || c == '\t') break; - prefix = b_strndup(src + start, current - start); + prefix = sb_strndup(src + start, current - start); state = CONTENT_UNORDERED_LIST_START; break; @@ -791,7 +820,7 @@ blogc_content_parse(const char *src, size_t *end_excerpt) break; } if (c == '\n' || c == '\r' || is_last) { - b_string_append_printf(rv, "<hr />%s", line_ending); + sb_string_append_printf(rv, "<hr />%s", line_ending); state = CONTENT_START_LINE; start = current; d = '\0'; @@ -804,30 +833,30 @@ blogc_content_parse(const char *src, size_t *end_excerpt) if (c == '\n' || c == '\r' || is_last) { end = is_last && c != '\n' && c != '\r' ? src_len : (real_end != 0 ? real_end : current); - tmp = b_strndup(src + start2, end - start2); - tmp2 = b_strdup_printf("%-*s", strlen(prefix), ""); - if (b_str_starts_with(tmp, prefix)) { + tmp = sb_strndup(src + start2, end - start2); + tmp2 = sb_strdup_printf("%-*s", strlen(prefix), ""); + if (sb_str_starts_with(tmp, prefix)) { if (lines2 != NULL) { - tmp_str = b_string_new(); - for (b_slist_t *l = lines2; l != NULL; l = l->next) { + tmp_str = sb_string_new(); + for (sb_slist_t *l = lines2; l != NULL; l = l->next) { if (l->next == NULL) - b_string_append_printf(tmp_str, "%s", l->data); + sb_string_append_printf(tmp_str, "%s", l->data); else - b_string_append_printf(tmp_str, "%s%s", l->data, + sb_string_append_printf(tmp_str, "%s%s", l->data, line_ending); } - b_slist_free_full(lines2, free); + sb_slist_free_full(lines2, free); lines2 = NULL; parsed = blogc_content_parse_inline(tmp_str->str); - b_string_free(tmp_str, true); - lines = b_slist_append(lines, b_strdup(parsed)); + sb_string_free(tmp_str, true); + lines = sb_slist_append(lines, sb_strdup(parsed)); free(parsed); parsed = NULL; } - lines2 = b_slist_append(lines2, b_strdup(tmp + strlen(prefix))); + lines2 = sb_slist_append(lines2, sb_strdup(tmp + strlen(prefix))); } - else if (b_str_starts_with(tmp, tmp2)) { - lines2 = b_slist_append(lines2, b_strdup(tmp + strlen(prefix))); + else if (sb_str_starts_with(tmp, tmp2)) { + lines2 = sb_slist_append(lines2, sb_strdup(tmp + strlen(prefix))); } else { state = CONTENT_PARAGRAPH_END; @@ -837,8 +866,8 @@ blogc_content_parse(const char *src, size_t *end_excerpt) tmp2 = NULL; free(prefix); prefix = NULL; - b_slist_free_full(lines, free); - b_slist_free_full(lines2, free); + sb_slist_free_full(lines, free); + sb_slist_free_full(lines2, free); lines = NULL; if (is_last) continue; @@ -857,28 +886,28 @@ blogc_content_parse(const char *src, size_t *end_excerpt) if (c == '\n' || c == '\r' || is_last) { if (lines2 != NULL) { // FIXME: avoid repeting the code below - tmp_str = b_string_new(); - for (b_slist_t *l = lines2; l != NULL; l = l->next) { + tmp_str = sb_string_new(); + for (sb_slist_t *l = lines2; l != NULL; l = l->next) { if (l->next == NULL) - b_string_append_printf(tmp_str, "%s", l->data); + sb_string_append_printf(tmp_str, "%s", l->data); else - b_string_append_printf(tmp_str, "%s%s", l->data, + sb_string_append_printf(tmp_str, "%s%s", l->data, line_ending); } - b_slist_free_full(lines2, free); + sb_slist_free_full(lines2, free); lines2 = NULL; parsed = blogc_content_parse_inline(tmp_str->str); - b_string_free(tmp_str, true); - lines = b_slist_append(lines, b_strdup(parsed)); + sb_string_free(tmp_str, true); + lines = sb_slist_append(lines, sb_strdup(parsed)); free(parsed); parsed = NULL; } - b_string_append_printf(rv, "<ul>%s", line_ending); - for (b_slist_t *l = lines; l != NULL; l = l->next) - b_string_append_printf(rv, "<li>%s</li>%s", l->data, + sb_string_append_printf(rv, "<ul>%s", line_ending); + for (sb_slist_t *l = lines; l != NULL; l = l->next) + sb_string_append_printf(rv, "<li>%s</li>%s", l->data, line_ending); - b_string_append_printf(rv, "</ul>%s", line_ending); - b_slist_free_full(lines, free); + sb_string_append_printf(rv, "</ul>%s", line_ending); + sb_slist_free_full(lines, free); lines = NULL; free(prefix); prefix = NULL; @@ -915,30 +944,30 @@ blogc_content_parse(const char *src, size_t *end_excerpt) if (c == '\n' || c == '\r' || is_last) { end = is_last && c != '\n' && c != '\r' ? src_len : (real_end != 0 ? real_end : current); - tmp = b_strndup(src + start2, end - start2); - tmp2 = b_strdup_printf("%-*s", prefix_len, ""); + tmp = sb_strndup(src + start2, end - start2); + tmp2 = sb_strdup_printf("%-*s", prefix_len, ""); if (blogc_is_ordered_list_item(tmp, prefix_len)) { if (lines2 != NULL) { - tmp_str = b_string_new(); - for (b_slist_t *l = lines2; l != NULL; l = l->next) { + tmp_str = sb_string_new(); + for (sb_slist_t *l = lines2; l != NULL; l = l->next) { if (l->next == NULL) - b_string_append_printf(tmp_str, "%s", l->data); + sb_string_append_printf(tmp_str, "%s", l->data); else - b_string_append_printf(tmp_str, "%s%s", l->data, + sb_string_append_printf(tmp_str, "%s%s", l->data, line_ending); } - b_slist_free_full(lines2, free); + sb_slist_free_full(lines2, free); lines2 = NULL; parsed = blogc_content_parse_inline(tmp_str->str); - b_string_free(tmp_str, true); - lines = b_slist_append(lines, b_strdup(parsed)); + sb_string_free(tmp_str, true); + lines = sb_slist_append(lines, sb_strdup(parsed)); free(parsed); parsed = NULL; } - lines2 = b_slist_append(lines2, b_strdup(tmp + prefix_len)); + lines2 = sb_slist_append(lines2, sb_strdup(tmp + prefix_len)); } - else if (b_str_starts_with(tmp, tmp2)) { - lines2 = b_slist_append(lines2, b_strdup(tmp + prefix_len)); + else if (sb_str_starts_with(tmp, tmp2)) { + lines2 = sb_slist_append(lines2, sb_strdup(tmp + prefix_len)); } else { state = CONTENT_PARAGRAPH_END; @@ -948,8 +977,8 @@ blogc_content_parse(const char *src, size_t *end_excerpt) tmp2 = NULL; free(parsed); parsed = NULL; - b_slist_free_full(lines, free); - b_slist_free_full(lines2, free); + sb_slist_free_full(lines, free); + sb_slist_free_full(lines2, free); lines = NULL; if (is_last) continue; @@ -968,28 +997,28 @@ blogc_content_parse(const char *src, size_t *end_excerpt) if (c == '\n' || c == '\r' || is_last) { if (lines2 != NULL) { // FIXME: avoid repeting the code below - tmp_str = b_string_new(); - for (b_slist_t *l = lines2; l != NULL; l = l->next) { + tmp_str = sb_string_new(); + for (sb_slist_t *l = lines2; l != NULL; l = l->next) { if (l->next == NULL) - b_string_append_printf(tmp_str, "%s", l->data); + sb_string_append_printf(tmp_str, "%s", l->data); else - b_string_append_printf(tmp_str, "%s%s", l->data, + sb_string_append_printf(tmp_str, "%s%s", l->data, line_ending); } - b_slist_free_full(lines2, free); + sb_slist_free_full(lines2, free); lines2 = NULL; parsed = blogc_content_parse_inline(tmp_str->str); - b_string_free(tmp_str, true); - lines = b_slist_append(lines, b_strdup(parsed)); + sb_string_free(tmp_str, true); + lines = sb_slist_append(lines, sb_strdup(parsed)); free(parsed); parsed = NULL; } - b_string_append_printf(rv, "<ol>%s", line_ending); - for (b_slist_t *l = lines; l != NULL; l = l->next) - b_string_append_printf(rv, "<li>%s</li>%s", l->data, + sb_string_append_printf(rv, "<ol>%s", line_ending); + for (sb_slist_t *l = lines; l != NULL; l = l->next) + sb_string_append_printf(rv, "<li>%s</li>%s", l->data, line_ending); - b_string_append_printf(rv, "</ol>%s", line_ending); - b_slist_free_full(lines, free); + sb_string_append_printf(rv, "</ol>%s", line_ending); + sb_slist_free_full(lines, free); lines = NULL; free(prefix); prefix = NULL; @@ -1033,7 +1062,7 @@ blogc_content_parse(const char *src, size_t *end_excerpt) case CONTENT_DIRECTIVE_COLON: if (c == ':') { free(directive_name); - directive_name = b_strndup(src + start2, end - start2); + directive_name = sb_strndup(src + start2, end - start2); state = CONTENT_DIRECTIVE_ARGUMENT_START; if (is_last) { state = CONTENT_DIRECTIVE_PARAM_END; @@ -1077,7 +1106,7 @@ blogc_content_parse(const char *src, size_t *end_excerpt) end = is_last && c != '\n' && c != '\r' ? src_len : (real_end != 0 ? real_end : current); free(directive_argument); - directive_argument = b_strndup(src + start2, end - start2); + directive_argument = sb_strndup(src + start2, end - start2); if (is_last) { state = CONTENT_DIRECTIVE_PARAM_END; continue; @@ -1098,7 +1127,7 @@ blogc_content_parse(const char *src, size_t *end_excerpt) state = CONTENT_DIRECTIVE_PARAM_END; continue; } - prefix = b_strndup(src + start2, current - start2); + prefix = sb_strndup(src + start2, current - start2); state = CONTENT_DIRECTIVE_PARAM_PREFIX; current--; break; @@ -1106,7 +1135,7 @@ blogc_content_parse(const char *src, size_t *end_excerpt) case CONTENT_DIRECTIVE_PARAM_PREFIX: if (c == ' ' || c == '\t') break; - if (c == ':' && b_str_starts_with(src + start2, prefix)) { + if (c == ':' && sb_str_starts_with(src + start2, prefix)) { state = CONTENT_DIRECTIVE_PARAM_KEY_START; break; } @@ -1137,7 +1166,7 @@ blogc_content_parse(const char *src, size_t *end_excerpt) break; if (c == ':') { free(directive_key); - directive_key = b_strndup(src + start2, current - start2); + directive_key = sb_strndup(src + start2, current - start2); state = CONTENT_DIRECTIVE_PARAM_VALUE_START; break; } @@ -1161,9 +1190,9 @@ blogc_content_parse(const char *src, size_t *end_excerpt) end = is_last && c != '\n' && c != '\r' ? src_len : (real_end != 0 ? real_end : current); if (directive_params == NULL) - directive_params = b_trie_new(free); - b_trie_insert(directive_params, directive_key, - b_strndup(src + start2, end - start2)); + directive_params = sb_trie_new(free); + sb_trie_insert(directive_params, directive_key, + sb_strndup(src + start2, end - start2)); free(directive_key); directive_key = NULL; if (!is_last) @@ -1176,7 +1205,7 @@ blogc_content_parse(const char *src, size_t *end_excerpt) if (c == '\n' || c == '\r' || is_last) { // FIXME: handle errors in the rest of the parser. blogc_error_t *err = NULL; - blogc_directive_ctx_t *ctx = b_malloc( + blogc_directive_ctx_t *ctx = sb_malloc( sizeof(blogc_directive_ctx_t)); ctx->name = directive_name; ctx->argument = directive_argument; @@ -1186,7 +1215,7 @@ blogc_content_parse(const char *src, size_t *end_excerpt) free(ctx); blogc_error_print(err); if (rv_d != NULL) - b_string_append(rv, rv_d); + sb_string_append(rv, rv_d); free(rv_d); state = CONTENT_START_LINE; start = current; @@ -1194,7 +1223,7 @@ blogc_content_parse(const char *src, size_t *end_excerpt) directive_name = NULL; free(directive_argument); directive_argument = NULL; - b_trie_free(directive_params); + sb_trie_free(directive_params); directive_params = NULL; free(prefix); prefix = NULL; @@ -1215,15 +1244,17 @@ blogc_content_parse(const char *src, size_t *end_excerpt) state = CONTENT_PARAGRAPH_END; end = is_last && c != '\n' && c != '\r' ? src_len : (real_end != 0 ? real_end : current); + if (description != NULL && *description == NULL) + *description = sb_strndup(src + start, end - start); } if (!is_last) break; case CONTENT_PARAGRAPH_END: if (c == '\n' || c == '\r' || is_last) { - tmp = b_strndup(src + start, end - start); + tmp = sb_strndup(src + start, end - start); parsed = blogc_content_parse_inline(tmp); - b_string_append_printf(rv, "<p>%s</p>%s", parsed, + sb_string_append_printf(rv, "<p>%s</p>%s", parsed, line_ending); free(parsed); parsed = NULL; @@ -1244,8 +1275,8 @@ blogc_content_parse(const char *src, size_t *end_excerpt) free(directive_name); free(directive_argument); free(directive_key); - b_trie_free(directive_params); + sb_trie_free(directive_params); free(prefix); - return b_string_free(rv, false); + return sb_string_free(rv, false); } diff --git a/src/content-parser.h b/src/content-parser.h index 6617bb4..148d5ed 100644 --- a/src/content-parser.h +++ b/src/content-parser.h @@ -16,6 +16,7 @@ char* blogc_slugify(const char *str); char* blogc_htmlentities(const char *str); char* blogc_content_parse_inline(const char *src); bool blogc_is_ordered_list_item(const char *str, size_t prefix_len); -char* blogc_content_parse(const char *src, size_t *end_excerpt); +char* blogc_content_parse(const char *src, size_t *end_excerpt, + char **description); #endif /* _CONTENT_PARSER_H */ diff --git a/src/datetime-parser.c b/src/datetime-parser.c index 8785a89..ad65ff7 100644 --- a/src/datetime-parser.c +++ b/src/datetime-parser.c @@ -17,8 +17,8 @@ #include <string.h> #include "error.h" -#include "utils/utils.h" #include "datetime-parser.h" +#include "utils.h" typedef enum { @@ -380,7 +380,7 @@ blogc_convert_datetime(const char *orig, const char *format, return NULL; } - return b_strdup(buf); + return sb_strdup(buf); #endif } diff --git a/src/directives.c b/src/directives.c index b538825..eb6166b 100644 --- a/src/directives.c +++ b/src/directives.c @@ -12,9 +12,9 @@ #include <string.h> -#include "utils/utils.h" #include "directives.h" #include "error.h" +#include "utils.h" const static blogc_directive_t registry[] = { @@ -48,11 +48,11 @@ blogc_directive_youtube(blogc_directive_ctx_t *ctx, blogc_error_t **err) return NULL; } - char *width = b_trie_lookup(ctx->params, "width"); - char *height = b_trie_lookup(ctx->params, "height"); + char *width = sb_trie_lookup(ctx->params, "width"); + char *height = sb_trie_lookup(ctx->params, "height"); // using default 16:9 sizes provided by youtube as of 2015-11-04 - return b_strdup_printf( + return sb_strdup_printf( "<iframe width=\"%s\" height=\"%s\" " "src=\"https://www.youtube.com/embed/%s\" frameborder=\"0\" " "allowfullscreen></iframe>%s", diff --git a/src/directives.h b/src/directives.h index dd27f03..0c6e35b 100644 --- a/src/directives.h +++ b/src/directives.h @@ -9,13 +9,13 @@ #ifndef _DIRECTIVES_H #define _DIRECTIVES_H -#include "utils/utils.h" +#include "utils.h" #include "error.h" typedef struct { const char *name; const char *argument; - b_trie_t *params; + sb_trie_t *params; const char *eol; } blogc_directive_ctx_t; diff --git a/src/error.c b/src/error.c index 59a85a3..3aea641 100644 --- a/src/error.c +++ b/src/error.c @@ -14,16 +14,16 @@ #include <stdlib.h> #include <stdarg.h> #include <string.h> -#include "utils/utils.h" #include "error.h" +#include "utils.h" blogc_error_t* blogc_error_new(blogc_error_type_t type, const char *msg) { - blogc_error_t *err = b_malloc(sizeof(blogc_error_t)); + blogc_error_t *err = sb_malloc(sizeof(blogc_error_t)); err->type = type; - err->msg = b_strdup(msg); + err->msg = sb_strdup(msg); return err; } @@ -33,7 +33,7 @@ blogc_error_new_printf(blogc_error_type_t type, const char *format, ...) { va_list ap; va_start(ap, format); - char *tmp = b_strdup_vprintf(format, ap); + char *tmp = sb_strdup_vprintf(format, ap); va_end(ap); blogc_error_t *rv = blogc_error_new(type, tmp); free(tmp); @@ -47,7 +47,7 @@ blogc_error_parser(blogc_error_type_t type, const char *src, size_t src_len, { va_list ap; va_start(ap, format); - char *msg = b_strdup_vprintf(format, ap); + char *msg = sb_strdup_vprintf(format, ap); va_end(ap); size_t lineno = 1; @@ -88,7 +88,7 @@ blogc_error_parser(blogc_error_type_t type, const char *src, size_t src_len, if (lineend <= linestart && src_len >= linestart) lineend = src_len; - char *line = b_strndup(src + linestart, lineend - linestart); + char *line = sb_strndup(src + linestart, lineend - linestart); blogc_error_t *rv = NULL; @@ -14,9 +14,9 @@ #include <stdarg.h> #include <stdio.h> #include <string.h> -#include "utils/utils.h" #include "file.h" #include "error.h" +#include "utils.h" // this would belong to loader.c, but we need it in a separated file to be // able to mock it when unit testing the loader functions. @@ -38,16 +38,16 @@ blogc_file_get_contents(const char *path, size_t *len, blogc_error_t **err) return NULL; } - b_string_t *str = b_string_new(); + sb_string_t *str = sb_string_new(); char buffer[BLOGC_FILE_CHUNK_SIZE]; while (!feof(fp)) { size_t read_len = fread(buffer, sizeof(char), BLOGC_FILE_CHUNK_SIZE, fp); *len += read_len; - b_string_append_len(str, buffer, read_len); + sb_string_append_len(str, buffer, read_len); } fclose(fp); - return b_string_free(str, false); + return sb_string_free(str, false); } diff --git a/src/loader.c b/src/loader.c index baa81fa..5ca0aac 100644 --- a/src/loader.c +++ b/src/loader.c @@ -14,12 +14,12 @@ #include <stdbool.h> #include <stdio.h> #include <string.h> -#include "utils/utils.h" #include "file.h" #include "source-parser.h" #include "template-parser.h" #include "loader.h" #include "error.h" +#include "utils.h" char* @@ -31,7 +31,7 @@ blogc_get_filename(const char *f) if (strlen(f) == 0) return NULL; - char *filename = b_strdup(f); + char *filename = sb_strdup(f); // keep a pointer to original string char *tmp = filename; @@ -52,14 +52,14 @@ blogc_get_filename(const char *f) } } - char *final_filename = b_strdup(tmp); + char *final_filename = sb_strdup(tmp); free(filename); return final_filename; } -b_slist_t* +sb_slist_t* blogc_template_parse_from_file(const char *f, blogc_error_t **err) { if (err == NULL || *err != NULL) @@ -68,13 +68,13 @@ blogc_template_parse_from_file(const char *f, blogc_error_t **err) char *s = blogc_file_get_contents(f, &len, err); if (s == NULL) return NULL; - b_slist_t *rv = blogc_template_parse(s, len, err); + sb_slist_t *rv = blogc_template_parse(s, len, err); free(s); return rv; } -b_trie_t* +sb_trie_t* blogc_source_parse_from_file(const char *f, blogc_error_t **err) { if (err == NULL || *err != NULL) @@ -83,13 +83,13 @@ blogc_source_parse_from_file(const char *f, blogc_error_t **err) char *s = blogc_file_get_contents(f, &len, err); if (s == NULL) return NULL; - b_trie_t *rv = blogc_source_parse(s, len, err); + sb_trie_t *rv = blogc_source_parse(s, len, err); // set FILENAME variable if (rv != NULL) { char *filename = blogc_get_filename(f); if (filename != NULL) - b_trie_insert(rv, "FILENAME", filename); + sb_trie_insert(rv, "FILENAME", filename); } free(s); @@ -97,16 +97,16 @@ blogc_source_parse_from_file(const char *f, blogc_error_t **err) } -b_slist_t* -blogc_source_parse_from_files(b_trie_t *conf, b_slist_t *l, blogc_error_t **err) +sb_slist_t* +blogc_source_parse_from_files(sb_trie_t *conf, sb_slist_t *l, blogc_error_t **err) { blogc_error_t *tmp_err = NULL; - b_slist_t *rv = NULL; + sb_slist_t *rv = NULL; unsigned int with_date = 0; - const char *filter_tag = b_trie_lookup(conf, "FILTER_TAG"); - const char *filter_page = b_trie_lookup(conf, "FILTER_PAGE"); - const char *filter_per_page = b_trie_lookup(conf, "FILTER_PER_PAGE"); + const char *filter_tag = sb_trie_lookup(conf, "FILTER_TAG"); + const char *filter_page = sb_trie_lookup(conf, "FILTER_PAGE"); + const char *filter_per_page = sb_trie_lookup(conf, "FILTER_PER_PAGE"); long page = strtol(filter_page != NULL ? filter_page : "", NULL, 10); if (page <= 0) @@ -121,27 +121,27 @@ blogc_source_parse_from_files(b_trie_t *conf, b_slist_t *l, blogc_error_t **err) unsigned int end = start + per_page; unsigned int counter = 0; - for (b_slist_t *tmp = l; tmp != NULL; tmp = tmp->next) { + for (sb_slist_t *tmp = l; tmp != NULL; tmp = tmp->next) { char *f = tmp->data; - b_trie_t *s = blogc_source_parse_from_file(f, &tmp_err); + sb_trie_t *s = blogc_source_parse_from_file(f, &tmp_err); if (s == NULL) { *err = blogc_error_new_printf(BLOGC_ERROR_LOADER, "An error occurred while parsing source file: %s\n\n%s", f, tmp_err->msg); blogc_error_free(tmp_err); tmp_err = NULL; - b_slist_free_full(rv, (b_free_func_t) b_trie_free); + sb_slist_free_full(rv, (sb_free_func_t) sb_trie_free); rv = NULL; break; } if (filter_tag != NULL) { - const char *tags_str = b_trie_lookup(s, "TAGS"); + const char *tags_str = sb_trie_lookup(s, "TAGS"); // if user wants to filter by tag and no tag is provided, skip it if (tags_str == NULL) { - b_trie_free(s); + sb_trie_free(s); continue; } - char **tags = b_str_split(tags_str, ' ', 0); + char **tags = sb_str_split(tags_str, ' ', 0); bool found = false; for (unsigned int i = 0; tags[i] != NULL; i++) { if (tags[i][0] == '\0') @@ -149,26 +149,26 @@ blogc_source_parse_from_files(b_trie_t *conf, b_slist_t *l, blogc_error_t **err) if (0 == strcmp(tags[i], filter_tag)) found = true; } - b_strv_free(tags); + sb_strv_free(tags); if (!found) { - b_trie_free(s); + sb_trie_free(s); continue; } } if (filter_page != NULL) { if (counter < start || counter >= end) { counter++; - b_trie_free(s); + sb_trie_free(s); continue; } counter++; } - if (b_trie_lookup(s, "DATE") != NULL) + if (sb_trie_lookup(s, "DATE") != NULL) with_date++; - rv = b_slist_append(rv, s); + rv = sb_slist_append(rv, s); } - if (with_date > 0 && with_date < b_slist_length(rv)) + if (with_date > 0 && with_date < sb_slist_length(rv)) // fatal error, maybe? blogc_fprintf(stderr, "blogc: warning: 'DATE' variable provided for at least one source " @@ -176,38 +176,38 @@ blogc_source_parse_from_files(b_trie_t *conf, b_slist_t *l, blogc_error_t **err) "wrong values for 'DATE_FIRST' and 'DATE_LAST' variables.\n"); bool first = true; - for (b_slist_t *tmp = rv; tmp != NULL; tmp = tmp->next) { - b_trie_t *s = tmp->data; + for (sb_slist_t *tmp = rv; tmp != NULL; tmp = tmp->next) { + sb_trie_t *s = tmp->data; if (first) { - const char *val = b_trie_lookup(s, "DATE"); + const char *val = sb_trie_lookup(s, "DATE"); if (val != NULL) - b_trie_insert(conf, "DATE_FIRST", b_strdup(val)); - val = b_trie_lookup(s, "FILENAME"); + sb_trie_insert(conf, "DATE_FIRST", sb_strdup(val)); + val = sb_trie_lookup(s, "FILENAME"); if (val != NULL) - b_trie_insert(conf, "FILENAME_FIRST", b_strdup(val)); + sb_trie_insert(conf, "FILENAME_FIRST", sb_strdup(val)); first = false; } if (tmp->next == NULL) { // last - const char *val = b_trie_lookup(s, "DATE"); + const char *val = sb_trie_lookup(s, "DATE"); if (val != NULL) - b_trie_insert(conf, "DATE_LAST", b_strdup(val)); - val = b_trie_lookup(s, "FILENAME"); + sb_trie_insert(conf, "DATE_LAST", sb_strdup(val)); + val = sb_trie_lookup(s, "FILENAME"); if (val != NULL) - b_trie_insert(conf, "FILENAME_LAST", b_strdup(val)); + sb_trie_insert(conf, "FILENAME_LAST", sb_strdup(val)); } } if (filter_page != NULL) { unsigned int last_page = ceilf(((float) counter) / per_page); - b_trie_insert(conf, "CURRENT_PAGE", b_strdup_printf("%ld", page)); + sb_trie_insert(conf, "CURRENT_PAGE", sb_strdup_printf("%ld", page)); if (page > 1) - b_trie_insert(conf, "PREVIOUS_PAGE", b_strdup_printf("%ld", page - 1)); + sb_trie_insert(conf, "PREVIOUS_PAGE", sb_strdup_printf("%ld", page - 1)); if (page < last_page) - b_trie_insert(conf, "NEXT_PAGE", b_strdup_printf("%ld", page + 1)); - if (b_slist_length(rv) > 0) - b_trie_insert(conf, "FIRST_PAGE", b_strdup("1")); + sb_trie_insert(conf, "NEXT_PAGE", sb_strdup_printf("%ld", page + 1)); + if (sb_slist_length(rv) > 0) + sb_trie_insert(conf, "FIRST_PAGE", sb_strdup("1")); if (last_page > 0) - b_trie_insert(conf, "LAST_PAGE", b_strdup_printf("%d", last_page)); + sb_trie_insert(conf, "LAST_PAGE", sb_strdup_printf("%d", last_page)); } return rv; diff --git a/src/loader.h b/src/loader.h index c432e20..32b58be 100644 --- a/src/loader.h +++ b/src/loader.h @@ -9,13 +9,13 @@ #ifndef _LOADER_H #define _LOADER_H -#include "utils/utils.h" #include "error.h" +#include "utils.h" char* blogc_get_filename(const char *f); -b_slist_t* blogc_template_parse_from_file(const char *f, blogc_error_t **err); -b_trie_t* blogc_source_parse_from_file(const char *f, blogc_error_t **err); -b_slist_t* blogc_source_parse_from_files(b_trie_t *conf, b_slist_t *l, +sb_slist_t* blogc_template_parse_from_file(const char *f, blogc_error_t **err); +sb_trie_t* blogc_source_parse_from_file(const char *f, blogc_error_t **err); +sb_slist_t* blogc_source_parse_from_files(sb_trie_t *conf, sb_slist_t *l, blogc_error_t **err); #endif /* _LOADER_H */ diff --git a/src/renderer.c b/src/renderer.c index 5e07b0c..5af3b8a 100644 --- a/src/renderer.c +++ b/src/renderer.c @@ -13,69 +13,69 @@ #include <stdbool.h> #include <stdio.h> #include <string.h> -#include "utils/utils.h" #include "datetime-parser.h" #include "error.h" #include "loader.h" #include "source-parser.h" #include "template-parser.h" #include "renderer.h" +#include "utils.h" const char* -blogc_get_variable(const char *name, b_trie_t *global, b_trie_t *local) +blogc_get_variable(const char *name, sb_trie_t *global, sb_trie_t *local) { const char *rv = NULL; if (local != NULL) { - rv = b_trie_lookup(local, name); + rv = sb_trie_lookup(local, name); if (rv != NULL) return rv; } if (global != NULL) - rv = b_trie_lookup(global, name); + rv = sb_trie_lookup(global, name); return rv; } char* -blogc_format_date(const char *date, b_trie_t *global, b_trie_t *local) +blogc_format_date(const char *date, sb_trie_t *global, sb_trie_t *local) { const char *date_format = blogc_get_variable("DATE_FORMAT", global, local); if (date == NULL) return NULL; if (date_format == NULL) - return b_strdup(date); + return sb_strdup(date); blogc_error_t *err = NULL; char *rv = blogc_convert_datetime(date, date_format, &err); if (err != NULL) { blogc_error_print(err); blogc_error_free(err); - return b_strdup(date); + return sb_strdup(date); } return rv; } char* -blogc_format_variable(const char *name, b_trie_t *global, b_trie_t *local, - b_slist_t *foreach_var) +blogc_format_variable(const char *name, sb_trie_t *global, sb_trie_t *local, + sb_slist_t *foreach_var) { if (0 == strcmp(name, "FOREACH_ITEM")) { if (foreach_var != NULL && foreach_var->data != NULL) { - return b_strdup(foreach_var->data); + return sb_strdup(foreach_var->data); } return NULL; } char *var = NULL; bool must_format = false; - if (b_str_ends_with(name, "_FORMATTED")) { - var = b_strndup(name, strlen(name) - 10); + if (sb_str_ends_with(name, "_FORMATTED")) { + var = sb_strndup(name, strlen(name) - 10); must_format = true; } if (var == NULL) - var = b_strdup(name); + var = sb_strdup(name); const char *value = blogc_get_variable(var, global, local); free(var); @@ -85,30 +85,30 @@ blogc_format_variable(const char *name, b_trie_t *global, b_trie_t *local, char *rv = NULL; if (must_format) { - if (b_str_starts_with(name, "DATE_")) { + if (sb_str_starts_with(name, "DATE_")) { rv = blogc_format_date(value, global, local); } } if (rv == NULL) - return b_strdup(value); + return sb_strdup(value); return rv; } -b_slist_t* -blogc_split_list_variable(const char *name, b_trie_t *global, b_trie_t *local) +sb_slist_t* +blogc_split_list_variable(const char *name, sb_trie_t *global, sb_trie_t *local) { const char *value = blogc_get_variable(name, global, local); if (value == NULL) return NULL; - b_slist_t *rv = NULL; + sb_slist_t *rv = NULL; - char **tmp = b_str_split(value, ' ', 0); + char **tmp = sb_str_split(value, ' ', 0); for (unsigned int i = 0; tmp[i] != NULL; i++) { if (tmp[i][0] != '\0') // ignore empty strings - rv = b_slist_append(rv, tmp[i]); + rv = sb_slist_append(rv, tmp[i]); else free(tmp[i]); } @@ -119,25 +119,25 @@ blogc_split_list_variable(const char *name, b_trie_t *global, b_trie_t *local) char* -blogc_render(b_slist_t *tmpl, b_slist_t *sources, b_trie_t *config, bool listing) +blogc_render(sb_slist_t *tmpl, sb_slist_t *sources, sb_trie_t *config, bool listing) { if (tmpl == NULL) return NULL; - b_slist_t *current_source = NULL; - b_slist_t *listing_start = NULL; + sb_slist_t *current_source = NULL; + sb_slist_t *listing_start = NULL; - b_string_t *str = b_string_new(); + sb_string_t *str = sb_string_new(); - b_trie_t *tmp_source = NULL; + sb_trie_t *tmp_source = NULL; char *config_value = NULL; char *defined = NULL; unsigned int if_count = 0; - b_slist_t *foreach_var = NULL; - b_slist_t *foreach_var_start = NULL; - b_slist_t *foreach_start = NULL; + sb_slist_t *foreach_var = NULL; + sb_slist_t *foreach_var_start = NULL; + sb_slist_t *foreach_start = NULL; bool if_not = false; bool inside_block = false; @@ -145,7 +145,7 @@ blogc_render(b_slist_t *tmpl, b_slist_t *sources, b_trie_t *config, bool listing int cmp = 0; - b_slist_t *tmp = tmpl; + sb_slist_t *tmp = tmpl; while (tmp != NULL) { blogc_template_stmt_t *stmt = tmp->data; @@ -153,7 +153,7 @@ blogc_render(b_slist_t *tmpl, b_slist_t *sources, b_trie_t *config, bool listing case BLOGC_TEMPLATE_CONTENT_STMT: if (stmt->value != NULL) - b_string_append(str, stmt->value); + sb_string_append(str, stmt->value); break; case BLOGC_TEMPLATE_BLOCK_STMT: @@ -210,7 +210,7 @@ blogc_render(b_slist_t *tmpl, b_slist_t *sources, b_trie_t *config, bool listing config_value = blogc_format_variable(stmt->value, config, inside_block ? tmp_source : NULL, foreach_var); if (config_value != NULL) { - b_string_append(str, config_value); + sb_string_append(str, config_value); free(config_value); config_value = NULL; break; @@ -252,7 +252,7 @@ blogc_render(b_slist_t *tmpl, b_slist_t *sources, b_trie_t *config, bool listing (stmt->value2[0] == '"') && (stmt->value2[strlen(stmt->value2) - 1] == '"')) { - defined2 = b_strndup(stmt->value2 + 1, + defined2 = sb_strndup(stmt->value2 + 1, strlen(stmt->value2) - 2); } else { @@ -354,7 +354,7 @@ blogc_render(b_slist_t *tmpl, b_slist_t *sources, b_trie_t *config, bool listing } } foreach_start = NULL; - b_slist_free_full(foreach_var_start, free); + sb_slist_free_full(foreach_var_start, free); foreach_var_start = NULL; break; } @@ -364,5 +364,5 @@ blogc_render(b_slist_t *tmpl, b_slist_t *sources, b_trie_t *config, bool listing // no need to free temporary variables here. the template parser makes sure // that templates are sane and statements are closed. - return b_string_free(str, false); + return sb_string_free(str, false); } diff --git a/src/renderer.h b/src/renderer.h index 15204e6..2982ee8 100644 --- a/src/renderer.h +++ b/src/renderer.h @@ -10,15 +10,15 @@ #define _RENDERER_H #include <stdbool.h> -#include "utils/utils.h" +#include "utils.h" -const char* blogc_get_variable(const char *name, b_trie_t *global, b_trie_t *local); -char* blogc_format_date(const char *date, b_trie_t *global, b_trie_t *local); -char* blogc_format_variable(const char *name, b_trie_t *global, b_trie_t *local, - b_slist_t *foreach_var); -b_slist_t* blogc_split_list_variable(const char *name, b_trie_t *global, - b_trie_t *local); -char* blogc_render(b_slist_t *tmpl, b_slist_t *sources, b_trie_t *config, +const char* blogc_get_variable(const char *name, sb_trie_t *global, sb_trie_t *local); +char* blogc_format_date(const char *date, sb_trie_t *global, sb_trie_t *local); +char* blogc_format_variable(const char *name, sb_trie_t *global, sb_trie_t *local, + sb_slist_t *foreach_var); +sb_slist_t* blogc_split_list_variable(const char *name, sb_trie_t *global, + sb_trie_t *local); +char* blogc_render(sb_slist_t *tmpl, sb_slist_t *sources, sb_trie_t *config, bool listing); #endif /* _RENDERER_H */ diff --git a/src/source-parser.c b/src/source-parser.c index 65fdd4e..f250bd3 100644 --- a/src/source-parser.c +++ b/src/source-parser.c @@ -13,10 +13,10 @@ #include <stdbool.h> #include <string.h> -#include "utils/utils.h" #include "content-parser.h" #include "source-parser.h" #include "error.h" +#include "utils.h" typedef enum { @@ -30,7 +30,7 @@ typedef enum { } blogc_source_parser_state_t; -b_trie_t* +sb_trie_t* blogc_source_parse(const char *src, size_t src_len, blogc_error_t **err) { if (err == NULL || *err != NULL) @@ -43,7 +43,7 @@ blogc_source_parse(const char *src, size_t src_len, blogc_error_t **err) char *key = NULL; char *tmp = NULL; char *content = NULL; - b_trie_t *rv = b_trie_new(free); + sb_trie_t *rv = sb_trie_new(free); blogc_source_parser_state_t state = SOURCE_START; @@ -73,7 +73,7 @@ blogc_source_parse(const char *src, size_t src_len, blogc_error_t **err) if ((c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_') break; if (c == ':') { - key = b_strndup(src + start, current - start); + key = sb_strndup(src + start, current - start); if (((current - start == 8) && (0 == strncmp("FILENAME", src + start, 8))) || ((current - start == 7) && @@ -122,8 +122,8 @@ blogc_source_parse(const char *src, size_t src_len, blogc_error_t **err) case SOURCE_CONFIG_VALUE: if (c == '\n' || c == '\r') { - tmp = b_strndup(src + start, current - start); - b_trie_insert(rv, key, b_strdup(b_str_strip(tmp))); + tmp = sb_strndup(src + start, current - start); + sb_trie_insert(rv, key, sb_strdup(sb_str_strip(tmp))); free(tmp); free(key); key = NULL; @@ -152,12 +152,24 @@ blogc_source_parse(const char *src, size_t src_len, blogc_error_t **err) case SOURCE_CONTENT: if (current == (src_len - 1)) { - tmp = b_strndup(src + start, src_len - start); - b_trie_insert(rv, "RAW_CONTENT", tmp); - content = blogc_content_parse(tmp, &end_excerpt); - b_trie_insert(rv, "CONTENT", content); - b_trie_insert(rv, "EXCERPT", end_excerpt == 0 ? - b_strdup(content) : b_strndup(content, end_excerpt)); + tmp = sb_strndup(src + start, src_len - start); + sb_trie_insert(rv, "RAW_CONTENT", tmp); + char *description = NULL; + content = blogc_content_parse(tmp, &end_excerpt, &description); + if (description != NULL) { + // do not override source-provided description. + if (NULL == sb_trie_lookup(rv, "DESCRIPTION")) { + // no need to free, because we are transfering memory + // ownership to the trie. + sb_trie_insert(rv, "DESCRIPTION", description); + } + else { + free(description); + } + } + sb_trie_insert(rv, "CONTENT", content); + sb_trie_insert(rv, "EXCERPT", end_excerpt == 0 ? + sb_strdup(content) : sb_strndup(content, end_excerpt)); } break; } @@ -168,7 +180,7 @@ blogc_source_parse(const char *src, size_t src_len, blogc_error_t **err) current++; } - if (*err == NULL && b_trie_size(rv) == 0) { + if (*err == NULL && sb_trie_size(rv) == 0) { // ok, nothing found in the config trie, but no error set either. // let's try to be nice with the users and provide some reasonable @@ -202,7 +214,7 @@ blogc_source_parse(const char *src, size_t src_len, blogc_error_t **err) if (*err != NULL) { free(key); - b_trie_free(rv); + sb_trie_free(rv); return NULL; } diff --git a/src/source-parser.h b/src/source-parser.h index f359f9e..5cadf95 100644 --- a/src/source-parser.h +++ b/src/source-parser.h @@ -10,10 +10,10 @@ #define _SOURCE_PARSER_H #include <stdlib.h> -#include "utils/utils.h" #include "error.h" +#include "utils.h" -b_trie_t* blogc_source_parse(const char *src, size_t src_len, +sb_trie_t* blogc_source_parse(const char *src, size_t src_len, blogc_error_t **err); #endif /* _SOURCE_PARSER_H */ diff --git a/src/template-parser.c b/src/template-parser.c index 1d9046e..525f5f5 100644 --- a/src/template-parser.c +++ b/src/template-parser.c @@ -13,9 +13,9 @@ #include <stdbool.h> #include <string.h> -#include "utils/utils.h" #include "template-parser.h" #include "error.h" +#include "utils.h" typedef enum { @@ -52,7 +52,7 @@ typedef enum { } blogc_template_parser_block_state_t; -b_slist_t* +sb_slist_t* blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err) { if (err == NULL || *err != NULL) @@ -71,7 +71,7 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err) unsigned int if_count = 0; bool foreach_open = false; - b_slist_t *stmts = NULL; + sb_slist_t *stmts = NULL; blogc_template_stmt_t *stmt = NULL; /* @@ -100,21 +100,21 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err) case TEMPLATE_START: if (last) { - stmt = b_malloc(sizeof(blogc_template_stmt_t)); + stmt = sb_malloc(sizeof(blogc_template_stmt_t)); stmt->type = type; if (lstrip_next) { - tmp = b_strndup(src + start, src_len - start); - stmt->value = b_strdup(b_str_lstrip(tmp)); + tmp = sb_strndup(src + start, src_len - start); + stmt->value = sb_strdup(sb_str_lstrip(tmp)); free(tmp); tmp = NULL; lstrip_next = false; } else { - stmt->value = b_strndup(src + start, src_len - start); + stmt->value = sb_strndup(src + start, src_len - start); } stmt->op = 0; stmt->value2 = NULL; - stmts = b_slist_append(stmts, stmt); + stmts = sb_slist_append(stmts, stmt); previous = stmt; stmt = NULL; } @@ -131,21 +131,21 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err) else state = TEMPLATE_VARIABLE_START; if (end > start) { - stmt = b_malloc(sizeof(blogc_template_stmt_t)); + stmt = sb_malloc(sizeof(blogc_template_stmt_t)); stmt->type = type; if (lstrip_next) { - tmp = b_strndup(src + start, end - start); - stmt->value = b_strdup(b_str_lstrip(tmp)); + tmp = sb_strndup(src + start, end - start); + stmt->value = sb_strdup(sb_str_lstrip(tmp)); free(tmp); tmp = NULL; lstrip_next = false; } else { - stmt->value = b_strndup(src + start, end - start); + stmt->value = sb_strndup(src + start, end - start); } stmt->op = 0; stmt->value2 = NULL; - stmts = b_slist_append(stmts, stmt); + stmts = sb_slist_append(stmts, stmt); previous = stmt; stmt = NULL; } @@ -159,7 +159,7 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err) if ((previous != NULL) && (previous->type == BLOGC_TEMPLATE_CONTENT_STMT)) { - previous->value = b_str_rstrip(previous->value); // does not need copy + previous->value = sb_str_rstrip(previous->value); // does not need copy } state = TEMPLATE_BLOCK_START; break; @@ -559,19 +559,19 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err) op_start = 0; op_end = 0; } - stmt = b_malloc(sizeof(blogc_template_stmt_t)); + stmt = sb_malloc(sizeof(blogc_template_stmt_t)); stmt->type = type; stmt->value = NULL; stmt->op = tmp_op; stmt->value2 = NULL; if (end > start) - stmt->value = b_strndup(src + start, end - start); + stmt->value = sb_strndup(src + start, end - start); if (end2 > start2) { - stmt->value2 = b_strndup(src + start2, end2 - start2); + stmt->value2 = sb_strndup(src + start2, end2 - start2); start2 = 0; end2 = 0; } - stmts = b_slist_append(stmts, stmt); + stmts = sb_slist_append(stmts, stmt); previous = stmt; stmt = NULL; state = TEMPLATE_START; @@ -622,9 +622,9 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err) void -blogc_template_free_stmts(b_slist_t *stmts) +blogc_template_free_stmts(sb_slist_t *stmts) { - for (b_slist_t *tmp = stmts; tmp != NULL; tmp = tmp->next) { + for (sb_slist_t *tmp = stmts; tmp != NULL; tmp = tmp->next) { blogc_template_stmt_t *data = tmp->data; if (data == NULL) continue; @@ -632,5 +632,5 @@ blogc_template_free_stmts(b_slist_t *stmts) free(data->value2); free(data); } - b_slist_free(stmts); + sb_slist_free(stmts); } diff --git a/src/template-parser.h b/src/template-parser.h index 6cd2c80..a8b4e8b 100644 --- a/src/template-parser.h +++ b/src/template-parser.h @@ -9,8 +9,8 @@ #ifndef _TEMPLATE_PARSER_H #define _TEMPLATE_PARSER_H -#include "utils/utils.h" #include "error.h" +#include "utils.h" /* * note: whitespace cleaners are NOT added to ast. we fix strings right during @@ -44,8 +44,8 @@ typedef struct { blogc_template_stmt_operator_t op; } blogc_template_stmt_t; -b_slist_t* blogc_template_parse(const char *src, size_t src_len, +sb_slist_t* blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err); -void blogc_template_free_stmts(b_slist_t *stmts); +void blogc_template_free_stmts(sb_slist_t *stmts); #endif /* _TEMPLATE_GRAMMAR_H */ diff --git a/src/utils.c b/src/utils.c new file mode 100644 index 0000000..855b503 --- /dev/null +++ b/src/utils.c @@ -0,0 +1,612 @@ +/* + * blogc: A blog compiler. + * Copyright (C) 2014-2016 Rafael G. Martins <rafael@rafaelmartins.eng.br> + * + * This program can be distributed under the terms of the BSD License. + * See the file LICENSE. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif /* HAVE_CONFIG_H */ + +#define SB_STRING_CHUNK_SIZE 128 + +#include <ctype.h> +#include <string.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdio.h> + +#include "utils.h" + + +void* +sb_malloc(size_t size) +{ + // simple things simple! + void *rv = malloc(size); + if (rv == NULL) { + fprintf(stderr, "fatal: Failed to allocate memory!\n"); + abort(); + } + return rv; +} + + +void* +sb_realloc(void *ptr, size_t size) +{ + // simple things even simpler :P + void *rv = realloc(ptr, size); + if (rv == NULL && size != 0) { + fprintf(stderr, "fatal: Failed to reallocate memory!\n"); + free(ptr); + abort(); + } + return rv; +} + + +sb_slist_t* +sb_slist_append(sb_slist_t *l, void *data) +{ + sb_slist_t *node = sb_malloc(sizeof(sb_slist_t)); + node->data = data; + node->next = NULL; + if (l == NULL) { + l = node; + } + else { + sb_slist_t *tmp; + for (tmp = l; tmp->next != NULL; tmp = tmp->next); + tmp->next = node; + } + return l; +} + + +sb_slist_t* +sb_slist_prepend(sb_slist_t *l, void *data) +{ + sb_slist_t *node = sb_malloc(sizeof(sb_slist_t)); + node->data = data; + node->next = l; + l = node; + return l; +} + + +void +sb_slist_free_full(sb_slist_t *l, sb_free_func_t free_func) +{ + while (l != NULL) { + sb_slist_t *tmp = l->next; + if ((free_func != NULL) && (l->data != NULL)) + free_func(l->data); + free(l); + l = tmp; + } +} + + +void +sb_slist_free(sb_slist_t *l) +{ + sb_slist_free_full(l, NULL); +} + + +size_t +sb_slist_length(sb_slist_t *l) +{ + if (l == NULL) + return 0; + size_t i; + sb_slist_t *tmp; + for (tmp = l, i = 0; tmp != NULL; tmp = tmp->next, i++); + return i; +} + + +char* +sb_strdup(const char *s) +{ + if (s == NULL) + return NULL; + size_t l = strlen(s); + char *tmp = malloc(l + 1); + if (tmp == NULL) + return NULL; + memcpy(tmp, s, l + 1); + return tmp; +} + + +char* +sb_strndup(const char *s, size_t n) +{ + if (s == NULL) + return NULL; + size_t l = strnlen(s, n); + char *tmp = malloc(l + 1); + if (tmp == NULL) + return NULL; + memcpy(tmp, s, l); + tmp[l] = '\0'; + return tmp; +} + + +char* +sb_strdup_vprintf(const char *format, va_list ap) +{ + va_list ap2; + va_copy(ap2, ap); + int l = vsnprintf(NULL, 0, format, ap2); + va_end(ap2); + if (l < 0) + return NULL; + char *tmp = malloc(l + 1); + if (!tmp) + return NULL; + int l2 = vsnprintf(tmp, l + 1, format, ap); + if (l2 < 0) { + free(tmp); + return NULL; + } + return tmp; +} + + +char* +sb_strdup_printf(const char *format, ...) +{ + va_list ap; + va_start(ap, format); + char *tmp = sb_strdup_vprintf(format, ap); + va_end(ap); + return tmp; +} + + +bool +sb_str_starts_with(const char *str, const char *prefix) +{ + int str_l = strlen(str); + int str_lp = strlen(prefix); + if (str_lp > str_l) + return false; + return strncmp(str, prefix, str_lp) == 0; +} + + +bool +sb_str_ends_with(const char *str, const char *suffix) +{ + int str_l = strlen(str); + int str_ls = strlen(suffix); + if (str_ls > str_l) + return false; + return strcmp(str + str_l - str_ls, suffix) == 0; +} + + +char* +sb_str_lstrip(char *str) +{ + if (str == NULL) + return NULL; + int i; + size_t str_len = strlen(str); + for (i = 0; i < str_len; i++) { + if ((str[i] != ' ') && (str[i] != '\t') && (str[i] != '\n') && + (str[i] != '\r') && (str[i] != '\t') && (str[i] != '\f') && + (str[i] != '\v')) + { + str += i; + break; + } + if (i == str_len - 1) { + str += str_len; + break; + } + } + return str; +} + + +char* +sb_str_rstrip(char *str) +{ + if (str == NULL) + return NULL; + int i; + size_t str_len = strlen(str); + for (i = str_len - 1; i >= 0; i--) { + if ((str[i] != ' ') && (str[i] != '\t') && (str[i] != '\n') && + (str[i] != '\r') && (str[i] != '\t') && (str[i] != '\f') && + (str[i] != '\v')) + { + str[i + 1] = '\0'; + break; + } + if (i == 0) { + str[0] = '\0'; + break; + } + } + return str; +} + + +char* +sb_str_strip(char *str) +{ + return sb_str_lstrip(sb_str_rstrip(str)); +} + + +char** +sb_str_split(const char *str, char c, unsigned int max_pieces) +{ + if (str == NULL) + return NULL; + char **rv = sb_malloc(sizeof(char*)); + unsigned int i, start = 0, count = 0; + for (i = 0; i < strlen(str) + 1; i++) { + if (str[0] == '\0') + break; + if ((str[i] == c && (!max_pieces || count + 1 < max_pieces)) || str[i] == '\0') { + rv = sb_realloc(rv, (count + 1) * sizeof(char*)); + rv[count] = sb_malloc(i - start + 1); + memcpy(rv[count], str + start, i - start); + rv[count++][i - start] = '\0'; + start = i + 1; + } + } + rv = sb_realloc(rv, (count + 1) * sizeof(char*)); + rv[count] = NULL; + return rv; +} + + +char* +sb_str_replace(const char *str, const char search, const char *replace) +{ + char **pieces = sb_str_split(str, search, 0); + if (pieces == NULL) + return NULL; + char* rv = sb_strv_join(pieces, replace); + sb_strv_free(pieces); + if (rv == NULL) + return sb_strdup(str); + return rv; +} + + +void +sb_strv_free(char **strv) +{ + if (strv == NULL) + return; + for (size_t i = 0; strv[i] != NULL; i++) + free(strv[i]); + free(strv); +} + + +char* +sb_strv_join(char **strv, const char *separator) +{ + if (strv == NULL || separator == NULL) + return NULL; + sb_string_t *str = sb_string_new(); + for (size_t i = 0; strv[i] != NULL; i++) { + str = sb_string_append(str, strv[i]); + if (strv[i + 1] != NULL) + str = sb_string_append(str, separator); + } + return sb_string_free(str, false); +} + + +size_t +sb_strv_length(char **strv) +{ + if (strv == NULL) + return 0; + size_t i; + for (i = 0; strv[i] != NULL; i++); + return i; +} + + +sb_string_t* +sb_string_new(void) +{ + sb_string_t* rv = sb_malloc(sizeof(sb_string_t)); + rv->str = NULL; + rv->len = 0; + rv->allocated_len = 0; + + // initialize with empty string + rv = sb_string_append(rv, ""); + + return rv; +} + + +char* +sb_string_free(sb_string_t *str, bool free_str) +{ + if (str == NULL) + return NULL; + char *rv = NULL; + if (free_str) + free(str->str); + else + rv = str->str; + free(str); + return rv; +} + + +sb_string_t* +sb_string_dup(sb_string_t *str) +{ + if (str == NULL) + return NULL; + sb_string_t* new = sb_string_new(); + return sb_string_append_len(new, str->str, str->len); +} + + +sb_string_t* +sb_string_append_len(sb_string_t *str, const char *suffix, size_t len) +{ + if (str == NULL) + return NULL; + if (suffix == NULL) + return str; + size_t old_len = str->len; + str->len += len; + if (str->len + 1 > str->allocated_len) { + str->allocated_len = (((str->len + 1) / SB_STRING_CHUNK_SIZE) + 1) * SB_STRING_CHUNK_SIZE; + str->str = sb_realloc(str->str, str->allocated_len); + } + memcpy(str->str + old_len, suffix, len); + str->str[str->len] = '\0'; + return str; +} + + +sb_string_t* +sb_string_append(sb_string_t *str, const char *suffix) +{ + if (str == NULL) + return NULL; + const char *my_suffix = suffix == NULL ? "" : suffix; + return sb_string_append_len(str, my_suffix, strlen(my_suffix)); +} + + +sb_string_t* +sb_string_append_c(sb_string_t *str, char c) +{ + if (str == NULL) + return NULL; + size_t old_len = str->len; + str->len += 1; + if (str->len + 1 > str->allocated_len) { + str->allocated_len = (((str->len + 1) / SB_STRING_CHUNK_SIZE) + 1) * SB_STRING_CHUNK_SIZE; + str->str = sb_realloc(str->str, str->allocated_len); + } + str->str[old_len] = c; + str->str[str->len] = '\0'; + return str; +} + + +sb_string_t* +sb_string_append_printf(sb_string_t *str, const char *format, ...) +{ + if (str == NULL) + return NULL; + va_list ap; + va_start(ap, format); + char *tmp = sb_strdup_vprintf(format, ap); + va_end(ap); + str = sb_string_append(str, tmp); + free(tmp); + return str; +} + + +sb_trie_t* +sb_trie_new(sb_free_func_t free_func) +{ + sb_trie_t *trie = sb_malloc(sizeof(sb_trie_t)); + trie->root = NULL; + trie->free_func = free_func; + return trie; +} + + +static void +sb_trie_free_node(sb_trie_t *trie, sb_trie_node_t *node) +{ + if (trie == NULL || node == NULL) + return; + if (node->data != NULL && trie->free_func != NULL) + trie->free_func(node->data); + sb_trie_free_node(trie, node->next); + sb_trie_free_node(trie, node->child); + free(node); +} + + +void +sb_trie_free(sb_trie_t *trie) +{ + if (trie == NULL) + return; + sb_trie_free_node(trie, trie->root); + free(trie); +} + + +void +sb_trie_insert(sb_trie_t *trie, const char *key, void *data) +{ + if (trie == NULL || key == NULL || data == NULL) + return; + + sb_trie_node_t *parent = NULL; + sb_trie_node_t *previous; + sb_trie_node_t *current; + sb_trie_node_t *tmp; + + while (1) { + + if (trie->root == NULL || (parent != NULL && parent->child == NULL)) { + current = sb_malloc(sizeof(sb_trie_node_t)); + current->key = *key; + current->data = NULL; + current->next = NULL; + current->child = NULL; + if (trie->root == NULL) + trie->root = current; + else + parent->child = current; + parent = current; + goto clean; + } + + tmp = parent == NULL ? trie->root : parent->child; + previous = NULL; + + while (tmp != NULL && tmp->key != *key) { + previous = tmp; + tmp = tmp->next; + } + + parent = tmp; + + if (previous == NULL || parent != NULL) + goto clean; + + current = sb_malloc(sizeof(sb_trie_node_t)); + current->key = *key; + current->data = NULL; + current->next = NULL; + current->child = NULL; + previous->next = current; + parent = current; + +clean: + if (*key == '\0') { + if (parent->data != NULL && trie->free_func != NULL) + trie->free_func(parent->data); + parent->data = data; + break; + } + key++; + } +} + + +void* +sb_trie_lookup(sb_trie_t *trie, const char *key) +{ + if (trie == NULL || trie->root == NULL || key == NULL) + return NULL; + + sb_trie_node_t *parent = trie->root; + sb_trie_node_t *tmp; + while (1) { + for (tmp = parent; tmp != NULL; tmp = tmp->next) { + + if (tmp->key == *key) { + if (tmp->key == '\0') + return tmp->data; + parent = tmp->child; + break; + } + } + if (tmp == NULL) + return NULL; + + if (*key == '\0') + break; + key++; + } + return NULL; +} + + +static void +sb_trie_size_node(sb_trie_node_t *node, size_t *count) +{ + if (node == NULL || count == NULL) + return; + + if (node->key == '\0') + (*count)++; + + sb_trie_size_node(node->next, count); + sb_trie_size_node(node->child, count); +} + + +size_t +sb_trie_size(sb_trie_t *trie) +{ + if (trie == NULL) + return 0; + + size_t count = 0; + sb_trie_size_node(trie->root, &count); + return count; +} + + +static void +sb_trie_foreach_node(sb_trie_node_t *node, sb_string_t *str, + sb_trie_foreach_func_t func, void *user_data) +{ + if (node == NULL || str == NULL || func == NULL) + return; + + if (node->key == '\0') { + char *tmp = sb_string_free(str, false); + func(tmp, node->data, user_data); + free(tmp); + } + + if (node->child != NULL) { + sb_string_t *child = sb_string_dup(str); + child = sb_string_append_c(child, node->key); + sb_trie_foreach_node(node->child, child, func, user_data); + } + + if (node->next != NULL) + sb_trie_foreach_node(node->next, str, func, user_data); + + if (node->child != NULL && node->next == NULL) + sb_string_free(str, true); +} + + +void +sb_trie_foreach(sb_trie_t *trie, sb_trie_foreach_func_t func, + void *user_data) +{ + if (trie == NULL || trie->root == NULL || func == NULL) + return; + + sb_string_t *str = sb_string_new(); + sb_trie_foreach_node(trie->root, str, func, user_data); +} diff --git a/src/utils.h b/src/utils.h new file mode 100644 index 0000000..411295a --- /dev/null +++ b/src/utils.h @@ -0,0 +1,102 @@ +/* + * blogc: A blog compiler. + * Copyright (C) 2014-2016 Rafael G. Martins <rafael@rafaelmartins.eng.br> + * + * This program can be distributed under the terms of the BSD License. + * See the file LICENSE. + */ + +#ifndef _UTILS_H +#define _UTILS_H + +#include <stddef.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdarg.h> +#include <stdlib.h> + + +// memory + +typedef void (*sb_free_func_t) (void *ptr); + +void* sb_malloc(size_t size); +void* sb_realloc(void *ptr, size_t size); + + +// slist + +typedef struct _sb_slist_t { + struct _sb_slist_t *next; + void *data; +} sb_slist_t; + +sb_slist_t* sb_slist_append(sb_slist_t *l, void *data); +sb_slist_t* sb_slist_prepend(sb_slist_t *l, void *data); +void sb_slist_free(sb_slist_t *l); +void sb_slist_free_full(sb_slist_t *l, sb_free_func_t free_func); +size_t sb_slist_length(sb_slist_t *l); + + +// strfuncs + +char* sb_strdup(const char *s); +char* sb_strndup(const char *s, size_t n); +char* sb_strdup_vprintf(const char *format, va_list ap); +char* sb_strdup_printf(const char *format, ...); +bool sb_str_starts_with(const char *str, const char *prefix); +bool sb_str_ends_with(const char *str, const char *suffix); +char* sb_str_lstrip(char *str); +char* sb_str_rstrip(char *str); +char* sb_str_strip(char *str); +char** sb_str_split(const char *str, char c, unsigned int max_pieces); +char* sb_str_replace(const char *str, const char search, const char *replace); +void sb_strv_free(char **strv); +char* sb_strv_join(char **strv, const char *separator); +size_t sb_strv_length(char **strv); + + +// string + +typedef struct { + char *str; + size_t len; + size_t allocated_len; +} sb_string_t; + +sb_string_t* sb_string_new(void); +char* sb_string_free(sb_string_t *str, bool free_str); +sb_string_t* sb_string_dup(sb_string_t *str); +sb_string_t* sb_string_append_len(sb_string_t *str, const char *suffix, size_t len); +sb_string_t* sb_string_append(sb_string_t *str, const char *suffix); +sb_string_t* sb_string_append_c(sb_string_t *str, char c); +sb_string_t* sb_string_append_printf(sb_string_t *str, const char *format, ...); + + +// trie + +typedef struct _sb_trie_node_t { + char key; + void *data; + struct _sb_trie_node_t *next, *child; +} sb_trie_node_t; + +struct _sb_trie_t { + sb_trie_node_t *root; + sb_free_func_t free_func; +}; + +typedef struct _sb_trie_t sb_trie_t; + +typedef void (*sb_trie_foreach_func_t)(const char *key, void *data, + void *user_data); + +sb_trie_t* sb_trie_new(sb_free_func_t free_func); +void sb_trie_free(sb_trie_t *trie); +void sb_trie_insert(sb_trie_t *trie, const char *key, void *data); +void* sb_trie_lookup(sb_trie_t *trie, const char *key); +size_t sb_trie_size(sb_trie_t *trie); +void sb_trie_foreach(sb_trie_t *trie, sb_trie_foreach_func_t func, + void *user_data); + +#endif /* _UTILS_H */ diff --git a/src/utils/mem.c b/src/utils/mem.c deleted file mode 100644 index 693d555..0000000 --- a/src/utils/mem.c +++ /dev/null @@ -1,42 +0,0 @@ -/* - * blogc: A blog compiler. - * Copyright (C) 2014-2016 Rafael G. Martins <rafael@rafaelmartins.eng.br> - * - * This program can be distributed under the terms of the BSD License. - * See the file LICENSE. - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif /* HAVE_CONFIG_H */ - -#include <stdlib.h> -#include <stdio.h> -#include "utils.h" - - -void* -b_malloc(size_t size) -{ - // simple things simple! - void *rv = malloc(size); - if (rv == NULL) { - fprintf(stderr, "fatal error: Failed to allocate memory!\n"); - exit(1); - } - return rv; -} - - -void* -b_realloc(void *ptr, size_t size) -{ - // simple things even simpler :P - void *rv = realloc(ptr, size); - if (rv == NULL && size != 0) { - fprintf(stderr, "fatal error: Failed to reallocate memory!\n"); - free(ptr); - exit(1); - } - return rv; -} diff --git a/src/utils/slist.c b/src/utils/slist.c deleted file mode 100644 index 9753aa7..0000000 --- a/src/utils/slist.c +++ /dev/null @@ -1,68 +0,0 @@ -/* - * blogc: A blog compiler. - * Copyright (C) 2014-2016 Rafael G. Martins <rafael@rafaelmartins.eng.br> - * - * This program can be distributed under the terms of the BSD License. - * See the file LICENSE. - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif /* HAVE_CONFIG_H */ - -#include <stdlib.h> -#include "utils.h" - - -b_slist_t* -b_slist_append(b_slist_t *l, void *data) -{ - b_slist_t *node = malloc(sizeof(b_slist_t)); - if (node == NULL) { - l = NULL; - return l; - } - node->data = data; - node->next = NULL; - if (l == NULL) - l = node; - else { - b_slist_t *tmp; - for (tmp = l; tmp->next != NULL; tmp = tmp->next); - tmp->next = node; - } - return l; -} - - -void -b_slist_free_full(b_slist_t *l, b_free_func_t free_func) -{ - while (l != NULL) { - b_slist_t *tmp = l->next; - free_func(l->data); - free(l); - l = tmp; - } -} - - -void -b_slist_free(b_slist_t *l) -{ - while (l != NULL) { - b_slist_t *tmp = l->next; - free(l); - l = tmp; - } -} - - -unsigned int -b_slist_length(b_slist_t *l) -{ - unsigned int i; - b_slist_t *tmp; - for (tmp = l, i = 0; tmp != NULL; tmp = tmp->next, i++); - return i; -} diff --git a/src/utils/strings.c b/src/utils/strings.c deleted file mode 100644 index 3151612..0000000 --- a/src/utils/strings.c +++ /dev/null @@ -1,314 +0,0 @@ -/* - * blogc: A blog compiler. - * Copyright (C) 2014-2016 Rafael G. Martins <rafael@rafaelmartins.eng.br> - * - * This program can be distributed under the terms of the BSD License. - * See the file LICENSE. - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif /* HAVE_CONFIG_H */ - -#include <ctype.h> -#include <string.h> -#include <stdarg.h> -#include <stdbool.h> -#include <stdio.h> -#include <stdlib.h> -#include "utils.h" - - -char* -b_strdup(const char *s) -{ - if (s == NULL) - return NULL; - size_t l = strlen(s); - char *tmp = malloc(l + 1); - if (tmp == NULL) - return NULL; - memcpy(tmp, s, l + 1); - return tmp; -} - - -char* -b_strndup(const char *s, size_t n) -{ - if (s == NULL) - return NULL; - size_t l = strnlen(s, n); - char *tmp = malloc(l + 1); - if (tmp == NULL) - return NULL; - memcpy(tmp, s, l); - tmp[l] = '\0'; - return tmp; -} - - -char* -b_strdup_vprintf(const char *format, va_list ap) -{ - va_list ap2; - va_copy(ap2, ap); - int l = vsnprintf(NULL, 0, format, ap2); - va_end(ap2); - if (l < 0) - return NULL; - char *tmp = malloc(l + 1); - if (!tmp) - return NULL; - int l2 = vsnprintf(tmp, l + 1, format, ap); - if (l2 < 0) { - free(tmp); - return NULL; - } - return tmp; -} - - -char* -b_strdup_printf(const char *format, ...) -{ - va_list ap; - va_start(ap, format); - char *tmp = b_strdup_vprintf(format, ap); - va_end(ap); - return tmp; -} - - -bool -b_str_starts_with(const char *str, const char *prefix) -{ - int str_l = strlen(str); - int str_lp = strlen(prefix); - if (str_lp > str_l) - return false; - return strncmp(str, prefix, str_lp) == 0; -} - - -bool -b_str_ends_with(const char *str, const char *suffix) -{ - int str_l = strlen(str); - int str_ls = strlen(suffix); - if (str_ls > str_l) - return false; - return strcmp(str + str_l - str_ls, suffix) == 0; -} - - -char* -b_str_lstrip(char *str) -{ - if (str == NULL) - return NULL; - int i; - size_t str_len = strlen(str); - for (i = 0; i < str_len; i++) { - if ((str[i] != ' ') && (str[i] != '\t') && (str[i] != '\n') && - (str[i] != '\r') && (str[i] != '\t') && (str[i] != '\f') && - (str[i] != '\v')) - { - str += i; - break; - } - if (i == str_len - 1) { - str += str_len; - break; - } - } - return str; -} - - -char* -b_str_rstrip(char *str) -{ - if (str == NULL) - return NULL; - int i; - size_t str_len = strlen(str); - for (i = str_len - 1; i >= 0; i--) { - if ((str[i] != ' ') && (str[i] != '\t') && (str[i] != '\n') && - (str[i] != '\r') && (str[i] != '\t') && (str[i] != '\f') && - (str[i] != '\v')) - { - str[i + 1] = '\0'; - break; - } - if (i == 0) { - str[0] = '\0'; - break; - } - } - return str; -} - - -char* -b_str_strip(char *str) -{ - return b_str_lstrip(b_str_rstrip(str)); -} - - -char** -b_str_split(const char *str, char c, unsigned int max_pieces) -{ - if (!str) - return NULL; - char **rv = b_malloc(sizeof(char*)); - unsigned int i, start = 0, count = 0; - for (i = 0; i < strlen(str) + 1; i++) { - if (str[0] == '\0') - break; - if ((str[i] == c && (!max_pieces || count + 1 < max_pieces)) || str[i] == '\0') { - rv = b_realloc(rv, (count + 1) * sizeof(char*)); - rv[count] = b_malloc(i - start + 1); - memcpy(rv[count], str + start, i - start); - rv[count++][i - start] = '\0'; - start = i + 1; - } - } - rv = b_realloc(rv, (count + 1) * sizeof(char*)); - rv[count] = NULL; - return rv; -} - - -char* -b_str_replace(const char *str, const char search, const char *replace) -{ - char **pieces = b_str_split(str, search, 0); - if (pieces == NULL) - return NULL; - char* rv = b_strv_join((const char**) pieces, replace); - b_strv_free(pieces); - return rv; -} - - -void -b_strv_free(char **strv) -{ - if (strv == NULL) - return; - unsigned int i; - for (i = 0; strv[i] != NULL; i++) - free(strv[i]); - free(strv); -} - - -char* -b_strv_join(const char **strv, const char *separator) -{ - if (strv == NULL) - return NULL; - unsigned int i = 0; - b_string_t *str = b_string_new(); - for (i = 0; strv[i] != NULL; i++) { - str = b_string_append(str, strv[i]); - if (strv[i+1] != NULL) - str = b_string_append(str, separator); - } - return b_string_free(str, false); -} - - -unsigned int -b_strv_length(char **strv) -{ - if (!strv) - return 0; - unsigned int i; - for (i = 0; strv[i] != NULL; i++); - return i; -} - - -b_string_t* -b_string_new(void) -{ - b_string_t* rv = b_malloc(sizeof(b_string_t)); - rv->str = NULL; - rv->len = 0; - rv->allocated_len = 0; - - // initialize with empty string - rv = b_string_append(rv, ""); - - return rv; -} - - -char* -b_string_free(b_string_t *str, bool free_str) -{ - char *rv = NULL; - if (free_str) - free(str->str); - else - rv = str->str; - free(str); - return rv; -} - - -b_string_t* -b_string_append_len(b_string_t *str, const char *suffix, size_t len) -{ - if (suffix == NULL) - return str; - size_t old_len = str->len; - str->len += len; - if (str->len + 1 > str->allocated_len) { - str->allocated_len = (((str->len + 1) / B_STRING_CHUNK_SIZE) + 1) * B_STRING_CHUNK_SIZE; - str->str = b_realloc(str->str, str->allocated_len); - } - memcpy(str->str + old_len, suffix, len); - str->str[str->len] = '\0'; - return str; -} - - -b_string_t* -b_string_append(b_string_t *str, const char *suffix) -{ - if (suffix == NULL) - return str; - return b_string_append_len(str, suffix, strlen(suffix)); -} - - -b_string_t* -b_string_append_c(b_string_t *str, char c) -{ - size_t old_len = str->len; - str->len += 1; - if (str->len + 1 > str->allocated_len) { - str->allocated_len = (((str->len + 1) / B_STRING_CHUNK_SIZE) + 1) * B_STRING_CHUNK_SIZE; - str->str = b_realloc(str->str, str->allocated_len); - } - str->str[old_len] = c; - str->str[str->len] = '\0'; - return str; -} - - -b_string_t* -b_string_append_printf(b_string_t *str, const char *format, ...) -{ - va_list ap; - va_start(ap, format); - char *tmp = b_strdup_vprintf(format, ap); - va_end(ap); - str = b_string_append(str, tmp); - free(tmp); - return str; -} diff --git a/src/utils/trie.c b/src/utils/trie.c deleted file mode 100644 index 2e6a0d8..0000000 --- a/src/utils/trie.c +++ /dev/null @@ -1,199 +0,0 @@ -/* - * blogc: A blog compiler. - * Copyright (C) 2014-2016 Rafael G. Martins <rafael@rafaelmartins.eng.br> - * - * This program can be distributed under the terms of the BSD License. - * See the file LICENSE. - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif /* HAVE_CONFIG_H */ - -#include <stdlib.h> -#include "utils.h" - - -b_trie_t* -b_trie_new(b_free_func_t free_func) -{ - b_trie_t *trie = b_malloc(sizeof(b_trie_t)); - trie->root = NULL; - trie->free_func = free_func; - return trie; -} - - -static void -b_trie_free_node(b_trie_t *trie, b_trie_node_t *node) -{ - if (node == NULL) - return; - if (node->data != NULL && trie->free_func != NULL) - trie->free_func(node->data); - b_trie_free_node(trie, node->next); - b_trie_free_node(trie, node->child); - free(node); -} - - -void -b_trie_free(b_trie_t *trie) -{ - if (trie == NULL) - return; - b_trie_free_node(trie, trie->root); - free(trie); -} - - -void -b_trie_insert(b_trie_t *trie, const char *key, void *data) -{ - if (data == NULL || key == NULL) - return; - - b_trie_node_t *parent = NULL; - b_trie_node_t *previous; - b_trie_node_t *current; - b_trie_node_t *tmp; - - while (1) { - - if (trie->root == NULL || (parent != NULL && parent->child == NULL)) { - current = b_malloc(sizeof(b_trie_node_t)); - current->key = *key; - current->data = NULL; - current->next = NULL; - current->child = NULL; - if (trie->root == NULL) - trie->root = current; - else - parent->child = current; - parent = current; - goto clean; - } - - tmp = parent == NULL ? trie->root : parent->child; - previous = NULL; - - while (tmp != NULL && tmp->key != *key) { - previous = tmp; - tmp = tmp->next; - } - - parent = tmp; - - if (previous == NULL || parent != NULL) - goto clean; - - current = b_malloc(sizeof(b_trie_node_t)); - current->key = *key; - current->data = NULL; - current->next = NULL; - current->child = NULL; - previous->next = current; - parent = current; - -clean: - if (*key == '\0') { - if (parent->data != NULL && trie->free_func != NULL) - trie->free_func(parent->data); - parent->data = data; - break; - } - key++; - } -} - - -void* -b_trie_lookup(b_trie_t *trie, const char *key) -{ - if (trie == NULL || trie->root == NULL || key == NULL) - return NULL; - - b_trie_node_t *parent = trie->root; - b_trie_node_t *tmp; - while (1) { - for (tmp = parent; tmp != NULL; tmp = tmp->next) { - - if (tmp->key == *key) { - if (tmp->key == '\0') - return tmp->data; - parent = tmp->child; - break; - } - } - if (tmp == NULL) - return NULL; - - if (*key == '\0') - break; - key++; - } - return NULL; -} - - -static void -b_trie_size_node(b_trie_node_t *node, unsigned int *count) -{ - if (node == NULL) - return; - - if (node->key == '\0') - (*count)++; - - b_trie_size_node(node->next, count); - b_trie_size_node(node->child, count); -} - - -unsigned int -b_trie_size(b_trie_t *trie) -{ - if (trie == NULL) - return 0; - - unsigned int count = 0; - b_trie_size_node(trie->root, &count); - return count; -} - - -static void -b_trie_foreach_node(b_trie_node_t *node, b_string_t *str, void (*func)(const char *key, void *data)) -{ - if (node == NULL) - return; - - if (node->key == '\0') { - func(str->str, node->data); - b_string_free(str, true); - } - - if (node->child != NULL) { - b_string_t *child = b_string_new(); - child = b_string_append(child, str->str); - child = b_string_append_c(child, node->key); - b_trie_foreach_node(node->child, child, func); - } - - if (node->next != NULL) - b_trie_foreach_node(node->next, str, func); - - if (node->child != NULL && node->next == NULL) - b_string_free(str, true); -} - - -void -b_trie_foreach(b_trie_t *trie, void (*func)(const char *key, void *data)) -{ - if (trie->root == NULL) - return; - - b_string_t *str = b_string_new(); - b_trie_foreach_node(trie->root, str, func); -} diff --git a/src/utils/utils.h b/src/utils/utils.h deleted file mode 100644 index dc67497..0000000 --- a/src/utils/utils.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * blogc: A blog compiler. - * Copyright (C) 2014-2016 Rafael G. Martins <rafael@rafaelmartins.eng.br> - * - * This program can be distributed under the terms of the BSD License. - * See the file LICENSE. - */ - -#ifndef _UTILS_UTILS_H -#define _UTILS_UTILS_H - -#include <stdbool.h> -#include <stdlib.h> -#include <stdarg.h> - -#define B_STRING_CHUNK_SIZE 128 - -typedef void (*b_free_func_t) (void *ptr); - -typedef struct _b_slist_t { - struct _b_slist_t *next; - void *data; -} b_slist_t; - -typedef struct _b_string_t { - char *str; - size_t len; - size_t allocated_len; -} b_string_t; - -typedef struct _b_trie_node_t { - char key; - void *data; - struct _b_trie_node_t *next, *child; -} b_trie_node_t; - -typedef struct _b_trie_t { - b_trie_node_t *root; - b_free_func_t free_func; -} b_trie_t; - -b_slist_t* b_slist_append(b_slist_t *l, void *data); -void b_slist_free_full(b_slist_t *l, b_free_func_t free_func); -void b_slist_free(b_slist_t *l); -unsigned int b_slist_length(b_slist_t *l); - -char* b_strdup(const char *s); -char* b_strndup(const char *s, size_t n); -char* b_strdup_vprintf(const char *format, va_list ap); -char* b_strdup_printf(const char *format, ...); -bool b_str_starts_with(const char *str, const char *prefix); -bool b_str_ends_with(const char *str, const char *suffix); -char* b_str_lstrip(char *str); -char* b_str_rstrip(char *str); -char* b_str_strip(char *str); -char** b_str_split(const char *str, char c, unsigned int max_pieces); -char* b_str_replace(const char *str, const char search, const char *replace); -void b_strv_free(char **strv); -char* b_strv_join(const char **strv, const char *separator); -unsigned int b_strv_length(char **strv); - -b_string_t* b_string_new(void); -char* b_string_free(b_string_t *str, bool free_str); -b_string_t* b_string_append_len(b_string_t *str, const char *suffix, size_t len); -b_string_t* b_string_append(b_string_t *str, const char *suffix); -b_string_t* b_string_append_c(b_string_t *str, char c); -b_string_t* b_string_append_printf(b_string_t *str, const char *format, ...); - -b_trie_t* b_trie_new(b_free_func_t free_func); -void b_trie_free(b_trie_t *trie); -void b_trie_insert(b_trie_t *trie, const char *key, void *data); -void* b_trie_lookup(b_trie_t *trie, const char *key); -unsigned int b_trie_size(b_trie_t *trie); -void b_trie_foreach(b_trie_t *trie, void (*func)(const char *key, void *data)); - -void* b_malloc(size_t size); -void* b_realloc(void *ptr, size_t size); - -#endif /* _UTILS_UTILS_H */ |