ssnail

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

commit 5e52c764c498d83c9a2433dfd9feac6951f31475
parent c881a66f770eba75347951ea58efad70dd0cdabf
Author: Paco Esteban <paco@e1e0.net>
Date:   Tue, 12 May 2020 19:58:29 +0200

progress on the struct conversion

Diffstat:
Mssnail.c | 171++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------
1 file changed, 117 insertions(+), 54 deletions(-)

diff --git a/ssnail.c b/ssnail.c @@ -16,7 +16,9 @@ #include <dirent.h> #include <err.h> +#include <errno.h> #include <sys/queue.h> +#include <sys/stat.h> #include <sys/types.h> #include <sys/syslimits.h> #include <stdio.h> @@ -28,11 +30,27 @@ #define MAX_META 255 +struct article { + char src_path[PATH_MAX]; + char dst_path[PATH_MAX]; + char *orig_content; + size_t origz; + char *html_content; + size_t htmlz; + char title[MAX_META]; + char author[MAX_META]; + char date[MAX_META]; + long long src_mtime; + long long dst_mtime; + SLIST_ENTRY(article) entries; +}; + char *str_rep(const char *, const char *, const char *); -int gen_html(char *, char *); +int gen_html(char **, size_t *, char *, char *, char *, char *, size_t); int build_full_path(char *, char *, char *); -int load_template(char **, char *); +int load_from_file(char **, char *); void usage(); +int populate_article_entry(struct article *); int main(int argc, char *argv[]) @@ -40,7 +58,8 @@ main(int argc, char *argv[]) DIR *dirp; struct dirent *dp; int ch; - char srcdir[PATH_MAX] = "", dstdir[PATH_MAX] = ""; + char srcdir[PATH_MAX] = "", dstdir[PATH_MAX] = "", *fbuf = NULL; + struct article *a = NULL, *ap = NULL; while ((ch = getopt(argc, argv, "s:d:")) != -1) { switch (ch) { @@ -57,28 +76,50 @@ main(int argc, char *argv[]) argc -= optind; argv += optind; + SLIST_HEAD(listhead, article) head; + SLIST_INIT(&head); // init the linked list + // src and dst dir are mandatory. if (srcdir[0] == '\0' || dstdir[0] == '\0') usage(); - if ((dirp = opendir(srcdir)) != NULL) { - while ((dp = readdir(dirp)) != NULL) { - if (dp->d_type == DT_REG) { // only take regular files - char srcpath[PATH_MAX] = ""; - char dstpath[PATH_MAX] = ""; - build_full_path(srcpath, srcdir, dp->d_name); - build_full_path(dstpath, dstdir, dp->d_name); - if(!gen_html(srcpath, dstpath)) - err(1, "cannot generate file %s", - srcpath); - } - } - closedir(dirp); - } else { - /* could not open directory */ + if ((dirp = opendir(srcdir)) == NULL) err(1, "cannot open src dir"); + + while ((dp = readdir(dirp)) != NULL) { + if (dp->d_type == DT_REG) { + //load all in a linked list + a = malloc(sizeof(struct article)); + build_full_path(a->src_path, srcdir, dp->d_name); + // replace markdown extension for html + fbuf = str_rep(dp->d_name, ".md", ".html"); + build_full_path(a->dst_path, dstdir, fbuf); + if((populate_article_entry(a) == -1)) + err(2, "cannot populate article"); + SLIST_INSERT_HEAD(&head, a, entries); + } + } + + SLIST_FOREACH(ap, &head, entries) { + printf("%s (%lld) --> %s (%lld)\n", + ap->src_path, ap->src_mtime, + ap->dst_path, ap->dst_mtime + ); + /* printf("----\n%s\n----\nsize(%zd)\n", */ + /* ap->orig_content, ap->origz); */ + printf("- Title: %s\n", ap->title); + printf("- Author: %s\n", ap->author); + printf("- Date: %s\n", ap->date); + printf("----\n%s\n----\nsize(%zd)\n", + ap->html_content, ap->htmlz); } + closedir(dirp); + /* TODO: free the linked list structure <06-05-2020, paco> */ + free(ap); + free(a); + free(fbuf); + return 0; } @@ -134,14 +175,12 @@ str_rep(const char *s, const char *oldW, const char *newW) } int -gen_html(char origfile[PATH_MAX], char destfile[PATH_MAX]) +gen_html(char **dest, size_t *destz, + char title[MAX_META], char author[MAX_META], char date[MAX_META], + char *orig, size_t origz) { - FILE *fin, *fout; - char *ret = NULL, *head_tpl = NULL, *foot_tpl = NULL, + char *head_tpl = NULL, *foot_tpl = NULL, *header = NULL, *footer = NULL; - char title[MAX_META] = "", author[MAX_META] = "", - date[MAX_META] = ""; - size_t retsz = 0; struct lowdown_opts opts; struct lowdown_metaq mq; struct lowdown_meta *md; @@ -151,7 +190,6 @@ gen_html(char origfile[PATH_MAX], char destfile[PATH_MAX]) memset(&opts, 0, sizeof(struct lowdown_opts)); // init opts to 0 opts.maxdepth = 128; - /* opts.type = LOWDOWN_TERM; */ opts.type = LOWDOWN_HTML; opts.feat = LOWDOWN_FOOTNOTES | LOWDOWN_AUTOLINK | @@ -166,10 +204,8 @@ gen_html(char origfile[PATH_MAX], char destfile[PATH_MAX]) LOWDOWN_HTML_OWASP | LOWDOWN_HTML_SKIP_HTML; - if ((fin = fopen(origfile, "r")) == NULL) - goto out1; - if (!lowdown_file(&opts, fin, &ret, &retsz, &mq)) - goto out1; + lowdown_buf(&opts, orig, origz, dest, destz, &mq); + /* printf("%s\n%zd\n", dest, *destz); */ TAILQ_FOREACH(md, &mq, entries) { if (strcmp(md->key, "title") == 0 ) @@ -180,40 +216,67 @@ gen_html(char origfile[PATH_MAX], char destfile[PATH_MAX]) (void)strlcpy(date, md->value, MAX_META); } - if (strlen(title) == 0 || strlen(author) == 0 || strlen(date) == 0) - goto out1; + /* if (strlen(title) == 0 || strlen(author) == 0 || strlen(date) == 0) */ + /* goto out; */ - load_template(&head_tpl, "_header.html"); - header = str_rep(head_tpl, "$title$", title); - header = str_rep(header, "$author$", author); - header = str_rep(header, "$date$", date); - load_template(&foot_tpl, "_footer.html"); - footer = str_rep(foot_tpl, "$title$", title); + /* load_from_file(&head_tpl, "_header.html"); */ + /* header = str_rep(head_tpl, "$title$", title); */ + /* header = str_rep(header, "$author$", author); */ + /* header = str_rep(header, "$date$", date); */ + /* load_from_file(&foot_tpl, "_footer.html"); */ + /* footer = str_rep(foot_tpl, "$title$", title); */ - if ((fout = fopen(destfile, "w")) == NULL) - goto out2; - fwrite(header, 1, strlen(header), fout); - fwrite(ret, 1, retsz, fout); - fwrite(footer, 1, strlen(footer), fout); + /* if ((fout = fopen(destfile, "w")) == NULL) */ + /* goto out; */ + /* fwrite(header, 1, strlen(header), fout); */ + /* fwrite(ret, 1, retsz, fout); */ + /* fwrite(footer, 1, strlen(footer), fout); */ r = 1; -out2: - fclose(fout); -out1: - fclose(fin); - free(ret); +out: + /* free(ret); */ lowdown_metaq_free(&mq); - free(head_tpl); - free(header); - free(footer); - free(foot_tpl); + /* free(head_tpl); */ + /* free(header); */ + /* free(footer); */ + /* free(foot_tpl); */ return r; } int +populate_article_entry(struct article *ap) +{ + struct stat st; + int retval = -1; + int len = 0; + + if (stat(ap->src_path, &st) == -1) + 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 (errno != ENOENT) + goto out; + ap->dst_mtime = 0; + } else { + ap->dst_mtime = st.st_mtim.tv_sec; + } + + if ((ap->origz = load_from_file(&ap->orig_content, ap->src_path)) == 0) + goto out; + + gen_html(&ap->html_content, &ap->htmlz, + ap->title, ap->author, ap->date, + ap->orig_content, ap->origz); + retval = 0; +out: + return retval; +} + +int build_full_path(char fullpath[PATH_MAX], char *dir, char *file) { // build the full path @@ -226,12 +289,12 @@ build_full_path(char fullpath[PATH_MAX], char *dir, char *file) } int -load_template(char **buffer, char *path) +load_from_file(char **buffer, char *path) { long length; FILE *f = NULL; - if ((f = fopen(path, "rb")) == NULL) + if ((f = fopen(path, "r")) == NULL) return 0; if (f) { @@ -250,7 +313,7 @@ load_template(char **buffer, char *path) *(*buffer + length) = '\0'; } - return 1; + return length + 1; } void