aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/blogc/content-parser.c34
-rw-r--r--src/blogc/content-parser.h6
-rw-r--r--src/blogc/loader.c20
-rw-r--r--src/blogc/loader.h5
-rw-r--r--src/blogc/main.c2
-rw-r--r--src/blogc/source-parser.c36
-rw-r--r--src/blogc/source-parser.h4
-rw-r--r--src/blogc/toctree.c103
-rw-r--r--src/blogc/toctree.h26
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 */