From 14e9d7b2299f15efb695b0202f9c1f6a9f7a4ba6 Mon Sep 17 00:00:00 2001
From: "Rafael G. Martins" <rafael@rafaelmartins.eng.br>
Date: Wed, 23 Dec 2015 23:45:54 +0100
Subject: Revert "build: removing src/utils and replacing with squareball"

This reverts commit 950e6c9148eca244a89d18a21d4ae4e5c3d1c646.
---
 src/content-parser.c  | 252 ++++++++++++++++++++++----------------------
 src/datetime-parser.c |   4 +-
 src/error.c           |  12 +--
 src/file.c            |   8 +-
 src/loader.c          |  86 +++++++--------
 src/loader.h          |   8 +-
 src/main.c            |  52 +++++-----
 src/renderer.c        |  46 ++++----
 src/renderer.h        |  10 +-
 src/source-parser.c   |  26 ++---
 src/source-parser.h   |   4 +-
 src/template-parser.c |  32 +++---
 src/template-parser.h |   6 +-
 src/utils/mem.c       |  42 ++++++++
 src/utils/slist.c     |  68 ++++++++++++
 src/utils/strings.c   | 283 ++++++++++++++++++++++++++++++++++++++++++++++++++
 src/utils/trie.c      | 199 +++++++++++++++++++++++++++++++++++
 src/utils/utils.h     |  77 ++++++++++++++
 18 files changed, 942 insertions(+), 273 deletions(-)
 create mode 100644 src/utils/mem.c
 create mode 100644 src/utils/slist.c
 create mode 100644 src/utils/strings.c
 create mode 100644 src/utils/trie.c
 create mode 100644 src/utils/utils.h

(limited to 'src')

diff --git a/src/content-parser.c b/src/content-parser.c
index 1a80572..f5450d6 100644
--- a/src/content-parser.c
+++ b/src/content-parser.c
@@ -12,8 +12,8 @@
 
 #include <stdbool.h>
 #include <string.h>
-#include <squareball.h>
 
+#include "utils/utils.h"
 #include "content-parser.h"
 
 // this is a half ass implementation of a markdown-like syntax. bugs are
@@ -25,7 +25,7 @@ blogc_slugify(const char *str)
 {
     if (str == NULL)
         return NULL;
-    char *new_str = sb_strdup(str);
+    char *new_str = b_strdup(str);
     int diff = 'a' - 'A';  // just to avoid magic numbers
     for (unsigned int i = 0; new_str[i] != '\0'; i++) {
         if (new_str[i] >= 'a' && new_str[i] <= 'z')
@@ -92,7 +92,7 @@ blogc_content_parse_inline(const char *src)
     size_t start_state = 0;
     size_t end = 0;
 
-    sb_string_t *rv = sb_string_new();
+    b_string_t *rv = b_string_new();
 
     bool open_em_ast = false;
     bool open_strong_ast = false;
@@ -118,7 +118,7 @@ blogc_content_parse_inline(const char *src)
 
         if (escape) {
             if (state == LINK_CLOSED)
-                sb_string_append_c(rv, c);
+                b_string_append_c(rv, c);
             current++;
             escape = false;
             continue;
@@ -131,7 +131,7 @@ blogc_content_parse_inline(const char *src)
 
             case '\\':
                 if (state == LINK_CLOSED && (open_code || open_code_double)) {
-                    sb_string_append_c(rv, c);
+                    b_string_append_c(rv, c);
                     break;
                 }
                 if (!escape)
@@ -141,7 +141,7 @@ blogc_content_parse_inline(const char *src)
             case '*':
             case '_':
                 if (state == LINK_CLOSED && (open_code || open_code_double)) {
-                    sb_string_append_c(rv, c);
+                    b_string_append_c(rv, c);
                     break;
                 }
                 if (!is_last && src[current + 1] == c) {
@@ -150,7 +150,7 @@ blogc_content_parse_inline(const char *src)
                         (c == '_' && open_strong_und))
                     {
                         if (state == LINK_CLOSED)
-                            sb_string_append(rv, "</strong>");
+                            b_string_append(rv, "</strong>");
                         if (c == '*')
                             open_strong_ast = false;
                         else
@@ -158,7 +158,7 @@ blogc_content_parse_inline(const char *src)
                         break;
                     }
                     if (state == LINK_CLOSED)
-                        sb_string_append(rv, "<strong>");
+                        b_string_append(rv, "<strong>");
                     if (c == '*')
                         open_strong_ast = true;
                     else
@@ -167,7 +167,7 @@ blogc_content_parse_inline(const char *src)
                 }
                 if ((c == '*' && open_em_ast) || (c == '_' && open_em_und)) {
                     if (state == LINK_CLOSED)
-                        sb_string_append(rv, "</em>");
+                        b_string_append(rv, "</em>");
                     if (c == '*')
                         open_em_ast = false;
                     else
@@ -175,7 +175,7 @@ blogc_content_parse_inline(const char *src)
                     break;
                 }
                 if (state == LINK_CLOSED)
-                    sb_string_append(rv, "<em>");
+                    b_string_append(rv, "<em>");
                 if (c == '*')
                     open_em_ast = true;
                 else
@@ -186,19 +186,19 @@ blogc_content_parse_inline(const char *src)
                 if (!is_last && src[current + 1] == c) {
                     current++;
                     if (state == LINK_CLOSED)
-                        sb_string_append_printf(rv, "<%scode>",
+                        b_string_append_printf(rv, "<%scode>",
                             open_code_double ? "/" : "");
                     open_code_double = !open_code_double;
                     break;
                 }
                 if (state == LINK_CLOSED)
-                    sb_string_append_printf(rv, "<%scode>", open_code ? "/" : "");
+                    b_string_append_printf(rv, "<%scode>", open_code ? "/" : "");
                 open_code = !open_code;
                 break;
 
             case '!':
                 if (state == LINK_CLOSED && (open_code || open_code_double)) {
-                    sb_string_append_c(rv, c);
+                    b_string_append_c(rv, c);
                     break;
                 }
                 if (state == LINK_CLOSED) {
@@ -210,7 +210,7 @@ blogc_content_parse_inline(const char *src)
 
             case '[':
                 if (state == LINK_CLOSED && (open_code || open_code_double)) {
-                    sb_string_append_c(rv, c);
+                    b_string_append_c(rv, c);
                     break;
                 }
                 if (state == LINK_CLOSED || state == LINK_IMAGE) {
@@ -240,8 +240,8 @@ blogc_content_parse_inline(const char *src)
                 }
                 if (state == LINK_AUTO_CLOSE) {
                     state = LINK_CLOSED;
-                    tmp = sb_strndup(src + start, end - start);
-                    sb_string_append_printf(rv, "<a href=\"%s\">%s</a>", tmp, tmp);
+                    tmp = b_strndup(src + start, end - start);
+                    b_string_append_printf(rv, "<a href=\"%s\">%s</a>", tmp, tmp);
                     end = 0;
                     free(tmp);
                     tmp = NULL;
@@ -251,7 +251,7 @@ blogc_content_parse_inline(const char *src)
                 if (state == LINK_TEXT) {
                     if (open_bracket-- == 0) {
                         state = LINK_TEXT_CLOSE;
-                        tmp = sb_strndup(src + start, current - start);
+                        tmp = b_strndup(src + start, current - start);
                         tmp2 = blogc_content_parse_inline(tmp);
                         free(tmp);
                         tmp = NULL;
@@ -259,7 +259,7 @@ blogc_content_parse_inline(const char *src)
                     break;
                 }
                 if (state == LINK_CLOSED)
-                    sb_string_append_c(rv, c);
+                    b_string_append_c(rv, c);
                 break;
 
             case '(':
@@ -269,18 +269,18 @@ blogc_content_parse_inline(const char *src)
                     break;
                 }
                 if (state == LINK_CLOSED)
-                    sb_string_append_c(rv, c);
+                    b_string_append_c(rv, c);
                 break;
 
             case ')':
                 if (state == LINK_URL) {
                     state = LINK_CLOSED;
-                    tmp = sb_strndup(src + start, current - start);
+                    tmp = b_strndup(src + start, current - start);
                     if (is_image)
-                        sb_string_append_printf(rv, "<img src=\"%s\" alt=\"%s\">",
+                        b_string_append_printf(rv, "<img src=\"%s\" alt=\"%s\">",
                             tmp, tmp2);
                     else
-                        sb_string_append_printf(rv, "<a href=\"%s\">%s</a>",
+                        b_string_append_printf(rv, "<a href=\"%s\">%s</a>",
                             tmp, tmp2);
                     free(tmp);
                     tmp = NULL;
@@ -290,13 +290,13 @@ blogc_content_parse_inline(const char *src)
                     break;
                 }
                 if (state == LINK_CLOSED)
-                    sb_string_append_c(rv, c);
+                    b_string_append_c(rv, c);
                 break;
 
             case ' ':
                 if (state == LINK_CLOSED) {
                     spaces++;
-                    sb_string_append_c(rv, c);
+                    b_string_append_c(rv, c);
                 }
                 if (!is_last)
                     break;
@@ -305,53 +305,53 @@ blogc_content_parse_inline(const char *src)
             case '\r':
                 if (state == LINK_CLOSED) {
                     if (spaces >= 2) {
-                        sb_string_append(rv, "<br />");
+                        b_string_append(rv, "<br />");
                         spaces = 0;
                     }
                     if (c == '\n' || c == '\r')
-                        sb_string_append_c(rv, c);
+                        b_string_append_c(rv, c);
                 }
                 break;
 
             case '&':
                 if (state == LINK_CLOSED)
-                    sb_string_append(rv, "&amp;");
+                    b_string_append(rv, "&amp;");
                 break;
 
             case '<':
                 if (state == LINK_CLOSED)
-                    sb_string_append(rv, "&lt;");
+                    b_string_append(rv, "&lt;");
                 break;
 
             case '>':
                 if (state == LINK_CLOSED)
-                    sb_string_append(rv, "&gt;");
+                    b_string_append(rv, "&gt;");
                 break;
 
             case '"':
                 if (state == LINK_CLOSED)
-                    sb_string_append(rv, "&quot;");
+                    b_string_append(rv, "&quot;");
                 break;
 
             case '\'':
                 if (state == LINK_CLOSED)
-                    sb_string_append(rv, "&#x27;");
+                    b_string_append(rv, "&#x27;");
                 break;
 
             case '/':
                 if (state == LINK_CLOSED)
-                    sb_string_append(rv, "&#x2F;");
+                    b_string_append(rv, "&#x2F;");
                 break;
 
             default:
                 if (state == LINK_CLOSED)
-                    sb_string_append_c(rv, c);
+                    b_string_append_c(rv, c);
         }
 
         if (is_last && state != LINK_CLOSED) {
-            sb_string_append_c(rv, src[start_state]);
+            b_string_append_c(rv, src[start_state]);
             tmp = blogc_content_parse_inline(src + start_state + 1);
-            sb_string_append(rv, tmp);
+            b_string_append(rv, tmp);
             free(tmp);
             tmp = NULL;
         }
@@ -361,7 +361,7 @@ blogc_content_parse_inline(const char *src)
     free(tmp);
     free(tmp2);
 
-    return sb_string_free(rv, false);
+    return b_string_free(rv, false);
 }
 
 
@@ -423,11 +423,11 @@ blogc_content_parse(const char *src, size_t *end_excerpt)
 
     char d = '\0';
 
-    sb_slist_t *lines = NULL;
-    sb_slist_t *lines2 = NULL;
+    b_slist_t *lines = NULL;
+    b_slist_t *lines2 = NULL;
 
-    sb_string_t *rv = sb_string_new();
-    sb_string_t *tmp_str = NULL;
+    b_string_t *rv = b_string_new();
+    b_string_t *tmp_str = NULL;
 
     blogc_content_parser_state_t state = CONTENT_START_LINE;
 
@@ -554,14 +554,14 @@ blogc_content_parse(const char *src, size_t *end_excerpt)
                 if (c == '\n' || c == '\r' || is_last) {
                     end = is_last && c != '\n' && c != '\r' ? src_len :
                         (real_end != 0 ? real_end : current);
-                    tmp = sb_strndup(src + start, end - start);
+                    tmp = b_strndup(src + start, end - start);
                     parsed = blogc_content_parse_inline(tmp);
                     slug = blogc_slugify(tmp);
                     if (slug == NULL)
-                        sb_string_append_printf(rv, "<h%d>%s</h%d>%s",
+                        b_string_append_printf(rv, "<h%d>%s</h%d>%s",
                             header_level, parsed, header_level, line_ending);
                     else
-                        sb_string_append_printf(rv, "<h%d id=\"%s\">%s</h%d>%s",
+                        b_string_append_printf(rv, "<h%d id=\"%s\">%s</h%d>%s",
                             header_level, slug, parsed, header_level,
                             line_ending);
                     free(slug);
@@ -585,8 +585,8 @@ blogc_content_parse(const char *src, size_t *end_excerpt)
 
             case CONTENT_HTML_END:
                 if (c == '\n' || c == '\r' || is_last) {
-                    tmp = sb_strndup(src + start, end - start);
-                    sb_string_append_printf(rv, "%s%s", tmp, line_ending);
+                    tmp = b_strndup(src + start, end - start);
+                    b_string_append_printf(rv, "%s%s", tmp, line_ending);
                     free(tmp);
                     tmp = NULL;
                     state = CONTENT_START_LINE;
@@ -599,7 +599,7 @@ blogc_content_parse(const char *src, size_t *end_excerpt)
             case CONTENT_BLOCKQUOTE:
                 if (c == ' ' || c == '\t')
                     break;
-                prefix = sb_strndup(src + start, current - start);
+                prefix = b_strndup(src + start, current - start);
                 state = CONTENT_BLOCKQUOTE_START;
                 break;
 
@@ -607,16 +607,16 @@ blogc_content_parse(const char *src, size_t *end_excerpt)
                 if (c == '\n' || c == '\r' || is_last) {
                     end = is_last && c != '\n' && c != '\r' ? src_len :
                         (real_end != 0 ? real_end : current);
-                    tmp = sb_strndup(src + start2, end - start2);
-                    if (sb_str_starts_with(tmp, prefix)) {
-                        lines = sb_slist_append(lines, sb_strdup(tmp + strlen(prefix)));
+                    tmp = b_strndup(src + start2, end - start2);
+                    if (b_str_starts_with(tmp, prefix)) {
+                        lines = b_slist_append(lines, b_strdup(tmp + strlen(prefix)));
                         state = CONTENT_BLOCKQUOTE_END;
                     }
                     else {
                         state = CONTENT_PARAGRAPH;
                         free(prefix);
                         prefix = NULL;
-                        sb_slist_free_full(lines, free);
+                        b_slist_free_full(lines, free);
                         lines = NULL;
                         if (is_last) {
                             free(tmp);
@@ -632,22 +632,22 @@ blogc_content_parse(const char *src, size_t *end_excerpt)
 
             case CONTENT_BLOCKQUOTE_END:
                 if (c == '\n' || c == '\r' || is_last) {
-                    tmp_str = sb_string_new();
-                    for (sb_slist_t *l = lines; l != NULL; l = l->next) {
+                    tmp_str = b_string_new();
+                    for (b_slist_t *l = lines; l != NULL; l = l->next) {
                         if (l->next == NULL)
-                            sb_string_append_printf(tmp_str, "%s", l->data);
+                            b_string_append_printf(tmp_str, "%s", l->data);
                         else
-                            sb_string_append_printf(tmp_str, "%s%s", l->data,
+                            b_string_append_printf(tmp_str, "%s%s", l->data,
                                 line_ending);
                     }
                     tmp = blogc_content_parse(tmp_str->str, NULL);
-                    sb_string_append_printf(rv, "<blockquote>%s</blockquote>%s",
+                    b_string_append_printf(rv, "<blockquote>%s</blockquote>%s",
                         tmp, line_ending);
                     free(tmp);
                     tmp = NULL;
-                    sb_string_free(tmp_str, true);
+                    b_string_free(tmp_str, true);
                     tmp_str = NULL;
-                    sb_slist_free_full(lines, free);
+                    b_slist_free_full(lines, free);
                     lines = NULL;
                     free(prefix);
                     prefix = NULL;
@@ -663,7 +663,7 @@ blogc_content_parse(const char *src, size_t *end_excerpt)
             case CONTENT_CODE:
                 if (c == ' ' || c == '\t')
                     break;
-                prefix = sb_strndup(src + start, current - start);
+                prefix = b_strndup(src + start, current - start);
                 state = CONTENT_CODE_START;
                 break;
 
@@ -671,16 +671,16 @@ blogc_content_parse(const char *src, size_t *end_excerpt)
                 if (c == '\n' || c == '\r' || is_last) {
                     end = is_last && c != '\n' && c != '\r' ? src_len :
                         (real_end != 0 ? real_end : current);
-                    tmp = sb_strndup(src + start2, end - start2);
-                    if (sb_str_starts_with(tmp, prefix)) {
-                        lines = sb_slist_append(lines, sb_strdup(tmp + strlen(prefix)));
+                    tmp = b_strndup(src + start2, end - start2);
+                    if (b_str_starts_with(tmp, prefix)) {
+                        lines = b_slist_append(lines, b_strdup(tmp + strlen(prefix)));
                         state = CONTENT_CODE_END;
                     }
                     else {
                         state = CONTENT_PARAGRAPH;
                         free(prefix);
                         prefix = NULL;
-                        sb_slist_free_full(lines, free);
+                        b_slist_free_full(lines, free);
                         lines = NULL;
                         free(tmp);
                         tmp = NULL;
@@ -696,16 +696,16 @@ blogc_content_parse(const char *src, size_t *end_excerpt)
 
             case CONTENT_CODE_END:
                 if (c == '\n' || c == '\r' || is_last) {
-                    sb_string_append(rv, "<pre><code>");
-                    for (sb_slist_t *l = lines; l != NULL; l = l->next) {
+                    b_string_append(rv, "<pre><code>");
+                    for (b_slist_t *l = lines; l != NULL; l = l->next) {
                         if (l->next == NULL)
-                            sb_string_append_printf(rv, "%s", l->data);
+                            b_string_append_printf(rv, "%s", l->data);
                         else
-                            sb_string_append_printf(rv, "%s%s", l->data,
+                            b_string_append_printf(rv, "%s%s", l->data,
                                 line_ending);
                     }
-                    sb_string_append_printf(rv, "</code></pre>%s", line_ending);
-                    sb_slist_free_full(lines, free);
+                    b_string_append_printf(rv, "</code></pre>%s", line_ending);
+                    b_slist_free_full(lines, free);
                     lines = NULL;
                     free(prefix);
                     prefix = NULL;
@@ -727,7 +727,7 @@ blogc_content_parse(const char *src, size_t *end_excerpt)
                 }
                 if (c == ' ' || c == '\t')
                     break;
-                prefix = sb_strndup(src + start, current - start);
+                prefix = b_strndup(src + start, current - start);
                 state = CONTENT_UNORDERED_LIST_START;
                 break;
 
@@ -737,7 +737,7 @@ blogc_content_parse(const char *src, size_t *end_excerpt)
                 }
 hr:
                 if (c == '\n' || c == '\r' || is_last) {
-                    sb_string_append_printf(rv, "<hr />%s", line_ending);
+                    b_string_append_printf(rv, "<hr />%s", line_ending);
                     state = CONTENT_START_LINE;
                     start = current;
                     d = '\0';
@@ -750,30 +750,30 @@ hr:
                 if (c == '\n' || c == '\r' || is_last) {
                     end = is_last && c != '\n' && c != '\r' ? src_len :
                         (real_end != 0 ? real_end : current);
-                    tmp = sb_strndup(src + start2, end - start2);
-                    tmp2 = sb_strdup_printf("%-*s", strlen(prefix), "");
-                    if (sb_str_starts_with(tmp, prefix)) {
+                    tmp = b_strndup(src + start2, end - start2);
+                    tmp2 = b_strdup_printf("%-*s", strlen(prefix), "");
+                    if (b_str_starts_with(tmp, prefix)) {
                         if (lines2 != NULL) {
-                            tmp_str = sb_string_new();
-                            for (sb_slist_t *l = lines2; l != NULL; l = l->next) {
+                            tmp_str = b_string_new();
+                            for (b_slist_t *l = lines2; l != NULL; l = l->next) {
                                 if (l->next == NULL)
-                                    sb_string_append_printf(tmp_str, "%s", l->data);
+                                    b_string_append_printf(tmp_str, "%s", l->data);
                                 else
-                                    sb_string_append_printf(tmp_str, "%s%s", l->data,
+                                    b_string_append_printf(tmp_str, "%s%s", l->data,
                                         line_ending);
                             }
-                            sb_slist_free_full(lines2, free);
+                            b_slist_free_full(lines2, free);
                             lines2 = NULL;
                             parsed = blogc_content_parse_inline(tmp_str->str);
-                            sb_string_free(tmp_str, true);
-                            lines = sb_slist_append(lines, sb_strdup(parsed));
+                            b_string_free(tmp_str, true);
+                            lines = b_slist_append(lines, b_strdup(parsed));
                             free(parsed);
                             parsed = NULL;
                         }
-                        lines2 = sb_slist_append(lines2, sb_strdup(tmp + strlen(prefix)));
+                        lines2 = b_slist_append(lines2, b_strdup(tmp + strlen(prefix)));
                     }
-                    else if (sb_str_starts_with(tmp, tmp2)) {
-                        lines2 = sb_slist_append(lines2, sb_strdup(tmp + strlen(prefix)));
+                    else if (b_str_starts_with(tmp, tmp2)) {
+                        lines2 = b_slist_append(lines2, b_strdup(tmp + strlen(prefix)));
                     }
                     else {
                         state = CONTENT_PARAGRAPH_END;
@@ -783,8 +783,8 @@ hr:
                         tmp2 = NULL;
                         free(prefix);
                         prefix = NULL;
-                        sb_slist_free_full(lines, free);
-                        sb_slist_free_full(lines2, free);
+                        b_slist_free_full(lines, free);
+                        b_slist_free_full(lines2, free);
                         lines = NULL;
                         if (is_last)
                             goto para;
@@ -803,28 +803,28 @@ hr:
                 if (c == '\n' || c == '\r' || is_last) {
                     if (lines2 != NULL) {
                         // FIXME: avoid repeting the code below
-                        tmp_str = sb_string_new();
-                        for (sb_slist_t *l = lines2; l != NULL; l = l->next) {
+                        tmp_str = b_string_new();
+                        for (b_slist_t *l = lines2; l != NULL; l = l->next) {
                             if (l->next == NULL)
-                                sb_string_append_printf(tmp_str, "%s", l->data);
+                                b_string_append_printf(tmp_str, "%s", l->data);
                             else
-                                sb_string_append_printf(tmp_str, "%s%s", l->data,
+                                b_string_append_printf(tmp_str, "%s%s", l->data,
                                     line_ending);
                         }
-                        sb_slist_free_full(lines2, free);
+                        b_slist_free_full(lines2, free);
                         lines2 = NULL;
                         parsed = blogc_content_parse_inline(tmp_str->str);
-                        sb_string_free(tmp_str, true);
-                        lines = sb_slist_append(lines, sb_strdup(parsed));
+                        b_string_free(tmp_str, true);
+                        lines = b_slist_append(lines, b_strdup(parsed));
                         free(parsed);
                         parsed = NULL;
                     }
-                    sb_string_append_printf(rv, "<ul>%s", line_ending);
-                    for (sb_slist_t *l = lines; l != NULL; l = l->next)
-                        sb_string_append_printf(rv, "<li>%s</li>%s", l->data,
+                    b_string_append_printf(rv, "<ul>%s", line_ending);
+                    for (b_slist_t *l = lines; l != NULL; l = l->next)
+                        b_string_append_printf(rv, "<li>%s</li>%s", l->data,
                             line_ending);
-                    sb_string_append_printf(rv, "</ul>%s", line_ending);
-                    sb_slist_free_full(lines, free);
+                    b_string_append_printf(rv, "</ul>%s", line_ending);
+                    b_slist_free_full(lines, free);
                     lines = NULL;
                     free(prefix);
                     prefix = NULL;
@@ -861,30 +861,30 @@ hr:
                 if (c == '\n' || c == '\r' || is_last) {
                     end = is_last && c != '\n' && c != '\r' ? src_len :
                         (real_end != 0 ? real_end : current);
-                    tmp = sb_strndup(src + start2, end - start2);
-                    tmp2 = sb_strdup_printf("%-*s", prefix_len, "");
+                    tmp = b_strndup(src + start2, end - start2);
+                    tmp2 = b_strdup_printf("%-*s", prefix_len, "");
                     if (blogc_is_ordered_list_item(tmp, prefix_len)) {
                         if (lines2 != NULL) {
-                            tmp_str = sb_string_new();
-                            for (sb_slist_t *l = lines2; l != NULL; l = l->next) {
+                            tmp_str = b_string_new();
+                            for (b_slist_t *l = lines2; l != NULL; l = l->next) {
                                 if (l->next == NULL)
-                                    sb_string_append_printf(tmp_str, "%s", l->data);
+                                    b_string_append_printf(tmp_str, "%s", l->data);
                                 else
-                                    sb_string_append_printf(tmp_str, "%s%s", l->data,
+                                    b_string_append_printf(tmp_str, "%s%s", l->data,
                                         line_ending);
                             }
-                            sb_slist_free_full(lines2, free);
+                            b_slist_free_full(lines2, free);
                             lines2 = NULL;
                             parsed = blogc_content_parse_inline(tmp_str->str);
-                            sb_string_free(tmp_str, true);
-                            lines = sb_slist_append(lines, sb_strdup(parsed));
+                            b_string_free(tmp_str, true);
+                            lines = b_slist_append(lines, b_strdup(parsed));
                             free(parsed);
                             parsed = NULL;
                         }
-                        lines2 = sb_slist_append(lines2, sb_strdup(tmp + prefix_len));
+                        lines2 = b_slist_append(lines2, b_strdup(tmp + prefix_len));
                     }
-                    else if (sb_str_starts_with(tmp, tmp2)) {
-                        lines2 = sb_slist_append(lines2, sb_strdup(tmp + prefix_len));
+                    else if (b_str_starts_with(tmp, tmp2)) {
+                        lines2 = b_slist_append(lines2, b_strdup(tmp + prefix_len));
                     }
                     else {
                         state = CONTENT_PARAGRAPH_END;
@@ -894,8 +894,8 @@ hr:
                         tmp2 = NULL;
                         free(parsed);
                         parsed = NULL;
-                        sb_slist_free_full(lines, free);
-                        sb_slist_free_full(lines2, free);
+                        b_slist_free_full(lines, free);
+                        b_slist_free_full(lines2, free);
                         lines = NULL;
                         if (is_last)
                             goto para;
@@ -914,28 +914,28 @@ hr:
                 if (c == '\n' || c == '\r' || is_last) {
                     if (lines2 != NULL) {
                         // FIXME: avoid repeting the code below
-                        tmp_str = sb_string_new();
-                        for (sb_slist_t *l = lines2; l != NULL; l = l->next) {
+                        tmp_str = b_string_new();
+                        for (b_slist_t *l = lines2; l != NULL; l = l->next) {
                             if (l->next == NULL)
-                                sb_string_append_printf(tmp_str, "%s", l->data);
+                                b_string_append_printf(tmp_str, "%s", l->data);
                             else
-                                sb_string_append_printf(tmp_str, "%s%s", l->data,
+                                b_string_append_printf(tmp_str, "%s%s", l->data,
                                     line_ending);
                         }
-                        sb_slist_free_full(lines2, free);
+                        b_slist_free_full(lines2, free);
                         lines2 = NULL;
                         parsed = blogc_content_parse_inline(tmp_str->str);
-                        sb_string_free(tmp_str, true);
-                        lines = sb_slist_append(lines, sb_strdup(parsed));
+                        b_string_free(tmp_str, true);
+                        lines = b_slist_append(lines, b_strdup(parsed));
                         free(parsed);
                         parsed = NULL;
                     }
-                    sb_string_append_printf(rv, "<ol>%s", line_ending);
-                    for (sb_slist_t *l = lines; l != NULL; l = l->next)
-                        sb_string_append_printf(rv, "<li>%s</li>%s", l->data,
+                    b_string_append_printf(rv, "<ol>%s", line_ending);
+                    for (b_slist_t *l = lines; l != NULL; l = l->next)
+                        b_string_append_printf(rv, "<li>%s</li>%s", l->data,
                             line_ending);
-                    sb_string_append_printf(rv, "</ol>%s", line_ending);
-                    sb_slist_free_full(lines, free);
+                    b_string_append_printf(rv, "</ol>%s", line_ending);
+                    b_slist_free_full(lines, free);
                     lines = NULL;
                     free(prefix);
                     prefix = NULL;
@@ -967,9 +967,9 @@ para:
                         else
                             end = src_len;
                     }
-                    tmp = sb_strndup(src + start, end - start);
+                    tmp = b_strndup(src + start, end - start);
                     parsed = blogc_content_parse_inline(tmp);
-                    sb_string_append_printf(rv, "<p>%s</p>%s", parsed,
+                    b_string_append_printf(rv, "<p>%s</p>%s", parsed,
                         line_ending);
                     free(parsed);
                     parsed = NULL;
@@ -987,5 +987,5 @@ para:
         current++;
     }
 
-    return sb_string_free(rv, false);
+    return b_string_free(rv, false);
 }
diff --git a/src/datetime-parser.c b/src/datetime-parser.c
index 50694da..6a2162d 100644
--- a/src/datetime-parser.c
+++ b/src/datetime-parser.c
@@ -17,7 +17,7 @@
 #include <string.h>
 
 #include "error.h"
-#include <squareball.h>
+#include "utils/utils.h"
 #include "datetime-parser.h"
 
 
@@ -380,7 +380,7 @@ blogc_convert_datetime(const char *orig, const char *format,
         return NULL;
     }
 
-    return sb_strdup(buf);
+    return b_strdup(buf);
 
 #endif
 }
diff --git a/src/error.c b/src/error.c
index 94d6162..28396f8 100644
--- a/src/error.c
+++ b/src/error.c
@@ -14,16 +14,16 @@
 #include <stdlib.h>
 #include <stdarg.h>
 #include <string.h>
-#include <squareball.h>
+#include "utils/utils.h"
 #include "error.h"
 
 
 blogc_error_t*
 blogc_error_new(blogc_error_type_t type, const char *msg)
 {
-    blogc_error_t *err = sb_malloc(sizeof(blogc_error_t));
+    blogc_error_t *err = b_malloc(sizeof(blogc_error_t));
     err->type = type;
-    err->msg = sb_strdup(msg);
+    err->msg = b_strdup(msg);
     return err;
 }
 
@@ -33,7 +33,7 @@ blogc_error_new_printf(blogc_error_type_t type, const char *format, ...)
 {
     va_list ap;
     va_start(ap, format);
-    char *tmp = sb_strdup_vprintf(format, ap);
+    char *tmp = b_strdup_vprintf(format, ap);
     va_end(ap);
     blogc_error_t *rv = blogc_error_new(type, tmp);
     free(tmp);
@@ -47,7 +47,7 @@ blogc_error_parser(blogc_error_type_t type, const char *src, size_t src_len,
 {
     va_list ap;
     va_start(ap, format);
-    char *msg = sb_strdup_vprintf(format, ap);
+    char *msg = b_strdup_vprintf(format, ap);
     va_end(ap);
 
     size_t lineno = 1;
@@ -88,7 +88,7 @@ blogc_error_parser(blogc_error_type_t type, const char *src, size_t src_len,
     if (lineend <= linestart && src_len >= linestart)
         lineend = src_len;
 
-    char *line = sb_strndup(src + linestart, lineend - linestart);
+    char *line = b_strndup(src + linestart, lineend - linestart);
 
     blogc_error_t *rv = NULL;
 
diff --git a/src/file.c b/src/file.c
index f6a69c3..d660afc 100644
--- a/src/file.c
+++ b/src/file.c
@@ -14,7 +14,7 @@
 #include <stdarg.h>
 #include <stdio.h>
 #include <string.h>
-#include <squareball.h>
+#include "utils/utils.h"
 #include "file.h"
 #include "error.h"
 
@@ -38,16 +38,16 @@ blogc_file_get_contents(const char *path, size_t *len, blogc_error_t **err)
         return NULL;
     }
 
-    sb_string_t *str = sb_string_new();
+    b_string_t *str = b_string_new();
     char buffer[BLOGC_FILE_CHUNK_SIZE];
 
     while (!feof(fp)) {
         size_t read_len = fread(buffer, sizeof(char), BLOGC_FILE_CHUNK_SIZE, fp);
         *len += read_len;
-        sb_string_append_len(str, buffer, read_len);
+        b_string_append_len(str, buffer, read_len);
     }
     fclose(fp);
-    return sb_string_free(str, false);
+    return b_string_free(str, false);
 }
 
 
diff --git a/src/loader.c b/src/loader.c
index 6fc9581..8f04dae 100644
--- a/src/loader.c
+++ b/src/loader.c
@@ -14,7 +14,7 @@
 #include <stdbool.h>
 #include <stdio.h>
 #include <string.h>
-#include <squareball.h>
+#include "utils/utils.h"
 #include "file.h"
 #include "source-parser.h"
 #include "template-parser.h"
@@ -31,7 +31,7 @@ blogc_get_filename(const char *f)
     if (strlen(f) == 0)
         return NULL;
 
-    char *filename = sb_strdup(f);
+    char *filename = b_strdup(f);
 
     // keep a pointer to original string
     char *tmp = filename;
@@ -52,14 +52,14 @@ blogc_get_filename(const char *f)
         }
     }
 
-    char *final_filename = sb_strdup(tmp);
+    char *final_filename = b_strdup(tmp);
     free(filename);
 
     return final_filename;
 }
 
 
-sb_slist_t*
+b_slist_t*
 blogc_template_parse_from_file(const char *f, blogc_error_t **err)
 {
     if (err == NULL || *err != NULL)
@@ -68,13 +68,13 @@ blogc_template_parse_from_file(const char *f, blogc_error_t **err)
     char *s = blogc_file_get_contents(f, &len, err);
     if (s == NULL)
         return NULL;
-    sb_slist_t *rv = blogc_template_parse(s, len, err);
+    b_slist_t *rv = blogc_template_parse(s, len, err);
     free(s);
     return rv;
 }
 
 
-sb_trie_t*
+b_trie_t*
 blogc_source_parse_from_file(const char *f, blogc_error_t **err)
 {
     if (err == NULL || *err != NULL)
@@ -83,13 +83,13 @@ blogc_source_parse_from_file(const char *f, blogc_error_t **err)
     char *s = blogc_file_get_contents(f, &len, err);
     if (s == NULL)
         return NULL;
-    sb_trie_t *rv = blogc_source_parse(s, len, err);
+    b_trie_t *rv = blogc_source_parse(s, len, err);
 
     // set FILENAME variable
     if (rv != NULL) {
         char *filename = blogc_get_filename(f);
         if (filename != NULL)
-            sb_trie_insert(rv, "FILENAME", filename);
+            b_trie_insert(rv, "FILENAME", filename);
     }
 
     free(s);
@@ -97,16 +97,16 @@ blogc_source_parse_from_file(const char *f, blogc_error_t **err)
 }
 
 
-sb_slist_t*
-blogc_source_parse_from_files(sb_trie_t *conf, sb_slist_t *l, blogc_error_t **err)
+b_slist_t*
+blogc_source_parse_from_files(b_trie_t *conf, b_slist_t *l, blogc_error_t **err)
 {
     blogc_error_t *tmp_err = NULL;
-    sb_slist_t *rv = NULL;
+    b_slist_t *rv = NULL;
     unsigned int with_date = 0;
 
-    const char *filter_tag = sb_trie_lookup(conf, "FILTER_TAG");
-    const char *filter_page = sb_trie_lookup(conf, "FILTER_PAGE");
-    const char *filter_per_page = sb_trie_lookup(conf, "FILTER_PER_PAGE");
+    const char *filter_tag = b_trie_lookup(conf, "FILTER_TAG");
+    const char *filter_page = b_trie_lookup(conf, "FILTER_PAGE");
+    const char *filter_per_page = b_trie_lookup(conf, "FILTER_PER_PAGE");
 
     long page = strtol(filter_page != NULL ? filter_page : "", NULL, 10);
     if (page <= 0)
@@ -121,51 +121,51 @@ blogc_source_parse_from_files(sb_trie_t *conf, sb_slist_t *l, blogc_error_t **er
     unsigned int end = start + per_page;
     unsigned int counter = 0;
 
-    for (sb_slist_t *tmp = l; tmp != NULL; tmp = tmp->next) {
+    for (b_slist_t *tmp = l; tmp != NULL; tmp = tmp->next) {
         char *f = tmp->data;
-        sb_trie_t *s = blogc_source_parse_from_file(f, &tmp_err);
+        b_trie_t *s = blogc_source_parse_from_file(f, &tmp_err);
         if (s == NULL) {
             *err = blogc_error_new_printf(BLOGC_ERROR_LOADER,
                 "An error occurred while parsing source file: %s\n\n%s",
                 f, tmp_err->msg);
             blogc_error_free(tmp_err);
             tmp_err = NULL;
-            sb_slist_free_full(rv, (sb_free_func_t) sb_trie_free);
+            b_slist_free_full(rv, (b_free_func_t) b_trie_free);
             rv = NULL;
             break;
         }
         if (filter_tag != NULL) {
-            const char *tags_str = sb_trie_lookup(s, "TAGS");
+            const char *tags_str = b_trie_lookup(s, "TAGS");
             // if user wants to filter by tag and no tag is provided, skip it
             if (tags_str == NULL) {
-                sb_trie_free(s);
+                b_trie_free(s);
                 continue;
             }
-            char **tags = sb_str_split(tags_str, ',', 0);
+            char **tags = b_str_split(tags_str, ',', 0);
             bool found = false;
             for (unsigned int i = 0; tags[i] != NULL; i++)
-                if (0 == strcmp(sb_str_strip(tags[i]), filter_tag))
+                if (0 == strcmp(b_str_strip(tags[i]), filter_tag))
                     found = true;
-            sb_strv_free(tags);
+            b_strv_free(tags);
             if (!found) {
-                sb_trie_free(s);
+                b_trie_free(s);
                 continue;
             }
         }
         if (filter_page != NULL) {
             if (counter < start || counter >= end) {
                 counter++;
-                sb_trie_free(s);
+                b_trie_free(s);
                 continue;
             }
             counter++;
         }
-        if (sb_trie_lookup(s, "DATE") != NULL)
+        if (b_trie_lookup(s, "DATE") != NULL)
             with_date++;
-        rv = sb_slist_append(rv, s);
+        rv = b_slist_append(rv, s);
     }
 
-    if (with_date > 0 && with_date < sb_slist_length(rv))
+    if (with_date > 0 && with_date < b_slist_length(rv))
         // fatal error, maybe?
         blogc_fprintf(stderr,
             "blogc: warning: 'DATE' variable provided for at least one source "
@@ -173,38 +173,38 @@ blogc_source_parse_from_files(sb_trie_t *conf, sb_slist_t *l, blogc_error_t **er
             "wrong values for 'DATE_FIRST' and 'DATE_LAST' variables.\n");
 
     bool first = true;
-    for (sb_slist_t *tmp = rv; tmp != NULL; tmp = tmp->next) {
-        sb_trie_t *s = tmp->data;
+    for (b_slist_t *tmp = rv; tmp != NULL; tmp = tmp->next) {
+        b_trie_t *s = tmp->data;
         if (first) {
-            const char *val = sb_trie_lookup(s, "DATE");
+            const char *val = b_trie_lookup(s, "DATE");
             if (val != NULL)
-                sb_trie_insert(conf, "DATE_FIRST", sb_strdup(val));
-            val = sb_trie_lookup(s, "FILENAME");
+                b_trie_insert(conf, "DATE_FIRST", b_strdup(val));
+            val = b_trie_lookup(s, "FILENAME");
             if (val != NULL)
-                sb_trie_insert(conf, "FILENAME_FIRST", sb_strdup(val));
+                b_trie_insert(conf, "FILENAME_FIRST", b_strdup(val));
             first = false;
         }
         if (tmp->next == NULL) {  // last
-            const char *val = sb_trie_lookup(s, "DATE");
+            const char *val = b_trie_lookup(s, "DATE");
             if (val != NULL)
-                sb_trie_insert(conf, "DATE_LAST", sb_strdup(val));
-            val = sb_trie_lookup(s, "FILENAME");
+                b_trie_insert(conf, "DATE_LAST", b_strdup(val));
+            val = b_trie_lookup(s, "FILENAME");
             if (val != NULL)
-                sb_trie_insert(conf, "FILENAME_LAST", sb_strdup(val));
+                b_trie_insert(conf, "FILENAME_LAST", b_strdup(val));
         }
     }
 
     if (filter_page != NULL) {
         unsigned int last_page = ceilf(((float) counter) / per_page);
-        sb_trie_insert(conf, "CURRENT_PAGE", sb_strdup_printf("%ld", page));
+        b_trie_insert(conf, "CURRENT_PAGE", b_strdup_printf("%ld", page));
         if (page > 1)
-            sb_trie_insert(conf, "PREVIOUS_PAGE", sb_strdup_printf("%ld", page - 1));
+            b_trie_insert(conf, "PREVIOUS_PAGE", b_strdup_printf("%ld", page - 1));
         if (page < last_page)
-            sb_trie_insert(conf, "NEXT_PAGE", sb_strdup_printf("%ld", page + 1));
-        if (sb_slist_length(rv) > 0)
-            sb_trie_insert(conf, "FIRST_PAGE", sb_strdup("1"));
+            b_trie_insert(conf, "NEXT_PAGE", b_strdup_printf("%ld", page + 1));
+        if (b_slist_length(rv) > 0)
+            b_trie_insert(conf, "FIRST_PAGE", b_strdup("1"));
         if (last_page > 0)
-            sb_trie_insert(conf, "LAST_PAGE", sb_strdup_printf("%d", last_page));
+            b_trie_insert(conf, "LAST_PAGE", b_strdup_printf("%d", last_page));
     }
 
     return rv;
diff --git a/src/loader.h b/src/loader.h
index b4ce569..610aa42 100644
--- a/src/loader.h
+++ b/src/loader.h
@@ -9,13 +9,13 @@
 #ifndef _LOADER_H
 #define _LOADER_H
 
-#include <squareball.h>
+#include "utils/utils.h"
 #include "error.h"
 
 char* blogc_get_filename(const char *f);
-sb_slist_t* blogc_template_parse_from_file(const char *f, blogc_error_t **err);
-sb_trie_t* blogc_source_parse_from_file(const char *f, blogc_error_t **err);
-sb_slist_t* blogc_source_parse_from_files(sb_trie_t *conf, sb_slist_t *l,
+b_slist_t* blogc_template_parse_from_file(const char *f, blogc_error_t **err);
+b_trie_t* blogc_source_parse_from_file(const char *f, blogc_error_t **err);
+b_slist_t* blogc_source_parse_from_files(b_trie_t *conf, b_slist_t *l,
     blogc_error_t **err);
 
 #endif /* _LOADER_H */
diff --git a/src/main.c b/src/main.c
index 3315a80..600a131 100644
--- a/src/main.c
+++ b/src/main.c
@@ -24,7 +24,7 @@
 #include <stdio.h>
 #include <string.h>
 
-#include <squareball.h>
+#include "utils/utils.h"
 #include "source-parser.h"
 #include "template-parser.h"
 #include "loader.h"
@@ -71,7 +71,7 @@ blogc_print_usage(void)
 static void
 blogc_mkdir_recursive(const char *filename)
 {
-    char *fname = sb_strdup(filename);
+    char *fname = b_strdup(filename);
     for (char *tmp = fname; *tmp != '\0'; tmp++) {
         if (*tmp != '/' && *tmp != '\\')
             continue;
@@ -117,9 +117,9 @@ main(int argc, char **argv)
     char *tmp = NULL;
     char **pieces = NULL;
 
-    sb_slist_t *sources = NULL;
-    sb_trie_t *config = sb_trie_new(free);
-    sb_trie_insert(config, "BLOGC_VERSION", sb_strdup(PACKAGE_VERSION));
+    b_slist_t *sources = NULL;
+    b_trie_t *config = b_trie_new(free);
+    b_trie_insert(config, "BLOGC_VERSION", b_strdup(PACKAGE_VERSION));
 
     for (unsigned int i = 1; i < argc; i++) {
         tmp = NULL;
@@ -136,21 +136,21 @@ main(int argc, char **argv)
                     break;
                 case 't':
                     if (argv[i][2] != '\0')
-                        template = sb_strdup(argv[i] + 2);
+                        template = b_strdup(argv[i] + 2);
                     else if (i + 1 < argc)
-                        template = sb_strdup(argv[++i]);
+                        template = b_strdup(argv[++i]);
                     break;
                 case 'o':
                     if (argv[i][2] != '\0')
-                        output = sb_strdup(argv[i] + 2);
+                        output = b_strdup(argv[i] + 2);
                     else if (i + 1 < argc)
-                        output = sb_strdup(argv[++i]);
+                        output = b_strdup(argv[++i]);
                     break;
                 case 'p':
                     if (argv[i][2] != '\0')
-                        print = sb_strdup(argv[i] + 2);
+                        print = b_strdup(argv[i] + 2);
                     else if (i + 1 < argc)
-                        print = sb_strdup(argv[++i]);
+                        print = b_strdup(argv[++i]);
                     break;
                 case 'D':
                     if (argv[i][2] != '\0')
@@ -158,11 +158,11 @@ main(int argc, char **argv)
                     else if (i + 1 < argc)
                         tmp = argv[++i];
                     if (tmp != NULL) {
-                        pieces = sb_str_split(tmp, '=', 2);
-                        if (sb_strv_length(pieces) != 2) {
+                        pieces = b_str_split(tmp, '=', 2);
+                        if (b_strv_length(pieces) != 2) {
                             fprintf(stderr, "blogc: error: invalid value for "
                                 "-D (must have an '='): %s\n", tmp);
-                            sb_strv_free(pieces);
+                            b_strv_free(pieces);
                             rv = 2;
                             goto cleanup;
                         }
@@ -173,13 +173,13 @@ main(int argc, char **argv)
                                 fprintf(stderr, "blogc: error: invalid value "
                                     "for -D (configuration key must be uppercase "
                                     "with '_'): %s\n", pieces[0]);
-                                sb_strv_free(pieces);
+                                b_strv_free(pieces);
                                 rv = 2;
                                 goto cleanup;
                             }
                         }
-                        sb_trie_insert(config, pieces[0], sb_strdup(pieces[1]));
-                        sb_strv_free(pieces);
+                        b_trie_insert(config, pieces[0], b_strdup(pieces[1]));
+                        b_strv_free(pieces);
                         pieces = NULL;
                     }
                     break;
@@ -192,17 +192,17 @@ main(int argc, char **argv)
             }
         }
         else
-            sources = sb_slist_append(sources, sb_strdup(argv[i]));
+            sources = b_slist_append(sources, b_strdup(argv[i]));
     }
 
-    if (!listing && sb_slist_length(sources) == 0) {
+    if (!listing && b_slist_length(sources) == 0) {
         blogc_print_usage();
         fprintf(stderr, "blogc: error: one source file is required\n");
         rv = 2;
         goto cleanup;
     }
 
-    if (!listing && sb_slist_length(sources) > 1) {
+    if (!listing && b_slist_length(sources) > 1) {
         blogc_print_usage();
         fprintf(stderr, "blogc: error: only one source file should be provided, "
             "if running without '-l'\n");
@@ -212,14 +212,14 @@ main(int argc, char **argv)
 
     blogc_error_t *err = NULL;
 
-    sb_slist_t *s = blogc_source_parse_from_files(config, sources, &err);
+    b_slist_t *s = blogc_source_parse_from_files(config, sources, &err);
     if (err != NULL) {
         blogc_error_print(err);
         rv = 2;
         goto cleanup2;
     }
 
-    sb_slist_t* l = blogc_template_parse_from_file(template, &err);
+    b_slist_t* l = blogc_template_parse_from_file(template, &err);
     if (err != NULL) {
         blogc_error_print(err);
         rv = 2;
@@ -227,7 +227,7 @@ main(int argc, char **argv)
     }
 
     if (print != NULL) {
-        const char *val = sb_trie_lookup(config, print);
+        const char *val = b_trie_lookup(config, print);
         if (val == NULL) {
             fprintf(stderr, "blogc: error: configuration variable not found: %s\n",
                 print);
@@ -273,13 +273,13 @@ cleanup4:
 cleanup3:
     blogc_template_free_stmts(l);
 cleanup2:
-    sb_slist_free_full(s, (sb_free_func_t) sb_trie_free);
+    b_slist_free_full(s, (b_free_func_t) b_trie_free);
     blogc_error_free(err);
 cleanup:
-    sb_trie_free(config);
+    b_trie_free(config);
     free(template);
     free(output);
     free(print);
-    sb_slist_free_full(sources, free);
+    b_slist_free_full(sources, free);
     return rv;
 }
diff --git a/src/renderer.c b/src/renderer.c
index 52af8d9..3061c43 100644
--- a/src/renderer.c
+++ b/src/renderer.c
@@ -13,7 +13,7 @@
 #include <stdbool.h>
 #include <stdio.h>
 #include <string.h>
-#include <squareball.h>
+#include "utils/utils.h"
 #include "datetime-parser.h"
 #include "error.h"
 #include "loader.h"
@@ -23,51 +23,51 @@
 
 
 const char*
-blogc_get_variable(const char *name, sb_trie_t *global, sb_trie_t *local)
+blogc_get_variable(const char *name, b_trie_t *global, b_trie_t *local)
 {
     const char *rv = NULL;
     if (local != NULL) {
-        rv = sb_trie_lookup(local, name);
+        rv = b_trie_lookup(local, name);
         if (rv != NULL)
             return rv;
     }
     if (global != NULL)
-        rv = sb_trie_lookup(global, name);
+        rv = b_trie_lookup(global, name);
     return rv;
 }
 
 
 char*
-blogc_format_date(const char *date, sb_trie_t *global, sb_trie_t *local)
+blogc_format_date(const char *date, b_trie_t *global, b_trie_t *local)
 {
     const char *date_format = blogc_get_variable("DATE_FORMAT", global, local);
     if (date == NULL)
         return NULL;
     if (date_format == NULL)
-        return sb_strdup(date);
+        return b_strdup(date);
 
     blogc_error_t *err = NULL;
     char *rv = blogc_convert_datetime(date, date_format, &err);
     if (err != NULL) {
         blogc_error_print(err);
         blogc_error_free(err);
-        return sb_strdup(date);
+        return b_strdup(date);
     }
     return rv;
 }
 
 
 char*
-blogc_format_variable(const char *name, sb_trie_t *global, sb_trie_t *local)
+blogc_format_variable(const char *name, b_trie_t *global, b_trie_t *local)
 {
     char *var = NULL;
     bool must_format = false;
-    if (sb_str_ends_with(name, "_FORMATTED")) {
-        var = sb_strndup(name, strlen(name) - 10);
+    if (b_str_ends_with(name, "_FORMATTED")) {
+        var = b_strndup(name, strlen(name) - 10);
         must_format = true;
     }
     if (var == NULL)
-        var = sb_strdup(name);
+        var = b_strdup(name);
 
     const char *value = blogc_get_variable(var, global, local);
     free(var);
@@ -77,29 +77,29 @@ blogc_format_variable(const char *name, sb_trie_t *global, sb_trie_t *local)
 
     char *rv = NULL;
     if (must_format) {
-        if (sb_str_starts_with(name, "DATE_")) {
+        if (b_str_starts_with(name, "DATE_")) {
             rv = blogc_format_date(value, global, local);
         }
     }
 
     if (rv == NULL)
-        return sb_strdup(value);
+        return b_strdup(value);
     return rv;
 }
 
 
 char*
-blogc_render(sb_slist_t *tmpl, sb_slist_t *sources, sb_trie_t *config, bool listing)
+blogc_render(b_slist_t *tmpl, b_slist_t *sources, b_trie_t *config, bool listing)
 {
     if (tmpl == NULL)
         return NULL;
 
-    sb_slist_t *current_source = NULL;
-    sb_slist_t *listing_start = NULL;
+    b_slist_t *current_source = NULL;
+    b_slist_t *listing_start = NULL;
 
-    sb_string_t *str = sb_string_new();
+    b_string_t *str = b_string_new();
 
-    sb_trie_t *tmp_source = NULL;
+    b_trie_t *tmp_source = NULL;
     char *config_value = NULL;
     char *defined = NULL;
 
@@ -112,7 +112,7 @@ blogc_render(sb_slist_t *tmpl, sb_slist_t *sources, sb_trie_t *config, bool list
 
     int cmp = 0;
 
-    sb_slist_t *tmp = tmpl;
+    b_slist_t *tmp = tmpl;
     while (tmp != NULL) {
         blogc_template_stmt_t *stmt = tmp->data;
 
@@ -120,7 +120,7 @@ blogc_render(sb_slist_t *tmpl, sb_slist_t *sources, sb_trie_t *config, bool list
 
             case BLOGC_TEMPLATE_CONTENT_STMT:
                 if (stmt->value != NULL)
-                    sb_string_append(str, stmt->value);
+                    b_string_append(str, stmt->value);
                 break;
 
             case BLOGC_TEMPLATE_BLOCK_STMT:
@@ -177,7 +177,7 @@ blogc_render(sb_slist_t *tmpl, sb_slist_t *sources, sb_trie_t *config, bool list
                     config_value = blogc_format_variable(stmt->value,
                         config, inside_block ? tmp_source : NULL);
                     if (config_value != NULL) {
-                        sb_string_append(str, config_value);
+                        b_string_append(str, config_value);
                         free(config_value);
                         config_value = NULL;
                         break;
@@ -218,7 +218,7 @@ blogc_render(sb_slist_t *tmpl, sb_slist_t *sources, sb_trie_t *config, bool list
                             (stmt->value2[0] == '"') &&
                             (stmt->value2[strlen(stmt->value2) - 1] == '"'))
                         {
-                            defined2 = sb_strndup(stmt->value2 + 1,
+                            defined2 = b_strndup(stmt->value2 + 1,
                                 strlen(stmt->value2) - 2);
                         }
                         else {
@@ -285,5 +285,5 @@ blogc_render(sb_slist_t *tmpl, sb_slist_t *sources, sb_trie_t *config, bool list
         tmp = tmp->next;
     }
 
-    return sb_string_free(str, false);
+    return b_string_free(str, false);
 }
diff --git a/src/renderer.h b/src/renderer.h
index 4361c12..e5cff6e 100644
--- a/src/renderer.h
+++ b/src/renderer.h
@@ -10,12 +10,12 @@
 #define _RENDERER_H
 
 #include <stdbool.h>
-#include <squareball.h>
+#include "utils/utils.h"
 
-const char* blogc_get_variable(const char *name, sb_trie_t *global, sb_trie_t *local);
-char* blogc_format_date(const char *date, sb_trie_t *global, sb_trie_t *local);
-char* blogc_format_variable(const char *name, sb_trie_t *global, sb_trie_t *local);
-char* blogc_render(sb_slist_t *tmpl, sb_slist_t *sources, sb_trie_t *config,
+const char* blogc_get_variable(const char *name, b_trie_t *global, b_trie_t *local);
+char* blogc_format_date(const char *date, b_trie_t *global, b_trie_t *local);
+char* blogc_format_variable(const char *name, b_trie_t *global, b_trie_t *local);
+char* blogc_render(b_slist_t *tmpl, b_slist_t *sources, b_trie_t *config,
     bool listing);
 
 #endif /* _RENDERER_H */
diff --git a/src/source-parser.c b/src/source-parser.c
index 8801210..db0792c 100644
--- a/src/source-parser.c
+++ b/src/source-parser.c
@@ -13,7 +13,7 @@
 #include <stdbool.h>
 #include <string.h>
 
-#include <squareball.h>
+#include "utils/utils.h"
 #include "content-parser.h"
 #include "source-parser.h"
 #include "error.h"
@@ -30,7 +30,7 @@ typedef enum {
 } blogc_source_parser_state_t;
 
 
-sb_trie_t*
+b_trie_t*
 blogc_source_parse(const char *src, size_t src_len, blogc_error_t **err)
 {
     if (err == NULL || *err != NULL)
@@ -43,7 +43,7 @@ blogc_source_parse(const char *src, size_t src_len, blogc_error_t **err)
     char *key = NULL;
     char *tmp = NULL;
     char *content = NULL;
-    sb_trie_t *rv = sb_trie_new(free);
+    b_trie_t *rv = b_trie_new(free);
 
     blogc_source_parser_state_t state = SOURCE_START;
 
@@ -73,7 +73,7 @@ blogc_source_parse(const char *src, size_t src_len, blogc_error_t **err)
                 if ((c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_')
                     break;
                 if (c == ':') {
-                    key = sb_strndup(src + start, current - start);
+                    key = b_strndup(src + start, current - start);
                     if (((current - start == 8) &&
                          (0 == strncmp("FILENAME", src + start, 8))) ||
                         ((current - start == 7) &&
@@ -122,8 +122,8 @@ blogc_source_parse(const char *src, size_t src_len, blogc_error_t **err)
 
             case SOURCE_CONFIG_VALUE:
                 if (c == '\n' || c == '\r') {
-                    tmp = sb_strndup(src + start, current - start);
-                    sb_trie_insert(rv, key, sb_strdup(sb_str_strip(tmp)));
+                    tmp = b_strndup(src + start, current - start);
+                    b_trie_insert(rv, key, b_strdup(b_str_strip(tmp)));
                     free(tmp);
                     free(key);
                     key = NULL;
@@ -152,12 +152,12 @@ blogc_source_parse(const char *src, size_t src_len, blogc_error_t **err)
 
             case SOURCE_CONTENT:
                 if (current == (src_len - 1)) {
-                    tmp = sb_strndup(src + start, src_len - start);
-                    sb_trie_insert(rv, "RAW_CONTENT", tmp);
+                    tmp = b_strndup(src + start, src_len - start);
+                    b_trie_insert(rv, "RAW_CONTENT", tmp);
                     content = blogc_content_parse(tmp, &end_excerpt);
-                    sb_trie_insert(rv, "CONTENT", content);
-                    sb_trie_insert(rv, "EXCERPT", end_excerpt == 0 ?
-                        sb_strdup(content) : sb_strndup(content, end_excerpt));
+                    b_trie_insert(rv, "CONTENT", content);
+                    b_trie_insert(rv, "EXCERPT", end_excerpt == 0 ?
+                        b_strdup(content) : b_strndup(content, end_excerpt));
                 }
                 break;
         }
@@ -168,7 +168,7 @@ blogc_source_parse(const char *src, size_t src_len, blogc_error_t **err)
         current++;
     }
 
-    if (*err == NULL && sb_trie_size(rv) == 0) {
+    if (*err == NULL && b_trie_size(rv) == 0) {
 
         // ok, nothing found in the config trie, but no error set either.
         // let's try to be nice with the users and provide some reasonable
@@ -202,7 +202,7 @@ blogc_source_parse(const char *src, size_t src_len, blogc_error_t **err)
 
     if (*err != NULL) {
         free(key);
-        sb_trie_free(rv);
+        b_trie_free(rv);
         return NULL;
     }
 
diff --git a/src/source-parser.h b/src/source-parser.h
index 94bf0d4..d92b1ce 100644
--- a/src/source-parser.h
+++ b/src/source-parser.h
@@ -10,10 +10,10 @@
 #define _SOURCE_PARSER_H
 
 #include <stdlib.h>
-#include <squareball.h>
+#include "utils/utils.h"
 #include "error.h"
 
-sb_trie_t* blogc_source_parse(const char *src, size_t src_len,
+b_trie_t* blogc_source_parse(const char *src, size_t src_len,
     blogc_error_t **err);
 
 #endif /* _SOURCE_PARSER_H */
diff --git a/src/template-parser.c b/src/template-parser.c
index a00a2c2..f6912df 100644
--- a/src/template-parser.c
+++ b/src/template-parser.c
@@ -13,7 +13,7 @@
 #include <stdbool.h>
 #include <string.h>
 
-#include <squareball.h>
+#include "utils/utils.h"
 #include "template-parser.h"
 #include "error.h"
 
@@ -48,7 +48,7 @@ typedef enum {
 } blogc_template_parser_block_state_t;
 
 
-sb_slist_t*
+b_slist_t*
 blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err)
 {
     if (err == NULL || *err != NULL)
@@ -66,7 +66,7 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err)
 
     unsigned int if_count = 0;
 
-    sb_slist_t *stmts = NULL;
+    b_slist_t *stmts = NULL;
     blogc_template_stmt_t *stmt = NULL;
 
     blogc_template_parser_state_t state = TEMPLATE_START;
@@ -81,12 +81,12 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err)
 
             case TEMPLATE_START:
                 if (last) {
-                    stmt = sb_malloc(sizeof(blogc_template_stmt_t));
+                    stmt = b_malloc(sizeof(blogc_template_stmt_t));
                     stmt->type = type;
-                    stmt->value = sb_strndup(src + start, src_len - start);
+                    stmt->value = b_strndup(src + start, src_len - start);
                     stmt->op = 0;
                     stmt->value2 = NULL;
-                    stmts = sb_slist_append(stmts, stmt);
+                    stmts = b_slist_append(stmts, stmt);
                     stmt = NULL;
                 }
                 if (c == '{') {
@@ -102,12 +102,12 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err)
                     else
                         state = TEMPLATE_VARIABLE_START;
                     if (end > start) {
-                        stmt = sb_malloc(sizeof(blogc_template_stmt_t));
+                        stmt = b_malloc(sizeof(blogc_template_stmt_t));
                         stmt->type = type;
-                        stmt->value = sb_strndup(src + start, end - start);
+                        stmt->value = b_strndup(src + start, end - start);
                         stmt->op = 0;
                         stmt->value2 = NULL;
-                        stmts = sb_slist_append(stmts, stmt);
+                        stmts = b_slist_append(stmts, stmt);
                         stmt = NULL;
                     }
                     break;
@@ -426,19 +426,19 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err)
                         op_start = 0;
                         op_end = 0;
                     }
-                    stmt = sb_malloc(sizeof(blogc_template_stmt_t));
+                    stmt = b_malloc(sizeof(blogc_template_stmt_t));
                     stmt->type = type;
                     stmt->value = NULL;
                     stmt->op = tmp_op;
                     stmt->value2 = NULL;
                     if (end > start)
-                        stmt->value = sb_strndup(src + start, end - start);
+                        stmt->value = b_strndup(src + start, end - start);
                     if (end2 > start2) {
-                        stmt->value2 = sb_strndup(src + start2, end2 - start2);
+                        stmt->value2 = b_strndup(src + start2, end2 - start2);
                         start2 = 0;
                         end2 = 0;
                     }
-                    stmts = sb_slist_append(stmts, stmt);
+                    stmts = b_slist_append(stmts, stmt);
                     stmt = NULL;
                     state = TEMPLATE_START;
                     type = BLOGC_TEMPLATE_CONTENT_STMT;
@@ -485,9 +485,9 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err)
 
 
 void
-blogc_template_free_stmts(sb_slist_t *stmts)
+blogc_template_free_stmts(b_slist_t *stmts)
 {
-    for (sb_slist_t *tmp = stmts; tmp != NULL; tmp = tmp->next) {
+    for (b_slist_t *tmp = stmts; tmp != NULL; tmp = tmp->next) {
         blogc_template_stmt_t *data = tmp->data;
         if (data == NULL)
             continue;
@@ -495,5 +495,5 @@ blogc_template_free_stmts(sb_slist_t *stmts)
         free(data->value2);
         free(data);
     }
-    sb_slist_free(stmts);
+    b_slist_free(stmts);
 }
diff --git a/src/template-parser.h b/src/template-parser.h
index c576bc0..d1e9bd6 100644
--- a/src/template-parser.h
+++ b/src/template-parser.h
@@ -9,7 +9,7 @@
 #ifndef _TEMPLATE_PARSER_H
 #define _TEMPLATE_PARSER_H
 
-#include <squareball.h>
+#include "utils/utils.h"
 #include "error.h"
 
 typedef enum {
@@ -37,8 +37,8 @@ typedef struct {
     blogc_template_stmt_operator_t op;
 } blogc_template_stmt_t;
 
-sb_slist_t* blogc_template_parse(const char *src, size_t src_len,
+b_slist_t* blogc_template_parse(const char *src, size_t src_len,
     blogc_error_t **err);
-void blogc_template_free_stmts(sb_slist_t *stmts);
+void blogc_template_free_stmts(b_slist_t *stmts);
 
 #endif /* _TEMPLATE_GRAMMAR_H */
diff --git a/src/utils/mem.c b/src/utils/mem.c
new file mode 100644
index 0000000..7c5e0a2
--- /dev/null
+++ b/src/utils/mem.c
@@ -0,0 +1,42 @@
+/*
+ * blogc: A blog compiler.
+ * Copyright (C) 2014-2015 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 <stdlib.h>
+#include <stdio.h>
+#include "utils.h"
+
+
+void*
+b_malloc(size_t size)
+{
+    // simple things simple!
+    void *rv = malloc(size);
+    if (rv == NULL) {
+        fprintf(stderr, "fatal error: Failed to allocate memory!\n");
+        exit(1);
+    }
+    return rv;
+}
+
+
+void*
+b_realloc(void *ptr, size_t size)
+{
+    // simple things even simpler :P
+    void *rv = realloc(ptr, size);
+    if (rv == NULL && size != 0) {
+        fprintf(stderr, "fatal error: Failed to reallocate memory!\n");
+        free(ptr);
+        exit(1);
+    }
+    return rv;
+}
diff --git a/src/utils/slist.c b/src/utils/slist.c
new file mode 100644
index 0000000..3d9b892
--- /dev/null
+++ b/src/utils/slist.c
@@ -0,0 +1,68 @@
+/*
+ * blogc: A blog compiler.
+ * Copyright (C) 2014-2015 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 <stdlib.h>
+#include "utils.h"
+
+
+b_slist_t*
+b_slist_append(b_slist_t *l, void *data)
+{
+    b_slist_t *node = malloc(sizeof(b_slist_t));
+    if (node == NULL) {
+        l = NULL;
+        return l;
+    }
+    node->data = data;
+    node->next = NULL;
+    if (l == NULL)
+        l = node;
+    else {
+        b_slist_t *tmp;
+        for (tmp = l; tmp->next != NULL; tmp = tmp->next);
+        tmp->next = node;
+    }
+    return l;
+}
+
+
+void
+b_slist_free_full(b_slist_t *l, b_free_func_t free_func)
+{
+    while (l != NULL) {
+        b_slist_t *tmp = l->next;
+        free_func(l->data);
+        free(l);
+        l = tmp;
+    }
+}
+
+
+void
+b_slist_free(b_slist_t *l)
+{
+    while (l != NULL) {
+        b_slist_t *tmp = l->next;
+        free(l);
+        l = tmp;
+    }
+}
+
+
+unsigned int
+b_slist_length(b_slist_t *l)
+{
+    unsigned int i;
+    b_slist_t *tmp;
+    for (tmp = l, i = 0; tmp != NULL; tmp = tmp->next, i++);
+    return i;
+}
diff --git a/src/utils/strings.c b/src/utils/strings.c
new file mode 100644
index 0000000..40174a1
--- /dev/null
+++ b/src/utils/strings.c
@@ -0,0 +1,283 @@
+/*
+ * blogc: A blog compiler.
+ * Copyright (C) 2014-2015 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 <ctype.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "utils.h"
+
+
+char*
+b_strdup(const char *s)
+{
+    if (s == NULL)
+        return NULL;
+    size_t l = strlen(s);
+    char *tmp = malloc(l + 1);
+    if (tmp == NULL)
+        return NULL;
+    memcpy(tmp, s, l + 1);
+    return tmp;
+}
+
+
+char*
+b_strndup(const char *s, size_t n)
+{
+    if (s == NULL)
+        return NULL;
+    size_t l = strnlen(s, n);
+    char *tmp = malloc(l + 1);
+    if (tmp == NULL)
+        return NULL;
+    memcpy(tmp, s, l);
+    tmp[l] = '\0';
+    return tmp;
+}
+
+
+char*
+b_strdup_vprintf(const char *format, va_list ap)
+{
+    va_list ap2;
+    va_copy(ap2, ap);
+    int l = vsnprintf(NULL, 0, format, ap2);
+    va_end(ap2);
+    if (l < 0)
+        return NULL;
+    char *tmp = malloc(l + 1);
+    if (!tmp)
+        return NULL;
+    int l2 = vsnprintf(tmp, l + 1, format, ap);
+    if (l2 < 0) {
+        free(tmp);
+        return NULL;
+    }
+    return tmp;
+}
+
+
+char*
+b_strdup_printf(const char *format, ...)
+{
+    va_list ap;
+    va_start(ap, format);
+    char *tmp = b_strdup_vprintf(format, ap);
+    va_end(ap);
+    return tmp;
+}
+
+
+bool
+b_str_starts_with(const char *str, const char *prefix)
+{
+    int str_l = strlen(str);
+    int str_lp = strlen(prefix);
+    if (str_lp > str_l)
+        return false;
+    return strncmp(str, prefix, str_lp) == 0;
+}
+
+
+bool
+b_str_ends_with(const char *str, const char *suffix)
+{
+    int str_l = strlen(str);
+    int str_ls = strlen(suffix);
+    if (str_ls > str_l)
+        return false;
+    return strcmp(str + str_l - str_ls, suffix) == 0;
+}
+
+
+char*
+b_str_strip(char *str)
+{
+    if (str == NULL)
+        return str;
+    int i;
+    size_t str_len = strlen(str);
+    for (i = str_len - 1; i >= 0; i--) {
+        if (!isspace(str[i])) {
+            str[i + 1] = '\0';
+            break;
+        }
+    }
+    str_len = strlen(str);
+    for (i = 0; i < str_len; i++) {
+        if (!isspace(str[i])) {
+            str = str + i;
+            break;
+        }
+    }
+    return str;
+}
+
+
+char**
+b_str_split(const char *str, char c, unsigned int max_pieces)
+{
+    if (!str)
+        return NULL;
+    char **rv = b_malloc(sizeof(char*));
+    unsigned int i, start = 0, count = 0;
+    for (i = 0; i < strlen(str) + 1; i++) {
+        if (str[0] == '\0')
+            break;
+        if ((str[i] == c && (!max_pieces || count + 1 < max_pieces)) || str[i] == '\0') {
+            rv = b_realloc(rv, (count + 1) * sizeof(char*));
+            rv[count] = b_malloc(i - start + 1);
+            memcpy(rv[count], str + start, i - start);
+            rv[count++][i - start] = '\0';
+            start = i + 1;
+        }
+    }
+    rv = b_realloc(rv, (count + 1) * sizeof(char*));
+    rv[count] = NULL;
+    return rv;
+}
+
+
+char*
+b_str_replace(const char *str, const char search, const char *replace)
+{
+    char **pieces = b_str_split(str, search, 0);
+    if (pieces == NULL)
+        return NULL;
+    char* rv = b_strv_join((const char**) pieces, replace);
+    b_strv_free(pieces);
+    return rv;
+}
+
+
+void
+b_strv_free(char **strv)
+{
+    if (strv == NULL)
+        return;
+    unsigned int i;
+    for (i = 0; strv[i] != NULL; i++)
+        free(strv[i]);
+    free(strv);
+}
+
+
+char*
+b_strv_join(const char **strv, const char *separator)
+{
+    if (strv == NULL)
+        return NULL;
+    unsigned int i = 0;
+    b_string_t *str = b_string_new();
+    for (i = 0; strv[i] != NULL; i++) {
+        str = b_string_append(str, strv[i]);
+        if (strv[i+1] != NULL)
+            str = b_string_append(str, separator);
+    }
+    return b_string_free(str, false);
+}
+
+
+unsigned int
+b_strv_length(char **strv)
+{
+    if (!strv)
+        return 0;
+    unsigned int i;
+    for (i = 0; strv[i] != NULL; i++);
+    return i;
+}
+
+
+b_string_t*
+b_string_new(void)
+{
+    b_string_t* rv = b_malloc(sizeof(b_string_t));
+    rv->str = NULL;
+    rv->len = 0;
+    rv->allocated_len = 0;
+
+    // initialize with empty string
+    rv = b_string_append(rv, "");
+
+    return rv;
+}
+
+
+char*
+b_string_free(b_string_t *str, bool free_str)
+{
+    char *rv = NULL;
+    if (free_str)
+        free(str->str);
+    else
+        rv = str->str;
+    free(str);
+    return rv;
+}
+
+
+b_string_t*
+b_string_append_len(b_string_t *str, const char *suffix, size_t len)
+{
+    if (suffix == NULL)
+        return str;
+    size_t old_len = str->len;
+    str->len += len;
+    if (str->len + 1 > str->allocated_len) {
+        str->allocated_len = (((str->len + 1) / B_STRING_CHUNK_SIZE) + 1) * B_STRING_CHUNK_SIZE;
+        str->str = b_realloc(str->str, str->allocated_len);
+    }
+    memcpy(str->str + old_len, suffix, len);
+    str->str[str->len] = '\0';
+    return str;
+}
+
+
+b_string_t*
+b_string_append(b_string_t *str, const char *suffix)
+{
+    if (suffix == NULL)
+        return str;
+    return b_string_append_len(str, suffix, strlen(suffix));
+}
+
+
+b_string_t*
+b_string_append_c(b_string_t *str, char c)
+{
+    size_t old_len = str->len;
+    str->len += 1;
+    if (str->len + 1 > str->allocated_len) {
+        str->allocated_len = (((str->len + 1) / B_STRING_CHUNK_SIZE) + 1) * B_STRING_CHUNK_SIZE;
+        str->str = b_realloc(str->str, str->allocated_len);
+    }
+    str->str[old_len] = c;
+    str->str[str->len] = '\0';
+    return str;
+}
+
+
+b_string_t*
+b_string_append_printf(b_string_t *str, const char *format, ...)
+{
+    va_list ap;
+    va_start(ap, format);
+    char *tmp = b_strdup_vprintf(format, ap);
+    va_end(ap);
+    str = b_string_append(str, tmp);
+    free(tmp);
+    return str;
+}
diff --git a/src/utils/trie.c b/src/utils/trie.c
new file mode 100644
index 0000000..72a62f6
--- /dev/null
+++ b/src/utils/trie.c
@@ -0,0 +1,199 @@
+/*
+ * blogc: A blog compiler.
+ * Copyright (C) 2014-2015 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 <stdlib.h>
+#include "utils.h"
+
+
+b_trie_t*
+b_trie_new(b_free_func_t free_func)
+{
+    b_trie_t *trie = b_malloc(sizeof(b_trie_t));
+    trie->root = NULL;
+    trie->free_func = free_func;
+    return trie;
+}
+
+
+static void
+b_trie_free_node(b_trie_t *trie, b_trie_node_t *node)
+{
+    if (node == NULL)
+        return;
+    if (node->data != NULL && trie->free_func != NULL)
+        trie->free_func(node->data);
+    b_trie_free_node(trie, node->next);
+    b_trie_free_node(trie, node->child);
+    free(node);
+}
+
+
+void
+b_trie_free(b_trie_t *trie)
+{
+    if (trie == NULL)
+        return;
+    b_trie_free_node(trie, trie->root);
+    free(trie);
+}
+
+
+void
+b_trie_insert(b_trie_t *trie, const char *key, void *data)
+{
+    if (data == NULL || key == NULL)
+        return;
+
+    b_trie_node_t *parent = NULL;
+    b_trie_node_t *previous;
+    b_trie_node_t *current;
+    b_trie_node_t *tmp;
+
+    while (1) {
+
+        if (trie->root == NULL || (parent != NULL && parent->child == NULL)) {
+            current = b_malloc(sizeof(b_trie_node_t));
+            current->key = *key;
+            current->data = NULL;
+            current->next = NULL;
+            current->child = NULL;
+            if (trie->root == NULL)
+                trie->root = current;
+            else
+                parent->child = current;
+            parent = current;
+            goto clean;
+        }
+
+        tmp = parent == NULL ? trie->root : parent->child;
+        previous = NULL;
+
+        while (tmp != NULL && tmp->key != *key) {
+            previous = tmp;
+            tmp = tmp->next;
+        }
+
+        parent = tmp;
+
+        if (previous == NULL || parent != NULL)
+            goto clean;
+
+        current = b_malloc(sizeof(b_trie_node_t));
+        current->key = *key;
+        current->data = NULL;
+        current->next = NULL;
+        current->child = NULL;
+        previous->next = current;
+        parent = current;
+
+clean:
+        if (*key == '\0') {
+            if (parent->data != NULL && trie->free_func != NULL)
+                trie->free_func(parent->data);
+            parent->data = data;
+            break;
+        }
+        key++;
+    }
+}
+
+
+void*
+b_trie_lookup(b_trie_t *trie, const char *key)
+{
+    if (trie->root == NULL || key == NULL)
+        return NULL;
+
+    b_trie_node_t *parent = trie->root;
+    b_trie_node_t *tmp;
+    while (1) {
+        for (tmp = parent; tmp != NULL; tmp = tmp->next) {
+
+            if (tmp->key == *key) {
+                if (tmp->key == '\0')
+                    return tmp->data;
+                parent = tmp->child;
+                break;
+            }
+        }
+        if (tmp == NULL)
+            return NULL;
+
+        if (*key == '\0')
+            break;
+        key++;
+    }
+    return NULL;
+}
+
+
+static void
+b_trie_size_node(b_trie_node_t *node, unsigned int *count)
+{
+    if (node == NULL)
+        return;
+
+    if (node->key == '\0')
+        (*count)++;
+
+    b_trie_size_node(node->next, count);
+    b_trie_size_node(node->child, count);
+}
+
+
+unsigned int
+b_trie_size(b_trie_t *trie)
+{
+    if (trie == NULL)
+        return 0;
+
+    unsigned int count = 0;
+    b_trie_size_node(trie->root, &count);
+    return count;
+}
+
+
+static void
+b_trie_foreach_node(b_trie_node_t *node, b_string_t *str, void (*func)(const char *key, void *data))
+{
+    if (node == NULL)
+        return;
+
+    if (node->key == '\0') {
+        func(str->str, node->data);
+        b_string_free(str, true);
+    }
+
+    if (node->child != NULL) {
+        b_string_t *child = b_string_new();
+        child = b_string_append(child, str->str);
+        child = b_string_append_c(child, node->key);
+        b_trie_foreach_node(node->child, child, func);
+    }
+
+    if (node->next != NULL)
+        b_trie_foreach_node(node->next, str, func);
+
+    if (node->child != NULL && node->next == NULL)
+        b_string_free(str, true);
+}
+
+
+void
+b_trie_foreach(b_trie_t *trie, void (*func)(const char *key, void *data))
+{
+    if (trie->root == NULL)
+        return;
+
+    b_string_t *str = b_string_new();
+    b_trie_foreach_node(trie->root, str, func);
+}
diff --git a/src/utils/utils.h b/src/utils/utils.h
new file mode 100644
index 0000000..5a1505b
--- /dev/null
+++ b/src/utils/utils.h
@@ -0,0 +1,77 @@
+/*
+ * blogc: A blog compiler.
+ * Copyright (C) 2014-2015 Rafael G. Martins <rafael@rafaelmartins.eng.br>
+ *
+ * This program can be distributed under the terms of the BSD License.
+ * See the file LICENSE.
+ */
+
+#ifndef _UTILS_UTILS_H
+#define _UTILS_UTILS_H
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#define B_STRING_CHUNK_SIZE 128
+
+typedef void (*b_free_func_t) (void *ptr);
+
+typedef struct _b_slist_t {
+    struct _b_slist_t *next;
+    void *data;
+} b_slist_t;
+
+typedef struct _b_string_t {
+    char *str;
+    size_t len;
+    size_t allocated_len;
+} b_string_t;
+
+typedef struct _b_trie_node_t {
+    char key;
+    void *data;
+    struct _b_trie_node_t *next, *child;
+} b_trie_node_t;
+
+typedef struct _b_trie_t {
+    b_trie_node_t *root;
+    b_free_func_t free_func;
+} b_trie_t;
+
+b_slist_t* b_slist_append(b_slist_t *l, void *data);
+void b_slist_free_full(b_slist_t *l, b_free_func_t free_func);
+void b_slist_free(b_slist_t *l);
+unsigned int b_slist_length(b_slist_t *l);
+
+char* b_strdup(const char *s);
+char* b_strndup(const char *s, size_t n);
+char* b_strdup_vprintf(const char *format, va_list ap);
+char* b_strdup_printf(const char *format, ...);
+bool b_str_starts_with(const char *str, const char *prefix);
+bool b_str_ends_with(const char *str, const char *suffix);
+char* b_str_strip(char *str);
+char** b_str_split(const char *str, char c, unsigned int max_pieces);
+char* b_str_replace(const char *str, const char search, const char *replace);
+void b_strv_free(char **strv);
+char* b_strv_join(const char **strv, const char *separator);
+unsigned int b_strv_length(char **strv);
+
+b_string_t* b_string_new(void);
+char* b_string_free(b_string_t *str, bool free_str);
+b_string_t* b_string_append_len(b_string_t *str, const char *suffix, size_t len);
+b_string_t* b_string_append(b_string_t *str, const char *suffix);
+b_string_t* b_string_append_c(b_string_t *str, char c);
+b_string_t* b_string_append_printf(b_string_t *str, const char *format, ...);
+
+b_trie_t* b_trie_new(b_free_func_t free_func);
+void b_trie_free(b_trie_t *trie);
+void b_trie_insert(b_trie_t *trie, const char *key, void *data);
+void* b_trie_lookup(b_trie_t *trie, const char *key);
+unsigned int b_trie_size(b_trie_t *trie);
+void b_trie_foreach(b_trie_t *trie, void (*func)(const char *key, void *data));
+
+void* b_malloc(size_t size);
+void* b_realloc(void *ptr, size_t size);
+
+#endif /* _UTILS_UTILS_H */
-- 
cgit v1.2.3-18-g5258