ssnail

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

commit 1cbec25e63e0a6243547ceda6f6cd880a6926d5a
parent 2dd1881b35fdeb12f7a696ee437a52a7e61ab6b3
Author: Paco Esteban <paco@e1e0.net>
Date:   Thu, 11 Jun 2020 19:42:29 +0200

process markdown and assets in the same way

and copy/process recursively.

Diffstat:
M.gitignore | 2+-
Mssnail.c | 153+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------
2 files changed, 124 insertions(+), 31 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -2,7 +2,7 @@ ssnail *.d *.o *.core -data +source destHtml destTxt _*.html diff --git a/ssnail.c b/ssnail.c @@ -50,15 +50,18 @@ struct article { struct article *a = NULL; SLIST_HEAD(listhead, article) head; -char *str_rep(const char *, const char *, const char *); -int gen_html(struct article *); -int build_full_path(char *, char *, char *); -int load_from_file(char **, char *); -void usage(); -int populate_article_entry(struct article *); -int write_html(struct article *, char *, char *); -void articleq_free(struct listhead *); -int generate_index(struct listhead *, char *, char *, char *); +char *str_rep(const char *, const char *, const char *); +int gen_html(struct article *); +int build_full_path(char *, char *, char *); +int load_from_file(char **, char *); +void usage(); +int populate_article_entry(struct article *); +int write_html(struct article *, char *, char *); +void articleq_free(struct listhead *); +int generate_index(struct listhead *, char *, char *, char *); +int process_dir(char[PATH_MAX], char[PATH_MAX], int); +const char *get_filename_ext(const char *); +int copy_file(const char *, const char *, int); int main(int argc, char *argv[]) @@ -104,24 +107,8 @@ main(int argc, char *argv[]) if (srcdir[0] == '\0' || dstdir[0] == '\0') usage(); - 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); - } - } - closedir(dirp); - free(fbuf); + if (process_dir(srcdir, dstdir, force) == -1) + err(1, "cannot process src dir"); printf("Generate html files ... \n"); SLIST_FOREACH(ap, &head, entries) { @@ -173,9 +160,11 @@ generate_index(struct listhead *h, char head_tpl[PATH_MAX], // TODO: make this list reverse date ordered fprintf(fout, "<ul>\n"); SLIST_FOREACH(a, h, entries) { - if (strcmp(a->type, "article") == 0) - fprintf(fout, "<li><a href='%s'>%s</a></li>\n", - a->dst_path, a->title); + if (strcmp(a->type, "article") == 0) { + char *href = strchr(a->dst_path, '/') + 1; + fprintf(fout, "<li><a href=\"%s\">%s</a></li>\n", + href, a->title); + } } fprintf(fout, "</ul>\n"); fwrite(footer, 1, strlen(footer), fout); @@ -426,3 +415,107 @@ usage() printf("usage\n"); exit(1); } + +int +process_dir(char orig[PATH_MAX], char dest[PATH_MAX], int force) +{ + DIR *dirp; + struct dirent *dp; + struct stat st; + int retval = -1; + + if (stat(dest, &st) == -1 && errno == ENOENT) { + if (mkdir(dest, 0755) == -1) + return -1; + } + + if ((dirp = opendir(orig)) == NULL) + goto out; + + while ((dp = readdir(dirp)) != NULL) { + if (strcmp(dp->d_name, ".") == 0 + || 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) + goto out; + if (build_full_path(dest_path, dest, dp->d_name) == -1) + goto out; + + if (dp->d_type == DT_REG) { + if (strcmp(get_filename_ext(orig_path), "md") == 0) { + char *fbuf = NULL; + 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); + 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) + goto out; + } + } + if (dp->d_type == DT_DIR) { + if (process_dir(orig_path, dest_path, force) == -1) + goto out; + } + } + + retval = 0; + +out: + closedir(dirp); + return retval; +} + +const char * +get_filename_ext(const char *filename) { + const char *dot = strrchr(filename, '.'); + if(!dot || dot == filename) + return ""; + return dot + 1; +} + +int +copy_file(const char *source_file, const char *dest_file, int force) +{ + FILE *src, *dst; + struct stat st; + char ch; + long long src_mtime, dst_mtime; + + if (stat(source_file, &st) == -1) + return -1; + src_mtime = st.st_mtim.tv_sec; + + if (stat(dest_file, &st) == -1) { // dst file does not have to exist + if (errno != ENOENT) + return -1; + dst_mtime = 0; + } else { + dst_mtime = st.st_mtim.tv_sec; + } + + if ((src_mtime > dst_mtime) || force) { + if ((src = fopen(source_file, "r")) == NULL) + return -1; + if ((dst = fopen(dest_file, "w")) == NULL) + return -1; + + printf("copying %s --> %s\n", source_file, dest_file); + while ((ch = fgetc(src)) != EOF) + fputc(ch, dst); + + fclose(src); + fclose(dst); + } + + return 0; +}