Преглед на файлове

New error system, building a tree of posts now works in theory

master
mort преди 9 години
родител
ревизия
03e5f0a8a9

+ 2
- 2
Makefile Целия файл

@@ -1,10 +1,10 @@
appname = cms

build:
gcc -o $(appname) src/*.c -std=c99
gcc -o3 -o $(appname) src/*.c -std=c99

debug:
gcc -o $(appname) src/*.c -std=c99 -DDEBUG=1
gcc -o3 -o $(appname) src/*.c -std=c99 -DDEBUG=1

install:
mv $(appname) /usr/bin/$(appname)

+ 3
- 0
resources/pages/0001-example/0001-example Целия файл

@@ -0,0 +1,3 @@
Example Post

<p>This post is an example.</p>

+ 1
- 0
resources/pages/0001-example/page Целия файл

@@ -0,0 +1 @@
Example Page

+ 0
- 7
resources/placeholder Целия файл

@@ -1,7 +0,0 @@
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.

+ 0
- 8
resources/subdirtest/placeholder Целия файл

@@ -1,8 +0,0 @@
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.

+ 4
- 0
resources/theme/html/article.html Целия файл

@@ -0,0 +1,4 @@
<article>
<header>
<h1>{title}</h1>
</article>

+ 15
- 0
resources/theme/html/index.html Целия файл

@@ -0,0 +1,15 @@
<!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>

+ 8
- 0
resources/theme/html/menu-page.html Целия файл

@@ -0,0 +1,8 @@
<div class="page">
<span class="name">
{name}
</span>
<div class="sub">
{sub}
</div>
</div>

+ 5
- 0
resources/theme/html/menu.html Целия файл

@@ -0,0 +1,5 @@
<header class="menu">
<nav class="menu-nav">
{pages}
</nav>
</header>

+ 92
- 0
src/cms_build.c Целия файл

@@ -0,0 +1,92 @@
#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);
}

+ 9
- 0
src/cms_build.h Целия файл

@@ -0,0 +1,9 @@
#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

+ 67
- 16
src/cms_err.c Целия файл

@@ -1,5 +1,6 @@
#include "cms_err.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>

@@ -7,9 +8,9 @@
#include <error.h>
#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:
return "";
@@ -27,6 +28,8 @@ static char* get_error_message(cms_err err)
return "Not a directory.";
case CMS_ERR_FILEEXISTS:
return "File exists.";
case CMS_ERR_FILEREAD:
return "Failed to read file.";
case CMS_ERR_DIREXISTS:
return "Directory exists.";
case CMS_ERR_PERM:
@@ -38,24 +41,72 @@ static char* get_error_message(cms_err err)
}
}

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)
return;

#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

if (msg == NULL)
if (err->msg == NULL)
fprintf(stderr, "Error: %s\n", get_error_message(err));
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);
}

cms_err cms_err_from_std_err(int err)
cms_err* cms_err_from_std_err(int err)
{
#ifdef DEBUG
error(0, err, "converting to cms_err");
@@ -64,22 +115,22 @@ cms_err cms_err_from_std_err(int err)
switch (err)
{
case EACCES:
return CMS_ERR_PERM;
return cms_err_create(CMS_ERR_PERM, NULL);
case EEXIST:
return CMS_ERR_FILEEXISTS;
return cms_err_create(CMS_ERR_FILEEXISTS, NULL);
case EFAULT:
return CMS_ERR_PERM;
return cms_err_create(CMS_ERR_PERM, NULL);
case EISDIR:
return CMS_ERR_NOTFILE;
return cms_err_create(CMS_ERR_NOTFILE, NULL);
case ENOENT:
return CMS_ERR_NOENT;
return cms_err_create(CMS_ERR_NOENT, NULL);
case ENOMEM:
return CMS_ERR_ALLOC;
return cms_err_create(CMS_ERR_ALLOC, NULL);
case ENOTDIR:
return CMS_ERR_NOTDIR;
return cms_err_create(CMS_ERR_NOTDIR, NULL);
case EROFS:
return CMS_ERR_PERM;
return cms_err_create(CMS_ERR_PERM, NULL);
default:
return CMS_ERR_UNKNOWN;
return cms_err_create(CMS_ERR_UNKNOWN, NULL);
}
}

+ 19
- 5
src/cms_err.h Целия файл

@@ -1,9 +1,9 @@
#ifndef 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_ALLOC,
CMS_ERR_PARSE,
@@ -11,16 +11,30 @@ typedef enum cms_err
CMS_ERR_NOTFILE,
CMS_ERR_NOTDIR,
CMS_ERR_FILEEXISTS,
CMS_ERR_FILEREAD,
CMS_ERR_DIREXISTS,
CMS_ERR_PERM,
CMS_ERR_INITED,
CMS_ERR_NOTINITED
} cms_err_code;

typedef struct cms_err
{
cms_err_code code;
char* msg;
const char* file;
int line;
} 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


+ 7
- 0
src/cms_files.h Целия файл

@@ -7,4 +7,11 @@
//File which tells us if a directory is already initiated.
#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

+ 37
- 28
src/cms_page.c Целия файл

@@ -7,28 +7,33 @@
#include <sys/types.h>
#include <errno.h>

#define PREFIX_LENGTH 5

cms_page* cms_page_create()
{
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;
}

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;

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

//The page's title will be the first line.
page->title = page->_str;

size_t line = 0;
//Replace newlines with \0
for (size_t i = 0; i < len; ++i)
{
char c = str[i];
@@ -36,45 +41,49 @@ cms_err cms_page_parse(cms_page* page, char* str)
switch (c)
{
case '\n':
line += 1;
if (line == 1)
page->slug = (page->_str + i + 1);

case '\r':
page->_str[i] = '\0';
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->posts = realloc(page->posts, page->numposts * sizeof(cms_post));

page->posts = realloc(page->posts, page->numposts * sizeof(cms_post));
if (page->posts == NULL)
return CMS_ERR_ALLOC;
return cms_err_create(CMS_ERR_ALLOC, NULL);

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);
}


+ 6
- 14
src/cms_page.h Целия файл

@@ -1,8 +1,8 @@
#ifndef CMS_PAGE_H
#define CMS_PAGE_H

#include "cms_post.h"
#include "cms_err.h"
#include "cms_post.h"
#include <stddef.h>

typedef struct cms_page
@@ -12,24 +12,16 @@ typedef struct cms_page
char* slug;
cms_post* posts;
size_t numposts;
struct cms_page* subs;
size_t numsubs;
} cms_page;

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

+ 30
- 9
src/cms_post.c Целия файл

@@ -1,22 +1,29 @@
#include "cms_post.h"
#include "cms_err.h"
#include <stdlib.h>
#include <stddef.h>
#include <string.h>

#define PREFIX_LENGTH 5

cms_post* cms_post_create()
{
cms_post* post = malloc(sizeof(cms_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
size_t len = strlen(str) + 1;

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

//The post's title will be the first line.
post->title = post->_str;

size_t line = 0;
@@ -28,22 +35,36 @@ int cms_post_parse(cms_post* post, char* str)
{
case '\n':
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':
post->_str[i] = '\0';
break;
}

if (line == 3)
if (line == 2)
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
return 1;
return cms_err_create(CMS_ERR_PARSE, slugstr);
}

+ 4
- 2
src/cms_post.h Целия файл

@@ -1,16 +1,18 @@
#ifndef CMS_POST_H
#define CMS_POST_H

#include "cms_err.h"

typedef struct cms_post
{
char* _str;
char* title;
char* slug;
char* markdown;
char* html;
} cms_post;

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

+ 51
- 22
src/cms_util.c Целия файл

@@ -1,3 +1,5 @@
#include "cms_util.h"
#include "cms_err.h"
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
@@ -9,8 +11,6 @@
#include <sys/types.h>
#include <errno.h>

#include "cms_util.h"

int cms_util_file_exists(char* fname)
{
int f = open(fname, O_RDONLY);
@@ -26,7 +26,7 @@ int cms_util_file_exists(char* fname)
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);
close(f);
@@ -34,10 +34,10 @@ cms_err cms_util_file_create(char* fname)
if (f == -1)
return cms_err_from_std_err(errno);
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);
if (f1 == -1)
@@ -47,29 +47,54 @@ cms_err cms_util_file_copy(char* fname1, char* fname2)
if (f1 == -1)
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)
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(f2);

free(s);
free(st);
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)
return cms_err_from_std_err(errno);
@@ -82,7 +107,7 @@ cms_err cms_util_dir_copy_recursive(char* dir1, char* dir2)

struct stat* st = malloc(sizeof(struct stat));
if (st == NULL)
return CMS_ERR_ALLOC;
return cms_err_create(CMS_ERR_ALLOC, NULL);

while (ep = readdir(dp))
{
@@ -97,13 +122,17 @@ cms_err cms_util_dir_copy_recursive(char* dir1, char* dir2)

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)
return err;
}
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)
return err;
}
@@ -112,7 +141,7 @@ cms_err cms_util_dir_copy_recursive(char* dir1, char* dir2)
closedir(dp);
free(st);

return CMS_ERR_NONE;
return cms_err_create(CMS_ERR_NONE, NULL);
}

char* cms_util_path_join(char* str1, char* str2)
@@ -125,9 +154,9 @@ char* cms_util_path_join(char* str1, char* str2)
len1 -= 1;
}

char* path = malloc((len1 + len2 + 1) * sizeof(char));
char* path = malloc((len1 + len2 + 2) * sizeof(char));
if (path == NULL)
cms_err_panic(CMS_ERR_ALLOC, "");
cms_err_panic(cms_err_create(CMS_ERR_ALLOC, NULL));

if (path == NULL)
return NULL;

+ 6
- 3
src/cms_util.h Целия файл

@@ -7,13 +7,16 @@
int cms_util_file_exists(char* fname);

//Create a file
cms_err cms_util_file_create(char* fname);
cms_err* cms_util_file_create(char* fname);

//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
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
char* cms_util_path_join(char* str1, char* str2);

+ 33
- 6
src/main.c Целия файл

@@ -1,15 +1,18 @@
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

#include "cms_util.h"
#include "cms_err.h"
#include "cms_files.h"
#include "cms_page.h"
#include "cms_build.h"

int main(int argc, char** argv)
{
if (argc < 2)
{
fprintf(stderr, "Usage: %s <init|deinit|build>\n", argv[0]);
fprintf(stderr, "Usage: %s <init|build>\n", argv[0]);
return 1;
}

@@ -27,21 +30,23 @@ int main(int argc, char** argv)
//Get the path of .cmsinited, which tells us
//whether or not the directory is already 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
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
cms_err err;
cms_err* err;
err = cms_util_dir_copy_recursive(CMS_FILE_RESOURCES, dirname);
if (err)
cms_err_panic(err, dirname);
cms_err_panic(err);

//Create .cmsinited file
err = cms_util_file_create(initedPath);
if (err)
cms_err_panic(err, initedPath);
cms_err_panic(err);
}

//Build
@@ -61,6 +66,28 @@ int main(int argc, char** argv)

//Panic if the directory isn't initiated
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;
}
}

Loading…
Отказ
Запис