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 */ | 
