Allow executing `run.sh`.
parent
a17d6eb3e3
commit
683bf863ab
4
Makefile
4
Makefile
|
@ -1,4 +1,4 @@
|
||||||
BUILD=clang -Og -g -I include src/*.c main.c -o bootstrap
|
BUILD=clang -Og -g -I include src/*.c main.c -o bootstrap -lm
|
||||||
|
|
||||||
all: build bear
|
all: build bear
|
||||||
|
|
||||||
|
@ -12,6 +12,6 @@ test: test/runner
|
||||||
$^
|
$^
|
||||||
|
|
||||||
test/runner: include/*.h src/*.c test/*.h test/*.c
|
test/runner: include/*.h src/*.c test/*.h test/*.c
|
||||||
clang -I include src/*.c test/*.c -o test/runner
|
clang -I include src/*.c test/*.c -o test/runner -lm
|
||||||
|
|
||||||
.PHONY: test
|
.PHONY: test
|
||||||
|
|
|
@ -5,8 +5,10 @@
|
||||||
#include "validator.h"
|
#include "validator.h"
|
||||||
|
|
||||||
enum SpecEvaluationError {
|
enum SpecEvaluationError {
|
||||||
|
// Then `run.sh` file could not be found.
|
||||||
|
SEE_RUN_SH_NOT_FOUND = 1,
|
||||||
// The provided input does not match the expected prompt response type.
|
// The provided input does not match the expected prompt response type.
|
||||||
SEE_INVALID_PROMPT_RESPONSE = 1
|
SEE_INVALID_PROMPT_RESPONSE,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum SpecEvaluationError evaluate_spec_json(
|
enum SpecEvaluationError evaluate_spec_json(
|
||||||
|
|
|
@ -0,0 +1,96 @@
|
||||||
|
#ifndef _BOOTSTRAP_STRING_BUF_H
|
||||||
|
#define _BOOTSTRAP_STRING_BUF_H
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A dynamic character array.
|
||||||
|
*
|
||||||
|
* A `char*` wrapper. Appending `char`s or NUL-terminated strings allocates
|
||||||
|
* additional space as needed.
|
||||||
|
*/
|
||||||
|
struct StringBuf;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new `StringBuf` instance.
|
||||||
|
*
|
||||||
|
* @param capacity
|
||||||
|
* The initial size of the internal array (including the trailing `NUL`
|
||||||
|
* character). To avoid too many reallocations, aim to make this value large
|
||||||
|
* enough to accommodate the size the string is expected to eventually take.
|
||||||
|
* @return
|
||||||
|
* A new `StringBuf` instance. The caller takes ownership of this value.
|
||||||
|
*
|
||||||
|
* @see string_buf_free
|
||||||
|
*/
|
||||||
|
struct StringBuf *string_buf_new(size_t capacity);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the number of characters contained in the internal buffer.
|
||||||
|
*
|
||||||
|
* @param sb
|
||||||
|
* A valid pointer to a `StringBuf` instance.
|
||||||
|
* @return
|
||||||
|
* The number of characters contained in the internal buffer.
|
||||||
|
*/
|
||||||
|
size_t string_buf_size(struct StringBuf *sb);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the internal `NUL`-terminated string buffer.
|
||||||
|
*
|
||||||
|
* @param sb
|
||||||
|
* A valid pointer to a `StringBuf` instance.
|
||||||
|
* @return
|
||||||
|
* The internally managed string.
|
||||||
|
*/
|
||||||
|
const char *string_buf_value(struct StringBuf *sb);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append a character to the end of a `StringBuf`.
|
||||||
|
*
|
||||||
|
* If appending would cause the internal buffer to overflow, reallocates the
|
||||||
|
* internal array to accommodate.
|
||||||
|
*
|
||||||
|
* @param sb
|
||||||
|
* A valid pointer to a `StringBuf` instance.
|
||||||
|
* @param c
|
||||||
|
* The `char` to append to the end of `sb`.
|
||||||
|
*/
|
||||||
|
void string_buf_cappend(struct StringBuf *sb, char c);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append a `NUL`-terminated string to the end of a `StringBuf`.
|
||||||
|
*
|
||||||
|
* If appending would cause the internal buffer to overflow, `realloc`s are
|
||||||
|
* performed internally to accommodate.
|
||||||
|
*
|
||||||
|
* @param sb
|
||||||
|
* A valid pointer to a `StringBuf` instance.
|
||||||
|
* @param s
|
||||||
|
* The `char*` to append to the end of `sb`.
|
||||||
|
*/
|
||||||
|
void string_buf_sappend(struct StringBuf *sb, const char s[static 1]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a `StringBuf` instance into a `char*`.
|
||||||
|
*
|
||||||
|
* @param sb
|
||||||
|
* A valid pointer to a `StringBuf` instance.
|
||||||
|
* @return
|
||||||
|
* A null pointer if `sb` is null. Otherwise a `NUL`-terminated string
|
||||||
|
* corresponding to the value of `sb`. The caller takes ownership of this
|
||||||
|
* value.
|
||||||
|
*/
|
||||||
|
const char *string_buf_convert(struct StringBuf *sb);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deallocate a previously allocated `StringBuf` instance.
|
||||||
|
*
|
||||||
|
* @param sb
|
||||||
|
* A valid pointer to a `StringBuf` instance.
|
||||||
|
*
|
||||||
|
* @see string_buf_new
|
||||||
|
*/
|
||||||
|
void string_buf_free(struct StringBuf *sb);
|
||||||
|
|
||||||
|
#endif /* _BOOTSTRAP_STRING_BUF_H */
|
10
main.c
10
main.c
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
#include "cJSON.h"
|
#include "cJSON.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "evaluator.h"
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
#include "validator.h"
|
#include "validator.h"
|
||||||
|
|
||||||
|
@ -73,7 +74,14 @@ static int run(const char *root_dir, const char *target) {
|
||||||
goto cleanup_parsed;
|
goto cleanup_parsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Run `run.sh`.
|
switch (evaluate_spec_json(config, prompts)) {
|
||||||
|
case SEE_RUN_SH_NOT_FOUND:
|
||||||
|
fprintf(stderr, "Could not find `%s/run.sh`.\n", target);
|
||||||
|
goto cleanup_parsed;
|
||||||
|
case SEE_INVALID_PROMPT_RESPONSE:
|
||||||
|
fprintf(stderr, "Could not interpret response.\n");
|
||||||
|
goto cleanup_parsed;
|
||||||
|
}
|
||||||
|
|
||||||
retval = EXIT_SUCCESS;
|
retval = EXIT_SUCCESS;
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
cp -r "template/*" "$OUT"
|
cp -r "template" "$OUT"
|
||||||
|
|
|
@ -57,4 +57,5 @@ void config_free(struct Config *config) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
free(config);
|
free(config);
|
||||||
|
config = 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,4 +35,5 @@ void dyn_array_free(struct DynArray *a) {
|
||||||
}
|
}
|
||||||
free(a->buf);
|
free(a->buf);
|
||||||
free(a);
|
free(a);
|
||||||
|
a = 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,36 +2,61 @@
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
#include "path.h"
|
#include "path.h"
|
||||||
|
#include "string_buf.h"
|
||||||
|
|
||||||
static int find_run_sh(const struct Config *const config, FILE **handle) {
|
static enum SpecEvaluationError find_run_sh(const struct Config *const config) {
|
||||||
|
struct stat sb;
|
||||||
const char *segments[] = {config->root_dir, config->target, "run.sh"};
|
const char *segments[] = {config->root_dir, config->target, "run.sh"};
|
||||||
char *filepath =
|
char *filepath =
|
||||||
join_path_segments(sizeof(segments) / sizeof(char *), segments);
|
join_path_segments(sizeof(segments) / sizeof(char *), segments);
|
||||||
|
int stat_res = stat(filepath, &sb);
|
||||||
|
free(filepath);
|
||||||
|
|
||||||
int retval = 0;
|
if (stat_res == -1 && errno == ENOENT) {
|
||||||
// It is ok if the file does not exist. It is not ok if we couldn't open the
|
return SEE_RUN_SH_NOT_FOUND;
|
||||||
// file for any other reason.
|
|
||||||
*handle = fopen(filepath, "r");
|
|
||||||
if (!*handle && errno != ENOENT) {
|
|
||||||
retval = errno;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
free(filepath);
|
return 0;
|
||||||
return retval;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum SpecEvaluationError evaluate_spec_json(
|
enum SpecEvaluationError evaluate_spec_json(
|
||||||
const struct Config *const config, const struct DynArray *const prompts
|
const struct Config *const config, const struct DynArray *const prompts
|
||||||
) {
|
) {
|
||||||
|
enum SpecEvaluationError retval = find_run_sh(config);
|
||||||
|
if (retval != 0) {
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
if (prompts) {
|
if (prompts) {
|
||||||
for (int i = 0; i < prompts->size; ++i) {
|
for (int i = 0; i < prompts->size; ++i) {
|
||||||
}
|
}
|
||||||
// TODO: Display prompts and collect answers.
|
// TODO: Display prompts and collect answers.
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Run `run.sh`.
|
const char *segments[] = {config->root_dir, config->target, "run.sh"};
|
||||||
|
char *filepath =
|
||||||
|
join_path_segments(sizeof(segments) / sizeof(char *), segments);
|
||||||
|
|
||||||
|
struct StringBuf *command_buf = string_buf_new(1024);
|
||||||
|
string_buf_sappend(command_buf, "cd ");
|
||||||
|
string_buf_sappend(command_buf, config->root_dir);
|
||||||
|
string_buf_cappend(command_buf, '/');
|
||||||
|
string_buf_sappend(command_buf, config->target);
|
||||||
|
string_buf_sappend(command_buf, " && ");
|
||||||
|
string_buf_sappend(command_buf, "OUT=");
|
||||||
|
string_buf_sappend(command_buf, config->cwd);
|
||||||
|
string_buf_cappend(command_buf, ' ');
|
||||||
|
string_buf_sappend(command_buf, filepath);
|
||||||
|
const char *command = string_buf_convert(command_buf);
|
||||||
|
|
||||||
|
free(filepath);
|
||||||
|
|
||||||
|
// TODO: Want to return this status out.
|
||||||
|
int status = system(command);
|
||||||
|
;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,84 @@
|
||||||
|
#include "string_buf.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
struct StringBuf {
|
||||||
|
char *buf;
|
||||||
|
// The length of @buf excluding `NUL`.
|
||||||
|
size_t size;
|
||||||
|
// The allocated size of @buf including `NUL`.
|
||||||
|
size_t _capacity;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StringBuf *string_buf_new(size_t capacity) {
|
||||||
|
struct StringBuf *sb = malloc(sizeof(struct StringBuf));
|
||||||
|
sb->buf = calloc(capacity, sizeof(char));
|
||||||
|
sb->size = 0;
|
||||||
|
sb->_capacity = capacity;
|
||||||
|
return sb;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t string_buf_size(struct StringBuf *sb) {
|
||||||
|
assert(sb);
|
||||||
|
|
||||||
|
return sb->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *string_buf_value(struct StringBuf *sb) {
|
||||||
|
assert(sb);
|
||||||
|
|
||||||
|
return sb->buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
void string_buf_cappend(struct StringBuf *sb, char c) {
|
||||||
|
assert(sb);
|
||||||
|
|
||||||
|
if (sb->_capacity) {
|
||||||
|
sb->_capacity *= 2;
|
||||||
|
} else {
|
||||||
|
sb->_capacity = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
sb->buf = realloc((void *)sb->buf, sb->_capacity);
|
||||||
|
sb->buf[sb->size++] = c;
|
||||||
|
sb->buf[sb->size] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void string_buf_sappend(struct StringBuf *sb, const char s[static 1]) {
|
||||||
|
assert(sb);
|
||||||
|
|
||||||
|
double goal = sb->size + strlen(s) + 1;
|
||||||
|
double denom = sb->_capacity ? sb->_capacity : 1;
|
||||||
|
double scale = pow(2, ceil(log2(goal / denom)));
|
||||||
|
|
||||||
|
if (sb->_capacity) {
|
||||||
|
sb->_capacity *= scale;
|
||||||
|
} else {
|
||||||
|
sb->_capacity = scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
sb->buf = realloc((void *)sb->buf, sb->_capacity);
|
||||||
|
for (const char *i = s; *i; ++i) {
|
||||||
|
sb->buf[sb->size++] = *i;
|
||||||
|
}
|
||||||
|
sb->buf[sb->size] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *string_buf_convert(struct StringBuf *sb) {
|
||||||
|
assert(sb);
|
||||||
|
|
||||||
|
const char *buf = sb->buf;
|
||||||
|
free(sb);
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
void string_buf_free(struct StringBuf *sb) {
|
||||||
|
assert(sb);
|
||||||
|
|
||||||
|
free((void *)sb->buf);
|
||||||
|
free(sb);
|
||||||
|
sb = 0;
|
||||||
|
}
|
|
@ -3,6 +3,7 @@
|
||||||
#include "test_dyn_array.h"
|
#include "test_dyn_array.h"
|
||||||
#include "test_parser.h"
|
#include "test_parser.h"
|
||||||
#include "test_path.h"
|
#include "test_path.h"
|
||||||
|
#include "test_string_buf.h"
|
||||||
#include "test_validator.h"
|
#include "test_validator.h"
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
|
@ -18,6 +19,10 @@ int main(int argc, char *argv[]) {
|
||||||
sput_run_test(test_dyn_array_zero_capacity);
|
sput_run_test(test_dyn_array_zero_capacity);
|
||||||
sput_run_test(test_dyn_array_nonzero_capacity);
|
sput_run_test(test_dyn_array_nonzero_capacity);
|
||||||
|
|
||||||
|
sput_enter_suite("string_buf");
|
||||||
|
sput_run_test(test_string_buf_sappend);
|
||||||
|
sput_run_test(test_string_buf_cappend);
|
||||||
|
|
||||||
sput_enter_suite("path");
|
sput_enter_suite("path");
|
||||||
sput_run_test(test_join_path_single_segments);
|
sput_run_test(test_join_path_single_segments);
|
||||||
sput_run_test(test_join_path_multiple_segments);
|
sput_run_test(test_join_path_multiple_segments);
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
#ifndef _BOOTSTRAP_TEST_STRING_BUF
|
||||||
|
#define _BOOTSTRAP_TEST_STRING_BUF
|
||||||
|
|
||||||
|
#include "sput.h"
|
||||||
|
#include "string_buf.h"
|
||||||
|
|
||||||
|
static void test_string_buf_sappend() {
|
||||||
|
struct StringBuf *sb = string_buf_new(0);
|
||||||
|
string_buf_sappend(sb, "hello world");
|
||||||
|
string_buf_sappend(sb, "!!");
|
||||||
|
|
||||||
|
sput_fail_unless(
|
||||||
|
string_buf_size(sb) == strlen("hello world!!"), "sappend size"
|
||||||
|
);
|
||||||
|
const char *converted = string_buf_convert(sb);
|
||||||
|
sput_fail_unless(
|
||||||
|
strcmp(converted, "hello world!!") == 0, "sappend converted"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_string_buf_cappend() {
|
||||||
|
struct StringBuf *sb = string_buf_new(0);
|
||||||
|
string_buf_sappend(sb, "hello world");
|
||||||
|
string_buf_cappend(sb, '!');
|
||||||
|
string_buf_cappend(sb, '!');
|
||||||
|
|
||||||
|
sput_fail_unless(
|
||||||
|
string_buf_size(sb) == strlen("hello world!!"), "cappend size"
|
||||||
|
);
|
||||||
|
const char *converted = string_buf_convert(sb);
|
||||||
|
sput_fail_unless(
|
||||||
|
strcmp(converted, "hello world!!") == 0, "cappend converted"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_string_buf_nonzero_capacity() {
|
||||||
|
struct StringBuf *sb = string_buf_new(100);
|
||||||
|
string_buf_sappend(sb, "hello world");
|
||||||
|
string_buf_cappend(sb, '!');
|
||||||
|
string_buf_free(sb);
|
||||||
|
sput_fail_unless(sb == 0, "free");
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* _BOOTSTRAP_TEST_STRING_BUF */
|
Loading…
Reference in New Issue