File: | ctx.c |
Warning: | line 237, column 17 Value stored to 'slash' during its initialization is never read |
1 | /* |
2 | * blogc: A blog compiler. |
3 | * Copyright (C) 2014-2017 Rafael G. Martins <rafael@rafaelmartins.eng.br> |
4 | * |
5 | * This program can be distributed under the terms of the BSD License. |
6 | * See the file LICENSE. |
7 | */ |
8 | |
9 | #include <sys/stat.h> |
10 | #include <sys/types.h> |
11 | #include <dirent.h> |
12 | #include <libgen.h> |
13 | #include <time.h> |
14 | #include <stdlib.h> |
15 | #include <stdbool.h> |
16 | #include <string.h> |
17 | #include "../common/error.h" |
18 | #include "../common/file.h" |
19 | #include "../common/utils.h" |
20 | #include "atom.h" |
21 | #include "settings.h" |
22 | #include "exec.h" |
23 | #include "utils.h" |
24 | #include "ctx.h" |
25 | |
26 | |
27 | bm_filectx_t* |
28 | bm_filectx_new(bm_ctx_t *ctx, const char *filename, const char *slug, |
29 | struct stat *st) |
30 | { |
31 | if (ctx == NULL((void*)0) || filename == NULL((void*)0)) |
32 | return NULL((void*)0); |
33 | |
34 | char *f = filename[0] == '/' ? bc_strdup(filename) : |
35 | bc_strdup_printf("%s/%s", ctx->root_dir, filename); |
36 | |
37 | bm_filectx_t *rv = bc_malloc(sizeof(bm_filectx_t)); |
38 | rv->path = f; |
39 | rv->short_path = bc_strdup(filename); |
40 | rv->slug = bc_strdup(slug); |
41 | |
42 | if (st == NULL((void*)0)) { |
43 | struct stat buf; |
44 | |
45 | if (0 != stat(f, &buf)) { |
46 | rv->tv_sec = 0; |
47 | rv->tv_nsec = 0; |
48 | rv->readable = false0; |
49 | return rv; |
50 | } |
51 | |
52 | st = &buf; |
53 | } |
54 | |
55 | // if it isn't NULL the file exists for sure |
56 | rv->tv_sec = st->st_mtim_tv_secst_mtim.tv_sec; |
57 | rv->tv_nsec = st->st_mtim_tv_nsecst_mtim.tv_nsec; |
58 | rv->readable = true1; |
59 | return rv; |
60 | } |
61 | |
62 | |
63 | bc_slist_t* |
64 | bm_filectx_new_r(bc_slist_t *l, bm_ctx_t *ctx, const char *filename) |
65 | { |
66 | if (ctx == NULL((void*)0) || filename == NULL((void*)0)) |
67 | return NULL((void*)0); |
68 | |
69 | char *f = filename[0] == '/' ? bc_strdup(filename) : |
70 | bc_strdup_printf("%s/%s", ctx->root_dir, filename); |
71 | |
72 | struct stat buf; |
73 | if (0 != stat(f, &buf)) { |
74 | free(f); |
75 | return l; |
76 | } |
77 | |
78 | if (S_ISDIR(buf.st_mode)((((buf.st_mode)) & 0170000) == (0040000))) { |
79 | DIR *dir = opendir(f); |
80 | if (dir == NULL((void*)0)) { |
81 | free(f); |
82 | return l; |
83 | } |
84 | |
85 | struct dirent *e; |
86 | while (NULL((void*)0) != (e = readdir(dir))) { |
87 | if ((0 == strcmp(e->d_name, ".")) || (0 == strcmp(e->d_name, ".."))) |
88 | continue; |
89 | char *tmp = bc_strdup_printf("%s/%s", filename, e->d_name); |
90 | l = bm_filectx_new_r(l, ctx, tmp); |
91 | free(tmp); |
92 | } |
93 | |
94 | closedir(dir); |
95 | free(f); |
96 | return l; |
97 | } |
98 | |
99 | l = bc_slist_append(l, bm_filectx_new(ctx, filename, NULL((void*)0), &buf)); |
100 | free(f); |
101 | return l; |
102 | } |
103 | |
104 | |
105 | bool_Bool |
106 | bm_filectx_changed(bm_filectx_t *ctx, time_t *tv_sec, long *tv_nsec) |
107 | { |
108 | if (ctx == NULL((void*)0)) |
109 | return false0; |
110 | |
111 | struct stat buf; |
112 | |
113 | if (0 == stat(ctx->path, &buf)) { |
114 | if (buf.st_mtim_tv_secst_mtim.tv_sec == ctx->tv_sec) { |
115 | if (buf.st_mtim_tv_nsecst_mtim.tv_nsec > ctx->tv_nsec) { |
116 | if (tv_sec != NULL((void*)0)) |
117 | *tv_sec = buf.st_mtim_tv_secst_mtim.tv_sec; |
118 | if (tv_nsec != NULL((void*)0)) |
119 | *tv_nsec = buf.st_mtim_tv_nsecst_mtim.tv_nsec; |
120 | return true1; |
121 | } |
122 | } |
123 | else if (buf.st_mtim_tv_secst_mtim.tv_sec > ctx->tv_sec) { |
124 | if (tv_sec != NULL((void*)0)) |
125 | *tv_sec = buf.st_mtim_tv_secst_mtim.tv_sec; |
126 | if (tv_nsec != NULL((void*)0)) |
127 | *tv_nsec = buf.st_mtim_tv_nsecst_mtim.tv_nsec; |
128 | return true1; |
129 | } |
130 | } |
131 | |
132 | return false0; |
133 | } |
134 | |
135 | |
136 | void |
137 | bm_filectx_reload(bm_filectx_t *ctx) |
138 | { |
139 | if (ctx == NULL((void*)0)) |
140 | return; |
141 | |
142 | time_t tv_sec; |
143 | long tv_nsec; |
144 | |
145 | if (!bm_filectx_changed(ctx, &tv_sec, &tv_nsec)) |
146 | return; |
147 | |
148 | ctx->tv_sec = tv_sec; |
149 | ctx->tv_nsec = tv_nsec; |
150 | ctx->readable = true1; |
151 | } |
152 | |
153 | |
154 | void |
155 | bm_filectx_free(bm_filectx_t *fctx) |
156 | { |
157 | if (fctx == NULL((void*)0)) |
158 | return; |
159 | free(fctx->path); |
160 | free(fctx->short_path); |
161 | free(fctx->slug); |
162 | free(fctx); |
163 | } |
164 | |
165 | |
166 | bm_ctx_t* |
167 | bm_ctx_new(bm_ctx_t *base, const char *settings_file, const char *argv0, |
168 | bc_error_t **err) |
169 | { |
170 | if (settings_file == NULL((void*)0) || err == NULL((void*)0) || *err != NULL((void*)0)) |
171 | return NULL((void*)0); |
172 | |
173 | size_t content_len; |
174 | char *content = bc_file_get_contents(settings_file, true1, &content_len, |
175 | err); |
176 | if (*err != NULL((void*)0)) |
177 | return NULL((void*)0); |
178 | |
179 | bm_settings_t *settings = bm_settings_parse(content, content_len, err); |
180 | if (*err != NULL((void*)0)) { |
181 | free(content); |
182 | return NULL((void*)0); |
183 | } |
184 | free(content); |
185 | |
186 | char *atom_template = bm_atom_deploy(settings, err); |
187 | if (*err != NULL((void*)0)) { |
188 | return NULL((void*)0); |
189 | } |
190 | |
191 | bm_ctx_t *rv = NULL((void*)0); |
192 | if (base == NULL((void*)0)) { |
193 | rv = bc_malloc(sizeof(bm_ctx_t)); |
194 | rv->blogc = bm_exec_find_binary(argv0, "blogc", "BLOGC"); |
195 | rv->blogc_runserver = bm_exec_find_binary(argv0, "blogc-runserver", |
196 | "BLOGC_RUNSERVER"); |
197 | rv->dev = false0; |
198 | rv->verbose = false0; |
199 | } |
200 | else { |
201 | bm_ctx_free_internal(base); |
202 | rv = base; |
203 | } |
204 | rv->settings = settings; |
205 | |
206 | char *real_filename = realpath(settings_file, NULL((void*)0)); |
207 | rv->settings_fctx = bm_filectx_new(rv, real_filename, NULL((void*)0), NULL((void*)0)); |
208 | rv->root_dir = realpath(dirname(real_filename), NULL((void*)0)); |
209 | free(real_filename); |
210 | |
211 | const char *output_dir = getenv("OUTPUT_DIR"); |
212 | rv->short_output_dir = bc_strdup(output_dir != NULL((void*)0) ? output_dir : "_build"); |
213 | |
214 | if (rv->short_output_dir[0] == '/') { |
215 | rv->output_dir = bc_strdup(rv->short_output_dir); |
216 | } |
217 | else { |
218 | rv->output_dir = bc_strdup_printf("%s/%s", rv->root_dir, |
219 | rv->short_output_dir); |
220 | } |
221 | |
222 | // can't return null and set error after this! |
223 | |
224 | const char *template_dir = bm_ctx_settings_lookup(rv, "template_dir"); |
225 | |
226 | char *main_template = bc_strdup_printf("%s/%s", template_dir, |
227 | bm_ctx_settings_lookup(rv, "main_template")); |
228 | rv->main_template_fctx = bm_filectx_new(rv, main_template, NULL((void*)0), NULL((void*)0)); |
229 | free(main_template); |
230 | |
231 | rv->atom_template_fctx = bm_filectx_new(rv, atom_template, NULL((void*)0), NULL((void*)0)); |
232 | free(atom_template); |
233 | |
234 | const char *content_dir = bm_ctx_settings_lookup(rv, "content_dir"); |
235 | const char *post_prefix = bm_ctx_settings_lookup(rv, "post_prefix"); |
236 | const char *source_ext = bm_ctx_settings_lookup(rv, "source_ext"); |
237 | const char *slash = post_prefix[0] == '\0' ? "" : "/"; |
Value stored to 'slash' during its initialization is never read | |
238 | |
239 | rv->posts_fctx = NULL((void*)0); |
240 | if (settings->posts != NULL((void*)0)) { |
241 | for (size_t i = 0; settings->posts[i] != NULL((void*)0); i++) { |
242 | char *f = bm_generate_filename(content_dir, post_prefix, |
243 | settings->posts[i], source_ext); |
244 | rv->posts_fctx = bc_slist_append(rv->posts_fctx, |
245 | bm_filectx_new(rv, f, settings->posts[i], NULL((void*)0))); |
246 | free(f); |
247 | } |
248 | } |
249 | |
250 | rv->pages_fctx = NULL((void*)0); |
251 | if (settings->pages != NULL((void*)0)) { |
252 | for (size_t i = 0; settings->pages[i] != NULL((void*)0); i++) { |
253 | char *f = bm_generate_filename(content_dir, NULL((void*)0), settings->pages[i], |
254 | source_ext); |
255 | rv->pages_fctx = bc_slist_append(rv->pages_fctx, |
256 | bm_filectx_new(rv, f, settings->pages[i], NULL((void*)0))); |
257 | free(f); |
258 | } |
259 | } |
260 | |
261 | rv->copy_fctx = NULL((void*)0); |
262 | if (settings->copy != NULL((void*)0)) { |
263 | for (size_t i = 0; settings->copy[i] != NULL((void*)0); i++) { |
264 | rv->copy_fctx = bm_filectx_new_r(rv->copy_fctx, rv, |
265 | settings->copy[i]); |
266 | } |
267 | } |
268 | |
269 | return rv; |
270 | } |
271 | |
272 | |
273 | bool_Bool |
274 | bm_ctx_reload(bm_ctx_t **ctx) |
275 | { |
276 | if (*ctx == NULL((void*)0) || (*ctx)->settings_fctx == NULL((void*)0)) |
277 | return false0; |
278 | |
279 | if (bm_filectx_changed((*ctx)->settings_fctx, NULL((void*)0), NULL((void*)0))) { |
280 | // reload everything! we could just reload settings_fctx, as this |
281 | // would force rebuilding everything, but we need to know new/deleted |
282 | // files |
283 | |
284 | // needs to dup path, because it may be freed when reloading. |
285 | char *tmp = bc_strdup((*ctx)->settings_fctx->path); |
286 | bc_error_t *err = NULL((void*)0); |
287 | *ctx = bm_ctx_new(*ctx, tmp, NULL((void*)0), &err); |
288 | free(tmp); |
289 | if (err != NULL((void*)0)) { |
290 | bc_error_print(err, "blogc-make"); |
291 | bc_error_free(err); |
292 | return false0; |
293 | } |
294 | return true1; |
295 | } |
296 | |
297 | bm_filectx_reload((*ctx)->main_template_fctx); |
298 | bm_filectx_reload((*ctx)->atom_template_fctx); |
299 | |
300 | for (bc_slist_t *tmp = (*ctx)->posts_fctx; tmp != NULL((void*)0); tmp = tmp->next) |
301 | bm_filectx_reload((bm_filectx_t*) tmp->data); |
302 | |
303 | for (bc_slist_t *tmp = (*ctx)->pages_fctx; tmp != NULL((void*)0); tmp = tmp->next) |
304 | bm_filectx_reload((bm_filectx_t*) tmp->data); |
305 | |
306 | for (bc_slist_t *tmp = (*ctx)->copy_fctx; tmp != NULL((void*)0); tmp = tmp->next) |
307 | bm_filectx_reload((bm_filectx_t*) tmp->data); |
308 | |
309 | return true1; |
310 | } |
311 | |
312 | |
313 | void |
314 | bm_ctx_free_internal(bm_ctx_t *ctx) |
315 | { |
316 | if (ctx == NULL((void*)0)) |
317 | return; |
318 | |
319 | bm_settings_free(ctx->settings); |
320 | ctx->settings = NULL((void*)0); |
321 | |
322 | free(ctx->root_dir); |
323 | ctx->root_dir = NULL((void*)0); |
324 | free(ctx->short_output_dir); |
325 | ctx->short_output_dir = NULL((void*)0); |
326 | free(ctx->output_dir); |
327 | ctx->output_dir = NULL((void*)0); |
328 | |
329 | bm_atom_destroy(ctx->atom_template_fctx->path); |
330 | |
331 | bm_filectx_free(ctx->main_template_fctx); |
332 | ctx->main_template_fctx = NULL((void*)0); |
333 | bm_filectx_free(ctx->atom_template_fctx); |
334 | ctx->atom_template_fctx = NULL((void*)0); |
335 | bm_filectx_free(ctx->settings_fctx); |
336 | ctx->settings_fctx = NULL((void*)0); |
337 | |
338 | bc_slist_free_full(ctx->posts_fctx, (bc_free_func_t) bm_filectx_free); |
339 | ctx->posts_fctx = NULL((void*)0); |
340 | bc_slist_free_full(ctx->pages_fctx, (bc_free_func_t) bm_filectx_free); |
341 | ctx->pages_fctx = NULL((void*)0); |
342 | bc_slist_free_full(ctx->copy_fctx, (bc_free_func_t) bm_filectx_free); |
343 | ctx->copy_fctx = NULL((void*)0); |
344 | } |
345 | |
346 | |
347 | void |
348 | bm_ctx_free(bm_ctx_t *ctx) |
349 | { |
350 | if (ctx == NULL((void*)0)) |
351 | return; |
352 | bm_ctx_free_internal(ctx); |
353 | free(ctx->blogc); |
354 | free(ctx->blogc_runserver); |
355 | free(ctx); |
356 | } |
357 | |
358 | |
359 | const char* |
360 | bm_ctx_settings_lookup(bm_ctx_t *ctx, const char *key) |
361 | { |
362 | if (ctx == NULL((void*)0) || ctx->settings == NULL((void*)0) || ctx->settings->settings == NULL((void*)0)) |
363 | return NULL((void*)0); |
364 | return bc_trie_lookup(ctx->settings->settings, key); |
365 | } |
366 | |
367 | |
368 | const char* |
369 | bm_ctx_settings_lookup_str(bm_ctx_t *ctx, const char *key) |
370 | { |
371 | const char *rv = bm_ctx_settings_lookup(ctx, key); |
372 | return rv == NULL((void*)0) ? "" : rv; |
373 | } |