| <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 |