From 5bc7d084ca129637e4782de5fc0c13be76ad27b8 Mon Sep 17 00:00:00 2001 From: sanine Date: Sun, 2 Jan 2022 17:09:29 -0600 Subject: add README.md and logging --- CMakeLists.txt | 1 + README.md | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/argent.c | 21 +++++++++++--------- src/bindings.c | 14 +++++++++++-- src/logging.c | 42 +++++++++++++++++++++++++++++++++++++++ src/logging.h | 16 +++++++++++++++ src/options.c | 15 +++++++++++--- src/options.h | 1 + 8 files changed, 158 insertions(+), 14 deletions(-) create mode 100644 README.md create mode 100644 src/logging.c create mode 100644 src/logging.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 68a57e4..c6cd35d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,6 +30,7 @@ add_executable(argent ${SRC_ROOT}/argent.c ${SRC_ROOT}/options.c ${SRC_ROOT}/bindings.c + ${SRC_ROOT}/logging.c ${MD4C_SOURCES} ${HONEYSUCKLE_SOURCES}) set_target_properties(argent PROPERTIES diff --git a/README.md b/README.md new file mode 100644 index 0000000..7f53a8e --- /dev/null +++ b/README.md @@ -0,0 +1,62 @@ +argent +================================ + +*a super-simple static site generator* + +Argent is a static site generator written in C and using Lua 5.1 for scripting. I wrote it because many other static site generators I experimented with were either very rigid and complex or had been written for old versions of their chosen language and no longer worked in the modern version. Argent brings its own Lua interpreter and is written in C99, and so it should run just about anywhere that you can compile POSIX programs. + +installation +-------------------------------- + +``` +git clone https://sanine.net/git/argent +mkdir argent/build +cd argent/build +cmake .. +make +``` + +Move the resulting `argent` binary to somewhere on your PATH (probably `~/bin`). + + +using argent +-------------------------------- + +You need to provide Argent with a configuration file. By default this file is `argent.lua` in the current working directory; you can override that with the `-c [config_file]` command-line option. The configuration file should be a Lua script that returns a table containing the following: + +| Key | Type | Meaning | +|------------------|--------|--------------------------------------------------------------------------------------------------------------------------------------------------------| +| site_directory | string | filename of the directory where the site files are located | +| layout_directory | string | filename of the directory where layouts are located | +| exclude | table | array of files and directories in the `site_directory` to exclude from the public site | +| include | table | array of files and directories in the `site_directory` to forcibly include (e.g. `.htaccess` files, since dotfiles are normally excluded) | +| keep | table | array of files and directories in the public result to not touch during site generation. | +| noprocess | table | array of files and directories in the `site_directory` to exclude from processing (e.g. lua files specified here will **not** be converted into HTML). | +| rss_include | table | array of files and directories to include in the site's `rss.xml` file. | + +### site directory + +This is the directory that will be compiled into the public site. All of the files within it are copied verbatim to the output directory, with the exception of `.lua` files, which should return tables with at least a markup key. They can also contain any other arbitrary keys, which will be passed on the the layout function. Certain non-markup keys are always present, and have a default value which can be overridden by the page table. + +| Key | Type | Meaning | +|----------|--------|-------------------------------------------------------------------------------------------------------------------------------------------------------------| +| markdown | string | A markup key -- will be converted to HTML | +| html | string | A markup key -- will be inserted into the resulting HTML file | +| layout | string | Should match one of the layout files' filename (e.g. `layout1.lua` -> `layout='layout1'`) -- specifies a layout function for postprocessing. (default: nil) | +| title | string | The content of the tag. (default: the bare filename) | +| date | string | A date for the page, which can be used by the layout function. (default: the file's actual modification date.) | + + +### layouts + +A layout is simply a `.lua` file that returns a function, taking as input `(string, table)`, where the string is the target page's HTML, and the table contains any non-markup keys from the target page's table. This table is guaranteed to contain a `title` and `date` key. + +### rss + +If the `rss_include` key in the configuration table is non-nil, then an `rss.xml` file will be generated in the output root, containing all of the pages specified by `rss_include` and sorted by date. + + +license +-------------------------------- + +This software is licensed under the [Anti-Capitalist Software License](https://anticapitalist.software) diff --git a/src/argent.c b/src/argent.c index 7426394..b83f851 100644 --- a/src/argent.c +++ b/src/argent.c @@ -6,6 +6,7 @@ #include "options.h" #include "bindings.h" +#include "logging.h" struct settings { @@ -15,41 +16,43 @@ struct settings { int main(int argc, char **argv) { + argent_log(DEBUG, "parse command-line options"); struct argent_options opts; int error = parse_options(&opts, argc, argv); - if (error) return 1; - printf("configuration file: %s\n" - "output directory: %s\n", - opts.conf_filename, - opts.output_dir); + argent_log(INFO, "log level: %s", level_string(argent_log_level)); + argent_log(INFO, "configuration file: %s", opts.conf_filename); + argent_log(INFO, "output directory: %s", opts.output_dir); + argent_log(DEBUG, "create lua state"); lua_State *L = luaL_newstate(); luaL_openlibs(L); + argent_log(DEBUG, "create argent table"); hs_create_table (L, hs_str_cfunc("markdown", markdown) ); lua_setglobal(L, "argent"); + argent_log(DEBUG, "load configuration file"); error = luaL_loadfile(L, opts.conf_filename); if (error != 0) { - fprintf(stderr, "error: %s\n", lua_tostring(L, -1)); + argent_log(FATAL, "lua error: %s", lua_tostring(L, -1)); lua_close(L); return error; } + argent_log(DEBUG, "run configuration file"); error = hs_call(L, 0, 1); if (error != 0) { - fprintf(stderr, "error: %s\n", lua_tostring(L, -1)); + argent_log(FATAL, "lua error: %s", lua_tostring(L, -1)); lua_close(L); return error; } - printf("here!\n"); - + argent_log(DEBUG, "close lua state"); lua_close(L); return 0; } diff --git a/src/bindings.c b/src/bindings.c index eb9710c..b02911b 100644 --- a/src/bindings.c +++ b/src/bindings.c @@ -5,6 +5,7 @@ #include "honeysuckle.h" #include "md4c-html.h" #include "bindings.h" +#include "logging.h" struct concat_buffer { char *buf; @@ -15,6 +16,7 @@ struct concat_buffer { static void md_callback(const MD_CHAR *html, MD_SIZE size, void *data) { + argent_log(TRACE, "begin md_callback()"); struct concat_buffer *d = data; if (!d->ok) @@ -24,6 +26,7 @@ static void md_callback(const MD_CHAR *html, MD_SIZE size, void *data) char *new_buf = realloc(d->buf, d->size * 2); if (new_buf == NULL) { // failed to allocate memory, abort! + argent_log(WARN, "failed to properly allocate memory for html buffer!"); d->ok = false; return; } @@ -34,13 +37,17 @@ static void md_callback(const MD_CHAR *html, MD_SIZE size, void *data) memcpy((d->buf) + d->index, html, size); d->index += size; + + argent_log(TRACE, "finish md_callback()"); } int markdown(lua_State *L) { + argent_log(DEBUG, "begin markdown parsing"); char *markdown_buffer; hs_parse_args(L, hs_str(markdown_buffer)); size_t len = strlen(markdown_buffer); + argent_log(TRACE, "markdown input (%ld bytes): %s", len, markdown_buffer); unsigned int md_flags = MD_FLAG_TABLES | MD_FLAG_STRIKETHROUGH | MD_FLAG_UNDERLINE; @@ -50,6 +57,7 @@ int markdown(lua_State *L) data.index = 0; data.ok = true; + argent_log(TRACE, "call md_html()"); // fill out the buffer int error = md_html(markdown_buffer, len, md_callback, &data, md_flags, 0); if (error) @@ -60,9 +68,11 @@ int markdown(lua_State *L) data.buf[data.index] = 0; + argent_log(TRACE, "finished HTML buffer (%d bytes, %d chars): %s", + data.size, data.index, data.buf); lua_pushstring(L, data.buf); - free(data.buf); - + + argent_log(DEBUG, "finish markdown parsing"); return 1; } diff --git a/src/logging.c b/src/logging.c new file mode 100644 index 0000000..0481908 --- /dev/null +++ b/src/logging.c @@ -0,0 +1,42 @@ +#include <stdio.h> +#include <stdarg.h> + +#include "logging.h" + +int argent_log_level; + +const char *level_string(int level) +{ + switch(level) { + case FATAL: + return "FATAL"; + case ERROR: + return "ERROR"; + case WARN: + return "WARN"; + case INFO: + return "INFO"; + case DEBUG: + return "DEBUG"; + case TRACE: + return "TRACE"; + + default: + if (level > TRACE) + return "TRACE"; + return "[BAD LOG LEVEL]"; + } +} + + +void argent_log(int level, const char *format_string, ...) +{ + if (argent_log_level >= level) { + va_list args; + va_start(args, format_string); + fprintf(stderr, "[%s] ", level_string(level)); + vfprintf(stderr, format_string, args); + fprintf(stderr, "\n"); + va_end(args); + } +} diff --git a/src/logging.h b/src/logging.h new file mode 100644 index 0000000..53232ca --- /dev/null +++ b/src/logging.h @@ -0,0 +1,16 @@ +#ifndef ARGENT_LOGGING_H +#define ARGENT_LOGGING_H + +#define FATAL 0 +#define ERROR 1 +#define WARN 2 +#define INFO 3 +#define DEBUG 4 +#define TRACE 5 + +extern int argent_log_level; + +const char *level_string(int level); +void argent_log(int level, const char *format_string, ...); + +#endif diff --git a/src/options.c b/src/options.c index b3836a7..c4eb8d4 100644 --- a/src/options.c +++ b/src/options.c @@ -2,21 +2,27 @@ #include <unistd.h> #include "options.h" +#include "logging.h" static void print_usage(const char *progname) { - printf("Usage: %s [-c config_file] [-o output_directory]\n", + printf("Usage: %s [-c config_file] [-i input_directory] [-o output_directory]\n", progname); } int parse_options(struct argent_options *opts, int argc, char **argv) { + opts->log_level = 0; opts->conf_filename = "argent.lua"; - opts->output_dir = "build"; + opts->output_dir = "public"; int opt; - while ((opt = getopt(argc, argv, "c:o:")) != -1) { + while ((opt = getopt(argc, argv, "vc:o:")) != -1) { switch (opt) { + case 'v': + opts->log_level += 1; + break; + case 'c': opts->conf_filename = optarg; break; @@ -31,5 +37,8 @@ int parse_options(struct argent_options *opts, int argc, char **argv) } } + // ew, globals (sorry) + argent_log_level = opts->log_level; + return 0; } diff --git a/src/options.h b/src/options.h index ae4e621..d62eb58 100644 --- a/src/options.h +++ b/src/options.h @@ -4,6 +4,7 @@ struct argent_options { const char *conf_filename; const char *output_dir; + int log_level; }; /* return 0 and fill `opts` on success; return nonzero on failure */ -- cgit v1.2.1