2 7ea8226e 2021-09-06 xhr * Copyright (c) 2021 Matthias Schmidt <xhr@giessen.ccc.de>
4 7ea8226e 2021-09-06 xhr * Permission to use, copy, modify, and distribute this software for any
5 7ea8226e 2021-09-06 xhr * purpose with or without fee is hereby granted, provided that the above
6 7ea8226e 2021-09-06 xhr * copyright notice and this permission notice appear in all copies.
8 7ea8226e 2021-09-06 xhr * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 7ea8226e 2021-09-06 xhr * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 7ea8226e 2021-09-06 xhr * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 7ea8226e 2021-09-06 xhr * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 7ea8226e 2021-09-06 xhr * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 7ea8226e 2021-09-06 xhr * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 7ea8226e 2021-09-06 xhr * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 180e58f6 2021-09-06 xhr #include <sys/stat.h>
18 180e58f6 2021-09-06 xhr #include <sys/types.h>
20 5e7ac800 2021-09-01 xhr #include <limits.h>
21 40b0885d 2021-09-06 xhr #include <signal.h>
22 726131df 2021-09-01 xhr #include <stdarg.h>
23 13a0bc68 2021-08-31 xhr #include <stdio.h>
24 13a0bc68 2021-08-31 xhr #include <stdlib.h>
25 13a0bc68 2021-08-31 xhr #include <string.h>
26 a20c5f9c 2021-09-02 xhr #include <time.h>
27 726131df 2021-09-01 xhr #include <unistd.h>
29 944c5da4 2021-09-01 xhr #include <readline/readline.h>
30 944c5da4 2021-09-01 xhr #include <readline/history.h>
32 63354cc5 2021-09-01 xhr #include "isscrolls.h"
34 e340b5dc 2021-09-09 xhr static char prompt[MAX_PROMPT_LEN];
35 180e58f6 2021-09-06 xhr char isscrolls_dir[_POSIX_PATH_MAX];
37 726131df 2021-09-01 xhr static int debug = 0;
38 af92ffb1 2021-09-15 xhr static int color = 0;
41 40b0885d 2021-09-06 xhr signal_handler(int signal)
43 40b0885d 2021-09-06 xhr switch (signal) {
45 40b0885d 2021-09-06 xhr case SIGTERM:
49 40b0885d 2021-09-06 xhr log_errx(1, "Unknown signal");
54 a844ca20 2021-09-05 xhr show_banner(__attribute__((unused)) char *unused)
56 4cf6dd8f 2021-09-15 xhr pm(GREEN, "\n██▓ ██████ ██████ ▄████▄ ██▀███ ▒█████ ██▓ ██▓ ██████\n");
57 4cf6dd8f 2021-09-15 xhr pm(GREEN, "▓██▒▒██ ▒ ▒██ ▒ ▒██▀ ▀█ ▓██ ▒ ██▒▒██▒ ██▒▓██▒ ▓██▒ ▒██ ▒\n");
58 4cf6dd8f 2021-09-15 xhr pm(GREEN, "▒██▒░ ▓██▄ ░ ▓██▄ ▒▓█ ▄ ▓██ ░▄█ ▒▒██░ ██▒▒██░ ▒██░ ░ ▓██▄\n");
59 4cf6dd8f 2021-09-15 xhr pm(GREEN, "░██░ ▒ ██▒ ▒ ██▒▒▓▓▄ ▄██▒▒██▀▀█▄ ▒██ ██░▒██░ ▒██░ ▒ ██▒\n");
60 4cf6dd8f 2021-09-15 xhr pm(GREEN, "░██░▒██████▒▒▒██████▒▒▒ ▓███▀ ░░██▓ ▒██▒░ ████▓▒░░██████▒░██████▒▒██████▒▒\n");
61 4cf6dd8f 2021-09-15 xhr pm(GREEN, "░▓ ▒ ▒▓▒ ▒ ░▒ ▒▓▒ ▒ ░░ ░▒ ▒ ░░ ▒▓ ░▒▓░░ ▒░▒░▒░ ░ ▒░▓ ░░ ▒░▓ ░▒ ▒▓▒ ▒ ░\n");
62 4cf6dd8f 2021-09-15 xhr pm(GREEN, " ▒ ░░ ░▒ ░ ░░ ░▒ ░ ░ ░ ▒ ░▒ ░ ▒░ ░ ▒ ▒░ ░ ░ ▒ ░░ ░ ▒ ░░ ░▒ ░ ░\n");
63 4cf6dd8f 2021-09-15 xhr pm(GREEN, " ▒ ░░ ░ ░ ░ ░ ░ ░ ░░ ░ ░ ░ ░ ▒ ░ ░ ░ ░ ░ ░ ░\n");
64 4cf6dd8f 2021-09-15 xhr pm(GREEN, " ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░\n");
65 4cf6dd8f 2021-09-15 xhr pm(GREEN, " ░\n");
66 834b5df8 2021-09-06 xhr printf(" Version %s\n\n", VERSION);
67 834b5df8 2021-09-06 xhr printf("\tSimple player toolkit for the Ironsworn tabletop RPG\n");
68 2ba8efca 2021-09-05 xhr printf("\tBy Matthias Schmidt - https://mastodon.social/@_xhr_\n\n");
69 5b446e52 2021-09-05 xhr printf("Enter 'help' for available commands\n\n");
73 63354cc5 2021-09-01 xhr main(int argc, char **argv)
75 63354cc5 2021-09-01 xhr char *line, *res;
79 8f2dede1 2021-09-02 xhr * Seed the PRNG with the current time of the day. This is not fine
80 8f2dede1 2021-09-02 xhr * for a security critical application, for rolling dice it is
82 a20c5f9c 2021-09-02 xhr srandom(time(NULL));
84 af92ffb1 2021-09-15 xhr while ((ch = getopt(argc, argv, "cd")) != -1) {
85 726131df 2021-09-01 xhr switch (ch) {
95 726131df 2021-09-01 xhr argc -= optind;
96 726131df 2021-09-01 xhr argv += optind;
98 180e58f6 2021-09-06 xhr setup_base_dir();
100 180e58f6 2021-09-06 xhr initialize_readline(isscrolls_dir);
102 2ba8efca 2021-09-05 xhr show_banner(NULL);
104 40b0885d 2021-09-06 xhr if (signal(SIGINT, signal_handler) == SIG_ERR)
105 40b0885d 2021-09-06 xhr log_errx(1, "signal");
106 40b0885d 2021-09-06 xhr if (signal(SIGTERM, signal_handler) == SIG_ERR)
107 40b0885d 2021-09-06 xhr log_errx(1, "signal");
109 875fbef1 2021-09-06 xhr sandbox(isscrolls_dir);
111 142b407e 2021-09-07 xhr load_characters_list();
113 e952d8d3 2021-09-06 xhr set_prompt("> ");
115 e952d8d3 2021-09-06 xhr line = readline(prompt);
116 63354cc5 2021-09-01 xhr if (line == NULL)
118 63354cc5 2021-09-01 xhr res = stripwhite(line);
121 63354cc5 2021-09-01 xhr add_history(res);
122 63354cc5 2021-09-01 xhr execute_command(res);
134 e952d8d3 2021-09-06 xhr set_prompt(const char *p)
136 e952d8d3 2021-09-06 xhr if (p == NULL || strlen(p) == 0)
139 e952d8d3 2021-09-06 xhr snprintf(prompt, sizeof(prompt), "%s", p);
143 875fbef1 2021-09-06 xhr sandbox(const char *dir)
145 875fbef1 2021-09-06 xhr #ifdef __OpenBSD__
146 875fbef1 2021-09-06 xhr if (unveil(_PATH_SHARE_DIR, "r") == -1)
147 875fbef1 2021-09-06 xhr log_errx(1, "unveil");
148 875fbef1 2021-09-06 xhr if (unveil(dir, "rwc") == -1)
149 875fbef1 2021-09-06 xhr log_errx(1, "unveil");
150 875fbef1 2021-09-06 xhr if (unveil(NULL, NULL) == -1)
151 875fbef1 2021-09-06 xhr log_errx(1, "unveil");
153 875fbef1 2021-09-06 xhr if (pledge("stdio rpath wpath cpath tty", NULL) == -1)
154 875fbef1 2021-09-06 xhr log_errx(1, "pledge");
155 875fbef1 2021-09-06 xhr #endif /* __OpenBSD__ */
159 40b0885d 2021-09-06 xhr cmd_quit(__attribute__((unused)) char *unused)
167 40b0885d 2021-09-06 xhr char hist_path[_POSIX_PATH_MAX];
169 142b407e 2021-09-07 xhr save_current_character();
171 40b0885d 2021-09-06 xhr snprintf(hist_path, _POSIX_PATH_MAX, "%s/history", isscrolls_dir);
173 40b0885d 2021-09-06 xhr log_debug("Writing history to %s\n", hist_path);
174 40b0885d 2021-09-06 xhr write_history(hist_path);
180 180e58f6 2021-09-06 xhr setup_base_dir()
182 180e58f6 2021-09-06 xhr struct stat sb;
183 180e58f6 2021-09-06 xhr char *home, *xdg_home;
185 180e58f6 2021-09-06 xhr if ((xdg_home = getenv("XDG_CONFIG_HOME")) != NULL) {
186 0d49d28e 2021-09-06 xhr snprintf(isscrolls_dir, _POSIX_PATH_MAX, "%s/isscrolls", xdg_home);
187 180e58f6 2021-09-06 xhr } else if ((home = getenv("HOME")) != NULL) {
188 0d49d28e 2021-09-06 xhr snprintf(isscrolls_dir, _POSIX_PATH_MAX, "%s/.isscrolls", home);
190 180e58f6 2021-09-06 xhr log_errx(1, "Neither $XDG_CONFIG_HOME nor $HOME is set!");
193 180e58f6 2021-09-06 xhr if (stat(isscrolls_dir, &sb) == 0 && S_ISDIR(sb.st_mode)) {
194 180e58f6 2021-09-06 xhr log_debug("%s already exists\n", isscrolls_dir);
196 180e58f6 2021-09-06 xhr log_debug("%s does not exists. Attempt to create it\n", isscrolls_dir);
197 180e58f6 2021-09-06 xhr if (mkdir(isscrolls_dir, 0755) == -1) {
198 180e58f6 2021-09-06 xhr log_errx(1, "Cannot create %s directory\n", isscrolls_dir);
204 726131df 2021-09-01 xhr log_debug(const char *fmt, ...)
208 726131df 2021-09-01 xhr if (debug == 0)
211 726131df 2021-09-01 xhr va_start(ap, fmt);
212 29ba21d7 2021-09-06 xhr fprintf(stdout, "[*] ");
213 726131df 2021-09-01 xhr vfprintf(stdout, fmt, ap);
218 1d916766 2021-09-01 xhr log_errx(int prio, const char *fmt, ...)
222 1d916766 2021-09-01 xhr va_start(ap, fmt);
223 1d916766 2021-09-01 xhr vfprintf(stderr, fmt, ap);
230 af92ffb1 2021-09-15 xhr pm(int what, const char *fmt, ...)
234 af92ffb1 2021-09-15 xhr va_start(ap, fmt);
235 af92ffb1 2021-09-15 xhr if (color == 1) {
236 af92ffb1 2021-09-15 xhr switch (what) {
238 af92ffb1 2021-09-15 xhr fprintf(stdout, ANSI_COLOR_RED);
240 af92ffb1 2021-09-15 xhr case YELLOW:
241 af92ffb1 2021-09-15 xhr fprintf(stdout, ANSI_COLOR_YELLOW);
244 af92ffb1 2021-09-15 xhr fprintf(stdout, ANSI_COLOR_GREEN);
251 af92ffb1 2021-09-15 xhr vfprintf(stdout, fmt, ap);
252 af92ffb1 2021-09-15 xhr if (color == 1)
253 af92ffb1 2021-09-15 xhr fprintf(stdout, ANSI_COLOR_RESET);
258 b49c8139 2021-09-06 xhr get_isscrolls_dir()
260 b49c8139 2021-09-06 xhr return isscrolls_dir;