<article> | <article> | ||||
<header> | <header> | ||||
<h1>{title}</h1> | |||||
<h1>{{title}}</h1> | |||||
</article> | </article> |
<head> | <head> | ||||
<meta charset="utf-8"> | <meta charset="utf-8"> | ||||
<link rel="stylesheet" href="/_style.css"> | <link rel="stylesheet" href="/_style.css"> | ||||
<title>{title}</title> | |||||
<title>{{title}}</title> | |||||
</head> | </head> | ||||
<body> | <body> | ||||
{menu} | |||||
{{menu}} | |||||
<div id="articles"> | <div id="articles"> | ||||
{articles} | |||||
{{articles}} | |||||
</div> | </div> | ||||
</body> | </body> | ||||
</html> | </html> |
<div class="page"> | <div class="page"> | ||||
<span class="name"> | <span class="name"> | ||||
{name} | |||||
{{name}} | |||||
</span> | </span> | ||||
<div class="sub"> | <div class="sub"> | ||||
{sub} | |||||
{{sub}} | |||||
</div> | </div> | ||||
</div> | </div> |
<header class="menu"> | <header class="menu"> | ||||
<nav class="menu-nav"> | <nav class="menu-nav"> | ||||
{pages} | |||||
{{pages}} | |||||
</nav> | </nav> | ||||
</header> | </header> |
#include <stdio.h> | #include <stdio.h> | ||||
cms_err* cms_build_write_files(cms_page* root, char* path) | |||||
static char* make_post(cms_page* parent, cms_post post, char* rootpath) | |||||
{ | { | ||||
char* fstr; | |||||
char* fname; | |||||
cms_template_args* args; | |||||
cms_err* err; | |||||
char* str; | |||||
//Template index.html | |||||
fname = cms_util_path_join(rootpath, CMS_FILE_THEME "/html/index.html"); | |||||
if (fname == NULL) return NULL; | |||||
fstr = cms_util_file_read(fname); | |||||
if (fstr == NULL) return NULL; | |||||
args = cms_template_args_create(); | |||||
err = cms_template_args_append(args, "articles", post.html); | |||||
if (err) return NULL; | |||||
str = cms_templateify(fstr, args); | |||||
if (str == NULL) return NULL; | |||||
free(fstr); | |||||
free(fname); | |||||
free(args); | |||||
free(err); | |||||
return str; | |||||
} | |||||
cms_err* cms_build_write_files(cms_page* root, char* path, char* rootpath) | |||||
{ | |||||
printf( | |||||
"page: '%s', n posts: %i, n subs: %i\n", | |||||
root->title, | |||||
(int)root->numposts, | |||||
(int)root->numsubs | |||||
); | |||||
char* dirpath = cms_util_path_join(path, root->slug); | char* dirpath = cms_util_path_join(path, root->slug); | ||||
if (dirpath == NULL) | if (dirpath == NULL) | ||||
return cms_err_create(CMS_ERR_ALLOC, NULL); | return cms_err_create(CMS_ERR_ALLOC, NULL); | ||||
if (mkdir(dirpath, 077) == -1 && errno != EEXIST) | |||||
return cms_err_from_std_err(errno); | |||||
if (mkdir(dirpath, 0777) == -1 && errno != EEXIST) | |||||
return cms_err_from_std_err(errno, dirpath); | |||||
//Go through each post in the page, writing it to disk | //Go through each post in the page, writing it to disk | ||||
size_t i; | size_t i; | ||||
for (i = 0; i < root->numposts; ++i) | |||||
for (i = 0; i < (root->numposts); ++i) | |||||
{ | { | ||||
cms_post post = root->posts[i]; | cms_post post = root->posts[i]; | ||||
return cms_err_create(CMS_ERR_ALLOC, NULL); | return cms_err_create(CMS_ERR_ALLOC, NULL); | ||||
if (mkdir(postdirpath, 0777) == -1 && errno != EEXIST) | if (mkdir(postdirpath, 0777) == -1 && errno != EEXIST) | ||||
return cms_err_from_std_err(errno); | |||||
return cms_err_from_std_err(errno, postdirpath); | |||||
char* filepath = cms_util_path_join(postdirpath, CMS_FILE_INDEX); | char* filepath = cms_util_path_join(postdirpath, CMS_FILE_INDEX); | ||||
if (postdirpath == NULL) | if (postdirpath == NULL) | ||||
return cms_err_create(CMS_ERR_ALLOC, NULL); | return cms_err_create(CMS_ERR_ALLOC, NULL); | ||||
int file = open(filepath, O_WRONLY | O_CREAT, 0777); | |||||
int file = open(filepath, O_WRONLY | O_CREAT | O_TRUNC, 0777); | |||||
if (file == -1) | if (file == -1) | ||||
return cms_err_from_std_err(errno); | |||||
return cms_err_from_std_err(errno, NULL); | |||||
write(file, post.html, strlen(post.html)); | |||||
//Create the HTML for the post | |||||
char* html = make_post(root, post, rootpath); | |||||
if (html == NULL) | |||||
return cms_err_create(CMS_ERR_ALLOC, NULL); | |||||
//Write post's HTML file | |||||
ssize_t nbytes = write(file, html, strlen(html)); | |||||
if (nbytes == -1) | |||||
return cms_err_from_std_err(errno, NULL); | |||||
close(file); | close(file); | ||||
free(filepath); | free(filepath); | ||||
if (subdirpath == NULL) | if (subdirpath == NULL) | ||||
return cms_err_create(CMS_ERR_ALLOC, NULL); | return cms_err_create(CMS_ERR_ALLOC, NULL); | ||||
cms_build_write_files(&sub, subdirpath); | |||||
if (mkdir(subdirpath, 0777) == -1 && errno != EEXIST) | |||||
return cms_err_from_std_err(errno, subdirpath); | |||||
cms_err* err = cms_build_write_files(&sub, subdirpath, rootpath); | |||||
if (err) | |||||
return err; | |||||
free(subdirpath); | free(subdirpath); | ||||
} | } | ||||
struct dirent** namelist; | struct dirent** namelist; | ||||
int n = scandir(path, &namelist, 0, alphasort); | int n = scandir(path, &namelist, 0, alphasort); | ||||
if (n == -1) | if (n == -1) | ||||
return cms_err_from_std_err(errno); | |||||
return cms_err_from_std_err(errno, NULL); | |||||
struct dirent* ep; | struct dirent* ep; | ||||
#include "cms_err.h" | #include "cms_err.h" | ||||
#include "cms_page.h" | #include "cms_page.h" | ||||
cms_err* cms_build_write_files(cms_page* root, char* path); | |||||
cms_err* cms_build_write_files(cms_page* root, char* path, char* rootpath); | |||||
cms_err* cms_build_make_tree(cms_page* root, char* path, char* dirname); | cms_err* cms_build_make_tree(cms_page* root, char* path, char* dirname); | ||||
exit(1); | exit(1); | ||||
} | } | ||||
cms_err* _cms_err_from_std_err(int err, const char* file, int line) | |||||
cms_err* _cms_err_from_std_err(int err, char* msg, const char* file, int line) | |||||
{ | { | ||||
switch (err) | switch (err) | ||||
{ | { | ||||
case EACCES: | case EACCES: | ||||
return _cms_err_create(CMS_ERR_PERM, NULL, file, line); | |||||
return _cms_err_create(CMS_ERR_PERM, msg, file, line); | |||||
case EEXIST: | case EEXIST: | ||||
return _cms_err_create(CMS_ERR_FILEEXISTS, NULL, file, line); | |||||
return _cms_err_create(CMS_ERR_FILEEXISTS, msg, file, line); | |||||
case EFAULT: | case EFAULT: | ||||
return _cms_err_create(CMS_ERR_PERM, NULL, file, line); | |||||
return _cms_err_create(CMS_ERR_PERM, msg, file, line); | |||||
case EISDIR: | case EISDIR: | ||||
return _cms_err_create(CMS_ERR_NOTFILE, NULL, file, line); | |||||
return _cms_err_create(CMS_ERR_NOTFILE, msg, file, line); | |||||
case ENOENT: | case ENOENT: | ||||
return _cms_err_create(CMS_ERR_NOENT, NULL, file, line); | |||||
return _cms_err_create(CMS_ERR_NOENT, msg, file, line); | |||||
case ENOMEM: | case ENOMEM: | ||||
return _cms_err_create(CMS_ERR_ALLOC, NULL, file, line); | |||||
return _cms_err_create(CMS_ERR_ALLOC, msg, file, line); | |||||
case ENOTDIR: | case ENOTDIR: | ||||
return _cms_err_create(CMS_ERR_NOTDIR, NULL, file, line); | |||||
return _cms_err_create(CMS_ERR_NOTDIR, msg, file, line); | |||||
case EROFS: | case EROFS: | ||||
return _cms_err_create(CMS_ERR_PERM, NULL, file, line); | |||||
return _cms_err_create(CMS_ERR_PERM, msg, file, line); | |||||
default: | default: | ||||
return _cms_err_create(CMS_ERR_UNKNOWN, NULL, file, line); | |||||
return _cms_err_create(CMS_ERR_UNKNOWN, msg, file, line); | |||||
} | } | ||||
} | } |
void cms_err_panic(cms_err* err); | void cms_err_panic(cms_err* err); | ||||
cms_err* _cms_err_from_std_err(int err, const char* file, int line); | |||||
#define cms_err_from_std_err(err) _cms_err_from_std_err(err, __FILE__, __LINE__) | |||||
cms_err* _cms_err_from_std_err(int err, char* msg, const char* file, int line); | |||||
#define cms_err_from_std_err(err, msg) _cms_err_from_std_err(err, msg, __FILE__, __LINE__) | |||||
#endif | #endif | ||||
#define CMS_FILE_INITED ".cmsinited" | #define CMS_FILE_INITED ".cmsinited" | ||||
//The name of the dir which specifies the title and | //The name of the dir which specifies the title and | ||||
//other metadata of a page | |||||
//other metadata of a page. | |||||
#define CMS_FILE_PAGE "page" | #define CMS_FILE_PAGE "page" | ||||
//Directory containing the user's resources. | //Directory containing the user's resources. | ||||
#define CMS_FILE_ROOT "pages" | #define CMS_FILE_ROOT "pages" | ||||
//Directory containing the user's theme. | |||||
#define CMS_FILE_THEME "theme" | |||||
//Directory to write the output to. | //Directory to write the output to. | ||||
#define CMS_FILE_OUT "public" | #define CMS_FILE_OUT "public" | ||||
#include "cms_template.h" | #include "cms_template.h" | ||||
#include <stdio.h> | |||||
cms_template_args* cms_template_args_create() | cms_template_args* cms_template_args_create() | ||||
{ | { | ||||
cms_template_args* args = malloc(sizeof(cms_template_args)); | cms_template_args* args = malloc(sizeof(cms_template_args)); | ||||
if (args->argnum > args->allocd) | if (args->argnum > args->allocd) | ||||
{ | { | ||||
args->allocd *= 2; | |||||
if (!args->allocd) | |||||
args->allocd = 1; | |||||
else | |||||
args->allocd *= 2; | |||||
args->arguments = realloc( | args->arguments = realloc( | ||||
args->arguments, | args->arguments, | ||||
sizeof(cms_template_arg) * args->allocd | sizeof(cms_template_arg) * args->allocd | ||||
return cms_err_create(CMS_ERR_ALLOC, 0); | return cms_err_create(CMS_ERR_ALLOC, 0); | ||||
} | } | ||||
cms_template_arg arg = {key, val}; | |||||
//Wrap key in {{ and }} | |||||
size_t len = strlen(key); | |||||
char* fullkey = malloc(len + 5); | |||||
memcpy(fullkey, "{{", 2); | |||||
memcpy(fullkey + 2, key, len); | |||||
memcpy(fullkey + len + 2, "}}\0", 3); | |||||
cms_template_arg arg = {fullkey, val}; | |||||
args->arguments[args->argnum - 1] = arg; | args->arguments[args->argnum - 1] = arg; | ||||
return cms_err_create(CMS_ERR_NONE, NULL); | return cms_err_create(CMS_ERR_NONE, NULL); | ||||
char* str2, | char* str2, | ||||
size_t start, | size_t start, | ||||
size_t end, | size_t end, | ||||
size_t len) | |||||
size_t str1len) | |||||
{ | { | ||||
size_t len2 = strlen(str2); | |||||
size_t str2len = strlen(str2); | |||||
str1 = realloc(str1, len + len2 - (end - start)); | |||||
str1 = realloc(str1, str1len + str2len - (end - start)); | |||||
if (str1 == NULL) | if (str1 == NULL) | ||||
return NULL; | return NULL; | ||||
memmove(str1 + end, str1 + start, len - start); | |||||
memcpy(str1 + start, str2, len2); | |||||
memcpy(str1 + start + str2len, str1 + end, str1len - end); | |||||
memcpy(str1 + start, str2, str2len); | |||||
return str1; | return str1; | ||||
} | } | ||||
static char* templatify_arg(char* str, cms_template_arg arg, size_t len) | |||||
static char* templateify_arg(char* str, cms_template_arg arg, size_t len) | |||||
{ | { | ||||
#define OFFSET i - match_start | #define OFFSET i - match_start | ||||
return str; | return str; | ||||
} | } | ||||
char* cms_templateify(char* str, cms_template_args* args) | |||||
char* cms_templateify(char* fstr, cms_template_args* args) | |||||
{ | { | ||||
size_t len = strlen(str); | |||||
size_t len = strlen(fstr); | |||||
char* str = malloc(len); | |||||
if (str == NULL) | |||||
return NULL; | |||||
memcpy(str, fstr, len); | |||||
size_t i; | size_t i; | ||||
for (i = 0; i < args->argnum; ++i) | for (i = 0; i < args->argnum; ++i) | ||||
{ | { | ||||
str = templatify_arg(str, args->arguments[i], len); | |||||
str = templateify_arg(str, args->arguments[i], len); | |||||
if (str == NULL) | if (str == NULL) | ||||
return NULL; | return NULL; | ||||
} | |||||
len = strlen(str); | |||||
} | |||||
return str; | return str; | ||||
} | } |
close(f); | close(f); | ||||
if (f == -1) | if (f == -1) | ||||
return cms_err_from_std_err(errno); | |||||
return cms_err_from_std_err(errno, NULL); | |||||
else | else | ||||
return cms_err_create(CMS_ERR_NONE, NULL); | return cms_err_create(CMS_ERR_NONE, NULL); | ||||
} | } | ||||
{ | { | ||||
int f1 = open(fname1, O_RDONLY); | int f1 = open(fname1, O_RDONLY); | ||||
if (f1 == -1) | if (f1 == -1) | ||||
return cms_err_from_std_err(errno); | |||||
return cms_err_from_std_err(errno, NULL); | |||||
int f2 = open(fname2, O_WRONLY | O_CREAT, 0777); | int f2 = open(fname2, O_WRONLY | O_CREAT, 0777); | ||||
if (f1 == -1) | if (f1 == -1) | ||||
return cms_err_from_std_err(errno); | |||||
return cms_err_from_std_err(errno, NULL); | |||||
struct stat* st = malloc(sizeof(struct stat)); | struct stat* st = malloc(sizeof(struct stat)); | ||||
if (st == NULL) | if (st == NULL) | ||||
cms_err* cms_util_dir_copy_recursive(char* dir1, char* dir2) | cms_err* cms_util_dir_copy_recursive(char* dir1, char* dir2) | ||||
{ | { | ||||
if (mkdir(dir2, 0777) == -1 && errno != EEXIST) | if (mkdir(dir2, 0777) == -1 && errno != EEXIST) | ||||
return cms_err_from_std_err(errno); | |||||
return cms_err_from_std_err(errno, NULL); | |||||
DIR* dp = opendir(dir1); | DIR* dp = opendir(dir1); | ||||
if (dp == NULL) | if (dp == NULL) | ||||
return cms_err_from_std_err(errno); | |||||
return cms_err_from_std_err(errno, NULL); | |||||
struct dirent* ep; | struct dirent* ep; | ||||
char* path2 = cms_util_path_join(dir2, ep->d_name); | char* path2 = cms_util_path_join(dir2, ep->d_name); | ||||
if (stat(path1, st) == -1) | if (stat(path1, st) == -1) | ||||
return cms_err_from_std_err(errno); | |||||
return cms_err_from_std_err(errno, NULL); | |||||
if (S_ISDIR(st->st_mode)) | if (S_ISDIR(st->st_mode)) | ||||
{ | { |
#include "cms_page.h" | #include "cms_page.h" | ||||
#include "cms_build.h" | #include "cms_build.h" | ||||
//Temporary, for testing purposes | |||||
static void print_page_tree(cms_page* page) | |||||
{ | |||||
if (page->title) | |||||
printf("Page: %s\n", page->title); | |||||
//Loop over posts | |||||
size_t i; | |||||
for (i = 0; i < page->numposts; ++i) | |||||
{ | |||||
printf("printing post\n"); | |||||
printf("\tPost: %s\n", (page->posts[i]).title); | |||||
} | |||||
//Loop over subs | |||||
for (i = 0; i < page->numsubs; ++i) | |||||
{ | |||||
print_page_tree(&page->subs[i]); | |||||
} | |||||
printf("---------\n"); | |||||
} | |||||
int main(int argc, char** argv) | int main(int argc, char** argv) | ||||
{ | { | ||||
if (argc < 2) | if (argc < 2) | ||||
cms_page* root = cms_page_create(); | cms_page* root = cms_page_create(); | ||||
if (root == NULL) | if (root == NULL) | ||||
cms_err_panic(cms_err_create(CMS_ERR_ALLOC, NULL)); | cms_err_panic(cms_err_create(CMS_ERR_ALLOC, NULL)); | ||||
root->slug = ""; | |||||
root->title = ""; | |||||
char* path = cms_util_path_join(dirname, CMS_FILE_ROOT); | char* path = cms_util_path_join(dirname, CMS_FILE_ROOT); | ||||
if (path == NULL) | if (path == NULL) | ||||
if (outpath == NULL) | if (outpath == NULL) | ||||
cms_err_panic(cms_err_create(CMS_ERR_ALLOC, NULL)); | cms_err_panic(cms_err_create(CMS_ERR_ALLOC, NULL)); | ||||
cms_build_write_files(root, outpath); | |||||
print_page_tree(root); | |||||
err = cms_build_write_files(root, outpath, dirname); | |||||
if (err) | |||||
cms_err_panic(err); | |||||
} | } | ||||
//Nothing, print usage | //Nothing, print usage |