commit 8c77114c013b2aed0883d3fe36a9e601b55522df Author: Florian Stinglmayr Date: Sun Aug 25 15:11:36 2019 +0200 begin work on a d20 framework diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..f7c54fb --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,12 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 3.2) + +# Submodules might need pkg-config so include it here +FIND_PACKAGE(PkgConfig) + +ADD_DEFINITIONS("-Wall -Werror -D_GNU_SOURCE") + +SET(LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib/d20") +ADD_DEFINITIONS("-DD20_LIB_DIR=\"${LIB_DIR}\"") + +ADD_SUBDIRECTORY(d20) +ADD_SUBDIRECTORY(dice) diff --git a/d20/CMakeLists.txt b/d20/CMakeLists.txt new file mode 100644 index 0000000..1ad3d3e --- /dev/null +++ b/d20/CMakeLists.txt @@ -0,0 +1,9 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 3.2) + +SET(TARGET "d20") +SET(SOURCES + "src/d20.c" + ) + +ADD_EXECUTABLE(${TARGET} ${SOURCES}) +INSTALL(TARGETS ${TARGET} DESTINATION bin) diff --git a/d20/src/d20.c b/d20/src/d20.c new file mode 100644 index 0000000..21c1bfa --- /dev/null +++ b/d20/src/d20.c @@ -0,0 +1,67 @@ +#include +#include +#include +#include +#include + +#include +#include + +#ifndef D20_LIB_DIR +#define D20_LIB_DIR "/usr/lib/d20" +#endif + +static void usage(void) +{ + puts("d20 [command] [parameters]"); +} + +int main(int ac, char **av) +{ + char const *command = NULL; + char *file = NULL; + char **args = NULL; + struct stat s; + int i = 0, ret = 0; + + if (ac <= 1) { + usage(); + exit(0); + } + + if (av[1][0] == '-') { + /* parameter given, assume default command `dice` + */ + command = "dice"; + } else { + command = av[1]; + ++av; + --ac; + } + + asprintf(&file, "%s/d20-%s", D20_LIB_DIR, command); + + if (stat(file, &s) != 0) { + fprintf(stderr, "failed to run command: %s\n", strerror(errno)); + exit(3); + } + + args = calloc(ac + 1, sizeof(char*)); + if (args == NULL) { + exit(3); + } + + asprintf(&args[0], "d20-%s", command); + for (i = 1; i < ac; i++) { + args[i] = strdup(av[i]); + } + + ret = execv(file, args); + if (WIFEXITED(ret) && WEXITSTATUS(ret) != 0) { + return WEXITSTATUS(ret); + } else if (!WIFEXITED(ret)) { + return 127; + } + + return 0; +} diff --git a/dice/CMakeLists.txt b/dice/CMakeLists.txt new file mode 100644 index 0000000..3bb70c4 --- /dev/null +++ b/dice/CMakeLists.txt @@ -0,0 +1,15 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 3.2) + +SET(TARGET "d20-dice") +SET(SOURCE + "src/dice.c" + ) + +PKG_CHECK_MODULES(DICE REQUIRED libdice) + +INCLUDE_DIRECTORIES(${DICE_INCLUDE_DIRS}) + +ADD_EXECUTABLE(${TARGET} ${SOURCE}) +TARGET_LINK_LIBRARIES(${TARGET} ${DICE_LIBRARIES}) + +INSTALL(TARGETS ${TARGET} DESTINATION ${LIB_DIR}) diff --git a/dice/src/dice.c b/dice/src/dice.c new file mode 100644 index 0000000..9a1994f --- /dev/null +++ b/dice/src/dice.c @@ -0,0 +1,104 @@ +#include +#include +#include +#include + +#include + +#include + +static bool evaluate_expression(char const *s) +{ + dice_expression_t e = dice_expression_new(); + int error = 0; + int64_t result = 0; + bool ret = false; + + if (e == NULL) { + fprintf(stderr, "oom\n"); + goto error; + } + + if (!dice_expression_parse(e, s, &error)) { + fprintf(stderr, "failed to parse expression `%s` around column %d\n", + s, error + ); + goto error; + } + + if (!dice_expression_roll(e, &result)) { + fprintf(stderr, "failed to evaluate expression `%s`", s); + goto error; + } + + printf("%ld\n", result); + + ret = true; + +error: + + dice_expression_free(e); + return ret; +} + +int main(int ac, char **av) +{ + static char const *optstr = "e:"; + static struct option opts[] = { + { "expression", required_argument, NULL, 'e' }, + { NULL, 0, NULL, 0} + }; + + int c = 0, i = 0; + FILE *f = NULL; + char *buf = NULL; + size_t buflen = 0; + bool ret = false; + + while ((c = getopt_long(ac, av, optstr, opts, NULL)) != -1) { + switch (c) { + case 'e': + { + if (!evaluate_expression(optarg)) { + exit(3); + } + } break; + + default: + { + fprintf(stderr, "invalid option specified\n"); + exit(3); + } break; + + } + } + + /* parse remainderes + */ + if (optind < ac) { + f = open_memstream(&buf, &buflen); + if (f == NULL) { + exit(3); + } + + for (i = optind; i < ac; i++) { + fprintf(f, "%s", av[i]); + if (i < ac) { + fputc(' ', f); + } + } + + fclose(f); + + ret = evaluate_expression(buf); + free(buf); + buf = NULL; + buflen = 0; + + if (!ret) { + exit(3); + } + } + + return 0; +}