diff options
Diffstat (limited to 'src/render.c')
-rw-r--r-- | src/render.c | 234 |
1 files changed, 234 insertions, 0 deletions
diff --git a/src/render.c b/src/render.c new file mode 100644 index 0000000..7c72cad --- /dev/null +++ b/src/render.c @@ -0,0 +1,234 @@ +#include "render.h" + +#include <stdio.h> +#include <stdlib.h> + +#include "fs.h" +#include "log.h" +#include "site.h" + +static bool +images_walk(struct bstnode *node, void *data) +{ + struct image *image = node->value; + + hashmap_insert(image->map, "source", image->url_image); + hashmap_insert(image->map, "date", image->datestr); + struct bstnode *prev = bstree_predecessor(node), + *next = bstree_successor(node); + char *url; + if (prev) { + url = ((struct image *)prev->value)->url; + hashmap_insert(image->map, "prev", url); + } + if (next) { + url = ((struct image *)next->value)->url; + hashmap_insert(image->map, "next", url); + } + + hashmap_insert(image->thumb, "link", image->url); + hashmap_insert(image->thumb, "source", image->url_thumb); + + vector_push(image->album->thumbs, image->thumb); + + return true; +} + +static struct hashmap * +years_push_new_year(struct vector *years, char *yearstr) +{ + struct hashmap *year = hashmap_new_with_cap(4); + struct vector *albums = vector_new(8); + hashmap_insert(year, "name", yearstr); + hashmap_insert(year, "albums", albums); + vector_push(years, year); + + return year; +} + +static void +years_push_album(struct vector *years, struct album *album) +{ + struct hashmap *year; + struct vector *albums; + if (years->size == 0) { + year = years_push_new_year(years, album->year); + } else { + year = years->values[years->size - 1]; + char *yearstr = hashmap_get(year, "name"); + if (strcmp(yearstr, album->year)) { + year = years_push_new_year(years, album->year); + } + } + albums = hashmap_get(year, "albums"); + vector_push(albums, album->map); +} + +static void +year_walk(const void *k, void *v) +{ + if (!strcmp(k, "albums")) { + struct vector *albums = v; + vector_free(albums); + } +} + +static void +years_destroy(struct vector *years) +{ + for (size_t i = 0; i < years->size; i++) { + struct hashmap *year = years->values[i]; + hashmap_walk(year, year_walk); + hashmap_free(year); + } + vector_free(years); +} + +static bool +albums_walk(struct bstnode *node, void *data) +{ + struct album *album = node->value; + struct render *r = data; + + hashmap_insert(album->map, "title", album->config->title); + hashmap_insert(album->map, "desc", album->config->desc); + hashmap_insert(album->map, "link", album->url); + + bstree_inorder_walk(album->images->root, images_walk, NULL); + + for (uint32_t i = 0; + i < album->thumbs->size && i < album->previews->cap; i++) { + vector_push(album->previews, album->thumbs->values[i]); + } + + hashmap_insert(album->map, "thumbs", album->thumbs); + hashmap_insert(album->map, "previews", album->previews); + + years_push_album(r->years, album); + vector_push(r->albums, album->map); + + return true; +} + +static bool +render(struct env *env, const char *tmpl, const char *opath, + struct hashmap *vars) +{ + bool ok = true; + char *output = template(env, tmpl, vars); + size_t outlen = strlen(output); + FILE *f = fopen(opath, "w"); + if (fwrite(output, 1, outlen, f) != outlen) { + ok = false; + log_printl_errno(LOG_FATAL, "Can't write %s", opath); + } + fclose(f); + free(output); + return ok; +} + +#define RENDER_MAKE_START \ + bool ok = true; \ + int isupdate = file_is_uptodate(path, &r->modtime); \ + if (isupdate == -1) return false; \ + if (isupdate == 1) return true; \ + log_print(LOG_INFO, "Rendering %s...", path); \ + if (r->dry_run) goto done + +#define RENDER_MAKE_END \ + setdatetime(path, &r->modtime); \ +done: \ + log_printf(LOG_INFO, " done.\n"); \ + return ok + +bool +render_make_index(struct render *r, const char *path) +{ + RENDER_MAKE_START; + + hashmap_insert(r->common_vars, "years", r->years); + hashmap_insert(r->common_vars, "albums", r->years); + ok = render(r->env, "index.html", path, r->common_vars); + hashmap_remove(r->common_vars, "years"); + hashmap_remove(r->common_vars, "albums"); + + RENDER_MAKE_END; +} + +bool +render_make_album(struct render *r, const char *path, const struct album *album) +{ + hashmap_insert(r->common_vars, "album", album->map); + + RENDER_MAKE_START; + + ok = render(r->env, "album.html", path, r->common_vars); + /* + * Since we actually still want this album's map for the image inside the + * album, we don't remove it. + */ + + RENDER_MAKE_END; +} + +bool +render_make_image(struct render *r, const char *path, const struct image *image) +{ + RENDER_MAKE_START; + + hashmap_insert(r->common_vars, "image", image->map); + ok = render(r->env, "image.html", path, r->common_vars); + hashmap_remove(r->common_vars, "image"); + + RENDER_MAKE_END; +} + +bool +render_init(struct render *r, const char *root, struct site_config *conf, + struct bstree *albums) +{ + char *tmplpath = joinpath(root, TEMPLATESDIR); + struct stat tstat; + if (stat(tmplpath, &tstat) == -1) { + if (errno == ENOENT) { + free(tmplpath); + tmplpath = joinpath(SITE_DEFAULT_RESOURCES, TEMPLATESDIR); + } else { + log_printl_errno(LOG_FATAL, "Unable to read templates dir"); + return false; + } + } + + r->modtime = tstat.st_mtim; + + if (r->dry_run) return true; + + r->env = env_new(tmplpath); + if (r->env == NULL) { + log_printl_errno(LOG_FATAL, "Couldn't initialize template engine"); + return false; + } + r->years = vector_new(8); + r->albums = vector_new(64); + + r->common_vars = hashmap_new_with_cap(8); + hashmap_insert(r->common_vars, "title", conf->title); + if (strlen(conf->base_url) == 0) { + hashmap_insert(r->common_vars, "index", "/"); + } else { + hashmap_insert(r->common_vars, "index", conf->base_url); + } + + bstree_inorder_walk(albums->root, albums_walk, (void *)r); + + return true; +} + +void +render_deinit(struct render *r) +{ + env_free(r->env); + years_destroy(r->years); + vector_free(r->albums); + hashmap_free(r->common_vars); +} |