Long day .. actually add the new build flavor code.

This commit is contained in:
Joris Vink 2016-01-27 21:32:57 +01:00
parent c5ce707a91
commit b777ea65cd
4 changed files with 457 additions and 139 deletions

View File

@ -3,14 +3,17 @@ This example demonstrates how you can use external libs in your application.
In this case we link against yajl (Yet Another JSON library) in order to
parse a JSON string that was POSTed to the server.
Take a peek at conf/build.conf for different build flavors and how to
link to other libraries.
Run:
```
env LDFLAGS="-lyajl" kore run
$ kore run
```
Test:
```
curl -i -k -d '{"foo":{"bar": "Hello world"}}' https://127.0.0.1:8888
$ curl -i -k -d '{"foo":{"bar": "Hello world"}}' https://127.0.0.1:8888
```
The result should echo back the foo.bar JSON path value: Hello world.

View File

@ -89,7 +89,6 @@ page(struct http_request *req)
/* Release the JSON tree now. */
yajl_tree_free(node);
kore_mem_free(body);
/* Respond to the client. */
http_response(req, 200, buf->data, buf->offset);

View File

@ -6,16 +6,16 @@ before returning to the client.
Build:
```
# env LDFLAGS="-I/path/to/libcurl -lcurl" kore build
$ kore build
```
Run:
```
# kore run
$ kore run
```
Test:
```
# curl -i -k https://127.0.0.1:8888/?user=astring
$ curl -i -k https://127.0.0.1:8888/?user=astring
The returned data must match what you supplied in user ([a-z] string)
```

582
src/cli.c
View File

@ -60,6 +60,15 @@
#define LD_FLAGS_MAX 30
#define CFLAGS_MAX 30
struct buildopt {
char *name;
struct kore_buf *cflags;
struct kore_buf *ldflags;
TAILQ_ENTRY(buildopt) list;
};
TAILQ_HEAD(buildopt_list, buildopt);
struct cmd {
const char *name;
const char *descr;
@ -73,7 +82,6 @@ struct filegen {
struct cfile {
struct stat st;
int build;
int cpp;
char *name;
char *fpath;
char *opath;
@ -83,16 +91,18 @@ struct cfile {
TAILQ_HEAD(cfile_list, cfile);
static void cli_fatal(const char *, ...) __attribute__((noreturn));
static void cli_file_close(int);
static void cli_run_kore(void *);
static void cli_generate_certs(void);
static void cli_link_library(void *);
static void cli_compile_cfile(void *);
static char *cli_trim(char *, size_t);
static void cli_mkdir(const char *, int);
static int cli_dir_exists(const char *);
static int cli_file_exists(const char *);
static void cli_cleanup_files(const char *);
static void cli_build_cflags(struct buildopt *);
static void cli_build_ldflags(struct buildopt *);
static void cli_file_writef(int, const char *, ...);
static void cli_file_open(const char *, int, int *);
static void cli_file_remove(char *, struct dirent *);
@ -107,13 +117,24 @@ static int cli_file_requires_build(struct stat *, const char *);
static void cli_find_files(const char *,
void (*cb)(char *, struct dirent *));
static void cli_add_cfile(char *, char *, char *,
struct stat *, int, int);
struct stat *, int);
static struct buildopt *cli_buildopt_new(const char *);
static struct buildopt *cli_buildopt_find(const char *);
static void cli_buildopt_cleanup(void);
static void cli_buildopt_parse(const char *);
static void cli_buildopt_cflags(struct buildopt *, const char *);
static void cli_buildopt_ldflags(struct buildopt *, const char *);
static void cli_flavor_load(void);
static void cli_flavor_change(const char *);
static void cli_run(int, char **);
static void cli_help(int, char **);
static void cli_build(int, char **);
static void cli_clean(int, char **);
static void cli_create(int, char **);
static void cli_flavor(int, char **);
static void file_create_src(void);
static void file_create_config(void);
@ -125,6 +146,7 @@ static struct cmd cmds[] = {
{ "build", "build an application", cli_build },
{ "clean", "cleanup the build files", cli_clean },
{ "create", "create a new application skeleton", cli_create },
{ "flavor", "switch build flavor", cli_flavor },
{ NULL, NULL, NULL }
};
@ -159,7 +181,7 @@ static const char *src_data =
"}\n";
static const char *config_data =
"# Placeholder configuration\n"
"# %s configuration\n"
"\n"
"bind\t\t127.0.0.1 8888\n"
"load\t\t./%s.so\n"
@ -175,6 +197,26 @@ static const char *config_data =
"\tstatic\t/\tpage\n"
"}\n";
static const char *build_data =
"# %s build config\n"
"# You can switch flavors using: kore flavor [newflavor]\n"
"\n"
"# The cflags below are shared between flavors\n"
"cflags=-Wall -Wmissing-declarations -Wshadow\n"
"cflags=-Wstrict-prototypes -Wmissing-prototypes\n"
"cflags=-Wpointer-arith -Wcast-qual -Wsign-compare\n"
"\n"
"dev {\n"
" # These cflags are added to the shared ones when\n"
" # you build the \"dev\" flavor.\n"
" cflags=-g\n"
"}\n"
"\n"
"#prod {\n"
"# You can specify additional CFLAGS here which are only\n"
"# included if you build with the \"prod\" flavor.\n"
"#}\n";
#if !defined(KORE_NO_TLS)
static const char *dh2048_data =
"-----BEGIN DH PARAMETERS-----\n"
@ -187,15 +229,22 @@ static const char *dh2048_data =
"-----END DH PARAMETERS-----";
#endif
static const char *gitignore_data = "*.o\n.objs\n%s.so\nassets.h\ncert\n";
static const char *gitignore = "*.o\n.flavor\n.objs\n%s.so\nassets.h\ncert\n";
static int s_fd = -1;
static int verbose = 0;
static char *appl = NULL;
static char *rootdir = NULL;
static char *compiler = "gcc";
static struct cfile_list source_files;
static struct buildopt_list build_options;
static int cfiles_count;
static struct cmd *command = NULL;
static int cflags_count = 0;
static int ldflags_count = 0;
static char *flavor = NULL;
static char *cflags[CFLAGS_MAX];
static char *ldflags[LD_FLAGS_MAX];
void
kore_cli_usage(int local)
@ -229,6 +278,9 @@ kore_cli_main(int argc, char **argv)
(void)umask(S_IWGRP|S_IWOTH);
if ((flavor = strchr(argv[0], ':')) != NULL)
*(flavor)++ = '\0';
for (i = 0; cmds[i].name != NULL; i++) {
if (!strcmp(argv[0], cmds[i].name)) {
argc--;
@ -285,40 +337,96 @@ cli_create(int argc, char **argv)
}
static void
cli_build(int argc, char **argv)
cli_flavor(int argc, char **argv)
{
struct cfile *cf;
struct timeval times[2];
int requires_relink;
char pwd[PATH_MAX], *src_path, *assets_header;
char *assets_path, *p, *obj_path, *cpath, *config;
struct buildopt *bopt;
char pwd[MAXPATHLEN], *conf;
if (getcwd(pwd, sizeof(pwd)) == NULL)
cli_fatal("could not get cwd: %s", errno_s);
appl = basename(pwd);
(void)cli_vasprintf(&conf, "conf/%s.conf", appl);
if (!cli_dir_exists("conf") || !cli_file_exists(conf))
cli_fatal("%s doesn't appear to be a kore app", appl);
free(conf);
TAILQ_INIT(&build_options);
(void)cli_buildopt_new("_default");
cli_buildopt_parse("conf/build.conf");
if (argc == 0) {
if (getcwd(pwd, sizeof(pwd)) == NULL)
cli_fatal("could not get cwd: %s", errno_s);
rootdir = ".";
appl = basename(pwd);
cli_flavor_load();
TAILQ_FOREACH(bopt, &build_options, list) {
if (!strcmp(bopt->name, "_default"))
continue;
if (!strcmp(bopt->name, flavor)) {
printf("* %s\n", bopt->name);
} else {
printf(" %s\n", bopt->name);
}
}
} else {
appl = argv[0];
rootdir = appl;
cli_flavor_change(argv[0]);
printf("changed build flavor to: %s\n", argv[0]);
}
cli_buildopt_cleanup();
}
static void
cli_build(int argc, char **argv)
{
struct cfile *cf;
struct buildopt *bopt;
struct timeval times[2];
char *build_path;
int requires_relink, l;
char *sofile, *config, *data;
char *assets_path, *p, *obj_path, *cpath;
char pwd[PATH_MAX], *src_path, *assets_header;
if (argc == 1 && !strcmp(argv[0], "-v"))
verbose = 1;
if (getcwd(pwd, sizeof(pwd)) == NULL)
cli_fatal("could not get cwd: %s", errno_s);
rootdir = ".";
appl = basename(pwd);
if ((p = getenv("CC")) != NULL)
compiler = p;
cfiles_count = 0;
TAILQ_INIT(&source_files);
TAILQ_INIT(&build_options);
(void)cli_vasprintf(&src_path, "%s/src", rootdir);
(void)cli_vasprintf(&assets_path, "%s/assets", rootdir);
(void)cli_vasprintf(&config, "%s/conf/%s.conf", rootdir, appl);
(void)cli_vasprintf(&assets_header, "%s/src/assets.h", rootdir);
(void)cli_vasprintf(&build_path, "%s/conf/build.conf", rootdir);
if (!cli_dir_exists(src_path) || !cli_file_exists(config))
cli_fatal("%s doesn't appear to be a kore app", appl);
free(config);
cli_flavor_load();
bopt = cli_buildopt_new("_default");
if (!cli_file_exists(build_path)) {
l = cli_vasprintf(&data, build_data, appl);
cli_file_create("conf/build.conf", data, l);
free(data);
}
cli_buildopt_parse(build_path);
free(build_path);
printf("building %s (%s)\n", appl, flavor);
cli_build_cflags(bopt);
cli_build_ldflags(bopt);
(void)cli_vasprintf(&obj_path, "%s/.objs", rootdir);
if (!cli_dir_exists(obj_path))
cli_mkdir(obj_path, 0755);
@ -342,10 +450,9 @@ cli_build(int argc, char **argv)
/* Build all source files. */
cli_find_files(src_path, cli_register_cfile);
free(src_path);
requires_relink = 0;
requires_relink = 0;
TAILQ_FOREACH(cf, &source_files, list) {
if (cf->build == 0)
continue;
@ -373,12 +480,18 @@ cli_build(int argc, char **argv)
}
free(cpath);
(void)cli_vasprintf(&sofile, "%s.so", appl);
if (!cli_file_exists(sofile))
requires_relink++;
free(sofile);
if (requires_relink) {
cli_spawn_proc(cli_link_library, NULL);
printf("%s built successfully!\n", appl);
} else {
printf("nothing to be done\n");
printf("nothing to be done!\n");
}
cli_buildopt_cleanup();
}
static void
@ -432,11 +545,14 @@ file_create_config(void)
char *name, *data;
(void)cli_vasprintf(&name, "conf/%s.conf", appl);
l = cli_vasprintf(&data, config_data, appl);
l = cli_vasprintf(&data, config_data, appl, appl);
cli_file_create(name, data, l);
free(name);
free(data);
l = cli_vasprintf(&data, build_data, appl);
cli_file_create("conf/build.conf", data, l);
free(data);
}
static void
@ -445,7 +561,7 @@ file_create_gitignore(void)
int l;
char *data;
l = cli_vasprintf(&data, gitignore_data, appl);
l = cli_vasprintf(&data, gitignore, appl);
cli_file_create(".gitignore", data, l);
free(data);
}
@ -617,7 +733,7 @@ cli_build_asset(char *fpath, struct dirent *dp)
cli_write_asset(name, ext);
*ext = '_';
cli_add_cfile(name, cpath, opath, &st, 0, 0);
cli_add_cfile(name, cpath, opath, &st, 0);
kore_mem_free(name);
return;
}
@ -676,13 +792,13 @@ cli_build_asset(char *fpath, struct dirent *dp)
*--ext = '.';
/* Register the .c file now (cpath is free'd later). */
cli_add_cfile(name, cpath, opath, &st, 1, 0);
cli_add_cfile(name, cpath, opath, &st, 1);
kore_mem_free(name);
}
static void
cli_add_cfile(char *name, char *fpath, char *opath, struct stat *st,
int build, int cpp)
int build)
{
struct cfile *cf;
@ -691,7 +807,6 @@ cli_add_cfile(char *name, char *fpath, char *opath, struct stat *st,
cf->st = *st;
cf->build = build;
cf->cpp = cpp;
cf->fpath = fpath;
cf->opath = opath;
cf->name = kore_strdup(name);
@ -704,27 +819,21 @@ cli_register_cfile(char *fpath, struct dirent *dp)
{
struct stat st;
char *ext, *opath;
int cpp;
if ((ext = strrchr(fpath, '.')) == NULL ||
(strcmp(ext, ".c") && strcmp(ext, ".cpp")))
return;
if (!strcmp(ext, ".cpp"))
cpp = 1;
else
cpp = 0;
if (stat(fpath, &st) == -1)
cli_fatal("stat(%s): %s", fpath, errno_s);
(void)cli_vasprintf(&opath, "%s/.objs/%s.o", rootdir, dp->d_name);
if (!cli_file_requires_build(&st, opath)) {
cli_add_cfile(dp->d_name, fpath, opath, &st, 0, cpp);
cli_add_cfile(dp->d_name, fpath, opath, &st, 0);
return;
}
cli_add_cfile(dp->d_name, fpath, opath, &st, 1, cpp);
cli_add_cfile(dp->d_name, fpath, opath, &st, 1);
}
static void
@ -876,75 +985,15 @@ cli_generate_certs(void)
static void
cli_compile_cfile(void *arg)
{
int idx, f, i;
int idx, i;
struct cfile *cf = arg;
char *flags[CFLAGS_MAX], *p;
char *args[32 + CFLAGS_MAX], *ipath[2], *cppstandard;
#if defined(KORE_USE_PGSQL)
char *ppath;
#endif
(void)cli_vasprintf(&ipath[0], "-I%s/src", rootdir);
(void)cli_vasprintf(&ipath[1], "-I%s/src/includes", rootdir);
char *args[32 + CFLAGS_MAX];
idx = 0;
args[idx++] = compiler;
args[idx++] = ipath[0];
args[idx++] = ipath[1];
#if defined(PREFIX)
(void)cli_vasprintf(&args[idx++], "-I%s/include", PREFIX);
#else
args[idx++] = "-I/usr/local/include";
#endif
#if defined(__MACH__)
/* Add default openssl include path from homebrew / ports under OSX. */
args[idx++] = "-I/opt/local/include";
args[idx++] = "-I/usr/local/opt/openssl/include";
#endif
/* Add any user specified flags. */
if ((p = getenv("CFLAGS")) != NULL)
f = kore_split_string(p, " ", flags, CFLAGS_MAX);
else
f = 0;
for (i = 0; i < f; i++)
args[idx++] = flags[i];
#if defined(KORE_USE_PGSQL)
(void)cli_vasprintf(&ppath, "-I%s", PGSQL_INCLUDE_PATH);
args[idx++] = ppath;
#endif
#if defined(KORE_NO_HTTP)
args[idx++] = "-DKORE_NO_HTTP";
#endif
#if defined(KORE_NO_TLS)
args[idx++] = "-DKORE_NO_TLS";
#endif
args[idx++] = "-Wall";
args[idx++] = "-Wmissing-declarations";
args[idx++] = "-Wshadow";
args[idx++] = "-Wpointer-arith";
args[idx++] = "-Wcast-qual";
args[idx++] = "-Wsign-compare";
args[idx++] = "-fPIC";
args[idx++] = "-g";
if (cf->cpp) {
args[idx++] = "-Woverloaded-virtual";
args[idx++] = "-Wold-style-cast";
args[idx++] = "-Wnon-virtual-dtor";
if ((p = getenv("CXXSTD")) != NULL) {
(void)cli_vasprintf(&cppstandard, "-std=%s", p);
args[idx++] = cppstandard;
}
} else {
args[idx++] = "-Wstrict-prototypes";
args[idx++] = "-Wmissing-prototypes";
}
for (i = 0; i < cflags_count; i++)
args[idx++] = cflags[i];
args[idx++] = "-c";
args[idx++] = cf->fpath;
@ -959,47 +1008,20 @@ static void
cli_link_library(void *arg)
{
struct cfile *cf;
int idx, f, i, has_cpp;
int idx, i;
char *libname;
char *args[cfiles_count + 11 + LD_FLAGS_MAX];
char *p, *libname, *flags[LD_FLAGS_MAX], *cpplib;
if ((p = getenv("LDFLAGS")) != NULL)
f = kore_split_string(p, " ", flags, LD_FLAGS_MAX);
else
f = 0;
(void)cli_vasprintf(&libname, "%s/%s.so", rootdir, appl);
idx = 0;
args[idx++] = compiler;
#if defined(__MACH__)
args[idx++] = "-dynamiclib";
args[idx++] = "-undefined";
args[idx++] = "suppress";
args[idx++] = "-flat_namespace";
#else
args[idx++] = "-shared";
#endif
has_cpp = 0;
TAILQ_FOREACH(cf, &source_files, list) {
if (cf->cpp)
has_cpp = 1;
TAILQ_FOREACH(cf, &source_files, list)
args[idx++] = cf->opath;
}
if (has_cpp) {
if ((p = getenv("CXXLIB")) != NULL) {
(void)cli_vasprintf(&cpplib, "-l%s", p);
args[idx++] = cpplib;
} else {
args[idx++] = "-lstdc++";
}
}
for (i = 0; i < f; i++)
args[idx++] = flags[i];
for (i = 0; i < ldflags_count; i++)
args[idx++] = ldflags[i];
args[idx++] = "-o";
args[idx++] = libname;
@ -1023,6 +1045,285 @@ cli_run_kore(void *arg)
execvp("kore", args);
}
static void
cli_buildopt_parse(const char *path)
{
FILE *fp;
struct buildopt *bopt;
char buf[BUFSIZ], *p, *t, *s;
if ((fp = fopen(path, "r")) == NULL)
cli_fatal("cli_buildopt_parse: fopen(%s): %s", path, errno_s);
bopt = NULL;
while (fgets(buf, sizeof(buf), fp) != NULL) {
p = buf;
buf[strcspn(buf, "\n")] = '\0';
while (isspace(*p))
p++;
if (p[0] == '#' || p[0] == '\0')
continue;
for (t = p; *t != '\0'; t++) {
if (*t == '\t')
*t = ' ';
}
if (bopt != NULL && !strcmp(p, "}")) {
bopt = NULL;
continue;
}
if (bopt == NULL) {
if ((t = strchr(p, '=')) != NULL)
goto parse_option;
if ((t = strchr(p, ' ')) == NULL)
cli_fatal("unexpected '%s'", p);
*(t)++ = '\0';
if (strcmp(t, "{"))
cli_fatal("expected '{', got '%s'", t);
bopt = cli_buildopt_new(p);
continue;
}
if ((t = strchr(p, '=')) == NULL) {
printf("bad buildopt line: '%s'\n", p);
continue;
}
parse_option:
*(t)++ = '\0';
cli_trim(p, strlen(p));
cli_trim(t, strlen(t));
while (isspace(*p))
p++;
s = p + strlen(p) - 1;
while (isspace(*s))
*(s)-- = '\0';
while (isspace(*t))
t++;
s = t + strlen(t) - 1;
while (isspace(*s))
*(s)-- = '\0';
if (!strcasecmp(p, "cflags")) {
cli_buildopt_cflags(bopt, t);
} else if (!strcasecmp(p, "ldflags")) {
cli_buildopt_ldflags(bopt, t);
} else {
printf("ignoring unknown option %s\n", p);
}
}
}
static struct buildopt *
cli_buildopt_new(const char *name)
{
struct buildopt *bopt;
bopt = kore_malloc(sizeof(*bopt));
bopt->cflags = NULL;
bopt->ldflags = NULL;
bopt->name = kore_strdup(name);
TAILQ_INSERT_TAIL(&build_options, bopt, list);
return (bopt);
}
static struct buildopt *
cli_buildopt_find(const char *name)
{
struct buildopt *bopt;
TAILQ_FOREACH(bopt, &build_options, list) {
if (!strcmp(bopt->name, name))
return (bopt);
}
return (NULL);
}
static void
cli_buildopt_cleanup(void)
{
struct buildopt *bopt, *next;
for (bopt = TAILQ_FIRST(&build_options); bopt != NULL; bopt = next) {
next = TAILQ_NEXT(bopt, list);
TAILQ_REMOVE(&build_options, bopt, list);
if (bopt->cflags != NULL)
kore_buf_free(bopt->cflags);
if (bopt->ldflags != NULL)
kore_buf_free(bopt->ldflags);
kore_mem_free(bopt);
}
}
static void
cli_buildopt_cflags(struct buildopt *bopt, const char *string)
{
if (bopt == NULL) {
if ((bopt = cli_buildopt_find("_default")) == NULL)
cli_fatal("no _default build options");
}
if (bopt->cflags == NULL)
bopt->cflags = kore_buf_create(128);
kore_buf_appendf(bopt->cflags, "%s ", string);
}
static void
cli_buildopt_ldflags(struct buildopt *bopt, const char *string)
{
if (bopt == NULL) {
if ((bopt = cli_buildopt_find("_default")) == NULL)
cli_fatal("no _default build options");
}
if (bopt->ldflags == NULL)
bopt->ldflags = kore_buf_create(128);
kore_buf_appendf(bopt->ldflags, "%s ", string);
}
static void
cli_build_cflags(struct buildopt *bopt)
{
struct buildopt *obopt;
char *string;
if ((obopt = cli_buildopt_find(flavor)) == NULL)
cli_fatal("no such build flavor: %s", flavor);
if (bopt->cflags == NULL)
bopt->cflags = kore_buf_create(128);
kore_buf_appendf(bopt->cflags,
"-fPIC -I%s/src -I%s/src/includes ", rootdir, rootdir);
#if defined(PREFIX)
kore_buf_appendf(bopt->cflags, "-I%s/include ", PREFIX);
#else
kore_buf_appendf(bopt->cflags, "-I/usr/local/include ");
#endif
#if defined(__MACH__)
/* Add default openssl include path from homebrew / ports under OSX. */
kore_buf_appendf(bopt->cflags, "-I/opt/local/include ");
kore_buf_appendf(bopt->cflags, "-I/usr/local/opt/openssl/include ");
#endif
#if defined(KORE_USE_PGSQL)
kore_buf_appendf(bopt->cflags, "-I%s ", PGSQL_INCLUDE_PATH);
#endif
#if defined(KORE_NO_HTTP)
kore_buf_appendf(bopt->cflags, "-DKORE_NO_HTTP ");
#endif
#if defined(KORE_NO_TLS)
kore_buf_appendf(bopt->cflags, "-DKORE_NO_TLS ");
#endif
if (obopt != NULL && obopt->cflags != NULL) {
kore_buf_append(bopt->cflags, obopt->cflags->data,
obopt->cflags->offset);
}
string = kore_buf_stringify(bopt->cflags);
if (verbose)
printf("CFLAGS=%s\n", string);
cflags_count = kore_split_string(string, " ", cflags, CFLAGS_MAX);
}
static void
cli_build_ldflags(struct buildopt *bopt)
{
struct buildopt *obopt;
char *string;
if ((obopt = cli_buildopt_find(flavor)) == NULL)
cli_fatal("no such build flavor: %s", flavor);
if (bopt->ldflags == NULL)
bopt->ldflags = kore_buf_create(128);
#if defined(__MACH__)
kore_buf_appendf(bopt->ldflags,
"-dynamiclib -undefined suppress -flat_namespace ");
#else
kore_buf_appendf(bopt->ldflags, "-shared ");
#endif
if (obopt != NULL && obopt->ldflags != NULL) {
kore_buf_append(bopt->ldflags, obopt->ldflags->data,
obopt->ldflags->offset);
}
string = kore_buf_stringify(bopt->ldflags);
if (verbose)
printf("LDFLAGS=%s\n", string);
ldflags_count = kore_split_string(string, " ", ldflags, LD_FLAGS_MAX);
}
static void
cli_flavor_load(void)
{
FILE *fp;
char buf[BUFSIZ], pwd[MAXPATHLEN], *p, *conf;
if (getcwd(pwd, sizeof(pwd)) == NULL)
cli_fatal("could not get cwd: %s", errno_s);
appl = basename(pwd);
(void)cli_vasprintf(&conf, "conf/%s.conf", appl);
if (!cli_dir_exists("conf") || !cli_file_exists(conf))
cli_fatal("%s doesn't appear to be a kore app", appl);
free(conf);
if ((fp = fopen(".flavor", "r")) == NULL) {
flavor = kore_strdup("dev");
return;
}
if (fgets(buf, sizeof(buf), fp) == NULL)
cli_fatal("failed to read flavor from file");
if ((p = strchr(buf, '\n')) != NULL)
*p = '\0';
flavor = kore_strdup(buf);
(void)fclose(fp);
}
static void
cli_flavor_change(const char *name)
{
FILE *fp;
int ret;
struct buildopt *bopt;
if ((bopt = cli_buildopt_find(name)) == NULL)
cli_fatal("no such flavor: %s", name);
if ((fp = fopen(".flavor.tmp", "w")) == NULL)
cli_fatal("failed to open temporary file to save flavor");
ret = fprintf(fp, "%s\n", name);
if (ret == -1 || (size_t)ret != (strlen(name) + 1))
cli_fatal("failed to write new build flavor");
(void)fclose(fp);
if (rename(".flavor.tmp", ".flavor") == -1)
cli_fatal("failed to replace build flavor");
cli_clean(0, NULL);
}
static void
cli_spawn_proc(void (*cb)(void *), void *arg)
{
@ -1074,6 +1375,21 @@ cli_cleanup_files(const char *spath)
printf("couldn't rmdir %s\n", spath);
}
static char *
cli_trim(char *string, size_t len)
{
char *end;
end = string + strlen(string) - 1;
while (isspace(*string))
string++;
while (isspace(*end) && end > string)
*(end)-- = '\0';
return (string);
}
static void
cli_fatal(const char *fmt, ...)
{