diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/blogc/content-parser.c | 34 | ||||
-rw-r--r-- | src/blogc/content-parser.h | 6 | ||||
-rw-r--r-- | src/blogc/loader.c | 20 | ||||
-rw-r--r-- | src/blogc/loader.h | 5 | ||||
-rw-r--r-- | src/blogc/main.c | 2 | ||||
-rw-r--r-- | src/blogc/source-parser.c | 36 | ||||
-rw-r--r-- | src/blogc/source-parser.h | 4 | ||||
-rw-r--r-- | src/blogc/toctree.c | 103 | ||||
-rw-r--r-- | src/blogc/toctree.h | 26 |
9 files changed, 217 insertions, 19 deletions
diff --git a/src/blogc/content-parser.c b/src/blogc/content-parser.c index 047af4b..a42f6f6 100644 --- a/src/blogc/content-parser.c +++ b/src/blogc/content-parser.c @@ -1,6 +1,6 @@ /* * blogc: A blog compiler. - * Copyright (C) 2014-2019 Rafael G. Martins <rafael@rafaelmartins.eng.br> + * 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. @@ -11,6 +11,7 @@ #include <string.h> #include "content-parser.h" +#include "toctree.h" #include "../common/utils.h" // this is a half ass implementation of a markdown-like syntax. bugs are @@ -676,7 +677,7 @@ blogc_is_ordered_list_item(const char *str, size_t prefix_len) char* blogc_content_parse(const char *src, size_t *end_excerpt, char **first_header, - char **description) + char **description, char **endl, bc_slist_t **headers) { // src is always nul-terminated. size_t src_len = strlen(src); @@ -696,11 +697,28 @@ blogc_content_parse(const char *src, size_t *end_excerpt, char **first_header, char *parsed = NULL; char *slug = NULL; + char *line_ending = NULL; + bool line_ending_found = false; + if (endl != NULL) { + if (*endl != NULL) { + line_ending_found = true; + } + else { + *endl = bc_malloc(3 * sizeof(char)); + } + line_ending = *endl; + } + else { + line_ending = bc_malloc(3 * sizeof(char)); + } + // this isn't empty because we need some reasonable default value in the // unlikely case that we need to print some line ending before evaluating // the "real" value. - char line_ending[3] = "\n"; - bool line_ending_found = false; + if (!line_ending_found) { + line_ending[0] = '\n'; + line_ending[1] = '\0'; + } char d = '\0'; @@ -840,6 +858,8 @@ blogc_content_parse(const char *src, size_t *end_excerpt, char **first_header, *first_header = blogc_htmlentities(tmp); parsed = blogc_content_parse_inline(tmp); slug = blogc_slugify(tmp); + if (headers != NULL) + *headers = blogc_toctree_append(*headers, header_level, slug, parsed); if (slug == NULL) bc_string_append_printf(rv, "<h%d>%s</h%d>%s", header_level, parsed, header_level, line_ending); @@ -922,7 +942,7 @@ blogc_content_parse(const char *src, size_t *end_excerpt, char **first_header, // do not propagate title and description to blockquote parsing, // because we just want paragraphs from first level of // content. - tmp = blogc_content_parse(tmp_str->str, NULL, NULL, NULL); + tmp = blogc_content_parse(tmp_str->str, NULL, NULL, NULL, endl, NULL); bc_string_append_printf(rv, "<blockquote>%s</blockquote>%s", tmp, line_ending); free(tmp); @@ -1280,5 +1300,9 @@ blogc_content_parse(const char *src, size_t *end_excerpt, char **first_header, current++; } + if (endl == NULL) { + free(line_ending); + } + return bc_string_free(rv, false); } diff --git a/src/blogc/content-parser.h b/src/blogc/content-parser.h index ea5d29d..a321155 100644 --- a/src/blogc/content-parser.h +++ b/src/blogc/content-parser.h @@ -1,6 +1,6 @@ /* * blogc: A blog compiler. - * Copyright (C) 2014-2019 Rafael G. Martins <rafael@rafaelmartins.eng.br> + * 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. @@ -11,6 +11,7 @@ #include <stddef.h> #include <stdbool.h> +#include "../common/utils.h" char* blogc_slugify(const char *str); char* blogc_htmlentities(const char *str); @@ -18,6 +19,7 @@ char* blogc_fix_description(const char *paragraph); char* blogc_content_parse_inline(const char *src); bool blogc_is_ordered_list_item(const char *str, size_t prefix_len); char* blogc_content_parse(const char *src, size_t *end_excerpt, - char **first_header, char **description); + char **first_header, char **description, char **endl, + bc_slist_t **headers); #endif /* _CONTENT_PARSER_H */ diff --git a/src/blogc/loader.c b/src/blogc/loader.c index d620988..4e03ec3 100644 --- a/src/blogc/loader.c +++ b/src/blogc/loader.c @@ -1,6 +1,6 @@ /* * blogc: A blog compiler. - * Copyright (C) 2014-2019 Rafael G. Martins <rafael@rafaelmartins.eng.br> + * 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. @@ -76,7 +76,7 @@ blogc_template_parse_from_file(const char *f, bc_error_t **err) bc_trie_t* -blogc_source_parse_from_file(const char *f, bc_error_t **err) +blogc_source_parse_from_file(bc_trie_t *conf, const char *f, bc_error_t **err) { if (err == NULL || *err != NULL) return NULL; @@ -85,7 +85,19 @@ blogc_source_parse_from_file(const char *f, bc_error_t **err) char *s = bc_file_get_contents(f, true, &len, err); if (s == NULL) return NULL; - bc_trie_t *rv = blogc_source_parse(s, len, err); + + int toctree_maxdepth = -1; + const char *maxdepth = bc_trie_lookup(conf, "TOCTREE_MAXDEPTH"); + if (maxdepth != NULL) { + char *endptr; + toctree_maxdepth = strtol(maxdepth, &endptr, 10); + if (*maxdepth != '\0' && *endptr != '\0') { + fprintf(stderr, "warning: invalid value for 'TOCTREE_MAXDEPTH' " + "variable: %s. using %d instead\n", maxdepth, toctree_maxdepth); + } + } + + bc_trie_t *rv = blogc_source_parse(s, len, toctree_maxdepth, err); // set FILENAME variable if (rv != NULL) { @@ -133,7 +145,7 @@ blogc_source_parse_from_files(bc_trie_t *conf, bc_slist_t *l, bc_error_t **err) size_t with_date = 0; for (bc_slist_t *tmp = l; tmp != NULL; tmp = tmp->next) { char *f = tmp->data; - bc_trie_t *s = blogc_source_parse_from_file(f, &tmp_err); + bc_trie_t *s = blogc_source_parse_from_file(conf, f, &tmp_err); if (s == NULL) { *err = bc_error_new_printf(BLOGC_ERROR_LOADER, "An error occurred while parsing source file: %s\n\n%s", diff --git a/src/blogc/loader.h b/src/blogc/loader.h index 66da7d0..fe88730 100644 --- a/src/blogc/loader.h +++ b/src/blogc/loader.h @@ -1,6 +1,6 @@ /* * blogc: A blog compiler. - * Copyright (C) 2014-2019 Rafael G. Martins <rafael@rafaelmartins.eng.br> + * 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. @@ -14,7 +14,8 @@ char* blogc_get_filename(const char *f); bc_slist_t* blogc_template_parse_from_file(const char *f, bc_error_t **err); -bc_trie_t* blogc_source_parse_from_file(const char *f, bc_error_t **err); +bc_trie_t* blogc_source_parse_from_file(bc_trie_t *conf, const char *f, + bc_error_t **err); bc_slist_t* blogc_source_parse_from_files(bc_trie_t *conf, bc_slist_t *l, bc_error_t **err); diff --git a/src/blogc/main.c b/src/blogc/main.c index f952957..7024967 100644 --- a/src/blogc/main.c +++ b/src/blogc/main.c @@ -307,7 +307,7 @@ main(int argc, char **argv) listing_entries_source = bc_slist_append(listing_entries_source, NULL); continue; } - bc_trie_t *e = blogc_source_parse_from_file(tmp->data, &err); + bc_trie_t *e = blogc_source_parse_from_file(config, tmp->data, &err); if (err != NULL) { bc_error_print(err, "blogc"); rv = 1; diff --git a/src/blogc/source-parser.c b/src/blogc/source-parser.c index 18cf95a..13df9e3 100644 --- a/src/blogc/source-parser.c +++ b/src/blogc/source-parser.c @@ -1,6 +1,6 @@ /* * blogc: A blog compiler. - * Copyright (C) 2014-2019 Rafael G. Martins <rafael@rafaelmartins.eng.br> + * 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. @@ -11,6 +11,7 @@ #include "content-parser.h" #include "source-parser.h" +#include "toctree.h" #include "../common/error.h" #include "../common/utils.h" @@ -27,7 +28,8 @@ typedef enum { bc_trie_t* -blogc_source_parse(const char *src, size_t src_len, bc_error_t **err) +blogc_source_parse(const char *src, size_t src_len, int toctree_maxdepth, + bc_error_t **err) { if (err == NULL || *err != NULL) return NULL; @@ -153,8 +155,11 @@ blogc_source_parse(const char *src, size_t src_len, bc_error_t **err) bc_trie_insert(rv, "RAW_CONTENT", tmp); char *first_header = NULL; char *description = NULL; + char *endl = NULL; + bc_slist_t *headers = NULL; + bool read_headers = (NULL == bc_trie_lookup(rv, "TOCTREE")); content = blogc_content_parse(tmp, &end_excerpt, - &first_header, &description); + &first_header, &description, &endl, read_headers ? &headers : NULL); if (first_header != NULL) { // do not override source-provided first_header. if (NULL == bc_trie_lookup(rv, "FIRST_HEADER")) { @@ -177,6 +182,31 @@ blogc_source_parse(const char *src, size_t src_len, bc_error_t **err) free(description); } } + if (headers != NULL) { + // we already validated that the user do not defined TOCTREE + // manually in source file. + const char *maxdepth = bc_trie_lookup(rv, "TOCTREE_MAXDEPTH"); + if (maxdepth != NULL) { + char *endptr; + toctree_maxdepth = strtol(maxdepth, &endptr, 10); + if (*maxdepth != '\0' && *endptr != '\0') { + *err = bc_error_parser(BLOGC_ERROR_SOURCE_PARSER, src, src_len, + current, + "Invalid value for 'TOCTREE_MAXDEPTH' variable: %s.", + maxdepth); + blogc_toctree_free(headers); + free(endl); + free(content); + break; + } + } + char *toctree = blogc_toctree_render(headers, toctree_maxdepth, endl); + blogc_toctree_free(headers); + if (toctree != NULL) { + bc_trie_insert(rv, "TOCTREE", toctree); + } + } + free(endl); bc_trie_insert(rv, "CONTENT", content); bc_trie_insert(rv, "EXCERPT", end_excerpt == 0 ? bc_strdup(content) : bc_strndup(content, end_excerpt)); diff --git a/src/blogc/source-parser.h b/src/blogc/source-parser.h index 8672fb0..2acd753 100644 --- a/src/blogc/source-parser.h +++ b/src/blogc/source-parser.h @@ -1,6 +1,6 @@ /* * blogc: A blog compiler. - * Copyright (C) 2014-2019 Rafael G. Martins <rafael@rafaelmartins.eng.br> + * 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. @@ -13,7 +13,7 @@ #include "../common/error.h" #include "../common/utils.h" -bc_trie_t* blogc_source_parse(const char *src, size_t src_len, +bc_trie_t* blogc_source_parse(const char *src, size_t src_len, int toctree_maxdepth, bc_error_t **err); #endif /* _SOURCE_PARSER_H */ diff --git a/src/blogc/toctree.c b/src/blogc/toctree.c new file mode 100644 index 0000000..307c62c --- /dev/null +++ b/src/blogc/toctree.c @@ -0,0 +1,103 @@ +/* + * 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 "../common/utils.h" +#include "toctree.h" + +bc_slist_t* +blogc_toctree_append(bc_slist_t *headers, size_t level, const char *slug, const char *text) +{ + if (level == 0) + return headers; + + blogc_toctree_header_t *t = bc_malloc(sizeof(blogc_toctree_header_t)); + t->level = level; + t->slug = bc_strdup(slug); + t->text = bc_strdup(text); + return bc_slist_append(headers, t); +} + + +char* +blogc_toctree_render(bc_slist_t *headers, int maxdepth, const char *endl) +{ + if (headers == NULL || maxdepth == 0) + return NULL; + + // find lower level + size_t lower_level = 0; + for (bc_slist_t *l = headers; l != NULL; l = l->next) { + size_t lv = ((blogc_toctree_header_t*) l->data)->level; + if (lower_level == 0 || lower_level > lv) { + lower_level = lv; + } + } + + if (lower_level == 0) + return NULL; + + // render + bc_string_t *rv = bc_string_new(); + bc_string_append_printf(rv, "<ul>%s", endl == NULL ? "\n" : endl); + size_t spacing = 4; + size_t current_level = lower_level; + for (bc_slist_t *l = headers; l != NULL; l = l->next) { + blogc_toctree_header_t *t = l->data; + if (t->level - lower_level >= maxdepth) { + continue; + } + while (current_level > t->level) { + spacing -= 4; + bc_string_append_printf(rv, "%*s</ul>%s", spacing, "", + endl == NULL ? "\n" : endl); + current_level--; + } + while (current_level < t->level) { + bc_string_append_printf(rv, "%*s<ul>%s", spacing, "", + endl == NULL ? "\n" : endl); + current_level++; + spacing += 4; + } + bc_string_append_printf(rv, "%*s<li>", spacing, ""); + if (t->slug != NULL) { + bc_string_append_printf(rv, "<a href=\"#%s\">%s</a>", t->slug, + t->text != NULL ? t->text : ""); + } + else { + bc_string_append(rv, t->text); + } + bc_string_append_printf(rv, "</li>%s", endl == NULL ? "\n" : endl); + } + + // close leftovers + while (current_level >= lower_level) { + spacing -= 4; + bc_string_append_printf(rv, "%*s</ul>%s", spacing, "", + endl == NULL ? "\n" : endl); + current_level--; + } + + return bc_string_free(rv, false); +} + + +static void +free_header(blogc_toctree_header_t *h) +{ + free(h->slug); + free(h->text); + free(h); +} + + +void +blogc_toctree_free(bc_slist_t *l) +{ + bc_slist_free_full(l, (bc_free_func_t) free_header); +} diff --git a/src/blogc/toctree.h b/src/blogc/toctree.h new file mode 100644 index 0000000..460119b --- /dev/null +++ b/src/blogc/toctree.h @@ -0,0 +1,26 @@ +/* + * 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 ___TOCTREE_H +#define ___TOCTREE_H + +#include "../common/utils.h" + +typedef struct { + size_t level; + char *slug; + char *text; +} blogc_toctree_header_t; + +bc_slist_t* blogc_toctree_append(bc_slist_t *headers, size_t level, + const char *slug, const char *text); +char* blogc_toctree_render(bc_slist_t *headers, int maxdepth, + const char *endl); +void blogc_toctree_free(bc_slist_t *l); + +#endif /* ___TOCTREE_H */ |