ssnail

crappy and opinionated static site generator
git clone https://git.e1e0.net/ssnail.git
Log | Files | Refs | README | LICENSE

commit 4356b42ad6870ba72fc7eb247fff3069591bf6b9
parent 66c61872e8c278b8fb357d80c8bbb965afa38809
Author: Paco Esteban <paco@e1e0.net>
Date:   Wed, 17 Jun 2020 16:21:41 +0200

fixing horrors thanks to tracey

Diffstat:
MMakefile | 2++
Mhelpers.c | 66+++++++++++++++++++++++++++++++++++++-----------------------------
Mhelpers.h | 9+++++++--
Mssnail.c | 187+++++++++++++++++++++++++++++++++++++++++++++++++------------------------------
4 files changed, 162 insertions(+), 102 deletions(-)

diff --git a/Makefile b/Makefile @@ -6,4 +6,6 @@ LDFLAGS += -L/usr/local/lib LDADD += -llowdown -lm CFLAGS += -I/usr/local/include -I${.CURDIR} +DEBUG = -g -O2 + .include <bsd.prog.mk> diff --git a/helpers.c b/helpers.c @@ -16,6 +16,7 @@ #include <sys/stat.h> #include <sys/syslimits.h> + #include <errno.h> #include <stdio.h> #include <stdlib.h> @@ -23,16 +24,22 @@ #include "helpers.h" -int -build_full_path(char fullpath[PATH_MAX], char *dir, char *file) +char * +build_full_path(char *dir, char *file) { - // build the full path - (void)strlcpy(fullpath, dir, PATH_MAX); - if (fullpath[strlen(fullpath)-2] != '/') - (void)strlcat(fullpath, "/", PATH_MAX); - (void)strlcat(fullpath, file, PATH_MAX); + int n = 0; + char *fullpath = NULL, separator[2] = ""; + + /* if user input does not have trailing slash, add it */ + if (dir[strlen(dir)-1] != '/') + strlcat(separator, "/", sizeof(separator)); + + n = asprintf(&fullpath, "%s%s%s", dir, separator, file); + if ((n < 0) || (n > PATH_MAX)) { + return NULL; + } - return 1; + return fullpath; } int @@ -47,7 +54,7 @@ copy_file(const char *source_file, const char *dest_file, int force) return -1; src_mtime = st.st_mtim.tv_sec; - if (stat(dest_file, &st) == -1) { // dst file does not have to exist + if (stat(dest_file, &st) == -1) { /* dst file does not have to exist */ if (errno != ENOENT) return -1; dst_mtime = 0; @@ -101,9 +108,9 @@ load_from_file(char **buffer, char *path) return 0; if (f) { - fseek(f, 0, SEEK_END); // go to the end of file - length = ftell(f); // record the length of the file - fseek(f, 0, SEEK_SET); // go to the start again + fseek(f, 0, SEEK_END); /* go to the end of file */ + length = ftell(f); /* record the length of the file */ + fseek(f, 0, SEEK_SET); /* go to the start again */ *buffer = malloc(length + 1); if (*buffer) fread(*buffer, 1, length, f); @@ -120,28 +127,29 @@ load_from_file(char **buffer, char *path) } char * -str_rep(const char *s, const char *oldW, const char *newW) +str_rep(const char *s, const char *old, const char *new) { char *r; int i, cnt = 0; - int newWlen = strlen(newW); - int oldWlen = strlen(oldW); + int new_len = strlen(new); + int old_len = strlen(old); - if (newWlen == 0 || oldWlen == 0) + if (new_len == 0 || old_len == 0) return NULL; - // Counting the number of times old word - // occur in the string + /* Counting the number of times old word + * occur in the string + */ for (i = 0; s[i] != '\0'; i++) { - if (strstr(&s[i], oldW) == &s[i]) { + if (strstr(&s[i], old) == &s[i]) { cnt++; - // Jumping to index after the old word. - i += oldWlen - 1; + /* Jumping to index after the old word. */ + i += old_len - 1; } } - // Making new string long enough - r = (char *)malloc(i + cnt * (newWlen - oldWlen) + 1); + /* Making new string long enough */ + r = (char *)malloc(i + cnt * (new_len - old_len) + 1); if (!r) return NULL; i = 0; @@ -152,17 +160,17 @@ str_rep(const char *s, const char *oldW, const char *newW) * of result. Then increment by the lenght so we do not check * unnecessarily. */ - if (strstr(s, oldW) == s) { + if (strstr(s, old) == s) { /* * On the original example it was done like this: - * strcpy(&r[i], newW); + * strcpy(&r[i], new); * I think there's no need to dereference and reference * again. */ - strcpy(r+i, newW); - i += newWlen; - s += oldWlen; - } else // if not copy the char and increment pointers + strcpy(r+i, new); + i += new_len; + s += old_len; + } else /* if not copy the char and increment pointers */ r[i++] = *s++; } diff --git a/helpers.h b/helpers.h @@ -17,10 +17,15 @@ #ifndef HELPERS_H #define HELPERS_H -int build_full_path(char *, char *, char *); +#define HEADER "_header.html" +#define FOOTER "_footer.html" + int copy_file(const char *, const char *, int); -const char *get_filename_ext(const char *); int load_from_file(char **, char *); + +const char *get_filename_ext(const char *); + +char *build_full_path(char *, char *); char *str_rep(const char *, const char *, const char *); #endif /* HELPERS_H */ diff --git a/ssnail.c b/ssnail.c @@ -18,6 +18,7 @@ #include <sys/stat.h> #include <sys/syslimits.h> #include <sys/types.h> + #include <dirent.h> #include <err.h> #include <errno.h> @@ -26,7 +27,6 @@ #include <string.h> #include <time.h> #include <unistd.h> - #include <lowdown.h> #include "helpers.h" @@ -34,39 +34,40 @@ #define MAX_META 255 struct article { + size_t htmlz; + size_t origz; + char src_path[PATH_MAX]; char dst_path[PATH_MAX]; char *orig_content; - size_t origz; char *html_content; - size_t htmlz; char *title; char *author; char *date; char *type; + long long src_mtime; long long dst_mtime; + SLIST_ENTRY(article) entries; }; -struct article *a = NULL; SLIST_HEAD(listhead, article) head; -extern char *__progname; -void articleq_free(struct listhead *); -int gen_html(struct article *); -int generate_index(struct listhead *, char *, char *, char *); -int populate_article_entry(struct article *); -int process_dir(char[PATH_MAX], char[PATH_MAX], int); -void usage(); -int write_html(struct article *, char *, char *); +__dead static void usage(void); +static void articleq_free(struct listhead *); + +static int gen_html(struct article *); +static int generate_index(struct listhead *, char *, char *, char *); +static int populate_article_entry(struct article *); +static int process_dir(char *, char *, int); +static int write_html(struct article *, char *, char *); -void +__dead static void usage(void) { - (void)fprintf(stderr, - "usage: %s [-F] [-f footer] [-h header] [-i] " - "src_folder dest_folder\n", __progname); + fprintf(stderr, "usage: %s [-F] [-f footer] [-h header] [-i] " + "src_folder dst_folder\n", getprogname()); exit(1); } @@ -75,12 +76,17 @@ main(int argc, char *argv[]) { DIR *dirp; struct dirent *dp; - int ch, force = 0, index = 0, needs_index = 0; - char srcdir[PATH_MAX] = "", dstdir[PATH_MAX] = "", - header_tpl[PATH_MAX] = "./_header.html", - footer_tpl[PATH_MAX] = "./_footer.html", - *fbuf = NULL; struct article *ap = NULL; + int ch, force = 0, index = 0, needs_index = 0; + char *srcdir = NULL, *dstdir = NULL, *fbuf = NULL; + char *header_tpl = NULL, *footer_tpl = NULL; + + header_tpl = strdup(HEADER); + if (header_tpl == NULL) + return -1; + footer_tpl = strdup(FOOTER); + if (footer_tpl == NULL) + return -1; while ((ch = getopt(argc, argv, "Ff:h:i")) != -1) { switch (ch) { @@ -88,10 +94,16 @@ main(int argc, char *argv[]) force = 1; break; case 'f': - (void)strlcpy(footer_tpl, optarg, PATH_MAX); + free(footer_tpl); + footer_tpl = strdup(optarg); + if (footer_tpl == NULL) + return -1; break; case 'h': - (void)strlcpy(header_tpl, optarg, PATH_MAX); + free(header_tpl); + header_tpl = strdup(FOOTER); + if (header_tpl == NULL) + return -1; break; case 'i': index = 1; @@ -103,13 +115,17 @@ main(int argc, char *argv[]) argc -= optind; argv += optind; - SLIST_INIT(&head); // init the linked list - // src and dst dir are mandatory. + SLIST_INIT(&head); /* init the linked list */ + /* src and dst dir are mandatory. */ if (argc < 2) usage(); - (void)strlcpy(srcdir, argv[0], PATH_MAX); - (void)strlcpy(dstdir, argv[1], PATH_MAX); + srcdir = strdup(argv[0]); + if (srcdir == NULL) + return -1; + dstdir = strdup(argv[1]); + if (dstdir == NULL) + return -1; if (process_dir(srcdir, dstdir, force) == -1) err(1, "cannot process src dir"); @@ -129,14 +145,19 @@ main(int argc, char *argv[]) generate_index(&head, header_tpl, footer_tpl, dstdir); } + free(srcdir); + free(dstdir); + free(fbuf); + free(header_tpl); + free(footer_tpl); articleq_free(&head); return 0; } -int -generate_index(struct listhead *h, char head_tpl[PATH_MAX], - char foot_tpl[PATH_MAX], char *dst_dir) +static int +generate_index(struct listhead *h, char *head_tpl, + char *foot_tpl, char *dst_dir) { struct article *a; char *header = NULL, *footer = NULL; @@ -144,24 +165,28 @@ generate_index(struct listhead *h, char head_tpl[PATH_MAX], int r = -1; time_t now; struct tm *timeInfo; - char mytime[12], index_path[PATH_MAX]; + char mytime[12], *index_path = NULL; time(&now); timeInfo = localtime(&now); strftime(mytime, sizeof(mytime), "%Y-%m-%d", timeInfo); - load_from_file(&header, head_tpl); + if (load_from_file(&header, head_tpl) == 0) + goto out; + /* XXX: 13. here is where you would null term *header = '\0' */ header = str_rep(header, "$title$", "index"); header = str_rep(header, "$author$", getlogin()); header = str_rep(header, "$date$", mytime); - load_from_file(&footer, foot_tpl); + if (load_from_file(&footer, foot_tpl) == 0) + goto out; footer = str_rep(footer, "$title$", "index"); - build_full_path(index_path, dst_dir, "index.html"); + if ((index_path = build_full_path(dst_dir, "index.html")) == NULL) + goto out; if ((fout = fopen(index_path, "w")) == NULL) goto out; fwrite(header, 1, strlen(header), fout); - // TODO: make this list reverse date ordered + /* TODO: make this list reverse date ordered */ fprintf(fout, "<ul>\n"); SLIST_FOREACH(a, h, entries) { if (strcmp(a->type, "article") == 0) { @@ -176,13 +201,14 @@ generate_index(struct listhead *h, char head_tpl[PATH_MAX], r = 0; out: + free(index_path); free(header); free(footer); return r; } -void +static void articleq_free(struct listhead *h) { struct article *a; @@ -194,11 +220,12 @@ articleq_free(struct listhead *h) free(a->title); free(a->author); free(a->date); + free(a->type); free(a); } } -int +static int gen_html(struct article *a) { struct lowdown_opts opts; @@ -207,8 +234,8 @@ gen_html(struct article *a) int r = 0; size_t orig_size = 0; - TAILQ_INIT(&mq); // create the queue(linked list) of lowdown_meta - memset(&opts, 0, sizeof(struct lowdown_opts)); // init opts to 0 + TAILQ_INIT(&mq); /* create the queue(linked list) of lowdown_meta */ + memset(&opts, 0, sizeof(struct lowdown_opts)); /* init opts to 0 */ opts.maxdepth = 128; opts.type = LOWDOWN_HTML; @@ -225,30 +252,32 @@ gen_html(struct article *a) LOWDOWN_HTML_OWASP | LOWDOWN_HTML_SKIP_HTML; - // use strlen(orig) here because the of the \0 char that - // was showing up on the dest buffer. - // playing with origz did not work here. + /* use strlen(orig) here because the of the \0 char that + * was showing up on the dest buffer. + * playing with origz did not work here. + */ lowdown_buf(&opts, a->orig_content, strlen(a->orig_content), &a->html_content, &a->htmlz, &mq); + /* set default values for metadata */ + a->title = strdup(""); + a->author = strdup(""); + a->date = strdup(""); + a->type = strdup("page"); + + /* collect metadata from markdown */ TAILQ_FOREACH(md, &mq, entries) { - size_t valz = (strlen(md->value) > MAX_META) - ? MAX_META : strlen(md->value) + 1; if (strcmp(md->key, "title") == 0 ) { - a->title = malloc(valz); - (void)strlcpy(a->title, md->value, valz); + asprintf(&a->title, "%s", md->value); } if (strcmp(md->key, "author") == 0 ) { - a->author = malloc(valz); - (void)strlcpy(a->author, md->value, valz); + asprintf(&a->author, "%s", md->value); } if (strcmp(md->key, "date") == 0 ) { - a->date = malloc(valz); - (void)strlcpy(a->date, md->value, valz); + asprintf(&a->date, "%s", md->value); } if (strcmp(md->key, "type") == 0 ) { - a->type = malloc(valz); - (void)strlcpy(a->type, md->value, valz); + asprintf(&a->type, "%s", md->value); } } @@ -260,13 +289,19 @@ out: return r; } -int -write_html(struct article *ap, char head_tpl[PATH_MAX], char foot_tpl[PATH_MAX]) +static int +write_html(struct article *ap, char *head_tpl, char *foot_tpl) { char *header = NULL, *footer = NULL; FILE *fout; int r = -1; +/* + * XXX: 15. need error handling below. This is where the segfault is, because I + * don't have the required article struct filled. So, without pouring over + * everything you've written, I'm obviously missing something in a file + * somewhere. :D + */ if (strlen(ap->title) == 0 || strlen(ap->author) == 0 || strlen(ap->date) == 0) @@ -295,7 +330,7 @@ out: return r; } -int +static int populate_article_entry(struct article *ap) { struct stat st; @@ -306,7 +341,7 @@ populate_article_entry(struct article *ap) goto out; ap->src_mtime = st.st_mtim.tv_sec; - if (stat(ap->dst_path, &st) == -1) { // dst file does not have to exist + if (stat(ap->dst_path, &st) == -1) { /* dst file does not have to exist */ if (errno != ENOENT) goto out; ap->dst_mtime = 0; @@ -323,20 +358,24 @@ out: return retval; } -int -process_dir(char orig[PATH_MAX], char dest[PATH_MAX], int force) +static int +process_dir(char *src, char *dst, int force) { DIR *dirp; struct dirent *dp; struct stat st; + struct article *a = NULL; + int retval = -1; - if (stat(dest, &st) == -1 && errno == ENOENT) { - if (mkdir(dest, 0755) == -1) + char *src_path = NULL, *dst_path = NULL; + + if (stat(dst, &st) == -1 && errno == ENOENT) { + if (mkdir(dst, 0755) == -1) return -1; } - if ((dirp = opendir(orig)) == NULL) + if ((dirp = opendir(src)) == NULL) return -1; while ((dp = readdir(dirp)) != NULL) { @@ -344,40 +383,46 @@ process_dir(char orig[PATH_MAX], char dest[PATH_MAX], int force) || strcmp(dp->d_name, "..") == 0) continue; - char orig_path[PATH_MAX], dest_path[PATH_MAX]; - - if (build_full_path(orig_path, orig, dp->d_name) == -1) + if ((src_path = build_full_path(src, dp->d_name)) == NULL) goto out; - if (build_full_path(dest_path, dest, dp->d_name) == -1) + if ((dst_path = build_full_path(dst, dp->d_name)) == NULL) goto out; if (dp->d_type == DT_REG) { - if (strcmp(get_filename_ext(orig_path), "md") == 0) { + if (strcmp(get_filename_ext(src_path), "md") == 0) { char *fbuf = NULL; + int n = 0; + a = malloc(sizeof(struct article)); - (void)strlcpy(a->src_path, orig_path, PATH_MAX); - fbuf = str_rep(dest_path, ".md", ".html"); - (void)strlcpy(a->dst_path, fbuf, PATH_MAX); + strlcpy(a->src_path, src_path, PATH_MAX); + fbuf = str_rep(dst_path, ".md", ".html"); + strlcpy(a->dst_path, fbuf, PATH_MAX); free(fbuf); if((populate_article_entry(a) == -1)) err(2, "cannot populate article"); SLIST_INSERT_HEAD(&head, a, entries); } else { - if (copy_file(orig_path, dest_path, force) == -1) + if (copy_file(src_path, dst_path, force) == -1) goto out; } } if (dp->d_type == DT_DIR) { - if (process_dir(orig_path, dest_path, force) == -1) + if (process_dir(src_path, dst_path, force) == -1) goto out; } + free(src_path); + free(dst_path); + src_path = NULL; + dst_path = NULL; } retval = 0; out: + free(src_path); + free(dst_path); closedir(dirp); return retval; }