| appname = cms | appname = cms | ||||
| build: | build: | ||||
| gcc -o $(appname) src/*.c -std=c99 | |||||
| gcc -o3 -o $(appname) src/*.c -std=c99 | |||||
| debug: | debug: | ||||
| gcc -o $(appname) src/*.c -std=c99 -DDEBUG=1 | |||||
| gcc -o3 -o $(appname) src/*.c -std=c99 -DDEBUG=1 | |||||
| install: | install: | ||||
| mv $(appname) /usr/bin/$(appname) | mv $(appname) /usr/bin/$(appname) |
| Example Post | |||||
| <p>This post is an example.</p> |
| Example Page |
| This is placeholder text. | |||||
| This is placeholder text. | |||||
| This is placeholder text. | |||||
| This is placeholder text. | |||||
| This is placeholder text. | |||||
| This is placeholder text. | |||||
| This is placeholder text. |
| This is placeholder text. | |||||
| This is placeholder text. | |||||
| This is placeholder text. | |||||
| This is placeholder text. | |||||
| This is placeholder text. | |||||
| This is placeholder text. | |||||
| This is placeholder text. | |||||
| This is placeholder text. |
| <article> | |||||
| <header> | |||||
| <h1>{title}</h1> | |||||
| </article> |
| <!DOCTYPE html> | |||||
| <html> | |||||
| <head> | |||||
| <meta charset="utf-8"> | |||||
| <link rel="stylesheet" href="/_style.css"> | |||||
| <title>{title}</title> | |||||
| </head> | |||||
| <body> | |||||
| {menu} | |||||
| <div id="articles"> | |||||
| {articles} | |||||
| </div> | |||||
| </body> | |||||
| </html> |
| <div class="page"> | |||||
| <span class="name"> | |||||
| {name} | |||||
| </span> | |||||
| <div class="sub"> | |||||
| {sub} | |||||
| </div> | |||||
| </div> |
| <header class="menu"> | |||||
| <nav class="menu-nav"> | |||||
| {pages} | |||||
| </nav> | |||||
| </header> |
| #include "cms_build.h" | |||||
| #include "cms_err.h" | |||||
| #include "cms_files.h" | |||||
| #include "cms_util.h" | |||||
| #include "cms_page.h" | |||||
| #include "cms_post.h" | |||||
| #include <sys/stat.h> | |||||
| #include <sys/types.h> | |||||
| #include <dirent.h> | |||||
| #include <errno.h> | |||||
| #include <stdlib.h> | |||||
| #include <string.h> | |||||
| cms_err* cms_build_make_tree(cms_page* root, char* path, char* dirname) | |||||
| { | |||||
| DIR* dp = opendir(path); | |||||
| if (dp == NULL) | |||||
| return cms_err_from_std_err(errno); | |||||
| struct dirent* ep; | |||||
| struct stat* st = malloc(sizeof(struct stat)); | |||||
| if (st == NULL) | |||||
| return cms_err_create(CMS_ERR_ALLOC, NULL); | |||||
| while (ep = readdir(dp)) | |||||
| { | |||||
| if (ep->d_name[0] == '.') | |||||
| continue; | |||||
| char* entpath = cms_util_path_join(path, ep->d_name); | |||||
| stat(entpath, st); | |||||
| //Entry is directory, recurse | |||||
| if (S_ISDIR(st->st_mode)) | |||||
| { | |||||
| cms_page* sub = cms_page_create(); | |||||
| if (sub == NULL) | |||||
| return cms_err_create(CMS_ERR_ALLOC, NULL); | |||||
| cms_err* err; | |||||
| err = cms_build_make_tree(sub, entpath, ep->d_name); | |||||
| if (err) | |||||
| return err; | |||||
| err = cms_page_add_sub(root, sub); | |||||
| if (err) | |||||
| return err; | |||||
| } | |||||
| //Entry is the file which contains metadata | |||||
| //about a page, parse | |||||
| else if (strcmp(ep->d_name, CMS_FILE_PAGE) == 0) | |||||
| { | |||||
| char* content = cms_util_file_read(entpath); | |||||
| if (content == NULL) | |||||
| return cms_err_create(CMS_ERR_FILEREAD, entpath); | |||||
| cms_err* err = cms_page_parse(root, content, dirname); | |||||
| free(content); | |||||
| if (err) | |||||
| return err; | |||||
| } | |||||
| //Entry is a post, read it and add to page | |||||
| else | |||||
| { | |||||
| cms_post* post = cms_post_create(); | |||||
| char* content = cms_util_file_read(entpath); | |||||
| if (content == NULL) | |||||
| return cms_err_create(CMS_ERR_FILEREAD, entpath); | |||||
| cms_err* err; | |||||
| err = cms_post_parse(post, content, ep->d_name); | |||||
| free(content); | |||||
| if (err) | |||||
| return err; | |||||
| err = cms_page_add_post(root, post); | |||||
| if (err) | |||||
| return err; | |||||
| } | |||||
| free(entpath); | |||||
| } | |||||
| closedir(dp); | |||||
| free(st); | |||||
| return cms_err_create(CMS_ERR_NONE, NULL); | |||||
| } |
| #ifndef CMS_BUILD_H | |||||
| #define CMS_BUILD_H | |||||
| #include "cms_err.h" | |||||
| #include "cms_page.h" | |||||
| cms_err* cms_build_make_tree(cms_page* root, char* path, char* dirname); | |||||
| #endif |
| #include "cms_err.h" | #include "cms_err.h" | ||||
| #include <stdio.h> | #include <stdio.h> | ||||
| #include <string.h> | |||||
| #include <stdlib.h> | #include <stdlib.h> | ||||
| #include <errno.h> | #include <errno.h> | ||||
| #include <error.h> | #include <error.h> | ||||
| #endif | #endif | ||||
| static char* get_error_message(cms_err err) | |||||
| static char* get_error_message(cms_err* err) | |||||
| { | { | ||||
| switch (err) | |||||
| switch (err->code) | |||||
| { | { | ||||
| case CMS_ERR_NONE: | case CMS_ERR_NONE: | ||||
| return ""; | return ""; | ||||
| return "Not a directory."; | return "Not a directory."; | ||||
| case CMS_ERR_FILEEXISTS: | case CMS_ERR_FILEEXISTS: | ||||
| return "File exists."; | return "File exists."; | ||||
| case CMS_ERR_FILEREAD: | |||||
| return "Failed to read file."; | |||||
| case CMS_ERR_DIREXISTS: | case CMS_ERR_DIREXISTS: | ||||
| return "Directory exists."; | return "Directory exists."; | ||||
| case CMS_ERR_PERM: | case CMS_ERR_PERM: | ||||
| } | } | ||||
| } | } | ||||
| void _cms_err_panic(cms_err err, char* msg, const char* file, int line) | |||||
| cms_err* _cms_err_create(cms_err_code code, char* msg, const char* file, int line) | |||||
| { | |||||
| //We want to just return NULL if there is no error | |||||
| if (code == CMS_ERR_NONE) | |||||
| return NULL; | |||||
| cms_err* err = malloc(sizeof(cms_err)); | |||||
| if (err == NULL) | |||||
| { | |||||
| fprintf(stderr, "Failed to allocate memory.\n"); | |||||
| exit(1); | |||||
| } | |||||
| err->code = code; | |||||
| if (msg == NULL) | |||||
| { | |||||
| err->msg = NULL; | |||||
| } | |||||
| else | |||||
| { | |||||
| size_t msglen = strlen(msg) + 1; | |||||
| err->msg = malloc(msglen * sizeof(char)); | |||||
| if (err->msg == NULL) | |||||
| { | |||||
| fprintf(stderr, "Failed to allocate memory.\n"); | |||||
| exit(1); | |||||
| } | |||||
| memcpy(err->msg, msg, msglen * sizeof(char)); | |||||
| } | |||||
| err->file = file; | |||||
| err->line = line; | |||||
| return err; | |||||
| } | |||||
| void cms_err_free(cms_err* err) | |||||
| { | |||||
| //The error can be null, in which case, we don't want to do anything | |||||
| if (err == NULL) | |||||
| return; | |||||
| free(err->msg); | |||||
| free(err); | |||||
| } | |||||
| void cms_err_panic(cms_err* err) | |||||
| { | { | ||||
| if (!err) | if (!err) | ||||
| return; | return; | ||||
| #ifdef DEBUG | #ifdef DEBUG | ||||
| fprintf(stderr, "File %s, line %i:\n\t", file, line); | |||||
| fprintf(stderr, "File %s, line %i:\n\t", err->file, err->line); | |||||
| #endif | #endif | ||||
| if (msg == NULL) | |||||
| if (err->msg == NULL) | |||||
| fprintf(stderr, "Error: %s\n", get_error_message(err)); | fprintf(stderr, "Error: %s\n", get_error_message(err)); | ||||
| else | else | ||||
| fprintf(stderr, "Error: %s: %s\n", msg, get_error_message(err)); | |||||
| fprintf(stderr, "Error: %s: %s\n", err->msg, get_error_message(err)); | |||||
| exit(1); | exit(1); | ||||
| } | } | ||||
| cms_err cms_err_from_std_err(int err) | |||||
| cms_err* cms_err_from_std_err(int err) | |||||
| { | { | ||||
| #ifdef DEBUG | #ifdef DEBUG | ||||
| error(0, err, "converting to cms_err"); | error(0, err, "converting to cms_err"); | ||||
| switch (err) | switch (err) | ||||
| { | { | ||||
| case EACCES: | case EACCES: | ||||
| return CMS_ERR_PERM; | |||||
| return cms_err_create(CMS_ERR_PERM, NULL); | |||||
| case EEXIST: | case EEXIST: | ||||
| return CMS_ERR_FILEEXISTS; | |||||
| return cms_err_create(CMS_ERR_FILEEXISTS, NULL); | |||||
| case EFAULT: | case EFAULT: | ||||
| return CMS_ERR_PERM; | |||||
| return cms_err_create(CMS_ERR_PERM, NULL); | |||||
| case EISDIR: | case EISDIR: | ||||
| return CMS_ERR_NOTFILE; | |||||
| return cms_err_create(CMS_ERR_NOTFILE, NULL); | |||||
| case ENOENT: | case ENOENT: | ||||
| return CMS_ERR_NOENT; | |||||
| return cms_err_create(CMS_ERR_NOENT, NULL); | |||||
| case ENOMEM: | case ENOMEM: | ||||
| return CMS_ERR_ALLOC; | |||||
| return cms_err_create(CMS_ERR_ALLOC, NULL); | |||||
| case ENOTDIR: | case ENOTDIR: | ||||
| return CMS_ERR_NOTDIR; | |||||
| return cms_err_create(CMS_ERR_NOTDIR, NULL); | |||||
| case EROFS: | case EROFS: | ||||
| return CMS_ERR_PERM; | |||||
| return cms_err_create(CMS_ERR_PERM, NULL); | |||||
| default: | default: | ||||
| return CMS_ERR_UNKNOWN; | |||||
| return cms_err_create(CMS_ERR_UNKNOWN, NULL); | |||||
| } | } | ||||
| } | } |
| #ifndef CMS_ERR_H | #ifndef CMS_ERR_H | ||||
| #define CMS_ERR_H | #define CMS_ERR_H | ||||
| typedef enum cms_err | |||||
| typedef enum cms_err_code | |||||
| { | { | ||||
| CMS_ERR_NONE, | |||||
| CMS_ERR_NONE = 0, | |||||
| CMS_ERR_UNKNOWN, | CMS_ERR_UNKNOWN, | ||||
| CMS_ERR_ALLOC, | CMS_ERR_ALLOC, | ||||
| CMS_ERR_PARSE, | CMS_ERR_PARSE, | ||||
| CMS_ERR_NOTFILE, | CMS_ERR_NOTFILE, | ||||
| CMS_ERR_NOTDIR, | CMS_ERR_NOTDIR, | ||||
| CMS_ERR_FILEEXISTS, | CMS_ERR_FILEEXISTS, | ||||
| CMS_ERR_FILEREAD, | |||||
| CMS_ERR_DIREXISTS, | CMS_ERR_DIREXISTS, | ||||
| CMS_ERR_PERM, | CMS_ERR_PERM, | ||||
| CMS_ERR_INITED, | CMS_ERR_INITED, | ||||
| CMS_ERR_NOTINITED | CMS_ERR_NOTINITED | ||||
| } cms_err_code; | |||||
| typedef struct cms_err | |||||
| { | |||||
| cms_err_code code; | |||||
| char* msg; | |||||
| const char* file; | |||||
| int line; | |||||
| } cms_err; | } cms_err; | ||||
| void _cms_err_panic(cms_err err, char* msg, const char* file, int line); | |||||
| #define cms_err_panic(err, msg) _cms_err_panic(err, msg, __FILE__, __LINE__) | |||||
| //Create an error. Returns NULL if the error code is CMS_ERR_NONE. | |||||
| cms_err* _cms_err_create(cms_err_code code, char* msg, const char* file, int line); | |||||
| #define cms_err_create(code, msg) _cms_err_create(code, msg, __FILE__, __LINE__) | |||||
| void cms_err_free(cms_err* err); | |||||
| void cms_err_panic(cms_err* err); | |||||
| cms_err cms_err_from_std_err(int err); | |||||
| cms_err* cms_err_from_std_err(int err); | |||||
| #endif | #endif | ||||
| //File which tells us if a directory is already initiated. | //File which tells us if a directory is already initiated. | ||||
| #define CMS_FILE_INITED ".cmsinited" | #define CMS_FILE_INITED ".cmsinited" | ||||
| //The name of the dir which specifies the title and | |||||
| //other metadata of a page | |||||
| #define CMS_FILE_PAGE "page" | |||||
| //Directory containing the user's resources. | |||||
| #define CMS_FILE_ROOT "pages" | |||||
| #endif | #endif |
| #include <sys/types.h> | #include <sys/types.h> | ||||
| #include <errno.h> | #include <errno.h> | ||||
| #define PREFIX_LENGTH 5 | |||||
| cms_page* cms_page_create() | cms_page* cms_page_create() | ||||
| { | { | ||||
| cms_page* page = malloc(sizeof(cms_page)); | cms_page* page = malloc(sizeof(cms_page)); | ||||
| if (page == NULL) | |||||
| cms_err_panic(CMS_ERR_ALLOC, NULL); | |||||
| page->numposts = 0; | |||||
| page->numsubs = 0; | |||||
| page->posts = NULL; | |||||
| page->subs = NULL; | |||||
| return page; | return page; | ||||
| } | } | ||||
| cms_err cms_page_parse(cms_page* page, char* str) | |||||
| cms_err* cms_page_parse(cms_page* page, char* str, char* slugstr) | |||||
| { | { | ||||
| //Adding 1 because strlen() returns the length without \0 | |||||
| size_t len = strlen(str) + 1; | size_t len = strlen(str) + 1; | ||||
| page->_str = malloc(len * sizeof(char)); | page->_str = malloc(len * sizeof(char)); | ||||
| if (page->_str == 0) | |||||
| return CMS_ERR_ALLOC; | |||||
| if (page->_str == NULL) | |||||
| return cms_err_create(CMS_ERR_ALLOC, NULL); | |||||
| memcpy(page->_str, str, len * sizeof(char)); | memcpy(page->_str, str, len * sizeof(char)); | ||||
| //The page's title will be the first line. | |||||
| page->title = page->_str; | page->title = page->_str; | ||||
| size_t line = 0; | |||||
| //Replace newlines with \0 | |||||
| for (size_t i = 0; i < len; ++i) | for (size_t i = 0; i < len; ++i) | ||||
| { | { | ||||
| char c = str[i]; | char c = str[i]; | ||||
| switch (c) | switch (c) | ||||
| { | { | ||||
| case '\n': | case '\n': | ||||
| line += 1; | |||||
| if (line == 1) | |||||
| page->slug = (page->_str + i + 1); | |||||
| case '\r': | case '\r': | ||||
| page->_str[i] = '\0'; | page->_str[i] = '\0'; | ||||
| break; | break; | ||||
| } | } | ||||
| if (line == 2) | |||||
| break; | |||||
| } | } | ||||
| if (line == 2) | |||||
| return CMS_ERR_NONE; | |||||
| else | |||||
| return CMS_ERR_PARSE; | |||||
| //Strip out the leading "xxxx-" from slugstr (the filename) | |||||
| //to get the real slug | |||||
| size_t slugstrlen = strlen(slugstr); | |||||
| page->slug = malloc((slugstrlen + 1 - PREFIX_LENGTH) * sizeof(char)); | |||||
| if (page->slug == NULL) | |||||
| return cms_err_create(CMS_ERR_ALLOC, NULL); | |||||
| memcpy(page->slug, slugstr + PREFIX_LENGTH, (slugstrlen - PREFIX_LENGTH)); | |||||
| //Add \0 to the end of the string | |||||
| page->slug[slugstrlen - PREFIX_LENGTH] = '\0'; | |||||
| return cms_err_create(CMS_ERR_NONE, NULL); | |||||
| } | } | ||||
| cms_err cms_page_add_post(cms_page* page, cms_post* post) | |||||
| cms_err* cms_page_add_post(cms_page* page, cms_post* post) | |||||
| { | { | ||||
| page->numposts += 1; | page->numposts += 1; | ||||
| page->posts = realloc(page->posts, page->numposts * sizeof(cms_post)); | |||||
| page->posts = realloc(page->posts, page->numposts * sizeof(cms_post)); | |||||
| if (page->posts == NULL) | if (page->posts == NULL) | ||||
| return CMS_ERR_ALLOC; | |||||
| return cms_err_create(CMS_ERR_ALLOC, NULL); | |||||
| page->posts[page->numposts - 1] = *post; | page->posts[page->numposts - 1] = *post; | ||||
| return CMS_ERR_NONE; | |||||
| return cms_err_create(CMS_ERR_NONE, NULL); | |||||
| } | } | ||||
| cms_err cms_page_create_tree(cms_page* root, const char* path) | |||||
| cms_err* cms_page_add_sub(cms_page* page, cms_page* sub) | |||||
| { | { | ||||
| DIR* dp = opendir(path); | |||||
| if (dp == NULL) | |||||
| return cms_err_from_std_err(errno); | |||||
| page->numsubs += 1; | |||||
| page->subs = realloc(page->subs, page->numsubs * sizeof(cms_page)); | |||||
| if (page->subs == NULL) | |||||
| return cms_err_create(CMS_ERR_ALLOC, NULL); | |||||
| closedir(dp); | |||||
| page->subs[page->numsubs - 1] = *sub; | |||||
| return CMS_ERR_NONE; | |||||
| return cms_err_create(CMS_ERR_NONE, NULL); | |||||
| } | } | ||||
| #ifndef CMS_PAGE_H | #ifndef CMS_PAGE_H | ||||
| #define CMS_PAGE_H | #define CMS_PAGE_H | ||||
| #include "cms_post.h" | |||||
| #include "cms_err.h" | #include "cms_err.h" | ||||
| #include "cms_post.h" | |||||
| #include <stddef.h> | #include <stddef.h> | ||||
| typedef struct cms_page | typedef struct cms_page | ||||
| char* slug; | char* slug; | ||||
| cms_post* posts; | cms_post* posts; | ||||
| size_t numposts; | size_t numposts; | ||||
| struct cms_page* subs; | |||||
| size_t numsubs; | |||||
| } cms_page; | } cms_page; | ||||
| cms_page* cms_page_create(); | cms_page* cms_page_create(); | ||||
| // 1: allloc error | |||||
| // 2: parse error | |||||
| // 3: unknown | |||||
| cms_err cms_page_parse(cms_page* page, char* str); | |||||
| cms_err* cms_page_parse(cms_page* page, char* str, char* slugstr); | |||||
| //1: alloc error | |||||
| //2: unknown | |||||
| cms_err cms_page_add_post(cms_page* page, cms_post* post); | |||||
| cms_err* cms_page_add_post(cms_page* page, cms_post* post); | |||||
| //1: alloc error | |||||
| //2: permission denied | |||||
| //3: dir doesn't exist | |||||
| //4: not a directory | |||||
| //5: unknown | |||||
| cms_err cms_page_create_tree(cms_page* root, const char* path); | |||||
| cms_err* cms_page_add_sub(cms_page* page, cms_page* sub); | |||||
| #endif | #endif |
| #include "cms_post.h" | #include "cms_post.h" | ||||
| #include "cms_err.h" | |||||
| #include <stdlib.h> | #include <stdlib.h> | ||||
| #include <stddef.h> | #include <stddef.h> | ||||
| #include <string.h> | #include <string.h> | ||||
| #define PREFIX_LENGTH 5 | |||||
| cms_post* cms_post_create() | cms_post* cms_post_create() | ||||
| { | { | ||||
| cms_post* post = malloc(sizeof(cms_post)); | cms_post* post = malloc(sizeof(cms_post)); | ||||
| return post; | return post; | ||||
| } | } | ||||
| int cms_post_parse(cms_post* post, char* str) | |||||
| cms_err* cms_post_parse(cms_post* post, char* str, char* slugstr) | |||||
| { | { | ||||
| //Adding 1 because strlen() returns the length without \0 | //Adding 1 because strlen() returns the length without \0 | ||||
| size_t len = strlen(str) + 1; | size_t len = strlen(str) + 1; | ||||
| post->_str = malloc(len * sizeof(char)); | post->_str = malloc(len * sizeof(char)); | ||||
| if (post->_str == NULL) | |||||
| return cms_err_create(CMS_ERR_ALLOC, NULL); | |||||
| memcpy(post->_str, str, len * sizeof(char)); | memcpy(post->_str, str, len * sizeof(char)); | ||||
| //The post's title will be the first line. | |||||
| post->title = post->_str; | post->title = post->_str; | ||||
| size_t line = 0; | size_t line = 0; | ||||
| { | { | ||||
| case '\n': | case '\n': | ||||
| line += 1; | line += 1; | ||||
| if (line == 1) | |||||
| post->slug = (post->_str + i + 1); | |||||
| else if (line == 2) | |||||
| post->markdown = (post->_str + i + 1); | |||||
| if (line == 2) | |||||
| { | |||||
| post->html = (post->_str + i + 1); | |||||
| } | |||||
| //falls through | |||||
| case '\r': | case '\r': | ||||
| post->_str[i] = '\0'; | post->_str[i] = '\0'; | ||||
| break; | break; | ||||
| } | } | ||||
| if (line == 3) | |||||
| if (line == 2) | |||||
| break; | break; | ||||
| } | } | ||||
| if (line == 3) | |||||
| return 0; | |||||
| //Strip out the leading "xxxx-" from slugstr (the filename) | |||||
| //to get the real slug | |||||
| size_t slugstrlen = strlen(slugstr); | |||||
| post->slug = malloc((slugstrlen + 1 - PREFIX_LENGTH) * sizeof(char)); | |||||
| if (post->slug == NULL) | |||||
| return cms_err_create(CMS_ERR_ALLOC, NULL); | |||||
| memcpy(post->slug, slugstr + PREFIX_LENGTH, (slugstrlen - PREFIX_LENGTH)); | |||||
| //Add \0 to the end of the string | |||||
| post->slug[slugstrlen - PREFIX_LENGTH] = '\0'; | |||||
| if (line >= 2) | |||||
| return cms_err_create(CMS_ERR_NONE, NULL); | |||||
| else | else | ||||
| return 1; | |||||
| return cms_err_create(CMS_ERR_PARSE, slugstr); | |||||
| } | } |
| #ifndef CMS_POST_H | #ifndef CMS_POST_H | ||||
| #define CMS_POST_H | #define CMS_POST_H | ||||
| #include "cms_err.h" | |||||
| typedef struct cms_post | typedef struct cms_post | ||||
| { | { | ||||
| char* _str; | char* _str; | ||||
| char* title; | char* title; | ||||
| char* slug; | char* slug; | ||||
| char* markdown; | |||||
| char* html; | |||||
| } cms_post; | } cms_post; | ||||
| cms_post* cms_post_create(); | cms_post* cms_post_create(); | ||||
| int cms_post_parse(cms_post* post, char* str); | |||||
| cms_err* cms_post_parse(cms_post* post, char* str, char* slugstr); | |||||
| #endif | #endif |
| #include "cms_util.h" | |||||
| #include "cms_err.h" | |||||
| #include <fcntl.h> | #include <fcntl.h> | ||||
| #include <unistd.h> | #include <unistd.h> | ||||
| #include <stdio.h> | #include <stdio.h> | ||||
| #include <sys/types.h> | #include <sys/types.h> | ||||
| #include <errno.h> | #include <errno.h> | ||||
| #include "cms_util.h" | |||||
| int cms_util_file_exists(char* fname) | int cms_util_file_exists(char* fname) | ||||
| { | { | ||||
| int f = open(fname, O_RDONLY); | int f = open(fname, O_RDONLY); | ||||
| return 1; | return 1; | ||||
| } | } | ||||
| cms_err cms_util_file_create(char* fname) | |||||
| cms_err* cms_util_file_create(char* fname) | |||||
| { | { | ||||
| int f = open(fname, O_CREAT, 0777); | int f = open(fname, O_CREAT, 0777); | ||||
| close(f); | close(f); | ||||
| if (f == -1) | if (f == -1) | ||||
| return cms_err_from_std_err(errno); | return cms_err_from_std_err(errno); | ||||
| else | else | ||||
| return CMS_ERR_NONE; | |||||
| return cms_err_create(CMS_ERR_NONE, NULL); | |||||
| } | } | ||||
| cms_err cms_util_file_copy(char* fname1, char* fname2) | |||||
| cms_err* cms_util_file_copy(char* fname1, char* fname2) | |||||
| { | { | ||||
| int f1 = open(fname1, O_RDONLY); | int f1 = open(fname1, O_RDONLY); | ||||
| if (f1 == -1) | if (f1 == -1) | ||||
| if (f1 == -1) | if (f1 == -1) | ||||
| return cms_err_from_std_err(errno); | return cms_err_from_std_err(errno); | ||||
| struct stat* s = malloc(sizeof(struct stat)); | |||||
| if (s == NULL) | |||||
| return CMS_ERR_ALLOC; | |||||
| struct stat* st = malloc(sizeof(struct stat)); | |||||
| if (st == NULL) | |||||
| return cms_err_create(CMS_ERR_ALLOC, NULL); | |||||
| fstat(f1, s); | |||||
| fstat(f1, st); | |||||
| void* buf = malloc(s->st_size); | |||||
| void* buf = malloc(st->st_size); | |||||
| if (buf == NULL) | if (buf == NULL) | ||||
| return CMS_ERR_ALLOC; | |||||
| return cms_err_create(CMS_ERR_ALLOC, NULL); | |||||
| read(f1, buf, s->st_size); | |||||
| write(f2, buf, s->st_size); | |||||
| read(f1, buf, st->st_size); | |||||
| write(f2, buf, st->st_size); | |||||
| close(f1); | close(f1); | ||||
| close(f2); | close(f2); | ||||
| free(s); | |||||
| free(st); | |||||
| free(buf); | free(buf); | ||||
| return CMS_ERR_NONE; | |||||
| return cms_err_create(CMS_ERR_NONE, NULL); | |||||
| } | |||||
| char* cms_util_file_read(char* fname) | |||||
| { | |||||
| int file = open(fname, O_RDONLY); | |||||
| if (file == -1) | |||||
| return NULL; | |||||
| struct stat* st = malloc(sizeof(struct stat)); | |||||
| if (st == NULL) | |||||
| return NULL; | |||||
| fstat(file, st); | |||||
| char* buf = malloc(st->st_size + 1); | |||||
| if (buf == NULL) | |||||
| return NULL; | |||||
| read(file, buf, st->st_size + 1); | |||||
| buf[st->st_size] = '\0'; | |||||
| close(file); | |||||
| free(st); | |||||
| return buf; | |||||
| } | } | ||||
| 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); | ||||
| struct stat* st = malloc(sizeof(struct stat)); | struct stat* st = malloc(sizeof(struct stat)); | ||||
| if (st == NULL) | if (st == NULL) | ||||
| return CMS_ERR_ALLOC; | |||||
| return cms_err_create(CMS_ERR_ALLOC, NULL); | |||||
| while (ep = readdir(dp)) | while (ep = readdir(dp)) | ||||
| { | { | ||||
| if (S_ISDIR(st->st_mode)) | if (S_ISDIR(st->st_mode)) | ||||
| { | { | ||||
| cms_err err = cms_util_dir_copy_recursive(path1, path2); | |||||
| cms_err* err = cms_util_dir_copy_recursive(path1, path2); | |||||
| free(path1); | |||||
| free(path2); | |||||
| if (err) | if (err) | ||||
| return err; | return err; | ||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| cms_err err = cms_util_file_copy(path1, path2); | |||||
| cms_err* err = cms_util_file_copy(path1, path2); | |||||
| free(path1); | |||||
| free(path2); | |||||
| if (err) | if (err) | ||||
| return err; | return err; | ||||
| } | } | ||||
| closedir(dp); | closedir(dp); | ||||
| free(st); | free(st); | ||||
| return CMS_ERR_NONE; | |||||
| return cms_err_create(CMS_ERR_NONE, NULL); | |||||
| } | } | ||||
| char* cms_util_path_join(char* str1, char* str2) | char* cms_util_path_join(char* str1, char* str2) | ||||
| len1 -= 1; | len1 -= 1; | ||||
| } | } | ||||
| char* path = malloc((len1 + len2 + 1) * sizeof(char)); | |||||
| char* path = malloc((len1 + len2 + 2) * sizeof(char)); | |||||
| if (path == NULL) | if (path == NULL) | ||||
| cms_err_panic(CMS_ERR_ALLOC, ""); | |||||
| cms_err_panic(cms_err_create(CMS_ERR_ALLOC, NULL)); | |||||
| if (path == NULL) | if (path == NULL) | ||||
| return NULL; | return NULL; |
| int cms_util_file_exists(char* fname); | int cms_util_file_exists(char* fname); | ||||
| //Create a file | //Create a file | ||||
| cms_err cms_util_file_create(char* fname); | |||||
| cms_err* cms_util_file_create(char* fname); | |||||
| //Copy a file | //Copy a file | ||||
| cms_err cms_util_file_copy(char* fname1, char* fname2); | |||||
| cms_err* cms_util_file_copy(char* fname1, char* fname2); | |||||
| //Read a file into a string | |||||
| char* cms_util_file_read(char* fname); | |||||
| //Recursively copy a directory | //Recursively copy a directory | ||||
| cms_err cms_util_dir_copy_recursive(char* dir1, char* dir2); | |||||
| cms_err* cms_util_dir_copy_recursive(char* dir1, char* dir2); | |||||
| //Join together two paths | //Join together two paths | ||||
| char* cms_util_path_join(char* str1, char* str2); | char* cms_util_path_join(char* str1, char* str2); |
| #include <string.h> | #include <string.h> | ||||
| #include <stdio.h> | #include <stdio.h> | ||||
| #include <stdlib.h> | |||||
| #include "cms_util.h" | #include "cms_util.h" | ||||
| #include "cms_err.h" | #include "cms_err.h" | ||||
| #include "cms_files.h" | #include "cms_files.h" | ||||
| #include "cms_page.h" | |||||
| #include "cms_build.h" | |||||
| int main(int argc, char** argv) | int main(int argc, char** argv) | ||||
| { | { | ||||
| if (argc < 2) | if (argc < 2) | ||||
| { | { | ||||
| fprintf(stderr, "Usage: %s <init|deinit|build>\n", argv[0]); | |||||
| fprintf(stderr, "Usage: %s <init|build>\n", argv[0]); | |||||
| return 1; | return 1; | ||||
| } | } | ||||
| //Get the path of .cmsinited, which tells us | //Get the path of .cmsinited, which tells us | ||||
| //whether or not the directory is already inited | //whether or not the directory is already inited | ||||
| char* initedPath = cms_util_path_join(dirname, CMS_FILE_INITED); | char* initedPath = cms_util_path_join(dirname, CMS_FILE_INITED); | ||||
| if (initedPath == NULL) | |||||
| cms_err_panic(cms_err_create(CMS_ERR_ALLOC, NULL)); | |||||
| //Panic if the directory is already initiated | //Panic if the directory is already initiated | ||||
| if (cms_util_file_exists(initedPath)) | if (cms_util_file_exists(initedPath)) | ||||
| cms_err_panic(CMS_ERR_INITED, NULL); | |||||
| cms_err_panic(cms_err_create(CMS_ERR_INITED, NULL)); | |||||
| //Copy files from resources | //Copy files from resources | ||||
| cms_err err; | |||||
| cms_err* err; | |||||
| err = cms_util_dir_copy_recursive(CMS_FILE_RESOURCES, dirname); | err = cms_util_dir_copy_recursive(CMS_FILE_RESOURCES, dirname); | ||||
| if (err) | if (err) | ||||
| cms_err_panic(err, dirname); | |||||
| cms_err_panic(err); | |||||
| //Create .cmsinited file | //Create .cmsinited file | ||||
| err = cms_util_file_create(initedPath); | err = cms_util_file_create(initedPath); | ||||
| if (err) | if (err) | ||||
| cms_err_panic(err, initedPath); | |||||
| cms_err_panic(err); | |||||
| } | } | ||||
| //Build | //Build | ||||
| //Panic if the directory isn't initiated | //Panic if the directory isn't initiated | ||||
| if (!cms_util_file_exists(initedPath)) | if (!cms_util_file_exists(initedPath)) | ||||
| cms_err_panic(CMS_ERR_NOTINITED, NULL); | |||||
| cms_err_panic(cms_err_create(CMS_ERR_NOTINITED, NULL)); | |||||
| cms_page* root = cms_page_create(); | |||||
| if (root == NULL) | |||||
| cms_err_panic(cms_err_create(CMS_ERR_ALLOC, NULL)); | |||||
| char* path = cms_util_path_join(dirname, CMS_FILE_ROOT); | |||||
| if (path == NULL) | |||||
| cms_err_panic(cms_err_create(CMS_ERR_ALLOC, NULL)); | |||||
| //Build tree of pages and posts | |||||
| cms_err* err; | |||||
| err = cms_build_make_tree(root, path, NULL); | |||||
| free(path); | |||||
| if (err) | |||||
| cms_err_panic(err); | |||||
| } | |||||
| //Nothing, print usage | |||||
| else | |||||
| { | |||||
| fprintf(stderr, "Usage: %s <init|build>\n", argv[0]); | |||||
| return 1; | |||||
| } | } | ||||
| } | } |