diff options
Diffstat (limited to 'src/blogc-make')
-rw-r--r-- | src/blogc-make/atom.c | 137 | ||||
-rw-r--r-- | src/blogc-make/atom.h | 19 | ||||
-rw-r--r-- | src/blogc-make/ctx.c | 409 | ||||
-rw-r--r-- | src/blogc-make/ctx.h | 84 | ||||
-rw-r--r-- | src/blogc-make/exec-native.c | 192 | ||||
-rw-r--r-- | src/blogc-make/exec-native.h | 20 | ||||
-rw-r--r-- | src/blogc-make/exec.c | 498 | ||||
-rw-r--r-- | src/blogc-make/exec.h | 35 | ||||
-rw-r--r-- | src/blogc-make/httpd.c | 121 | ||||
-rw-r--r-- | src/blogc-make/httpd.h | 19 | ||||
-rw-r--r-- | src/blogc-make/main.c | 134 | ||||
-rw-r--r-- | src/blogc-make/reloader.c | 116 | ||||
-rw-r--r-- | src/blogc-make/reloader.h | 20 | ||||
-rw-r--r-- | src/blogc-make/rules.c | 1078 | ||||
-rw-r--r-- | src/blogc-make/rules.h | 36 | ||||
-rw-r--r-- | src/blogc-make/settings.c | 203 | ||||
-rw-r--r-- | src/blogc-make/settings.h | 29 | ||||
-rw-r--r-- | src/blogc-make/utils.c | 128 | ||||
-rw-r--r-- | src/blogc-make/utils.h | 20 |
19 files changed, 0 insertions, 3298 deletions
diff --git a/src/blogc-make/atom.c b/src/blogc-make/atom.c deleted file mode 100644 index 0b8cfd1..0000000 --- a/src/blogc-make/atom.c +++ /dev/null @@ -1,137 +0,0 @@ -/* - * blogc: A blog compiler. - * Copyright (C) 2014-2020 Rafael G. Martins <rafael@rafaelmartins.eng.br> - * - * This program can be distributed under the terms of the BSD License. - * See the file LICENSE. - */ - -#include <stdlib.h> -#include <string.h> -#include <errno.h> -#include <unistd.h> -#include "../common/error.h" -#include "../common/utils.h" -#include "settings.h" -#include "utils.h" -#include "atom.h" - -static const char atom_template[] = - "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" - "<feed xmlns=\"http://www.w3.org/2005/Atom\">\n" - " <title type=\"text\">{{ SITE_TITLE }}{%% ifdef FILTER_TAG %%} - " - "{{ FILTER_TAG }}{%% endif %%}</title>\n" - " <id>{{ BASE_DOMAIN }}{{ BASE_URL }}%s</id>\n" - " <updated>{{ DATE_FIRST_FORMATTED }}</updated>\n" - " <link href=\"{{ BASE_DOMAIN }}{{ BASE_URL }}/\" />\n" - " <link href=\"{{ BASE_DOMAIN }}{{ BASE_URL }}%s\" rel=\"self\" />\n" - " <author>\n" - " <name>{{ AUTHOR_NAME }}</name>\n" - " <email>{{ AUTHOR_EMAIL }}</email>\n" - " </author>\n" - " <subtitle type=\"text\">{{ SITE_TAGLINE }}</subtitle>\n" - " {%%- block listing %%}\n" - " <entry>\n" - " <title type=\"text\">{{ TITLE }}</title>\n" - " <id>{{ BASE_DOMAIN }}{{ BASE_URL }}%s</id>\n" - " <updated>{{ DATE_FORMATTED }}</updated>\n" - " <published>{{ DATE_FORMATTED }}</published>\n" - " <link href=\"{{ BASE_DOMAIN }}{{ BASE_URL }}%s\" />\n" - " <author>\n" - " <name>{{ AUTHOR_NAME }}</name>\n" - " <email>{{ AUTHOR_EMAIL }}</email>\n" - " </author>\n" - " <content type=\"html\"><![CDATA[{{ CONTENT }}]]></content>\n" - " </entry>\n" - " {%%- endblock %%}\n" - "</feed>\n"; - - -char* -bm_atom_generate(bm_settings_t *settings) -{ - if (settings == NULL) - return NULL; - - const char *atom_prefix = bc_trie_lookup(settings->settings, "atom_prefix"); - const char *atom_ext = bc_trie_lookup(settings->settings, "atom_ext"); - const char *post_prefix = bc_trie_lookup(settings->settings, "post_prefix"); - const char *post_ext = bc_trie_lookup(settings->settings, "html_ext"); - - bc_string_t *atom_url = bc_string_new(); - - if (atom_prefix[0] != '\0') - bc_string_append_c(atom_url, '/'); - - bc_string_append(atom_url, atom_prefix); - bc_string_append(atom_url, "{% ifdef FILTER_TAG %}/{{ FILTER_TAG }}"); - - if (atom_prefix[0] == '\0' && atom_ext[0] != '/') - bc_string_append(atom_url, "{% else %}/index"); - - bc_string_append(atom_url, "{% endif %}"); - bc_string_append(atom_url, atom_ext); - - char *post_url = bm_generate_filename(NULL, post_prefix, "{{ FILENAME }}", - post_ext); - - char *rv = bc_strdup_printf(atom_template, atom_url->str, atom_url->str, - post_url, post_url); - - bc_string_free(atom_url, true); - free(post_url); - - return rv; -} - - -char* -bm_atom_deploy(bm_settings_t *settings, bc_error_t **err) -{ - if (settings == NULL || err == NULL || *err != NULL) - return NULL; - - if (NULL != bc_trie_lookup(settings->settings, "atom_legacy_entry_id")) { - *err = bc_error_new_printf(BLOGC_MAKE_ERROR_ATOM, - "'atom_legacy_entry_id' setting is not supported anymore. see " - "https://blogc.rgm.io/news/blogc-0.16.1/ for details"); - return NULL; - } - - // this is not really portable - char fname[] = "/tmp/blogc-make_XXXXXX"; - int fd; - if (-1 == (fd = mkstemp(fname))) { - *err = bc_error_new_printf(BLOGC_MAKE_ERROR_ATOM, - "Failed to create temporary atom template: %s", strerror(errno)); - return NULL; - } - - char *content = bm_atom_generate(settings); - if (content == NULL) { - close(fd); - unlink(fname); - return NULL; - } - - if (-1 == write(fd, content, strlen(content))) { - *err = bc_error_new_printf(BLOGC_MAKE_ERROR_ATOM, - "Failed to write to temporary atom template: %s", strerror(errno)); - free(content); - close(fd); - unlink(fname); - return NULL; - } - - free(content); - close(fd); - - return bc_strdup(fname); -} - - -void -bm_atom_destroy(const char *fname) -{ - unlink(fname); -} diff --git a/src/blogc-make/atom.h b/src/blogc-make/atom.h deleted file mode 100644 index 29a6dcb..0000000 --- a/src/blogc-make/atom.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * blogc: A blog compiler. - * Copyright (C) 2014-2019 Rafael G. Martins <rafael@rafaelmartins.eng.br> - * - * This program can be distributed under the terms of the BSD License. - * See the file LICENSE. - */ - -#ifndef _MAKE_ATOM_H -#define _MAKE_ATOM_H - -#include "../common/error.h" -#include "settings.h" - -char* bm_atom_generate(bm_settings_t *settings); -char* bm_atom_deploy(bm_settings_t *settings, bc_error_t **err); -void bm_atom_destroy(const char *fname); - -#endif /* _MAKE_ATOM_H */ diff --git a/src/blogc-make/ctx.c b/src/blogc-make/ctx.c deleted file mode 100644 index b8d23dd..0000000 --- a/src/blogc-make/ctx.c +++ /dev/null @@ -1,409 +0,0 @@ -/* - * blogc: A blog compiler. - * Copyright (C) 2014-2020 Rafael G. Martins <rafael@rafaelmartins.eng.br> - * - * This program can be distributed under the terms of the BSD License. - * See the file LICENSE. - */ - -#include <sys/stat.h> -#include <sys/types.h> -#include <dirent.h> -#include <errno.h> -#include <libgen.h> -#include <limits.h> -#include <time.h> -#include <stdlib.h> -#include <stdbool.h> -#include <string.h> -#include <unistd.h> -#include "../common/error.h" -#include "../common/file.h" -#include "../common/utils.h" -#include "atom.h" -#include "settings.h" -#include "exec.h" -#include "utils.h" -#include "ctx.h" - - -bm_filectx_t* -bm_filectx_new(bm_ctx_t *ctx, const char *filename, const char *slug, - struct stat *st) -{ - if (ctx == NULL || filename == NULL) - return NULL; - - char *f = filename[0] == '/' ? bc_strdup(filename) : - bc_strdup_printf("%s/%s", ctx->root_dir, filename); - - bm_filectx_t *rv = bc_malloc(sizeof(bm_filectx_t)); - rv->path = f; - rv->short_path = bc_strdup(filename); - rv->slug = bc_strdup(slug); - - if (st == NULL) { - struct stat buf; - - if (0 != stat(f, &buf)) { - rv->tv_sec = 0; - rv->tv_nsec = 0; - rv->readable = false; - return rv; - } - - st = &buf; - } - - // if it isn't NULL the file exists for sure - rv->tv_sec = st->st_mtim_tv_sec; - rv->tv_nsec = st->st_mtim_tv_nsec; - rv->readable = true; - return rv; -} - - -bc_slist_t* -bm_filectx_new_r(bc_slist_t *l, bm_ctx_t *ctx, const char *filename) -{ - if (ctx == NULL || filename == NULL) - return NULL; - - char *f = filename[0] == '/' ? bc_strdup(filename) : - bc_strdup_printf("%s/%s", ctx->root_dir, filename); - - struct stat buf; - if (0 != stat(f, &buf)) { - free(f); - return l; - } - - if (S_ISDIR(buf.st_mode)) { - DIR *dir = opendir(f); - if (dir == NULL) { - free(f); - return l; - } - - struct dirent *e; - while (NULL != (e = readdir(dir))) { - if ((0 == strcmp(e->d_name, ".")) || (0 == strcmp(e->d_name, ".."))) - continue; - char *tmp = bc_strdup_printf("%s/%s", filename, e->d_name); - l = bm_filectx_new_r(l, ctx, tmp); - free(tmp); - } - - closedir(dir); - free(f); - return l; - } - - l = bc_slist_append(l, bm_filectx_new(ctx, filename, NULL, &buf)); - free(f); - return l; -} - - -bool -bm_filectx_changed(bm_filectx_t *ctx, time_t *tv_sec, long *tv_nsec) -{ - if (ctx == NULL) - return false; - - struct stat buf; - - if (0 == stat(ctx->path, &buf)) { - if (buf.st_mtim_tv_sec == ctx->tv_sec) { - if (buf.st_mtim_tv_nsec > ctx->tv_nsec) { - if (tv_sec != NULL) - *tv_sec = buf.st_mtim_tv_sec; - if (tv_nsec != NULL) - *tv_nsec = buf.st_mtim_tv_nsec; - return true; - } - } - else if (buf.st_mtim_tv_sec > ctx->tv_sec) { - if (tv_sec != NULL) - *tv_sec = buf.st_mtim_tv_sec; - if (tv_nsec != NULL) - *tv_nsec = buf.st_mtim_tv_nsec; - return true; - } - } - - return false; -} - - -void -bm_filectx_reload(bm_filectx_t *ctx) -{ - if (ctx == NULL) - return; - - time_t tv_sec; - long tv_nsec; - - if (!bm_filectx_changed(ctx, &tv_sec, &tv_nsec)) - return; - - ctx->tv_sec = tv_sec; - ctx->tv_nsec = tv_nsec; - ctx->readable = true; -} - - -void -bm_filectx_free(bm_filectx_t *fctx) -{ - if (fctx == NULL) - return; - free(fctx->path); - free(fctx->short_path); - free(fctx->slug); - free(fctx); -} - - -bm_ctx_t* -bm_ctx_new(bm_ctx_t *base, const char *settings_file, const char *argv0, - bc_error_t **err) -{ - if (settings_file == NULL || err == NULL || *err != NULL) - return NULL; - - char *abs_filename = bm_abspath(settings_file, err); - if (*err != NULL) - return NULL; - - size_t content_len; - char *content = bc_file_get_contents(abs_filename, true, &content_len, - err); - if (*err != NULL) { - free(abs_filename); - return NULL; - } - - bm_settings_t *settings = bm_settings_parse(content, content_len, err); - if (settings == NULL || *err != NULL) { - free(abs_filename); - free(content); - return NULL; - } - free(content); - - const char *template_dir = bc_trie_lookup(settings->settings, "template_dir"); - if (template_dir == NULL) - template_dir = ""; - - char *atom_template = NULL; - bool atom_template_tmp = false; - const char *atom_template_conf = bc_trie_lookup(settings->settings, - "atom_template"); - if (atom_template_conf != NULL) { - atom_template = bc_strdup_printf("%s/%s", template_dir, atom_template_conf); - } - else { - atom_template = bm_atom_deploy(settings, err); - atom_template_tmp = true; - if (*err != NULL) { - free(abs_filename); - bm_settings_free(settings); - return NULL; - } - } - - bm_ctx_t *rv = NULL; - if (base == NULL) { - rv = bc_malloc(sizeof(bm_ctx_t)); - rv->blogc = bm_exec_find_binary(argv0, "blogc", "BLOGC"); - rv->blogc_runserver = bm_exec_find_binary(argv0, "blogc-runserver", - "BLOGC_RUNSERVER"); - rv->dev = false; - rv->verbose = false; - } - else { - bm_ctx_free_internal(base); - rv = base; - } - rv->settings = settings; - - rv->settings_fctx = bm_filectx_new(rv, abs_filename, NULL, NULL); - rv->root_dir = bc_strdup(dirname(abs_filename)); - free(abs_filename); - - const char *output_dir = getenv("OUTPUT_DIR"); - rv->short_output_dir = bc_strdup(output_dir != NULL ? output_dir : "_build"); - - if (rv->short_output_dir[0] == '/') { - rv->output_dir = bc_strdup(rv->short_output_dir); - } - else { - rv->output_dir = bc_strdup_printf("%s/%s", rv->root_dir, - rv->short_output_dir); - } - - // can't return null and set error after this! - - char *main_template = bc_strdup_printf("%s/%s", template_dir, - bm_ctx_settings_lookup(rv, "main_template")); - rv->main_template_fctx = bm_filectx_new(rv, main_template, NULL, NULL); - free(main_template); - - rv->atom_template_tmp = atom_template_tmp; - rv->atom_template_fctx = bm_filectx_new(rv, atom_template, NULL, NULL); - free(atom_template); - - const char *content_dir = bm_ctx_settings_lookup(rv, "content_dir"); - const char *post_prefix = bm_ctx_settings_lookup(rv, "post_prefix"); - const char *source_ext = bm_ctx_settings_lookup(rv, "source_ext"); - const char *listing_entry = bm_ctx_settings_lookup(rv, "listing_entry"); - - rv->listing_entry_fctx = NULL; - if (listing_entry != NULL) { - char *f = bm_generate_filename(content_dir, NULL, listing_entry, source_ext); - rv->listing_entry_fctx = bm_filectx_new(rv, f, listing_entry, NULL); - free(f); - } - - rv->posts_fctx = NULL; - if (settings->posts != NULL) { - for (size_t i = 0; settings->posts[i] != NULL; i++) { - char *f = bm_generate_filename(content_dir, post_prefix, - settings->posts[i], source_ext); - rv->posts_fctx = bc_slist_append(rv->posts_fctx, - bm_filectx_new(rv, f, settings->posts[i], NULL)); - free(f); - } - } - - rv->pages_fctx = NULL; - if (settings->pages != NULL) { - for (size_t i = 0; settings->pages[i] != NULL; i++) { - char *f = bm_generate_filename(content_dir, NULL, settings->pages[i], - source_ext); - rv->pages_fctx = bc_slist_append(rv->pages_fctx, - bm_filectx_new(rv, f, settings->pages[i], NULL)); - free(f); - } - } - - rv->copy_fctx = NULL; - if (settings->copy != NULL) { - for (size_t i = 0; settings->copy[i] != NULL; i++) { - rv->copy_fctx = bm_filectx_new_r(rv->copy_fctx, rv, - settings->copy[i]); - } - } - - return rv; -} - - -bool -bm_ctx_reload(bm_ctx_t **ctx) -{ - if (*ctx == NULL || (*ctx)->settings_fctx == NULL) - return false; - - if (bm_filectx_changed((*ctx)->settings_fctx, NULL, NULL)) { - // reload everything! we could just reload settings_fctx, as this - // would force rebuilding everything, but we need to know new/deleted - // files - - // needs to dup path, because it may be freed when reloading. - char *tmp = bc_strdup((*ctx)->settings_fctx->path); - bc_error_t *err = NULL; - *ctx = bm_ctx_new(*ctx, tmp, NULL, &err); - free(tmp); - if (err != NULL) { - bc_error_print(err, "blogc-make"); - bc_error_free(err); - return false; - } - return true; - } - - bm_filectx_reload((*ctx)->main_template_fctx); - bm_filectx_reload((*ctx)->atom_template_fctx); - bm_filectx_reload((*ctx)->listing_entry_fctx); - - for (bc_slist_t *tmp = (*ctx)->posts_fctx; tmp != NULL; tmp = tmp->next) - bm_filectx_reload((bm_filectx_t*) tmp->data); - - for (bc_slist_t *tmp = (*ctx)->pages_fctx; tmp != NULL; tmp = tmp->next) - bm_filectx_reload((bm_filectx_t*) tmp->data); - - for (bc_slist_t *tmp = (*ctx)->copy_fctx; tmp != NULL; tmp = tmp->next) - bm_filectx_reload((bm_filectx_t*) tmp->data); - - return true; -} - - -void -bm_ctx_free_internal(bm_ctx_t *ctx) -{ - if (ctx == NULL) - return; - - bm_settings_free(ctx->settings); - ctx->settings = NULL; - - free(ctx->root_dir); - ctx->root_dir = NULL; - free(ctx->short_output_dir); - ctx->short_output_dir = NULL; - free(ctx->output_dir); - ctx->output_dir = NULL; - - if (ctx->atom_template_tmp) - bm_atom_destroy(ctx->atom_template_fctx->path); - ctx->atom_template_tmp = false; - - bm_filectx_free(ctx->main_template_fctx); - ctx->main_template_fctx = NULL; - bm_filectx_free(ctx->atom_template_fctx); - ctx->atom_template_fctx = NULL; - bm_filectx_free(ctx->settings_fctx); - ctx->settings_fctx = NULL; - bm_filectx_free(ctx->listing_entry_fctx); - ctx->listing_entry_fctx = NULL; - - bc_slist_free_full(ctx->posts_fctx, (bc_free_func_t) bm_filectx_free); - ctx->posts_fctx = NULL; - bc_slist_free_full(ctx->pages_fctx, (bc_free_func_t) bm_filectx_free); - ctx->pages_fctx = NULL; - bc_slist_free_full(ctx->copy_fctx, (bc_free_func_t) bm_filectx_free); - ctx->copy_fctx = NULL; -} - - -void -bm_ctx_free(bm_ctx_t *ctx) -{ - if (ctx == NULL) - return; - bm_ctx_free_internal(ctx); - free(ctx->blogc); - free(ctx->blogc_runserver); - free(ctx); -} - - -const char* -bm_ctx_settings_lookup(bm_ctx_t *ctx, const char *key) -{ - if (ctx == NULL || ctx->settings == NULL || ctx->settings->settings == NULL) - return NULL; - return bc_trie_lookup(ctx->settings->settings, key); -} - - -const char* -bm_ctx_settings_lookup_str(bm_ctx_t *ctx, const char *key) -{ - const char *rv = bm_ctx_settings_lookup(ctx, key); - return rv == NULL ? "" : rv; -} diff --git a/src/blogc-make/ctx.h b/src/blogc-make/ctx.h deleted file mode 100644 index a66d51c..0000000 --- a/src/blogc-make/ctx.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * blogc: A blog compiler. - * Copyright (C) 2014-2019 Rafael G. Martins <rafael@rafaelmartins.eng.br> - * - * This program can be distributed under the terms of the BSD License. - * See the file LICENSE. - */ - -#ifndef _MAKE_CTX_H -#define _MAKE_CTX_H - -#include <sys/stat.h> -#include <stdbool.h> -#include <time.h> -#include "settings.h" -#include "../common/error.h" -#include "../common/utils.h" - -#ifdef __APPLE__ -#define st_mtim_tv_sec st_mtimespec.tv_sec -#define st_mtim_tv_nsec st_mtimespec.tv_nsec -#endif - -#ifdef __ANDROID__ -#define st_mtim_tv_sec st_mtime -#define st_mtim_tv_nsec st_mtime_nsec -#endif - -#ifndef st_mtim_tv_sec -#define st_mtim_tv_sec st_mtim.tv_sec -#endif -#ifndef st_mtim_tv_nsec -#define st_mtim_tv_nsec st_mtim.tv_nsec -#endif - - -typedef struct { - char *path; - char *short_path; - char *slug; - time_t tv_sec; - long tv_nsec; - bool readable; -} bm_filectx_t; - -typedef struct { - char *blogc; - char *blogc_runserver; - - bool dev; - bool verbose; - bool atom_template_tmp; - - bm_settings_t *settings; - - char *root_dir; - char *output_dir; - char *short_output_dir; - - bm_filectx_t *main_template_fctx; - bm_filectx_t *atom_template_fctx; - bm_filectx_t *settings_fctx; - bm_filectx_t *listing_entry_fctx; - - bc_slist_t *posts_fctx; - bc_slist_t *pages_fctx; - bc_slist_t *copy_fctx; -} bm_ctx_t; - -bm_filectx_t* bm_filectx_new(bm_ctx_t *ctx, const char *filename, const char *slug, - struct stat *st); -bc_slist_t* bm_filectx_new_r(bc_slist_t *l, bm_ctx_t *ctx, const char *filename); -bool bm_filectx_changed(bm_filectx_t *ctx, time_t *tv_sec, long *tv_nsec); -void bm_filectx_reload(bm_filectx_t *ctx); -void bm_filectx_free(bm_filectx_t *fctx); -bm_ctx_t* bm_ctx_new(bm_ctx_t *base, const char *settings_file, - const char *argv0, bc_error_t **err); -bool bm_ctx_reload(bm_ctx_t **ctx); -void bm_ctx_free_internal(bm_ctx_t *ctx); -void bm_ctx_free(bm_ctx_t *ctx); -const char* bm_ctx_settings_lookup(bm_ctx_t *ctx, const char *key); -const char* bm_ctx_settings_lookup_str(bm_ctx_t *ctx, const char *key); - -#endif /* _MAKE_CTX_H */ diff --git a/src/blogc-make/exec-native.c b/src/blogc-make/exec-native.c deleted file mode 100644 index 6d7f58f..0000000 --- a/src/blogc-make/exec-native.c +++ /dev/null @@ -1,192 +0,0 @@ -/* - * blogc: A blog compiler. - * Copyright (C) 2014-2020 Rafael G. Martins <rafael@rafaelmartins.eng.br> - * - * This program can be distributed under the terms of the BSD License. - * See the file LICENSE. - */ - -#include <stdbool.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <sys/stat.h> -#include <dirent.h> -#include <fcntl.h> -#include <unistd.h> -#include <libgen.h> -#include <errno.h> -#include "../common/error.h" -#include "../common/file.h" -#include "../common/utils.h" -#include "exec-native.h" -#include "ctx.h" - - -int -bm_exec_native_cp(bm_filectx_t *source, bm_filectx_t *dest, bool verbose) -{ - if (verbose) - printf("Copying '%s' to '%s'\n", source->path, dest->path); - else - printf(" COPY %s\n", dest->short_path); - fflush(stdout); - - char *fname = bc_strdup(dest->path); - for (char *tmp = fname; *tmp != '\0'; tmp++) { - if (*tmp != '/' && *tmp != '\\') - continue; - char bkp = *tmp; - *tmp = '\0'; - if ((strlen(fname) > 0) && - (-1 == mkdir(fname, 0777)) && - (errno != EEXIST)) - { - fprintf(stderr, "blogc-make: error: failed to create output " - "directory (%s): %s\n", fname, strerror(errno)); - free(fname); - return 1; - } - *tmp = bkp; - } - free(fname); - - int fd_from = open(source->path, O_RDONLY); - if (fd_from < 0) { - fprintf(stderr, "blogc-make: error: failed to open source file to copy " - " (%s): %s\n", source->path, strerror(errno)); - return 1; - } - - int fd_to = open(dest->path, O_WRONLY | O_CREAT | O_TRUNC, 0666); - if (fd_to < 0) { - fprintf(stderr, "blogc-make: error: failed to open destination file to " - "copy (%s): %s\n", dest->path, strerror(errno)); - close(fd_from); - return 1; - } - - ssize_t nread; - char buffer[BC_FILE_CHUNK_SIZE]; - while (0 < (nread = read(fd_from, buffer, BC_FILE_CHUNK_SIZE))) { - char *out_ptr = buffer; - do { - ssize_t nwritten = write(fd_to, out_ptr, nread); - if (nwritten == -1) { - fprintf(stderr, "blogc-make: error: failed to write to " - "destination file (%s): %s\n", dest->path, strerror(errno)); - close(fd_from); - close(fd_to); - return 1; - } - nread -= nwritten; - out_ptr += nwritten; - } while (nread > 0); - } - - close(fd_from); - close(fd_to); - - return 0; -} - - -bool -bm_exec_native_is_empty_dir(const char *dir, bc_error_t **err) -{ - DIR *d = opendir(dir); - if (d == NULL) { - if (errno == ENOENT) { - return true; - } - if (err != NULL) { - *err = bc_error_new_printf(0, "failed to open directory (%s): %s\n", - dir, strerror(errno)); - } - return true; - } - - struct dirent *e; - size_t count = 0; - while (NULL != (e = readdir(d))) { - if ((0 == strcmp(e->d_name, ".")) || (0 == strcmp(e->d_name, ".."))) - continue; - count++; - break; - } - - if (0 != closedir(d)) { - if (err != NULL) { - *err = bc_error_new_printf(0, "failed to close directory (%s): %s\n", - dir, strerror(errno)); - } - return true; - } - - return count == 0; -} - - -int -bm_exec_native_rm(const char *output_dir, bm_filectx_t *dest, bool verbose) -{ - if (verbose) - printf("Removing file '%s'\n", dest->path); - else - printf(" CLEAN %s\n", dest->short_path); - fflush(stdout); - - if (0 != unlink(dest->path)) { - fprintf(stderr, "blogc-make: error: failed to remove file (%s): %s\n", - dest->path, strerror(errno)); - return 1; - } - - int rv = 0; - - // blame freebsd's libc for all of those memory allocations around dirname - // calls! - char *short_dir = bc_strdup(dirname(dest->short_path)); - char *dir = bc_strdup(dirname(dest->path)); - - bc_error_t *err = NULL; - - while ((0 != strcmp(short_dir, ".")) && (0 != strcmp(short_dir, "/"))) { - bool empty = bm_exec_native_is_empty_dir(dir, &err); - if (err != NULL) { - fprintf(stderr, "blogc-make: error: %s\n", err->msg); - bc_error_free(err); - rv = 1; - break; - } - if (!empty) { - break; - } - if (verbose) { - printf("Removing directory '%s'\n", dir); - fflush(stdout); - } - if (0 != rmdir(dir)) { - fprintf(stderr, - "blogc-make: error: failed to remove directory(%s): %s\n", - dir, strerror(errno)); - rv = 1; - break; - } - if (0 == strcmp(dir, output_dir)) { - break; - } - - char *tmp = short_dir; - short_dir = bc_strdup(dirname(short_dir)); - free(tmp); - tmp = dir; - dir = bc_strdup(dirname(dir)); - free(tmp); - } - - free(short_dir); - free(dir); - - return rv; -} diff --git a/src/blogc-make/exec-native.h b/src/blogc-make/exec-native.h deleted file mode 100644 index 56a1da1..0000000 --- a/src/blogc-make/exec-native.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * blogc: A blog compiler. - * Copyright (C) 2014-2019 Rafael G. Martins <rafael@rafaelmartins.eng.br> - * - * This program can be distributed under the terms of the BSD License. - * See the file LICENSE. - */ - -#ifndef _MAKE_EXEC_NATIVE_H -#define _MAKE_EXEC_NATIVE_H - -#include <stdbool.h> -#include "../common/error.h" -#include "ctx.h" - -int bm_exec_native_cp(bm_filectx_t *source, bm_filectx_t *dest, bool verbose); -bool bm_exec_native_is_empty_dir(const char *dir, bc_error_t **err); -int bm_exec_native_rm(const char *output_dir, bm_filectx_t *dest, bool verbose); - -#endif /* _MAKE_EXEC_NATIVE_H */ diff --git a/src/blogc-make/exec.c b/src/blogc-make/exec.c deleted file mode 100644 index 4b1f6df..0000000 --- a/src/blogc-make/exec.c +++ /dev/null @@ -1,498 +0,0 @@ -/* - * blogc: A blog compiler. - * Copyright (C) 2014-2020 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 */ - -#ifdef HAVE_SYSEXITS_H -#include <sysexits.h> -#else -#define EX_CONFIG 78 -#endif /* HAVE_SYSEXITS_H */ - -#include <stdbool.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <unistd.h> -#include <sys/wait.h> -#include <errno.h> -#include <libgen.h> -#include "../common/compat.h" -#include "../common/error.h" -#include "../common/file.h" -#include "../common/utils.h" -#include "ctx.h" -#include "exec.h" -#include "settings.h" - - -char* -bm_exec_find_binary(const char *argv0, const char *bin, const char *env) -{ -#ifdef MAKE_EMBEDDED - // for embedded blogc-make, if we are looking for blogc, we just return - // argv0, because the static binary may not be named `blogc`, and we - // prefer to use our own `blogc` instead of some other version around. - if (argv0 != NULL && bin != NULL && (0 == strcmp(bin, "blogc"))) { - return bc_shell_quote(argv0); - } -#endif - - // first try: env var - const char *env_bin = getenv(env); - if (env_bin != NULL) { - return bc_shell_quote(env_bin); - } - - // second try: same dir as current exec - // we rely on some assumptions here: - // - // - if binary is called without a directory, that means location will - // be resolved from $PATH, we don't care about doing a dir lookup. - // - we *never* call chdir anywhere in the code, so we can assume - // that relative paths will work as expected. - // - windows path sep is not supported - if (argv0 != NULL && (NULL != strchr(argv0, '/'))) { - char *path = bc_strdup(argv0); - char *dir = bc_strdup(dirname(path)); - free(path); - char *tmp = bc_strdup_printf("%s/%s", dir, bin); - free(dir); - if (0 == access(tmp, X_OK)) { - char *rv = bc_shell_quote(tmp); - free(tmp); - return rv; - } - free(tmp); - } - - // last try: $PATH - return bc_strdup(bin); -} - - -int -bm_exec_command(const char *cmd, const char *input, char **output, - char **error, bc_error_t **err) -{ - if (err == NULL || *err != NULL) - return 1; - - int fd_in[2]; - if (-1 == pipe(fd_in)) { - *err = bc_error_new_printf(BLOGC_MAKE_ERROR_EXEC, - "Failed to create stdin pipe: %s", strerror(errno)); - return 1; - } - - int fd_out[2]; - if (-1 == pipe(fd_out)) { - *err = bc_error_new_printf(BLOGC_MAKE_ERROR_EXEC, - "Failed to create stdout pipe: %s", strerror(errno)); - close(fd_in[0]); - close(fd_in[1]); - return 1; - } - - int fd_err[2]; - if (-1 == pipe(fd_err)) { - *err = bc_error_new_printf(BLOGC_MAKE_ERROR_EXEC, - "Failed to create stderr pipe: %s", strerror(errno)); - close(fd_in[0]); - close(fd_in[1]); - close(fd_out[0]); - close(fd_out[1]); - return 1; - } - - pid_t pid = fork(); - if (pid == -1) { - *err = bc_error_new_printf(BLOGC_MAKE_ERROR_EXEC, - "Failed to fork: %s", strerror(errno)); - close(fd_in[0]); - close(fd_in[1]); - close(fd_out[0]); - close(fd_out[1]); - close(fd_err[0]); - close(fd_err[1]); - return 1; - } - - // child - if (pid == 0) { - close(fd_in[1]); - close(fd_out[0]); - close(fd_err[0]); - - dup2(fd_in[0], STDIN_FILENO); - dup2(fd_out[1], STDOUT_FILENO); - dup2(fd_err[1], STDERR_FILENO); - - char *const argv[] = { - "/bin/sh", - "-c", - (char*) cmd, - NULL, - }; - - execv(argv[0], argv); - - exit(1); - } - - // parent - close(fd_in[0]); - close(fd_out[1]); - close(fd_err[1]); - - if (input != NULL) { - if (-1 == write(fd_in[1], input, strlen(input))) { - *err = bc_error_new_printf(BLOGC_MAKE_ERROR_EXEC, - "Failed to write to stdin pipe: %s", strerror(errno)); - close(fd_in[1]); - close(fd_out[0]); - close(fd_err[0]); - return 1; - } - } - - close(fd_in[1]); - - char buffer[BC_FILE_CHUNK_SIZE]; - ssize_t s; - - bc_string_t *out = NULL; - while(0 != (s = read(fd_out[0], buffer, BC_FILE_CHUNK_SIZE))) { - if (s == -1) { - *err = bc_error_new_printf(BLOGC_MAKE_ERROR_EXEC, - "Failed to read from stdout pipe: %s", strerror(errno)); - close(fd_out[0]); - close(fd_err[0]); - bc_string_free(out, true); - return 1; - } - if (out == NULL) { - out = bc_string_new(); - } - bc_string_append_len(out, buffer, s); - } - if (out != NULL) { - *output = bc_string_free(out, false); - } - close(fd_out[0]); - - out = NULL; - while(0 != (s = read(fd_err[0], buffer, BC_FILE_CHUNK_SIZE))) { - if (s == -1) { - *err = bc_error_new_printf(BLOGC_MAKE_ERROR_EXEC, - "Failed to read from stderr pipe: %s", strerror(errno)); - close(fd_err[0]); - bc_string_free(out, true); - return 1; - } - if (out == NULL) - out = bc_string_new(); - bc_string_append_len(out, buffer, s); - } - if (out != NULL) { - *error = bc_string_free(out, false); - } - close(fd_err[0]); - - int status; - waitpid(pid, &status, 0); - - return bc_compat_status_code(status); -} - - -static void -list_variables(const char *key, const char *value, bc_string_t *str) -{ - char *tmp = bc_shell_quote(value); - bc_string_append_printf(str, " -D %s=%s", key, tmp); - free(tmp); -} - - -char* -bm_exec_build_blogc_cmd(const char *blogc_bin, bm_settings_t *settings, - bc_trie_t *global_variables, bc_trie_t *local_variables, const char *print, - bool listing, const char *listing_entry, const char *template, - const char *output, bool dev, bool sources_stdin) -{ - bc_string_t *rv = bc_string_new(); - - const char *locale = NULL; - if (settings != NULL) { - locale = bc_trie_lookup(settings->settings, "locale"); - } - if (locale != NULL) { - char *tmp = bc_shell_quote(locale); - bc_string_append_printf(rv, "LC_ALL=%s ", tmp); - free(tmp); - } - - bc_string_append(rv, blogc_bin); - - if (settings != NULL) { - if (settings->tags != NULL) { - char *tags = bc_strv_join(settings->tags, " "); - bc_string_append_printf(rv, " -D MAKE_TAGS='%s'", tags); - free(tags); - } - - bc_trie_foreach(settings->global, - (bc_trie_foreach_func_t) list_variables, rv); - } - - bc_trie_foreach(global_variables, (bc_trie_foreach_func_t) list_variables, rv); - bc_trie_foreach(local_variables, (bc_trie_foreach_func_t) list_variables, rv); - - if (dev) { - bc_string_append(rv, " -D MAKE_ENV_DEV=1 -D MAKE_ENV='dev'"); - } - - if (print != NULL) { - bc_string_append_printf(rv, " -p %s", print); - } - - if (listing) { - bc_string_append(rv, " -l"); - if (listing_entry != NULL) { - char *tmp = bc_shell_quote(listing_entry); - bc_string_append_printf(rv, " -e %s", tmp); - free(tmp); - } - } - - if (template != NULL) { - char *tmp = bc_shell_quote(template); - bc_string_append_printf(rv, " -t %s", tmp); - free(tmp); - } - - if (output != NULL) { - char *tmp = bc_shell_quote(output); - bc_string_append_printf(rv, " -o %s", tmp); - free(tmp); - } - - if (sources_stdin) { - bc_string_append(rv, " -i"); - } - - return bc_string_free(rv, false); -} - - -int -bm_exec_blogc(bm_ctx_t *ctx, bc_trie_t *global_variables, bc_trie_t *local_variables, - bool listing, bm_filectx_t *listing_entry, bm_filectx_t *template, - bm_filectx_t *output, bc_slist_t *sources, bool only_first_source) -{ - if (ctx == NULL) - return 1; - - bc_string_t *input = bc_string_new(); - for (bc_slist_t *l = sources; l != NULL; l = l->next) { - bc_string_append_printf(input, "%s\n", ((bm_filectx_t*) l->data)->path); - if (only_first_source) - break; - } - - char *cmd = bm_exec_build_blogc_cmd(ctx->blogc, ctx->settings, global_variables, - local_variables, NULL, listing, listing_entry == NULL ? NULL : listing_entry->path, - template->path, output->path, ctx->dev, input->len > 0); - - if (ctx->verbose) - printf("%s\n", cmd); - else - printf(" BLOGC %s\n", output->short_path); - fflush(stdout); - - char *out = NULL; - char *err = NULL; - bc_error_t *error = NULL; - - int rv = bm_exec_command(cmd, input->str, &out, &err, &error); - - if (error != NULL) { - bc_error_print(error, "blogc-make"); - free(cmd); - free(out); - free(err); - bc_string_free(input, true); - bc_error_free(error); - return 1; - } - - if (rv != 0 && ctx->verbose) { - fprintf(stderr, - "blogc-make: error: Failed to execute command.\n" - "\n" - "STATUS CODE: %d\n", rv); - if (input->len > 0) { - fprintf(stderr, "\nSTDIN:\n" - "----------------------------->8-----------------------------\n" - "%s\n" - "----------------------------->8-----------------------------\n", - bc_str_strip(input->str)); - } - if (out != NULL) { - fprintf(stderr, "\nSTDOUT:\n" - "----------------------------->8-----------------------------\n" - "%s\n" - "----------------------------->8-----------------------------\n", - bc_str_strip(out)); - } - if (err != NULL) { - fprintf(stderr, "\nSTDERR:\n" - "----------------------------->8-----------------------------\n" - "%s\n" - "----------------------------->8-----------------------------\n", - bc_str_strip(err)); - } - fprintf(stderr, "\n"); - } - else if (err != NULL) { - fprintf(stderr, "%s\n", err); - } - - bc_string_free(input, true); - free(cmd); - free(out); - free(err); - - return rv == 127 ? 1 : rv; -} - - -char* -bm_exec_blogc_get_variable(bm_ctx_t *ctx, bc_trie_t *global_variables, - bc_trie_t *local_variables, const char *variable, bool listing, - bc_slist_t *sources, bool only_first_source) -{ - if (ctx == NULL) - return NULL; - - bc_string_t *input = bc_string_new(); - for (bc_slist_t *l = sources; l != NULL; l = l->next) { - bc_string_append_printf(input, "%s\n", ((bm_filectx_t*) l->data)->path); - if (only_first_source) - break; - } - - char *cmd = bm_exec_build_blogc_cmd(ctx->blogc, ctx->settings, global_variables, - local_variables, variable, listing, NULL, NULL, NULL, ctx->dev, input->len > 0); - - if (ctx->verbose) - printf("%s\n", cmd); - fflush(stdout); - - char *out = NULL; - char *err = NULL; - bc_error_t *error = NULL; - - int rv = bm_exec_command(cmd, input->str, &out, &err, &error); - - if (error != NULL) { - bc_error_print(error, "blogc-make"); - bc_error_free(error); - bc_string_free(input, true); - free(cmd); - free(out); - free(err); - return NULL; - } - - if (rv != 0) { - if (rv != EX_CONFIG) - fprintf(stderr, "blogc-make: error: %s\n", bc_str_strip(err)); - bc_string_free(input, true); - free(cmd); - free(out); - free(err); - return NULL; - } - - char *val = NULL; - if (out != NULL) - val = bc_strndup(out, strlen(out) - 1); - - bc_string_free(input, true); - free(cmd); - free(out); - free(err); - - return val; -} - - -int -bm_exec_blogc_runserver(bm_ctx_t *ctx, const char *host, const char *port, - const char *threads) -{ - if (ctx == NULL) - return 1; - - bc_string_t *cmd = bc_string_new(); - - bc_string_append(cmd, ctx->blogc_runserver); - - if (host != NULL) { - char *tmp = bc_shell_quote(host); - bc_string_append_printf(cmd, " -t %s", tmp); - free(tmp); - } - - if (port != NULL) { - char *tmp = bc_shell_quote(port); - bc_string_append_printf(cmd, " -p %s", tmp); - free(tmp); - } - - if (threads != NULL) { - char *tmp = bc_shell_quote(threads); - bc_string_append_printf(cmd, " -m %s", tmp); - free(tmp); - } - - char *tmp = bc_shell_quote(ctx->output_dir); - bc_string_append_printf(cmd, " %s", tmp); - free(tmp); - - if (ctx->verbose) - printf("%s\n\n", cmd->str); - else - printf("\n"); - fflush(stdout); - - // we don't need pipes to run blogc-runserver, because it is "interactive" - int status = system(cmd->str); - int rv = bc_compat_status_code(status); - bc_string_free(cmd, true); - - if (rv != 0 && rv != 130) { - if (rv == 127) { - fprintf(stderr, - "blogc-make: error: blogc-runserver command not found. Maybe " - "it is not installed?\n"); - rv = 1; // blogc-make exists, so we should not return 127 - } - else { - fprintf(stderr, - "blogc-make: error: Failed to execute command, returned " - "status code: %d\n", rv); - } - } - - return rv; -} diff --git a/src/blogc-make/exec.h b/src/blogc-make/exec.h deleted file mode 100644 index 6bc206f..0000000 --- a/src/blogc-make/exec.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * blogc: A blog compiler. - * Copyright (C) 2014-2019 Rafael G. Martins <rafael@rafaelmartins.eng.br> - * - * This program can be distributed under the terms of the BSD License. - * See the file LICENSE. - */ - -#ifndef _MAKE_EXEC_H -#define _MAKE_EXEC_H - -#include <stdbool.h> -#include "../common/error.h" -#include "../common/utils.h" -#include "ctx.h" -#include "settings.h" - -char* bm_exec_find_binary(const char *argv0, const char *bin, const char *env); -int bm_exec_command(const char *cmd, const char *input, char **output, - char **error, bc_error_t **err); -char* bm_exec_build_blogc_cmd(const char *blogc_bin, bm_settings_t *settings, - bc_trie_t *global_variables, bc_trie_t *local_variables, const char *print, - bool listing, const char *listing_entry, const char *template, - const char *output, bool dev, bool sources_stdin); -int bm_exec_blogc(bm_ctx_t *ctx, bc_trie_t *global_variables, - bc_trie_t *local_variables, bool listing, bm_filectx_t *listing_entry, - bm_filectx_t *template, bm_filectx_t *output, bc_slist_t *sources, - bool only_first_source); -char* bm_exec_blogc_get_variable(bm_ctx_t *ctx, bc_trie_t *global_variables, - bc_trie_t *local_variables, const char *variable, bool listing, - bc_slist_t *sources, bool only_first_source); -int bm_exec_blogc_runserver(bm_ctx_t *ctx, const char *host, const char *port, - const char *threads); - -#endif /* _MAKE_EXEC_H */ diff --git a/src/blogc-make/httpd.c b/src/blogc-make/httpd.c deleted file mode 100644 index c352da0..0000000 --- a/src/blogc-make/httpd.c +++ /dev/null @@ -1,121 +0,0 @@ -/* - * blogc: A blog compiler. - * Copyright (C) 2014-2020 Rafael G. Martins <rafael@rafaelmartins.eng.br> - * - * This program can be distributed under the terms of the BSD License. - * See the file LICENSE. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <pthread.h> -#include <unistd.h> -#include "../common/utils.h" -#include "ctx.h" -#include "exec.h" -#include "reloader.h" -#include "httpd.h" - -// we are not going to unit-test these functions, then printing errors -// directly is not a big issue - - -typedef struct { - bm_ctx_t *ctx; - bc_trie_t *args; -} bm_httpd_t; - -static pthread_mutex_t mutex_httpd_starting = PTHREAD_MUTEX_INITIALIZER; -static bool httpd_starting = false; - - -static void* -httpd_thread(void *arg) -{ - bm_httpd_t *httpd = arg; - - pthread_mutex_lock(&mutex_httpd_starting); - httpd_starting = true; - pthread_mutex_unlock(&mutex_httpd_starting); - - int rv = bm_exec_blogc_runserver(httpd->ctx, bc_trie_lookup(httpd->args, "host"), - bc_trie_lookup(httpd->args, "port"), bc_trie_lookup(httpd->args, "threads")); - - pthread_mutex_lock(&mutex_httpd_starting); - httpd_starting = false; - pthread_mutex_unlock(&mutex_httpd_starting); - - free(httpd); - - // stop the reloader - bm_reloader_stop(rv); - - return NULL; -} - - -int -bm_httpd_run(bm_ctx_t **ctx, bm_rule_exec_func_t rule_exec, bc_slist_t *outputs, - bc_trie_t *args) -{ - pthread_mutex_lock(&mutex_httpd_starting); - bool starting = httpd_starting; - pthread_mutex_unlock(&mutex_httpd_starting); - - if (starting) { - fprintf(stderr, "blogc-make: error: httpd already running\n"); - return 1; - } - - int err; - - pthread_attr_t attr; - if (0 != (err = pthread_attr_init(&attr))) { - fprintf(stderr, "blogc-make: error: failed to initialize httpd " - "thread attributes: %s\n", strerror(err)); - return 1; - } - - // we run the thread detached, because we don't want to wait it to join - // before exiting. the OS can clean it properly - if (0 != (err = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED))) { - fprintf(stderr, "blogc-make: error: failed to mark httpd thread as " - "detached: %s\n", strerror(err)); - return 1; - } - - bm_httpd_t *rv = bc_malloc(sizeof(bm_httpd_t)); - rv->ctx = *ctx; - rv->args = args; - - pthread_t thread; - if (0 != (err = pthread_create(&thread, &attr, httpd_thread, rv))) { - fprintf(stderr, "blogc-make: error: failed to create httpd " - "thread: %s\n", strerror(err)); - free(rv); - return 1; - } - - // we could use some pthread_*_timedwait() apis here, but I decided to - // just use simple mutexes for the sake of portability. - size_t count = 0; - while (true) { - pthread_mutex_lock(&mutex_httpd_starting); - starting = httpd_starting; - pthread_mutex_unlock(&mutex_httpd_starting); - - if (starting) - break; - - if (++count > 100) { - fprintf(stderr, "blogc-make: error: failed to start httpd thread: " - "too many retries\n"); - // rv will leak, but it is not safe to free here - return 1; - } - usleep(100000); - } - - return bm_reloader_run(ctx, rule_exec, outputs, args); -} diff --git a/src/blogc-make/httpd.h b/src/blogc-make/httpd.h deleted file mode 100644 index b0fa87d..0000000 --- a/src/blogc-make/httpd.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * blogc: A blog compiler. - * Copyright (C) 2014-2019 Rafael G. Martins <rafael@rafaelmartins.eng.br> - * - * This program can be distributed under the terms of the BSD License. - * See the file LICENSE. - */ - -#ifndef _MAKE_HTTPD_H -#define _MAKE_HTTPD_H - -#include "../common/utils.h" -#include "ctx.h" -#include "rules.h" - -int bm_httpd_run(bm_ctx_t **ctx, bm_rule_exec_func_t rule_exec, bc_slist_t *outputs, - bc_trie_t *args); - -#endif /* _MAKE_HTTPD_H */ diff --git a/src/blogc-make/main.c b/src/blogc-make/main.c deleted file mode 100644 index 5b4a030..0000000 --- a/src/blogc-make/main.c +++ /dev/null @@ -1,134 +0,0 @@ -/* - * blogc: A blog compiler. - * Copyright (C) 2014-2019 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 <locale.h> -#include <stdbool.h> -#include <stdio.h> -#include <stdlib.h> -#include "../common/error.h" -#include "../common/utils.h" -#include "ctx.h" -#include "rules.h" - - -static void -print_help(void) -{ - printf( - "usage:\n" - " blogc-make [-h] [-v] [-D] [-V] [-f FILE] [RULE ...]\n" - " - A simple build tool for blogc.\n" - "\n" - "positional arguments:\n" - " RULE build rule(s) to run. can include comma-separated\n" - " key-value pairs of rule arguments in the format\n" - " RULE:arg1=value1,arg2=value2,... (default: all)\n" - "\n" - "optional arguments:\n" - " -h show this help message and exit\n" - " -v show version and exit\n" - " -D build for development environment\n" - " -V be verbose when executing commands\n" - " -f FILE read FILE as blogcfile\n"); - bm_rule_print_help(); -} - - -static void -print_usage(void) -{ - printf("usage: blogc-make [-h] [-v] [-D] [-V] [-f FILE] [RULE ...]\n"); -} - - -int -#ifdef MAKE_EMBEDDED -bm_main(int argc, char **argv) -#else -main(int argc, char **argv) -#endif -{ - setlocale(LC_ALL, ""); - - int rv = 0; - bc_error_t *err = NULL; - - bc_slist_t *rules = NULL; - bool verbose = false; - bool dev = false; - char *blogcfile = NULL; - bm_ctx_t *ctx = NULL; - - for (size_t 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 'D': - dev = true; - break; - case 'V': - verbose = true; - break; - case 'f': - if (argv[i][2] != '\0') - blogcfile = bc_strdup(argv[i] + 2); - else if (i + 1 < argc) - blogcfile = bc_strdup(argv[++i]); - break; -#ifdef MAKE_EMBEDDED - case 'm': - // no-op, for embedding into blogc binary. - break; -#endif - default: - print_usage(); - fprintf(stderr, "blogc-make: error: invalid argument: " - "-%c\n", argv[i][1]); - rv = 1; - goto cleanup; - } - } - else { - rules = bc_slist_append(rules, bc_strdup(argv[i])); - } - } - - if (rules == NULL) { - rules = bc_slist_append(rules, bc_strdup("all")); - } - - ctx = bm_ctx_new(NULL, blogcfile ? blogcfile : "blogcfile", - argc > 0 ? argv[0] : NULL, &err); - if (err != NULL) { - bc_error_print(err, "blogc-make"); - rv = 1; - goto cleanup; - } - ctx->dev = dev; - ctx->verbose = verbose; - - rv = bm_rule_executor(ctx, rules); - -cleanup: - - bc_slist_free_full(rules, free); - free(blogcfile); - bm_ctx_free(ctx); - bc_error_free(err); - - return rv; -} diff --git a/src/blogc-make/reloader.c b/src/blogc-make/reloader.c deleted file mode 100644 index fea8bd4..0000000 --- a/src/blogc-make/reloader.c +++ /dev/null @@ -1,116 +0,0 @@ -/* - * blogc: A blog compiler. - * Copyright (C) 2014-2019 Rafael G. Martins <rafael@rafaelmartins.eng.br> - * - * This program can be distributed under the terms of the BSD License. - * See the file LICENSE. - */ - -#include <stdbool.h> -#include <stdio.h> -#include <stdlib.h> -#include <signal.h> -#include <string.h> -#include <unistd.h> -#include <pthread.h> -#include <errno.h> -#include "../common/utils.h" -#include "ctx.h" -#include "rules.h" -#include "reloader.h" - -// we are not going to unit-test these functions, then printing errors -// directly is not a big issue - -static pthread_mutex_t mutex_running = PTHREAD_MUTEX_INITIALIZER; -static bool running = false; -static int reloader_status_code = 0; -static void (*handler_func)(int) = NULL; - -static void -sig_handler(int signum) -{ - bm_reloader_stop(signum + 128); -} - - -int -bm_reloader_run(bm_ctx_t **ctx, bm_rule_exec_func_t rule_exec, - bc_slist_t *outputs, bc_trie_t *args) -{ - // install ^C handler - struct sigaction current_action; - if (sigaction(SIGINT, NULL, ¤t_action) < 0) { - fprintf(stderr, "blogc-make: failed to run reloader: %s\n", strerror(errno)); - return 1; - } - if (current_action.sa_handler != sig_handler) { // not installed yet - // backup current handler - pthread_mutex_lock(&mutex_running); - handler_func = current_action.sa_handler; - pthread_mutex_unlock(&mutex_running); - - // set new handler - struct sigaction new_action; - new_action.sa_handler = sig_handler; - sigemptyset(&new_action.sa_mask); - new_action.sa_flags = 0; - if (sigaction(SIGINT, &new_action, NULL) < 0) { - fprintf(stderr, "blogc-make: failed to run reloader: %s\n", - strerror(errno)); - return 1; - } - } - - pthread_mutex_lock(&mutex_running); - running = true; - pthread_mutex_unlock(&mutex_running); - - while (running) { - if (!bm_ctx_reload(ctx)) { - fprintf(stderr, "blogc-make: warning: failed to reload context. " - "retrying in 5 seconds ...\n\n"); - sleep(5); - continue; - } - if (0 != rule_exec(*ctx, outputs, args)) { - fprintf(stderr, "blogc-make: warning: failed to rebuild website. " - "retrying in 5 seconds ...\n\n"); - sleep(5); - continue; - } - sleep(1); - } - - return reloader_status_code; -} - - -void -bm_reloader_stop(int status_code) -{ - pthread_mutex_lock(&mutex_running); - - running = false; - reloader_status_code = status_code; - - // reraise if SIGINT - if (status_code == SIGINT + 128) { - - // reinstall old ^C handler - struct sigaction new_action; - new_action.sa_handler = handler_func; - sigemptyset(&new_action.sa_mask); - new_action.sa_flags = 0; - sigaction(SIGINT, &new_action, NULL); - - // run it - raise(SIGINT); - - // SIGINT will usually kill the process, but in the case that the - // `handler_func` prevents it, our custom handler will be reinstalled - // by `bm_reloader_run`. - } - - pthread_mutex_unlock(&mutex_running); -} diff --git a/src/blogc-make/reloader.h b/src/blogc-make/reloader.h deleted file mode 100644 index f3fddf4..0000000 --- a/src/blogc-make/reloader.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * blogc: A blog compiler. - * Copyright (C) 2014-2019 Rafael G. Martins <rafael@rafaelmartins.eng.br> - * - * This program can be distributed under the terms of the BSD License. - * See the file LICENSE. - */ - -#ifndef _MAKE_RELOADER_H -#define _MAKE_RELOADER_H - -#include "../common/utils.h" -#include "ctx.h" -#include "rules.h" - -int bm_reloader_run(bm_ctx_t **ctx, bm_rule_exec_func_t rule_exec, - bc_slist_t *outputs, bc_trie_t *args); -void bm_reloader_stop(int status_code); - -#endif /* _MAKE_RELOADER_H */ diff --git a/src/blogc-make/rules.c b/src/blogc-make/rules.c deleted file mode 100644 index 7d92b95..0000000 --- a/src/blogc-make/rules.c +++ /dev/null @@ -1,1078 +0,0 @@ -/* - * blogc: A blog compiler. - * Copyright (C) 2014-2020 Rafael G. Martins <rafael@rafaelmartins.eng.br> - * - * This program can be distributed under the terms of the BSD License. - * See the file LICENSE. - */ - -#include <stdbool.h> -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <time.h> -#include "../common/utils.h" -#include "atom.h" -#include "ctx.h" -#include "exec.h" -#include "exec-native.h" -#include "httpd.h" -#include "reloader.h" -#include "settings.h" -#include "utils.h" -#include "rules.h" - - -static void -posts_ordering(bm_ctx_t *ctx, bc_trie_t *variables, const char *variable) -{ - if (ctx == NULL) - return; // something is wrong, let's not add any variable - - const char *value = bm_ctx_settings_lookup_str(ctx, variable); - bool asc = 0 == strcasecmp(value, "asc"); - bool sort = bc_str_to_bool(bm_ctx_settings_lookup(ctx, "posts_sort")); - - if (sort) { - bc_trie_insert(variables, "FILTER_SORT", bc_strdup("1")); - } - - if ((sort && asc) || (!sort && !asc)) { - bc_trie_insert(variables, "FILTER_REVERSE", bc_strdup("1")); - } -} - - -static void -posts_pagination(bm_ctx_t *ctx, bc_trie_t *variables, const char *variable) -{ - if (ctx == NULL) - return; // something is wrong, let's not add any variable - - long posts_per_page = strtol(bm_ctx_settings_lookup_str(ctx, variable), NULL, 10); - if (posts_per_page >= 0) { - bc_trie_insert(variables, "FILTER_PAGE", bc_strdup("1")); - bc_trie_insert(variables, "FILTER_PER_PAGE", - bc_strdup(bm_ctx_settings_lookup(ctx, variable))); - } -} - - -static bool -posts_pagination_enabled(bm_ctx_t *ctx, const char *variable) -{ - if (ctx == NULL) - return false; - - long posts_per_page = strtol(bm_ctx_settings_lookup_str(ctx, variable), NULL, 10); - return posts_per_page != 0; -} - - -// INDEX RULE - -static bc_slist_t* -index_outputlist(bm_ctx_t *ctx) -{ - if (ctx == NULL || ctx->settings->posts == NULL) - return NULL; - - if (!posts_pagination_enabled(ctx, "posts_per_page")) - return NULL; - - bc_slist_t *rv = NULL; - - const char *index_prefix = bm_ctx_settings_lookup(ctx, "index_prefix"); - const char *html_ext = bm_ctx_settings_lookup(ctx, "html_ext"); - - char *f = bm_generate_filename(ctx->short_output_dir, index_prefix, NULL, - html_ext); - rv = bc_slist_append(rv, bm_filectx_new(ctx, f, NULL, NULL)); - free(f); - - return rv; -} - -static int -index_exec(bm_ctx_t *ctx, bc_slist_t *outputs, bc_trie_t *args) -{ - if (ctx == NULL || ctx->settings->posts == NULL) - return 0; - - int rv = 0; - - bc_trie_t *variables = bc_trie_new(free); - posts_pagination(ctx, variables, "posts_per_page"); - posts_ordering(ctx, variables, "html_order"); - bc_trie_insert(variables, "DATE_FORMAT", - bc_strdup(bm_ctx_settings_lookup_str(ctx, "date_format"))); - bc_trie_insert(variables, "MAKE_RULE", bc_strdup("index")); - bc_trie_insert(variables, "MAKE_TYPE", bc_strdup("post")); - - for (bc_slist_t *l = outputs; l != NULL; l = l->next) { - bm_filectx_t *fctx = l->data; - if (fctx == NULL) - continue; - if (bm_rule_need_rebuild(ctx->posts_fctx, ctx->settings_fctx, - ctx->listing_entry_fctx, ctx->main_template_fctx, fctx, false)) - { - rv = bm_exec_blogc(ctx, variables, NULL, true, ctx->listing_entry_fctx, - ctx->main_template_fctx, fctx, ctx->posts_fctx, false); - if (rv != 0) - break; - } - } - - bc_trie_free(variables); - - return rv; -} - - -// ATOM RULE - -static bc_slist_t* -atom_outputlist(bm_ctx_t *ctx) -{ - if (ctx == NULL || ctx->settings->posts == NULL) - return NULL; - - if (!posts_pagination_enabled(ctx, "atom_posts_per_page")) - return NULL; - - bc_slist_t *rv = NULL; - - const char *atom_prefix = bm_ctx_settings_lookup(ctx, "atom_prefix"); - const char *atom_ext = bm_ctx_settings_lookup(ctx, "atom_ext"); - - char *f = bm_generate_filename(ctx->short_output_dir, atom_prefix, NULL, - atom_ext); - rv = bc_slist_append(rv, bm_filectx_new(ctx, f, NULL, NULL)); - free(f); - - return rv; -} - -static int -atom_exec(bm_ctx_t *ctx, bc_slist_t *outputs, bc_trie_t *args) -{ - if (ctx == NULL || ctx->settings->posts == NULL) - return 0; - - int rv = 0; - - bc_trie_t *variables = bc_trie_new(free); - posts_pagination(ctx, variables, "atom_posts_per_page"); - posts_ordering(ctx, variables, "atom_order"); - bc_trie_insert(variables, "DATE_FORMAT", bc_strdup("%Y-%m-%dT%H:%M:%SZ")); - bc_trie_insert(variables, "MAKE_RULE", bc_strdup("atom")); - bc_trie_insert(variables, "MAKE_TYPE", bc_strdup("atom")); - - for (bc_slist_t *l = outputs; l != NULL; l = l->next) { - bm_filectx_t *fctx = l->data; - if (fctx == NULL) - continue; - if (bm_rule_need_rebuild(ctx->posts_fctx, ctx->settings_fctx, NULL, - ctx->atom_template_tmp ? NULL : ctx->atom_template_fctx, - fctx, false)) - { - rv = bm_exec_blogc(ctx, variables, NULL, true, NULL, ctx->atom_template_fctx, - fctx, ctx->posts_fctx, false); - if (rv != 0) - break; - } - } - - bc_trie_free(variables); - - return rv; -} - - -// ATOM TAGS RULE - -static bc_slist_t* -atom_tags_outputlist(bm_ctx_t *ctx) -{ - if (ctx == NULL || ctx->settings->posts == NULL || ctx->settings->tags == NULL) - return NULL; - - if (!posts_pagination_enabled(ctx, "atom_posts_per_page")) - return NULL; - - bc_slist_t *rv = NULL; - - const char *atom_prefix = bm_ctx_settings_lookup(ctx, "atom_prefix"); - const char *atom_ext = bm_ctx_settings_lookup(ctx, "atom_ext"); - - for (size_t i = 0; ctx->settings->tags[i] != NULL; i++) { - char *f = bm_generate_filename(ctx->short_output_dir, atom_prefix, - ctx->settings->tags[i], atom_ext); - rv = bc_slist_append(rv, bm_filectx_new(ctx, f, NULL, NULL)); - free(f); - } - - return rv; -} - -static int -atom_tags_exec(bm_ctx_t *ctx, bc_slist_t *outputs, bc_trie_t *args) -{ - if (ctx == NULL || ctx->settings->posts == NULL || ctx->settings->tags == NULL) - return 0; - - int rv = 0; - size_t i = 0; - - bc_trie_t *variables = bc_trie_new(free); - posts_pagination(ctx, variables, "atom_posts_per_page"); - posts_ordering(ctx, variables, "atom_order"); - bc_trie_insert(variables, "DATE_FORMAT", bc_strdup("%Y-%m-%dT%H:%M:%SZ")); - bc_trie_insert(variables, "MAKE_RULE", bc_strdup("atom_tags")); - bc_trie_insert(variables, "MAKE_TYPE", bc_strdup("atom")); - - for (bc_slist_t *l = outputs; l != NULL; l = l->next, i++) { - bm_filectx_t *fctx = l->data; - if (fctx == NULL) - continue; - - bc_trie_insert(variables, "FILTER_TAG", - bc_strdup(ctx->settings->tags[i])); - - if (bm_rule_need_rebuild(ctx->posts_fctx, ctx->settings_fctx, NULL, - ctx->atom_template_tmp ? NULL : ctx->atom_template_fctx, - fctx, false)) - { - rv = bm_exec_blogc(ctx, variables, NULL, true, NULL, ctx->atom_template_fctx, - fctx, ctx->posts_fctx, false); - if (rv != 0) - break; - } - } - - bc_trie_free(variables); - - return rv; -} - - -// PAGINATION RULE - -static bc_slist_t* -pagination_outputlist(bm_ctx_t *ctx) -{ - if (ctx == NULL || ctx->settings->posts == NULL) - return NULL; - - if (!posts_pagination_enabled(ctx, "posts_per_page")) - return NULL; - - bc_trie_t *variables = bc_trie_new(free); - posts_pagination(ctx, variables, "posts_per_page"); - - char *last_page = bm_exec_blogc_get_variable(ctx, variables, NULL, "LAST_PAGE", - true, ctx->posts_fctx, false); - - bc_trie_free(variables); - - if (last_page == NULL) - return NULL; - - long pages = strtol(last_page, NULL, 10); - free(last_page); - - bc_slist_t *rv = NULL; - - const char *pagination_prefix = bm_ctx_settings_lookup(ctx, "pagination_prefix"); - const char *html_ext = bm_ctx_settings_lookup(ctx, "html_ext"); - - for (size_t i = 0; i < pages; i++) { - char *j = bc_strdup_printf("%d", i + 1); - char *f = bm_generate_filename(ctx->short_output_dir, pagination_prefix, - j, html_ext); - rv = bc_slist_append(rv, bm_filectx_new(ctx, f, NULL, NULL)); - free(j); - free(f); - } - - return rv; -} - -static int -pagination_exec(bm_ctx_t *ctx, bc_slist_t *outputs, bc_trie_t *args) -{ - if (ctx == NULL || ctx->settings->posts == NULL) - return 0; - - int rv = 0; - size_t page = 1; - - bc_trie_t *variables = bc_trie_new(free); - // not using posts_pagination because we set FILTER_PAGE anyway, and the - // first value inserted in that function would be useless - bc_trie_insert(variables, "FILTER_PER_PAGE", - bc_strdup(bm_ctx_settings_lookup_str(ctx, "posts_per_page"))); - posts_ordering(ctx, variables, "html_order"); - bc_trie_insert(variables, "DATE_FORMAT", - bc_strdup(bm_ctx_settings_lookup_str(ctx, "date_format"))); - bc_trie_insert(variables, "MAKE_RULE", bc_strdup("pagination")); - bc_trie_insert(variables, "MAKE_TYPE", bc_strdup("post")); - - for (bc_slist_t *l = outputs; l != NULL; l = l->next, page++) { - bm_filectx_t *fctx = l->data; - if (fctx == NULL) - continue; - bc_trie_insert(variables, "FILTER_PAGE", bc_strdup_printf("%zu", page)); - if (bm_rule_need_rebuild(ctx->posts_fctx, ctx->settings_fctx, - ctx->listing_entry_fctx, ctx->main_template_fctx, fctx, false)) - { - rv = bm_exec_blogc(ctx, variables, NULL, true, ctx->listing_entry_fctx, - ctx->main_template_fctx, fctx, ctx->posts_fctx, false); - if (rv != 0) - break; - } - } - - bc_trie_free(variables); - - return rv; -} - - -// PAGINATION TAGS RULE - -static bc_slist_t* -pagination_tags_outputlist(bm_ctx_t *ctx) -{ - if (ctx == NULL || ctx->settings->posts == NULL || ctx->settings->tags == NULL) - return NULL; - - if (!posts_pagination_enabled(ctx, "posts_per_page")) - return NULL; - - bc_trie_t *variables = bc_trie_new(free); - posts_pagination(ctx, variables, "posts_per_page"); - - const char *tag_prefix = bm_ctx_settings_lookup(ctx, "tag_prefix"); - const char *pagination_prefix = bm_ctx_settings_lookup(ctx, "pagination_prefix"); - const char *html_ext = bm_ctx_settings_lookup(ctx, "html_ext"); - - bc_slist_t *rv = NULL; - - for (size_t k = 0; ctx->settings->tags[k] != NULL; k++) { - bc_trie_t *local = bc_trie_new(free); - bc_trie_insert(local, "FILTER_TAG", bc_strdup(ctx->settings->tags[k])); - - char *last_page = bm_exec_blogc_get_variable(ctx, variables, local, - "LAST_PAGE", true, ctx->posts_fctx, false); - - bc_trie_free(local); - - if (last_page == NULL) - continue; - - long pages = strtol(last_page, NULL, 10); - free(last_page); - - for (size_t i = 0; i < pages; i++) { - char *j = bc_strdup_printf("%d", i + 1); - char *f = bm_generate_filename2(ctx->short_output_dir, tag_prefix, - ctx->settings->tags[k], pagination_prefix, j, html_ext); - rv = bc_slist_append(rv, bm_filectx_new(ctx, f, NULL, NULL)); - free(j); - free(f); - } - } - - bc_trie_free(variables); - - return rv; -} - -static int -pagination_tags_exec(bm_ctx_t *ctx, bc_slist_t *outputs, bc_trie_t *args) -{ - if (ctx == NULL || ctx->settings->posts == NULL || ctx->settings->tags == NULL) - return 0; - - int rv = 0; - size_t page = 1; - - bc_trie_t *variables = bc_trie_new(free); - // not using posts_pagination because we set FILTER_PAGE anyway, and the - // first value inserted in that function would be useless - bc_trie_insert(variables, "FILTER_PER_PAGE", - bc_strdup(bm_ctx_settings_lookup_str(ctx, "posts_per_page"))); - posts_ordering(ctx, variables, "html_order"); - bc_trie_insert(variables, "DATE_FORMAT", - bc_strdup(bm_ctx_settings_lookup_str(ctx, "date_format"))); - bc_trie_insert(variables, "MAKE_RULE", bc_strdup("pagination_tags")); - bc_trie_insert(variables, "MAKE_TYPE", bc_strdup("post")); - - const char *tag_prefix = bm_ctx_settings_lookup(ctx, "tag_prefix"); - const char *pagination_prefix = bm_ctx_settings_lookup(ctx, "pagination_prefix"); - const char *html_ext = bm_ctx_settings_lookup(ctx, "html_ext"); - - for (bc_slist_t *l = outputs; l != NULL; l = l->next) { - bm_filectx_t *fctx = l->data; - if (fctx == NULL) - continue; - - // this is very expensive, but we don't have another way to detect the - // tag and page from the file path right now :/ - char *tag = NULL; - for (size_t i = 0; ctx->settings->tags[i] != NULL; i++) { - bool b = false; - - // it is impossible to have more output files per tag than the whole - // amount of output pages - for (size_t k = 1; k <= bc_slist_length(outputs); k++) { - char *j = bc_strdup_printf("%d", k); - char *f = bm_generate_filename2(ctx->short_output_dir, tag_prefix, - ctx->settings->tags[i], pagination_prefix, j, html_ext); - free(j); - if (0 == strcmp(fctx->short_path, f)) { - tag = ctx->settings->tags[i]; - page = k; - b = true; - free(f); - break; - } - free(f); - } - if (b) - break; - } - if (tag == NULL) - continue; - - bc_trie_insert(variables, "FILTER_TAG", bc_strdup(tag)); - bc_trie_insert(variables, "FILTER_PAGE", bc_strdup_printf("%zu", page)); - - if (bm_rule_need_rebuild(ctx->posts_fctx, ctx->settings_fctx, - ctx->listing_entry_fctx, ctx->main_template_fctx, fctx, false)) - { - rv = bm_exec_blogc(ctx, variables, NULL, true, ctx->listing_entry_fctx, - ctx->main_template_fctx, fctx, ctx->posts_fctx, false); - if (rv != 0) - break; - } - } - - bc_trie_free(variables); - - return rv; -} - - -// POSTS RULE - -static bc_slist_t* -posts_outputlist(bm_ctx_t *ctx) -{ - if (ctx == NULL || ctx->settings->posts == NULL) - return NULL; - - bc_slist_t *rv = NULL; - - const char *post_prefix = bm_ctx_settings_lookup(ctx, "post_prefix"); - const char *html_ext = bm_ctx_settings_lookup(ctx, "html_ext"); - - for (size_t i = 0; ctx->settings->posts[i] != NULL; i++) { - char *f = bm_generate_filename(ctx->short_output_dir, post_prefix, - ctx->settings->posts[i], html_ext); - rv = bc_slist_append(rv, bm_filectx_new(ctx, f, NULL, NULL)); - free(f); - } - - return rv; -} - -static int -posts_exec(bm_ctx_t *ctx, bc_slist_t *outputs, bc_trie_t *args) -{ - if (ctx == NULL || ctx->settings->posts == NULL) - return 0; - - int rv = 0; - - bc_trie_t *variables = bc_trie_new(free); - bc_trie_insert(variables, "IS_POST", bc_strdup("1")); - bc_trie_insert(variables, "DATE_FORMAT", - bc_strdup(bm_ctx_settings_lookup(ctx, "date_format"))); - posts_ordering(ctx, variables, "html_order"); - bc_trie_insert(variables, "MAKE_RULE", bc_strdup("posts")); - bc_trie_insert(variables, "MAKE_TYPE", bc_strdup("post")); - - bc_slist_t *s, *o; - - for (s = ctx->posts_fctx, o = outputs; s != NULL && o != NULL; - s = s->next, o = o->next) - { - bm_filectx_t *s_fctx = s->data; - bm_filectx_t *o_fctx = o->data; - if (o_fctx == NULL) - continue; - if (bm_rule_need_rebuild(s, ctx->settings_fctx, NULL, - ctx->main_template_fctx, o_fctx, true)) - { - bc_trie_t *local = bc_trie_new(NULL); - bc_trie_insert(local, "MAKE_SLUG", s_fctx->slug); // no need to copy - rv = bm_exec_blogc(ctx, variables, local, false, NULL, ctx->main_template_fctx, - o_fctx, s, true); - bc_trie_free(local); - if (rv != 0) - break; - } - } - - bc_trie_free(variables); - - return rv; -} - - -// TAGS RULE - -static bc_slist_t* -tags_outputlist(bm_ctx_t *ctx) -{ - if (ctx == NULL || ctx->settings->posts == NULL || ctx->settings->tags == NULL) - return NULL; - - if (!posts_pagination_enabled(ctx, "posts_per_page")) - return NULL; - - bc_slist_t *rv = NULL; - - const char *tag_prefix = bm_ctx_settings_lookup(ctx, "tag_prefix"); - const char *html_ext = bm_ctx_settings_lookup(ctx, "html_ext"); - - for (size_t i = 0; ctx->settings->tags[i] != NULL; i++) { - char *f = bm_generate_filename(ctx->short_output_dir, tag_prefix, - ctx->settings->tags[i], html_ext); - rv = bc_slist_append(rv, bm_filectx_new(ctx, f, NULL, NULL)); - free(f); - } - - return rv; -} - -static int -tags_exec(bm_ctx_t *ctx, bc_slist_t *outputs, bc_trie_t *args) -{ - if (ctx == NULL || ctx->settings->posts == NULL || ctx->settings->tags == NULL) - return 0; - - int rv = 0; - size_t i = 0; - - bc_trie_t *variables = bc_trie_new(free); - posts_pagination(ctx, variables, "posts_per_page"); - posts_ordering(ctx, variables, "html_order"); - bc_trie_insert(variables, "DATE_FORMAT", - bc_strdup(bm_ctx_settings_lookup_str(ctx, "date_format"))); - bc_trie_insert(variables, "MAKE_RULE", bc_strdup("tags")); - bc_trie_insert(variables, "MAKE_TYPE", bc_strdup("post")); - - for (bc_slist_t *l = outputs; l != NULL; l = l->next, i++) { - bm_filectx_t *fctx = l->data; - if (fctx == NULL) - continue; - - bc_trie_insert(variables, "FILTER_TAG", - bc_strdup(ctx->settings->tags[i])); - - if (bm_rule_need_rebuild(ctx->posts_fctx, ctx->settings_fctx, - ctx->listing_entry_fctx, ctx->main_template_fctx, fctx, false)) - { - rv = bm_exec_blogc(ctx, variables, NULL, true, ctx->listing_entry_fctx, - ctx->main_template_fctx, fctx, ctx->posts_fctx, false); - if (rv != 0) - break; - } - } - - bc_trie_free(variables); - - return rv; -} - - -// PAGES RULE - -static bc_slist_t* -pages_outputlist(bm_ctx_t *ctx) -{ - if (ctx == NULL || ctx->settings->pages == NULL) - return NULL; - - bc_slist_t *rv = NULL; - - const char *html_ext = bm_ctx_settings_lookup(ctx, "html_ext"); - - for (size_t i = 0; ctx->settings->pages[i] != NULL; i++) { - char *f = bm_generate_filename(ctx->short_output_dir, NULL, - ctx->settings->pages[i], html_ext); - rv = bc_slist_append(rv, bm_filectx_new(ctx, f, NULL, NULL)); - free(f); - } - - return rv; -} - -static int -pages_exec(bm_ctx_t *ctx, bc_slist_t *outputs, bc_trie_t *args) -{ - if (ctx == NULL || ctx->settings->pages == NULL) - return 0; - - int rv = 0; - - bc_trie_t *variables = bc_trie_new(free); - bc_trie_insert(variables, "DATE_FORMAT", - bc_strdup(bm_ctx_settings_lookup(ctx, "date_format"))); - bc_trie_insert(variables, "MAKE_RULE", bc_strdup("pages")); - bc_trie_insert(variables, "MAKE_TYPE", bc_strdup("page")); - - bc_slist_t *s, *o; - - for (s = ctx->pages_fctx, o = outputs; s != NULL && o != NULL; - s = s->next, o = o->next) - { - bm_filectx_t *s_fctx = s->data; - bm_filectx_t *o_fctx = o->data; - if (o_fctx == NULL) - continue; - if (bm_rule_need_rebuild(s, ctx->settings_fctx, NULL, - ctx->main_template_fctx, o_fctx, true)) - { - bc_trie_t *local = bc_trie_new(NULL); - bc_trie_insert(local, "MAKE_SLUG", s_fctx->slug); // no need to copy - rv = bm_exec_blogc(ctx, variables, local, false, NULL, ctx->main_template_fctx, - o_fctx, s, true); - bc_trie_free(local); - if (rv != 0) - break; - } - } - - bc_trie_free(variables); - - return rv; -} - - -// COPY FILES RULE - -static bc_slist_t* -copy_outputlist(bm_ctx_t *ctx) -{ - if (ctx == NULL || ctx->settings->copy == NULL) - return NULL; - - bc_slist_t *rv = NULL; - - // we iterate over ctx->copy_fctx list instead of ctx->settings->copy, - // because bm_ctx_new() expands directories into its files, recursively. - for (bc_slist_t *s = ctx->copy_fctx; s != NULL; s = s->next) { - char *f = bc_strdup_printf("%s/%s", ctx->short_output_dir, - ((bm_filectx_t*) s->data)->short_path); - rv = bc_slist_append(rv, bm_filectx_new(ctx, f, NULL, NULL)); - free(f); - } - - return rv; -} - -static int -copy_exec(bm_ctx_t *ctx, bc_slist_t *outputs, bc_trie_t *args) -{ - if (ctx == NULL || ctx->settings->copy == NULL) - return 0; - - int rv = 0; - - bc_slist_t *s, *o; - - for (s = ctx->copy_fctx, o = outputs; s != NULL && o != NULL; - s = s->next, o = o->next) - { - bm_filectx_t *o_fctx = o->data; - if (o_fctx == NULL) - continue; - - if (bm_rule_need_rebuild(s, ctx->settings_fctx, NULL, NULL, o_fctx, true)) { - rv = bm_exec_native_cp(s->data, o_fctx, ctx->verbose); - if (rv != 0) - break; - } - } - - return rv; -} - - -// CLEAN RULE - -static int -clean_exec(bm_ctx_t *ctx, bc_slist_t *outputs, bc_trie_t *args) -{ - int rv = 0; - - bc_slist_t *files = bm_rule_list_built_files(ctx); - for (bc_slist_t *l = files; l != NULL; l = l->next) { - bm_filectx_t *fctx = l->data; - if (fctx == NULL) - continue; - - if (fctx->readable) { - rv = bm_exec_native_rm(ctx->output_dir, fctx, ctx->verbose); - if (rv != 0) - break; - } - } - bc_slist_free_full(files, (bc_free_func_t) bm_filectx_free); - - if (!bm_exec_native_is_empty_dir(ctx->output_dir, NULL)) { - fprintf(stderr, "blogc-make: warning: output directory is not empty!\n"); - } - - return rv; -} - - -static int all_exec(bm_ctx_t *ctx, bc_slist_t *outputs, bc_trie_t *args); - - -// RUNSERVER RULE - -static int -runserver_exec(bm_ctx_t *ctx, bc_slist_t *outputs, bc_trie_t *args) -{ - return bm_httpd_run(&ctx, all_exec, outputs, args); -} - - -// WATCH RULE - -static int -watch_exec(bm_ctx_t *ctx, bc_slist_t *outputs, bc_trie_t *args) -{ - return bm_reloader_run(&ctx, all_exec, outputs, args); -} - - -// ATOM DUMP RULE - -static int -atom_dump_exec(bm_ctx_t *ctx, bc_slist_t *outputs, bc_trie_t *args) -{ - char *content = bm_atom_generate(ctx->settings); - if (content == NULL) - return 1; - printf("%s", content); - free(content); - return 0; -} - - -const bm_rule_t rules[] = { - { - .name = "all", - .help = "run all build rules", - .outputlist_func = NULL, - .exec_func = all_exec, - }, - { - .name = "index", - .help = "build website index from posts", - .outputlist_func = index_outputlist, - .exec_func = index_exec, - }, - { - .name = "atom", - .help = "build main atom feed from posts", - .outputlist_func = atom_outputlist, - .exec_func = atom_exec, - }, - { - .name = "atom_tags", - .help = "build atom feeds for each tag from posts", - .outputlist_func = atom_tags_outputlist, - .exec_func = atom_tags_exec, - }, - { - .name = "pagination", - .help = "build pagination pages from posts", - .outputlist_func = pagination_outputlist, - .exec_func = pagination_exec, - }, - { - .name = "pagination_tags", - .help = "build pagination pages for each tag from posts", - .outputlist_func = pagination_tags_outputlist, - .exec_func = pagination_tags_exec, - }, - { - .name = "posts", - .help = "build individual pages for each post", - .outputlist_func = posts_outputlist, - .exec_func = posts_exec, - }, - { - .name = "tags", - .help = "build post listings for each tag from posts", - .outputlist_func = tags_outputlist, - .exec_func = tags_exec, - }, - { - .name = "pages", - .help = "build individual pages for each page", - .outputlist_func = pages_outputlist, - .exec_func = pages_exec, - }, - { - .name = "copy", - .help = "copy static files from source directory to output directory", - .outputlist_func = copy_outputlist, - .exec_func = copy_exec, - }, - { - .name = "clean", - .help = "clean built files and empty directories in output directory", - .outputlist_func = NULL, - .exec_func = clean_exec, - }, - { - .name = "runserver", - .help = "run blogc-runserver pointing to output directory, if available,\n" - " rebuilding as needed\n" - " arguments: host (127.0.0.1), port (8080) and threads (20)", - .outputlist_func = NULL, - .exec_func = runserver_exec, - }, - { - .name = "watch", - .help = "watch for changes in the source files, rebuilding as needed", - .outputlist_func = NULL, - .exec_func = watch_exec, - }, - { - .name = "atom_dump", - .help = "dump default Atom feed template based on current settings", - .outputlist_func = NULL, - .exec_func = atom_dump_exec, - }, - {NULL, NULL, NULL, NULL}, -}; - - -// ALL RULE - -static int -all_exec(bm_ctx_t *ctx, bc_slist_t *outputs, bc_trie_t *args) -{ - for (size_t i = 0; rules[i].name != NULL; i++) { - if (rules[i].outputlist_func == NULL) { - continue; - } - - int rv = bm_rule_execute(ctx, &(rules[i]), NULL); - if (rv != 0) { - return rv; - } - } - - return 0; -} - - -bc_trie_t* -bm_rule_parse_args(const char *sep) -{ - if (sep == NULL || *sep == '\0' || *sep != ':') - return NULL; - - bc_trie_t *rv = bc_trie_new(free); - char *end = (char*) sep + 1; - char *kv_sep; - while (NULL != (kv_sep = strchr(end, '='))) { - char *key = bc_strndup(end, kv_sep - end); - end = kv_sep + 1; - kv_sep = strchr(end, ','); - if (kv_sep == NULL) - kv_sep = strchr(end, '\0'); - char *value = bc_strndup(end, kv_sep - end); - bc_trie_insert(rv, key, value); - free(key); - if (*kv_sep == '\0') - break; - end = kv_sep + 1; - } - if (kv_sep == NULL) { - bc_trie_free(rv); - return NULL; - } - - return rv; -} - - -int -bm_rule_executor(bm_ctx_t *ctx, bc_slist_t *rule_list) -{ - if (ctx == NULL) - return 1; - - const bm_rule_t *rule = NULL; - int rv = 0; - - for (bc_slist_t *l = rule_list; l != NULL; l = l->next) { - - char *rule_str = l->data; - char *sep = strchr(rule_str, ':'); - - bc_trie_t *args = NULL; - if (sep == NULL) { - sep = strchr(rule_str, '\0'); - } - else { - args = bm_rule_parse_args(sep); - if (args == NULL) { - fprintf(stderr, "blogc-make: warning: failed to parse rule " - "arguments, ignoring: %s\n", rule_str); - } - } - - rule = NULL; - for (size_t i = 0; rules[i].name != NULL; i++) { - if (strlen(rules[i].name) != (sep - rule_str)) - continue; - if (0 == strncmp(rule_str, rules[i].name, sep - rule_str)) { - rule = &(rules[i]); - rv = bm_rule_execute(ctx, rule, args); - if (rv != 0) - return rv; - break; - } - } - if (rule == NULL) { - fprintf(stderr, "blogc-make: error: rule not found: %.*s\n", - (int) (sep - rule_str), rule_str); - rv = 1; - } - } - - return rv; -} - - -int -bm_rule_execute(bm_ctx_t *ctx, const bm_rule_t *rule, bc_trie_t *args) -{ - if (ctx == NULL || rule == NULL) - return 1; - - bc_slist_t *outputs = NULL; - if (rule->outputlist_func != NULL) { - outputs = rule->outputlist_func(ctx); - } - - int rv = rule->exec_func(ctx, outputs, args); - - bc_slist_free_full(outputs, (bc_free_func_t) bm_filectx_free); - - return rv; -} - - -bool -bm_rule_need_rebuild(bc_slist_t *sources, bm_filectx_t *settings, - bm_filectx_t *listing_entry, bm_filectx_t *template, bm_filectx_t *output, - bool only_first_source) -{ - if (output == NULL || !output->readable) - return true; - - bool rv = false; - - bc_slist_t *s = NULL; - if (settings != NULL) - s = bc_slist_append(s, settings); - if (template != NULL) - s = bc_slist_append(s, template); - if (listing_entry != NULL) - s = bc_slist_append(s, listing_entry); - - for (bc_slist_t *l = sources; l != NULL; l = l->next) { - s = bc_slist_append(s, l->data); - if (only_first_source) - break; - } - - for (bc_slist_t *l = s; l != NULL; l = l->next) { - bm_filectx_t *source = l->data; - if (source == NULL || !source->readable) { - // this is unlikely to happen, but lets just say that we need - // a rebuild and let blogc bail out. - rv = true; - break; - } - if (source->tv_sec == output->tv_sec) { - if (source->tv_nsec > output->tv_nsec) { - rv = true; - break; - } - } - else if (source->tv_sec > output->tv_sec) { - rv = true; - break; - } - } - - bc_slist_free(s); - - return rv; -} - - -bc_slist_t* -bm_rule_list_built_files(bm_ctx_t *ctx) -{ - if (ctx == NULL) - return NULL; - - bc_slist_t *rv = NULL; - for (size_t i = 0; rules[i].name != NULL; i++) { - if (rules[i].outputlist_func == NULL) { - continue; - } - - bc_slist_t *o = rules[i].outputlist_func(ctx); - for (bc_slist_t *l = o; l != NULL; l = l->next) { - rv = bc_slist_append(rv, l->data); - } - bc_slist_free(o); - } - - return rv; -} - - -void -bm_rule_print_help(void) -{ - printf("\nhelper rules:\n"); - for (size_t i = 0; rules[i].name != NULL; i++) { - if (rules[i].outputlist_func == NULL) { - printf(" %-15s %s\n", rules[i].name, rules[i].help); - } - } - printf("\nbuild rules:\n"); - for (size_t i = 0; rules[i].name != NULL; i++) { - if (rules[i].outputlist_func != NULL) { - printf(" %-15s %s\n", rules[i].name, rules[i].help); - } - } -} diff --git a/src/blogc-make/rules.h b/src/blogc-make/rules.h deleted file mode 100644 index 9ff39ca..0000000 --- a/src/blogc-make/rules.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * blogc: A blog compiler. - * Copyright (C) 2014-2020 Rafael G. Martins <rafael@rafaelmartins.eng.br> - * - * This program can be distributed under the terms of the BSD License. - * See the file LICENSE. - */ - -#ifndef _MAKE_RULES_H -#define _MAKE_RULES_H - -#include <stdbool.h> -#include "ctx.h" -#include "../common/utils.h" - -typedef bc_slist_t* (*bm_rule_outputlist_func_t) (bm_ctx_t *ctx); -typedef int (*bm_rule_exec_func_t) (bm_ctx_t *ctx, bc_slist_t *outputs, - bc_trie_t *args); - -typedef struct { - const char *name; - const char *help; - bm_rule_outputlist_func_t outputlist_func; - bm_rule_exec_func_t exec_func; -} bm_rule_t; - -bc_trie_t* bm_rule_parse_args(const char *sep); -int bm_rule_executor(bm_ctx_t *ctx, bc_slist_t *rule_list); -int bm_rule_execute(bm_ctx_t *ctx, const bm_rule_t *rule, bc_trie_t *args); -bool bm_rule_need_rebuild(bc_slist_t *sources, bm_filectx_t *settings, - bm_filectx_t *listing_entry, bm_filectx_t *template, bm_filectx_t *output, - bool only_first_source); -bc_slist_t* bm_rule_list_built_files(bm_ctx_t *ctx); -void bm_rule_print_help(void); - -#endif /* _MAKE_RULES_H */ diff --git a/src/blogc-make/settings.c b/src/blogc-make/settings.c deleted file mode 100644 index 1079fc0..0000000 --- a/src/blogc-make/settings.c +++ /dev/null @@ -1,203 +0,0 @@ -/* - * blogc: A blog compiler. - * Copyright (C) 2014-2019 Rafael G. Martins <rafael@rafaelmartins.eng.br> - * - * This program can be distributed under the terms of the BSD License. - * See the file LICENSE. - */ - -#include <libgen.h> -#include <stdbool.h> -#include <stdlib.h> -#include "../common/config-parser.h" -#include "../common/error.h" -#include "../common/file.h" -#include "../common/utils.h" -#include "settings.h" - - -static const struct default_settings_map { - const char *key; - const char *default_value; -} default_settings[] = { - - // source - {"content_dir", "content"}, - {"template_dir", "templates"}, - {"atom_template", NULL}, // default: atom.c - {"main_template", "main.tmpl"}, - {"source_ext", ".txt"}, - {"listing_entry", NULL}, - {"posts_sort", NULL}, - - // pagination - {"pagination_prefix", "page"}, - {"posts_per_page", "10"}, - {"atom_posts_per_page", "10"}, - - // html - {"html_ext", "/index.html"}, - {"index_prefix", ""}, - {"post_prefix", "post"}, - {"tag_prefix", "tag"}, - {"html_order", "DESC"}, - - // atom - {"atom_prefix", "atom"}, - {"atom_ext", ".xml"}, - {"atom_order", "DESC"}, - {"atom_legacy_entry_id", NULL}, - - // generic - {"date_format", "%b %d, %Y, %I:%M %p GMT"}, - {"locale", NULL}, - - {NULL, NULL}, -}; - - -static const char* required_global[] = { - "AUTHOR_NAME", - "AUTHOR_EMAIL", - "SITE_TITLE", - "SITE_TAGLINE", - "BASE_DOMAIN", - NULL, -}; - - -static const char* list_sections[] = { - "posts", - "pages", - "copy", - "copy_files", // backward compatibility - "tags", - NULL, -}; - - -bm_settings_t* -bm_settings_parse(const char *content, size_t content_len, bc_error_t **err) -{ - if (err == NULL || *err != NULL) - return NULL; - - if (content == NULL) - return NULL; - - bc_config_t *config = bc_config_parse(content, content_len, list_sections, - err); - if (config == NULL || (err != NULL && *err != NULL)) - return NULL; - - bm_settings_t *rv = bc_malloc(sizeof(bm_settings_t)); - rv->global = bc_trie_new(free); - rv->settings = bc_trie_new(free); - rv->posts = NULL; - rv->pages = NULL; - rv->copy = NULL; - rv->tags = NULL; - - // this is some code for compatibility with the [environment] section, - // even if I never released a version with it, but some people is using - // it already. - const char *section = NULL; - char **global = bc_config_list_keys(config, "global"); - if (global != NULL) { - section = "global"; - } - else { - global = bc_config_list_keys(config, "environment"); - if (global != NULL) { - section = "environment"; - } - else { - section = "global"; - } - } - - if (global != NULL) { - for (size_t i = 0; global[i] != NULL; i++) { - for (size_t j = 0; global[i][j] != '\0'; j++) { - if (j == 0) { - if (!(global[i][j] >= 'A' && global[i][j] <= 'Z')) { - *err = bc_error_new_printf(BLOGC_MAKE_ERROR_SETTINGS, - "Invalid [%s] key (first character must be uppercase): %s", - section, global[i]); - bc_strv_free(global); - bm_settings_free(rv); - rv = NULL; - goto cleanup; - } - continue; - } - if (!((global[i][j] >= 'A' && global[i][j] <= 'Z') || - (global[i][j] >= '0' && global[i][j] <= '9') || - global[i][j] == '_')) { - *err = bc_error_new_printf(BLOGC_MAKE_ERROR_SETTINGS, - "Invalid [%s] key (must be uppercase with '_' and digits after first character): %s", - section, global[i]); - bc_strv_free(global); - bm_settings_free(rv); - rv = NULL; - goto cleanup; - } - } - bc_trie_insert(rv->global, global[i], - bc_strdup(bc_config_get(config, section, global[i]))); - } - } - bc_strv_free(global); - - for (size_t i = 0; required_global[i] != NULL; i++) { - const char *value = bc_trie_lookup(rv->global, required_global[i]); - if (value == NULL || value[0] == '\0') { - *err = bc_error_new_printf(BLOGC_MAKE_ERROR_SETTINGS, - "[%s] key required but not found or empty: %s", section, - required_global[i]); - bm_settings_free(rv); - rv = NULL; - goto cleanup; - } - } - - for (size_t i = 0; default_settings[i].key != NULL; i++) { - const char *value = bc_config_get_with_default( - config, "settings", default_settings[i].key, - default_settings[i].default_value); - if (value != NULL) { - bc_trie_insert(rv->settings, default_settings[i].key, - bc_strdup(value)); - } - } - - rv->posts = bc_config_get_list(config, "posts"); - rv->pages = bc_config_get_list(config, "pages"); - rv->tags = bc_config_get_list(config, "tags"); - - // this is for backward compatibility too. - rv->copy = bc_config_get_list(config, "copy"); - if (rv->copy == NULL) - rv->copy = bc_config_get_list(config, "copy_files"); - -cleanup: - - bc_config_free(config); - - return rv; -} - - -void -bm_settings_free(bm_settings_t *settings) -{ - if (settings == NULL) - return; - bc_trie_free(settings->global); - bc_trie_free(settings->settings); - bc_strv_free(settings->posts); - bc_strv_free(settings->pages); - bc_strv_free(settings->copy); - bc_strv_free(settings->tags); - free(settings); -} diff --git a/src/blogc-make/settings.h b/src/blogc-make/settings.h deleted file mode 100644 index 69fdbb6..0000000 --- a/src/blogc-make/settings.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * blogc: A blog compiler. - * Copyright (C) 2014-2019 Rafael G. Martins <rafael@rafaelmartins.eng.br> - * - * This program can be distributed under the terms of the BSD License. - * See the file LICENSE. - */ - -#ifndef _MAKE_SETTINGS_H -#define _MAKE_SETTINGS_H - -#include <stddef.h> -#include "../common/error.h" -#include "../common/utils.h" - -typedef struct { - bc_trie_t *global; - bc_trie_t *settings; - char **posts; - char **pages; - char **copy; - char **tags; -} bm_settings_t; - -bm_settings_t* bm_settings_parse(const char *content, size_t content_len, - bc_error_t **err); -void bm_settings_free(bm_settings_t *settings); - -#endif /* _MAKE_SETTINGS_H */ diff --git a/src/blogc-make/utils.c b/src/blogc-make/utils.c deleted file mode 100644 index 8f69e44..0000000 --- a/src/blogc-make/utils.c +++ /dev/null @@ -1,128 +0,0 @@ -/* - * blogc: A blog compiler. - * Copyright (C) 2014-2019 Rafael G. Martins <rafael@rafaelmartins.eng.br> - * - * This program can be distributed under the terms of the BSD License. - * See the file LICENSE. - */ - -#include <errno.h> -#include <limits.h> -#include <stdbool.h> -#include <string.h> -#include <unistd.h> -#include "../common/error.h" -#include "../common/utils.h" - -#ifndef PATH_MAX -#define PATH_MAX 4096 -#endif - - -char* -bm_generate_filename(const char *dir, const char *prefix, const char *fname, - const char *ext) -{ - bool have_prefix = prefix != NULL && prefix[0] != '\0'; - bool have_fname = fname != NULL && fname[0] != '\0'; - bool have_ext = ext != NULL && ext[0] != '\0'; - bool have_ext_noslash = have_ext && ext[0] != '/'; - bool is_index = have_fname && have_ext && ( - (0 == strcmp(fname, "index")) && ext[0] == '/') && !have_prefix; - - bc_string_t *rv = bc_string_new(); - - if (dir != NULL && (have_prefix || have_fname || have_ext)) - bc_string_append(rv, dir); - - if ((have_prefix || have_fname || have_ext_noslash) && !is_index) - bc_string_append_c(rv, '/'); - - if (have_prefix) - bc_string_append(rv, prefix); - - // with fname we have posts, pages and tags - if (have_fname) { - if (have_prefix && have_fname && fname[0] != '/') - bc_string_append_c(rv, '/'); - if (!is_index) - bc_string_append(rv, fname); - } - - // no fname means index - else if (have_ext_noslash) { - if (have_fname) - bc_string_append_c(rv, '/'); - if (!have_prefix) - bc_string_append(rv, "index"); - } - - if (have_ext) - bc_string_append(rv, ext); - - if (rv->len == 0) { - bc_string_free(rv, true); - return NULL; - } - - return bc_string_free(rv, false); -} - - -char* -bm_generate_filename2(const char *dir, const char *prefix, const char *fname, - const char *prefix2, const char *fname2, const char *ext) -{ - bool have_prefix = prefix != NULL && prefix[0] != '\0'; - bool have_fname = fname != NULL && fname[0] != '\0'; - bool have_prefix2 = prefix2 != NULL && prefix2[0] != '\0'; - - bc_string_t *p = bc_string_new(); - - if (have_prefix) - bc_string_append(p, prefix); - - if (have_prefix && (have_fname || have_prefix2)) - bc_string_append_c(p, '/'); - - if (have_fname) - bc_string_append(p, fname); - - if (have_fname && have_prefix2) - bc_string_append_c(p, '/'); - - if (have_prefix2) - bc_string_append(p, prefix2); - - char *rv = bm_generate_filename(dir, p->str, fname2, ext); - bc_string_free(p, true); - - return rv; -} - - -char* -bm_abspath(const char *path, bc_error_t **err) -{ - if (err == NULL || *err != NULL) - return NULL; - - if (path[0] == '/') { - return bc_strdup(path); - } - - char cwd[PATH_MAX]; - if (NULL == getcwd(cwd, sizeof(cwd))) { - *err = bc_error_new_printf(BLOGC_MAKE_ERROR_UTILS, - "Failed to detect absolute path (%s): %s", path, strerror(errno)); - return NULL; - } - - if (cwd[0] != '/') { - *err = bc_error_new_printf(BLOGC_MAKE_ERROR_UTILS, - "Failed to get current working directory: %s", cwd); - return NULL; - } - - return bc_strdup_printf("%s/%s", cwd, path); -} diff --git a/src/blogc-make/utils.h b/src/blogc-make/utils.h deleted file mode 100644 index cbcfc0e..0000000 --- a/src/blogc-make/utils.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * blogc: A blog compiler. - * Copyright (C) 2014-2019 Rafael G. Martins <rafael@rafaelmartins.eng.br> - * - * This program can be distributed under the terms of the BSD License. - * See the file LICENSE. - */ - -#ifndef _MAKE_UTILS_H -#define _MAKE_UTILS_H - -#include "../common/error.h" - -char* bm_generate_filename(const char *dir, const char *prefix, const char *fname, - const char *ext); -char* bm_generate_filename2(const char *dir, const char *prefix, const char *fname, - const char *prefix2, const char *fname2, const char *ext); -char* bm_abspath(const char *path, bc_error_t **err); - -#endif /* _MAKE_UTILS_H */ |