shayla

a simple yet fast static site builder
Log | Files | Refs | Submodules | README | LICENSE | git clone https://git.ne02ptzero.me/git/shayla

commit f6d0086b2029eef2e6993842523d46896050255e
parent 02d774e51479bd0f20a37b27f4ec1fd5de7fb8a9
Author: Louis Solofrizzo <lsolofrizzo@online.net>
Date:   Fri, 28 Sep 2018 04:14:13 +0200

Parser: Now parsing markdown from posts files

We now parse the content of a markdown post, and convert it to html.
I've also added more error messages in case of parsing error, and fixed
a crash on a file size of 0.

I've also modified the pool API a bit, with a more simple approach on
the user side, and the possibility to be called back with the current
thread number

Signed-off-by: Louis Solofrizzo <lsolofrizzo@online.net>

Diffstat:
Mfile.c | 28+++++++++++++++++++++++++++-
Mfile.h | 3++-
Mheader.c | 10++++++++--
Mpool.c | 48+++++++++++++++++++++++++++++-------------------
Mpool.h | 32+++++++++++++++++++++++---------
Mposts.c | 57++++++++++++++++++++++++++++++++++++++++++++++++++++-----
6 files changed, 141 insertions(+), 37 deletions(-)

diff --git a/file.c b/file.c @@ -27,9 +27,18 @@ bool file_read(file_t *file) return false; fstat(fd->_fileno, &st); + if (st.st_size == 0) + { + PROGRESS_WARNING("File %s is empty", file->path); + return false; + } + file->ts = st.st_mtime; file->ib = bufnew(st.st_size); + if (file->ib == NULL) + return false; + bufgrow(file->ib, st.st_size); fread(file->ib->data, 1, file->ib->asize, fd); @@ -38,7 +47,21 @@ bool file_read(file_t *file) return true; } -bool file_parse(file_t *ptr) +static bool file_parse_md(file_t *ptr, struct sd_markdown *ctx) +{ + ptr->ob = bufnew(4096); + if (ptr->ob == NULL) + return false; + + sd_markdown_render(ptr->ob, ptr->ib->data + ptr->header_end_pos, + ptr->ib->unit - ptr->header_end_pos, ctx); + + if (ptr->ob == NULL) + return false; + return true; +} + +bool file_parse(file_t *ptr, struct sd_markdown *ctx) { if (!file_read(ptr)) return false; @@ -46,5 +69,8 @@ bool file_parse(file_t *ptr) if (!file_parse_header(ptr)) return false; + if (!file_parse_md(ptr, ctx)) + return false; + return true; } diff --git a/file.h b/file.h @@ -52,6 +52,7 @@ static inline void file_dtr(file_t *ptr) free(ptr->summary); bufrelease(ptr->ib); + bufrelease(ptr->ob); } /*! @@ -155,7 +156,7 @@ static inline bool file_exist(const char *str) * * \return true on success, false on failure */ -bool file_parse(file_t *ptr); +bool file_parse(file_t *ptr, struct sd_markdown *ctx); /*! * \brief Read an entire file diff --git a/header.c b/header.c @@ -42,7 +42,7 @@ static bool header_set_route(file_t *file, char *val) static bool header_set_date(file_t *file, char *val) { - struct tm tm; + struct tm tm = { 0 }; time_t ts; if (strptime(val, "%Y-%m-%d", &tm) == NULL) @@ -140,13 +140,19 @@ bool file_parse_header(file_t *file) return false; if (!IS_HEADER_DELIM_LINE(data)) + { + PROGRESS_WARNING("The file %s does not have a beginning header", file->path); return false; + } str = strstr(data + sizeof(HEADER_DELIM), HEADER_DELIM); if (str == NULL || str == data) + { + PROGRESS_WARNING("The file %s does not have an end header", file->path); return false; + } - file->header_end_pos = str - data; + file->header_end_pos = str - data + sizeof(HEADER_DELIM); data += sizeof(HEADER_DELIM); while ((line = strsep(&data, "\n")) != NULL) diff --git a/pool.c b/pool.c @@ -13,6 +13,7 @@ * along with this program. If not, see <https://www.gnu.org/licenses/>. */ +#define POOL_SOURCE #include <pool.h> #include <log.h> @@ -23,10 +24,11 @@ #include <string.h> typedef struct { - job_callback_t *fn; + void *fn; void *data; struct list_head node; bool do_free; + bool with_num; } pool_job_t; static pthread_mutex_t pool_lock = { 0 }; @@ -35,11 +37,11 @@ static uint8_t pool_threads_size = 0; static bool pool_do_quit = false; static list_head_t pool_jobs = { 0 }; -static void *pool_job_worker(void *unused) +static void *pool_job_worker(void *thread) { pool_job_t *job = NULL; + uint8_t num = *((uint8_t *)thread); - UNUSED_ARG(unused); while (true) { pthread_mutex_lock(&pool_lock); @@ -55,7 +57,10 @@ static void *pool_job_worker(void *unused) pthread_mutex_unlock(&pool_lock); /* Treat the job and cleanup everything */ - job->fn(job->data); + if (job->with_num) + ((job_callback_num_t *)(job->fn))(job->data, num); + else + ((job_callback_t *)(job->fn))(job->data); if (job->do_free) free(job->data); @@ -66,7 +71,10 @@ static void *pool_job_worker(void *unused) /* Nothing to do, let's give back the lock and let the CPU sleep */ pthread_mutex_unlock(&pool_lock); if (!pool_do_quit) + { + free(thread); return NULL; + } usleep(500); } @@ -92,10 +100,14 @@ bool pool_init(uint8_t threads) void pool_run(void) { + uint8_t *num; + pool_do_quit = true; for (uint8_t i = 0; i < pool_threads_size; i++) { - pthread_create(&pool_threads[i], NULL, &pool_job_worker, NULL); + num = malloc(sizeof(*num)); + *num = i; + pthread_create(&pool_threads[i], NULL, &pool_job_worker, num); } DEBUG("Created a pool of %d threads\n", pool_threads_size); @@ -108,7 +120,7 @@ void pool_cleanup(void) pool_threads_size = 0; } -static bool pool_add_job_to_list(job_callback_t *fn, void *data, size_t data_size, bool do_copy) +bool pool_add_job(void *fn, void *data, job_args_t *args) { pool_job_t *ptr; @@ -118,16 +130,16 @@ static bool pool_add_job_to_list(job_callback_t *fn, void *data, size_t data_siz if (ptr == NULL) return false; - if (do_copy) + if (args->size != 0) { - ptr->data = calloc(1, data_size); + ptr->data = calloc(1, args->size); if (ptr->data == NULL) { free(ptr); return false; } - memcpy(ptr->data, data, data_size); + memcpy(ptr->data, data, args->size); ptr->do_free = true; } else @@ -135,6 +147,9 @@ static bool pool_add_job_to_list(job_callback_t *fn, void *data, size_t data_siz ptr->data = data; } + if (args->with_thread_num) + ptr->with_num = true; + ptr->fn = fn; pthread_mutex_lock(&pool_lock); @@ -144,16 +159,6 @@ static bool pool_add_job_to_list(job_callback_t *fn, void *data, size_t data_siz return true; } -bool pool_add_job(job_callback_t *fn, void *data, size_t data_size) -{ - return pool_add_job_to_list(fn, data, data_size, true); -} - -bool pool_add_job_no_copy(job_callback_t *fn, void *data) -{ - return pool_add_job_to_list(fn, data, 0, false); -} - void pool_wait(void) { pool_do_quit = false; @@ -163,3 +168,8 @@ void pool_wait(void) pthread_join(pool_threads[i], NULL); } } + +uint8_t pool_size(void) +{ + return pool_threads_size; +} diff --git a/pool.h b/pool.h @@ -21,6 +21,7 @@ # include <stddef.h> typedef void (job_callback_t)(void *data); +typedef void (job_callback_num_t)(void *data, int thread); /*! * \brief Init the thread pool @@ -41,24 +42,32 @@ void pool_cleanup(void); */ void pool_run(void); +typedef struct { + bool with_thread_num; /*!< Call the function with the thread number */ + size_t size; /*!< Size of the argument to copy */ +} job_args_t; + /*! * \brief Add a job to the thread pool * * \param[in] fn Callback of the job * \param[in] data Private pointer - * \param[in] data_size Private pointer size + * \param[in] args Variadic arguments + * \param[opt] with_thread_num Call the callback with the thread number. In this + * case, the callback type is expected to be job_callback_num_t + * \param[opt] size Size of the argument to copy. If this parameter is different + * than 0, the content of data is copied with allocation * - * \sa pool_add_job - * \note Data is copied of data_size bytes + * Examples: + * pool_add_job(&my_callback, ptr, .with_thread_num = true); + * pool_add_job(&my_callback, ptr, .size = sizeof(*ptr)); * * \return true on success, false on failure */ -bool pool_add_job(job_callback_t *fn, void *data, size_t data_size); - -/*! - * \brief Similar to pool_add_job, but with no copy of the pointer - */ -bool pool_add_job_no_copy(job_callback_t *fn, void *data); +bool pool_add_job(void *fn, void *data, job_args_t *args); +#ifndef POOL_SOURCE +# define pool_add_job(fn, data, ...) pool_add_job(fn, data, &(job_args_t){__VA_ARGS__}) +#endif /* POOL_SOURCE */ /*! * \brief Wrapper to pool_add_job @@ -92,4 +101,9 @@ bool pool_add_job_no_copy(job_callback_t *fn, void *data); */ void pool_wait(void); +/*! + * \brief Get the current pool size + */ +uint8_t pool_size(void); + #endif /* POOL_H */ diff --git a/posts.c b/posts.c @@ -16,16 +16,57 @@ #include <posts.h> #include <file.h> #include <pool.h> +#include <markdown.h> +#include <html.h> -static bool parse_error = false; +static bool parse_error = false; +static struct sd_markdown **markdown_context = NULL; -static void post_parse_callback(void *data) +static void markdown_context_cleanup(void) +{ + uint8_t threads_num = pool_size(); + + for (uint8_t i = 0; i < threads_num; i++) + { + if (markdown_context[i] != NULL) + sd_markdown_free(markdown_context[i]); + } + + free(markdown_context); +} + +static bool markdown_context_init(void) +{ + uint8_t threads_num = pool_size(); + struct html_renderopt options; + struct sd_callbacks callbacks; + + sdhtml_renderer(&callbacks, &options, 0); + + markdown_context = calloc(threads_num, sizeof(*markdown_context)); + if (markdown_context == NULL) + return false; + + for (uint8_t i = 0; i < threads_num; i++) + { + markdown_context[i] = sd_markdown_new(0, 12, &callbacks, &options); + if (markdown_context == NULL) + goto fail; + } + + return true; +fail: + markdown_context_cleanup(); + return false; +} + +static void post_parse_callback(void *data, uint8_t num) { file_t *file = data; PROGRESS_UPDATE("Parsing %s...", file->path); - if (!file_parse(file)) + if (!file_parse(file, markdown_context[num])) { PROGRESS_WARNING("Could not parse file %s", file->path); parse_error = true; @@ -36,17 +77,23 @@ bool posts_parse_all(list_head_t *head) { file_t *ptr; - SET_PREFIX("Posts:"); + if (!markdown_context_init()) + { + ERROR("Could not init markdown context"); + return false; + } + PROGRESS_BEGIN(); pool_run(); list_for_each_entry(ptr, head, list) { - pool_add_job_no_copy(&post_parse_callback, ptr); + pool_add_job(&post_parse_callback, ptr, .with_thread_num = true); } pool_wait(); PROGRESS_DONE(); + markdown_context_cleanup(); return !parse_error; }