aboutsummaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorYaroslav de la Peña Smirnov <yps@yaroslavps.com>2021-11-07 02:02:45 +0300
committerYaroslav de la Peña Smirnov <yps@yaroslavps.com>2021-11-07 02:02:45 +0300
commite3a41da5a0a3d70ac53591f2b66144f2be2b3871 (patch)
tree789cc69b05f2447c11f04dbb6ae972ffa0acd1c9 /include
downloadrevela-e3a41da5a0a3d70ac53591f2b66144f2be2b3871.tar.gz
revela-e3a41da5a0a3d70ac53591f2b66144f2be2b3871.zip
Initial commit.
Almost functional but still missing features and lacking testing.
Diffstat (limited to 'include')
-rw-r--r--include/bstree.h68
-rw-r--r--include/components.h82
-rw-r--r--include/config.h43
-rw-r--r--include/fs.h43
-rw-r--r--include/log.h58
-rw-r--r--include/render.h38
-rw-r--r--include/site.h46
-rw-r--r--include/tests/tests.h45
8 files changed, 423 insertions, 0 deletions
diff --git a/include/bstree.h b/include/bstree.h
new file mode 100644
index 0000000..9577b73
--- /dev/null
+++ b/include/bstree.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2021 Yaroslav de la Peña Smirnov
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef BSTREE_H
+#define BSTREE_H
+
+#include <stdbool.h>
+
+/* < 0 means a less than b; 0 means equal; > 0 means a more than b. */
+typedef int (*bst_cmp_fn)(const void *a, const void *b);
+typedef void (*bst_free_fn)(void *data);
+
+struct bstree {
+ struct bstnode *root;
+ bst_cmp_fn cmp;
+ /* It can be NULL, in which case you will have to free the values manually */
+ bst_free_fn free;
+};
+
+struct bstnode {
+ void *value;
+ struct bstnode *parent;
+ struct bstnode *left;
+ struct bstnode *right;
+};
+
+typedef bool (*bst_walk_cb)(struct bstnode *, void *data);
+
+struct bstree *bstree_new(bst_cmp_fn, bst_free_fn);
+
+struct bstnode *bstree_add(struct bstree *, void *val);
+
+/* Returns NULL if a node with the value wasn't found */
+struct bstnode *bstree_search(struct bstree *, void *val);
+
+struct bstnode *bstree_min(struct bstnode *);
+
+struct bstnode *bstree_max(struct bstnode *);
+
+struct bstnode *bstree_predecessor(struct bstnode *);
+
+struct bstnode *bstree_successor(struct bstnode *);
+
+bool bstree_inorder_walk(struct bstnode *, bst_walk_cb, void *data);
+
+void bstree_remove(struct bstree *, struct bstnode *);
+
+void bstree_destroy(struct bstree *);
+
+#endif
diff --git a/include/components.h b/include/components.h
new file mode 100644
index 0000000..ba5c866
--- /dev/null
+++ b/include/components.h
@@ -0,0 +1,82 @@
+#ifndef REVELA_COMPONENTS_H
+#define REVELA_COMPONENTS_H
+
+#include <time.h>
+#include <sys/stat.h>
+#include <libexif/exif-data.h>
+
+#include "config.h"
+#include "hashmap.h"
+
+#define PHOTO_THUMB_SUFFIX "_thumb"
+
+struct image {
+ /* The path to the source image file */
+ char *source;
+ /* Points to the basename in source */
+ const char *basename;
+ /* Points to the extension in source */
+ const char *ext;
+ /* The "url" to the dir where index.html for this image will be located */
+ char *url;
+ /* The "url" to the image file */
+ char *url_image;
+ /* The "url" to the thumbnail image file */
+ char *url_thumb;
+ /* Pointers to the relative urls in their respective urls */
+ const char *dst;
+ const char *dst_image;
+ const char *dst_thumb;
+ /* The "raw" exif data extracted from the original file */
+ ExifData *exif_data;
+ /* Last modified time of source file */
+ struct timespec modtime;
+ /* The datetime this image was taken in human friendly form */
+ char datestr[24];
+ /* Same as date but in seconds for easier comparison. See image_set_date() */
+ time_t tstamp;
+ struct album *album;
+ /* Hashmap with values to be passed to the image template */
+ struct hashmap *map;
+ /* Hashmap with values to be passed to thumbs and previews vectors */
+ struct hashmap *thumb;
+};
+
+struct album {
+ struct album_config *config;
+ /* The path to the source directory */
+ char *source;
+ /* The full url that will be used in the template */
+ char *url;
+ /* Pointer to the slug part in url that will be used for the new dir */
+ const char *slug;
+ /* Pointer to the human readable date of the earliest image */
+ const char *datestr;
+ /* The year of this album in human readable form; used to categorize */
+ char year[8];
+ /* The date of the album is the date of the earliest image */
+ time_t tstamp;
+ struct bstree *images;
+ /* Hashmap with values to be passed to the template */
+ struct hashmap *map;
+ /* Vector with hashmaps of images to be passed to the templates */
+ struct vector *thumbs;
+ struct vector *previews;
+};
+
+struct image *image_new(char *src, const struct stat *, struct album *);
+
+int image_cmp(const void *a, const void *b);
+
+void image_destroy(void *data);
+
+struct album *album_new(struct album_config *, struct site_config *,
+ const char *src, const char *rsrc, const struct stat *);
+
+int album_cmp(const void *a, const void *b);
+
+void album_add_image(struct album *, struct image *);
+
+void album_destroy(void *data);
+
+#endif
diff --git a/include/config.h b/include/config.h
new file mode 100644
index 0000000..398160b
--- /dev/null
+++ b/include/config.h
@@ -0,0 +1,43 @@
+#ifndef REVELA_CONFIG_H
+#define REVELA_CONFIG_H
+#include <stdbool.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#define SITE_CONF "site.ini"
+#define ALBUM_CONF "album.ini"
+
+struct image_config {
+ bool strip;
+ uint8_t quality;
+ size_t max_width;
+ size_t max_height;
+ bool smart_resize;
+};
+
+struct site_config {
+ char *title;
+ char *base_url;
+ uint32_t max_previews;
+ struct image_config images;
+ struct image_config thumbnails;
+};
+
+struct album_config {
+ char *title;
+ char *desc;
+};
+
+bool site_config_read_ini(const char *wdir, struct site_config *);
+
+bool album_config_read_ini(const char *adir, struct album_config *);
+
+struct site_config *site_config_init(void);
+
+struct album_config *album_config_init(void);
+
+void site_config_destroy(struct site_config *config);
+
+void album_config_destroy(struct album_config *config);
+
+#endif
diff --git a/include/fs.h b/include/fs.h
new file mode 100644
index 0000000..015214a
--- /dev/null
+++ b/include/fs.h
@@ -0,0 +1,43 @@
+#ifndef REVELA_FS_H
+#define REVELA_FS_H
+
+#include <stdio.h>
+#include <stdbool.h>
+#include <sys/stat.h>
+
+/*
+ * Returns a pointer to where the basename of the file is inside path.
+ */
+const char *rbasename(const char *path);
+
+/*
+ * Makes a new directory if it doesn't exist. If there were errors returns
+ * false, otherwise returns true.
+ */
+bool nmkdir(const char *path, struct stat *dstat, bool dry);
+
+#define joinpathb(buf, a, b) sprintf(buf, "%s/%s", a, b)
+
+/*
+ * Joins two paths into one, e.g. /hello, word -> /hello/world
+ * This function allocates a new string and returns it.
+ */
+char *joinpath(const char *restrict a, const char *restrict b);
+
+bool isimage(const char *fname);
+
+/*
+ * Removes extension from file name "e.g. pepe.gif -> pepe. Returns a pointer to
+ * location of the extension in the string.
+ */
+const char *delext(const char *restrict basename, char *restrict dest, size_t n);
+
+/*
+ * -1 if error; 0 if the timestamps are different; 1 if they are equal.
+ */
+int file_is_uptodate(const char *path, const struct timespec *srcmtim);
+
+/* Sets access and modification times to the time passed */
+void setdatetime(const char *path, const struct timespec *mtim);
+
+#endif
diff --git a/include/log.h b/include/log.h
new file mode 100644
index 0000000..2be35ee
--- /dev/null
+++ b/include/log.h
@@ -0,0 +1,58 @@
+#ifndef REVELA_LOG_H
+#define REVELA_LOG_H
+
+#include <errno.h>
+#include <string.h>
+
+enum log_level {
+ LOG_SILENT,
+ LOG_FATAL,
+ LOG_ERROR,
+ LOG_INFO,
+ LOG_DETAIL,
+ LOG_DEBUG,
+};
+
+#ifdef DEBUG
+static const char *log_level_names[] = {
+ "",
+ "FATAL",
+ "ERROR",
+ "INFO",
+ "DETAIL",
+ "DEBUG",
+};
+#endif
+
+void log_set_verbosity(enum log_level);
+
+void log_printf(enum log_level, const char *restrict fmt, ...);
+
+#ifdef DEBUG
+#define log_print(v, fmt, ...) \
+ log_printf(v, "[%s] %s:%d " fmt, log_level_names[v], \
+ __FILE__, __LINE__, ##__VA_ARGS__)
+#else
+#define log_print(v, fmt, ...) \
+ log_printf(v, fmt, ##__VA_ARGS__)
+#endif
+
+#ifdef DEBUG
+#define log_printl(v, fmt, ...) \
+ log_printf(v, "[%s] %s:%d " fmt "\n", log_level_names[v], \
+ __FILE__, __LINE__, ##__VA_ARGS__)
+#else
+#define log_printl(v, fmt, ...) \
+ log_printf(v, fmt "\n", ##__VA_ARGS__)
+#endif
+
+#ifdef DEBUG
+#define log_printl_errno(v, fmt, ...) \
+ log_printf(v, "[%s] %s:%d " fmt ": %s\n", log_level_names[v], \
+ __FILE__, __LINE__, ##__VA_ARGS__, strerror(errno))
+#else
+#define log_printl_errno(v, fmt, ...) \
+ log_printf(v, fmt ": %s\n", ##__VA_ARGS__, strerror(errno))
+#endif
+
+#endif
diff --git a/include/render.h b/include/render.h
new file mode 100644
index 0000000..faa6f73
--- /dev/null
+++ b/include/render.h
@@ -0,0 +1,38 @@
+#ifndef REVELA_RENDER_H
+#define REVELA_RENDER_H
+
+#include <sys/stat.h>
+
+#include "bstree.h"
+#include "config.h"
+#include "template.h"
+#include "components.h"
+
+struct render {
+ /* Unja environment */
+ struct env *env;
+ /* List of years with albums in each year */
+ struct vector *years;
+ /* List of albums */
+ struct vector *albums;
+ /* Hashmap used for all templates */
+ struct hashmap *common_vars;
+ /* Modification time for the templates dir */
+ struct timespec modtime;
+ bool dry_run;
+};
+
+bool render_make_index(struct render *, const char *path);
+
+bool render_make_album(struct render *r, const char *path,
+ const struct album *album);
+
+bool render_make_image(struct render *r, const char *path,
+ const struct image *image);
+
+bool render_init(struct render *, const char *path, struct site_config *,
+ struct bstree *albums);
+
+void render_deinit(struct render *);
+
+#endif
diff --git a/include/site.h b/include/site.h
new file mode 100644
index 0000000..678cd47
--- /dev/null
+++ b/include/site.h
@@ -0,0 +1,46 @@
+#ifndef REVELA_SITE_H
+#define REVELA_SITE_H
+
+#include "config.h"
+#include "bstree.h"
+#include "render.h"
+#include "components.h"
+
+#include <wand/magick_wand.h>
+
+#ifndef SITE_DEFAULT_RESOURCES
+#define SITE_DEFAULT_RESOURCES "/usr/share/revela"
+#endif
+
+#define CSSDIR "css"
+#define STATICDIR "static"
+#define CONTENTDIR "content"
+#define TEMPLATESDIR "templates"
+#define DEFAULTALBUM "unorganized"
+
+struct site {
+ struct site_config *config;
+ MagickWand *wand;
+ char *root_dir;
+ const char *output_dir;
+ char *content_dir;
+ /*
+ * Indicates how many characters after the full root dir path of the input
+ * directory the relative path of the albums + the content dir start. See
+ * site_init()
+ */
+ size_t rel_content_dir;
+ struct bstree *albums;
+ struct render render;
+ bool dry_run;
+};
+
+bool site_build(struct site *);
+
+bool site_load(struct site *);
+
+bool site_init(struct site *);
+
+void site_deinit(struct site *);
+
+#endif
diff --git a/include/tests/tests.h b/include/tests/tests.h
new file mode 100644
index 0000000..8c89fcc
--- /dev/null
+++ b/include/tests/tests.h
@@ -0,0 +1,45 @@
+#ifndef TESTS_H
+#define TESTS_H
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifndef NOCOLOR
+#define TBLD "\033[1m"
+#define TRED "\033[31m"
+#define TGRN "\033[32m"
+#define TBLU "\033[34m"
+#define TRST "\033[0m"
+#else
+#define TBLD ""
+#define TRED ""
+#define TGRN ""
+#define TBLU ""
+#define TRST ""
+#endif
+
+#define RUN_TEST(test_func) \
+ printf("%s:\t", #test_func); \
+ fflush(stdout); \
+ test_func(); \
+ printf(TGRN "OK!\n" TRST)
+
+#define INIT_TESTS() \
+ printf(TBLD "running %s tests\n" TRST, __FILE__)
+
+#define FAIL_TEST(reason) \
+ printf(TBLD TRED "FAIL!\n" TRST); \
+ printf("%s:%d: %s: ", __FILE__, __LINE__, __func__); \
+ printf(reason); \
+ abort()
+
+#define asserteq(a, b) \
+ if (a != b) { \
+ FAIL_TEST("assertion " TBLD TBLU #a " == " #b TRST " failed\n"); \
+ }
+
+#define assertneq(a, b) \
+ if (a == b) { \
+ FAIL_TEST("assertion " TBLD TBLU #a " != " #b TRST " failed\n"); \
+ }
+
+#endif