Blame


1 7ea8226e 2021-09-06 xhr /*
2 7ea8226e 2021-09-06 xhr * Copyright (c) 2021 Matthias Schmidt <xhr@giessen.ccc.de>
3 7ea8226e 2021-09-06 xhr *
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.
7 7ea8226e 2021-09-06 xhr *
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.
15 7ea8226e 2021-09-06 xhr */
16 7ea8226e 2021-09-06 xhr
17 180e58f6 2021-09-06 xhr #include <sys/stat.h>
18 180e58f6 2021-09-06 xhr #include <sys/types.h>
19 180e58f6 2021-09-06 xhr
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>
28 13a0bc68 2021-08-31 xhr
29 944c5da4 2021-09-01 xhr #include <readline/readline.h>
30 944c5da4 2021-09-01 xhr #include <readline/history.h>
31 944c5da4 2021-09-01 xhr
32 63354cc5 2021-09-01 xhr #include "isscrolls.h"
33 13a0bc68 2021-08-31 xhr
34 e340b5dc 2021-09-09 xhr static char prompt[MAX_PROMPT_LEN];
35 180e58f6 2021-09-06 xhr char isscrolls_dir[_POSIX_PATH_MAX];
36 180e58f6 2021-09-06 xhr
37 726131df 2021-09-01 xhr static int debug = 0;
38 af92ffb1 2021-09-15 xhr static int color = 0;
39 5e7ac800 2021-09-01 xhr
40 40b0885d 2021-09-06 xhr static void
41 40b0885d 2021-09-06 xhr signal_handler(int signal)
42 13a0bc68 2021-08-31 xhr {
43 40b0885d 2021-09-06 xhr switch (signal) {
44 40b0885d 2021-09-06 xhr case SIGINT:
45 40b0885d 2021-09-06 xhr case SIGTERM:
46 40b0885d 2021-09-06 xhr shutdown();
47 40b0885d 2021-09-06 xhr break;
48 40b0885d 2021-09-06 xhr default:
49 40b0885d 2021-09-06 xhr log_errx(1, "Unknown signal");
50 40b0885d 2021-09-06 xhr }
51 13a0bc68 2021-08-31 xhr }
52 13a0bc68 2021-08-31 xhr
53 2ba8efca 2021-09-05 xhr void
54 a844ca20 2021-09-05 xhr show_banner(__attribute__((unused)) char *unused)
55 2ba8efca 2021-09-05 xhr {
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");
70 2ba8efca 2021-09-05 xhr }
71 2ba8efca 2021-09-05 xhr
72 13a0bc68 2021-08-31 xhr int
73 63354cc5 2021-09-01 xhr main(int argc, char **argv)
74 13a0bc68 2021-08-31 xhr {
75 63354cc5 2021-09-01 xhr char *line, *res;
76 726131df 2021-09-01 xhr int ch;
77 13a0bc68 2021-08-31 xhr
78 a20c5f9c 2021-09-02 xhr /*
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
81 a20c5f9c 2021-09-02 xhr */
82 a20c5f9c 2021-09-02 xhr srandom(time(NULL));
83 a20c5f9c 2021-09-02 xhr
84 af92ffb1 2021-09-15 xhr while ((ch = getopt(argc, argv, "cd")) != -1) {
85 726131df 2021-09-01 xhr switch (ch) {
86 af92ffb1 2021-09-15 xhr case 'c':
87 af92ffb1 2021-09-15 xhr color = 1;
88 af92ffb1 2021-09-15 xhr break;
89 726131df 2021-09-01 xhr case 'd':
90 726131df 2021-09-01 xhr debug = 1;
91 726131df 2021-09-01 xhr break;
92 726131df 2021-09-01 xhr }
93 726131df 2021-09-01 xhr }
94 726131df 2021-09-01 xhr
95 726131df 2021-09-01 xhr argc -= optind;
96 726131df 2021-09-01 xhr argv += optind;
97 726131df 2021-09-01 xhr
98 180e58f6 2021-09-06 xhr setup_base_dir();
99 63354cc5 2021-09-01 xhr
100 180e58f6 2021-09-06 xhr initialize_readline(isscrolls_dir);
101 180e58f6 2021-09-06 xhr
102 2ba8efca 2021-09-05 xhr show_banner(NULL);
103 2ba8efca 2021-09-05 xhr
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");
108 40b0885d 2021-09-06 xhr
109 875fbef1 2021-09-06 xhr sandbox(isscrolls_dir);
110 875fbef1 2021-09-06 xhr
111 142b407e 2021-09-07 xhr load_characters_list();
112 ad45eeda 2021-09-07 xhr
113 e952d8d3 2021-09-06 xhr set_prompt("> ");
114 13a0bc68 2021-08-31 xhr while (1) {
115 e952d8d3 2021-09-06 xhr line = readline(prompt);
116 63354cc5 2021-09-01 xhr if (line == NULL)
117 63354cc5 2021-09-01 xhr continue;
118 63354cc5 2021-09-01 xhr res = stripwhite(line);
119 13a0bc68 2021-08-31 xhr
120 63354cc5 2021-09-01 xhr if (*res) {
121 63354cc5 2021-09-01 xhr add_history(res);
122 63354cc5 2021-09-01 xhr execute_command(res);
123 13a0bc68 2021-08-31 xhr }
124 63354cc5 2021-09-01 xhr
125 63354cc5 2021-09-01 xhr free(line);
126 13a0bc68 2021-08-31 xhr }
127 13a0bc68 2021-08-31 xhr
128 40b0885d 2021-09-06 xhr shutdown();
129 40b0885d 2021-09-06 xhr
130 13a0bc68 2021-08-31 xhr return 0;
131 13a0bc68 2021-08-31 xhr }
132 63354cc5 2021-09-01 xhr
133 726131df 2021-09-01 xhr void
134 e952d8d3 2021-09-06 xhr set_prompt(const char *p)
135 e952d8d3 2021-09-06 xhr {
136 e952d8d3 2021-09-06 xhr if (p == NULL || strlen(p) == 0)
137 e952d8d3 2021-09-06 xhr return;
138 e952d8d3 2021-09-06 xhr
139 e952d8d3 2021-09-06 xhr snprintf(prompt, sizeof(prompt), "%s", p);
140 e952d8d3 2021-09-06 xhr }
141 e952d8d3 2021-09-06 xhr
142 e952d8d3 2021-09-06 xhr void
143 875fbef1 2021-09-06 xhr sandbox(const char *dir)
144 875fbef1 2021-09-06 xhr {
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");
152 875fbef1 2021-09-06 xhr
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__ */
156 875fbef1 2021-09-06 xhr }
157 875fbef1 2021-09-06 xhr
158 875fbef1 2021-09-06 xhr void
159 40b0885d 2021-09-06 xhr cmd_quit(__attribute__((unused)) char *unused)
160 40b0885d 2021-09-06 xhr {
161 40b0885d 2021-09-06 xhr shutdown();
162 40b0885d 2021-09-06 xhr }
163 40b0885d 2021-09-06 xhr
164 40b0885d 2021-09-06 xhr void
165 40b0885d 2021-09-06 xhr shutdown()
166 40b0885d 2021-09-06 xhr {
167 40b0885d 2021-09-06 xhr char hist_path[_POSIX_PATH_MAX];
168 40b0885d 2021-09-06 xhr
169 142b407e 2021-09-07 xhr save_current_character();
170 142b407e 2021-09-07 xhr
171 40b0885d 2021-09-06 xhr snprintf(hist_path, _POSIX_PATH_MAX, "%s/history", isscrolls_dir);
172 40b0885d 2021-09-06 xhr
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);
175 40b0885d 2021-09-06 xhr
176 40b0885d 2021-09-06 xhr exit(0);
177 40b0885d 2021-09-06 xhr }
178 40b0885d 2021-09-06 xhr
179 40b0885d 2021-09-06 xhr void
180 180e58f6 2021-09-06 xhr setup_base_dir()
181 180e58f6 2021-09-06 xhr {
182 180e58f6 2021-09-06 xhr struct stat sb;
183 180e58f6 2021-09-06 xhr char *home, *xdg_home;
184 180e58f6 2021-09-06 xhr
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);
189 180e58f6 2021-09-06 xhr } else {
190 180e58f6 2021-09-06 xhr log_errx(1, "Neither $XDG_CONFIG_HOME nor $HOME is set!");
191 180e58f6 2021-09-06 xhr }
192 180e58f6 2021-09-06 xhr
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);
195 180e58f6 2021-09-06 xhr } else {
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);
199 180e58f6 2021-09-06 xhr }
200 180e58f6 2021-09-06 xhr }
201 180e58f6 2021-09-06 xhr }
202 180e58f6 2021-09-06 xhr
203 180e58f6 2021-09-06 xhr void
204 726131df 2021-09-01 xhr log_debug(const char *fmt, ...)
205 726131df 2021-09-01 xhr {
206 726131df 2021-09-01 xhr va_list ap;
207 63354cc5 2021-09-01 xhr
208 726131df 2021-09-01 xhr if (debug == 0)
209 726131df 2021-09-01 xhr return;
210 726131df 2021-09-01 xhr
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);
214 726131df 2021-09-01 xhr va_end(ap);
215 726131df 2021-09-01 xhr }
216 1d916766 2021-09-01 xhr
217 1d916766 2021-09-01 xhr void
218 1d916766 2021-09-01 xhr log_errx(int prio, const char *fmt, ...)
219 1d916766 2021-09-01 xhr {
220 1d916766 2021-09-01 xhr va_list ap;
221 1d916766 2021-09-01 xhr
222 1d916766 2021-09-01 xhr va_start(ap, fmt);
223 1d916766 2021-09-01 xhr vfprintf(stderr, fmt, ap);
224 1d916766 2021-09-01 xhr va_end(ap);
225 1d916766 2021-09-01 xhr
226 64d52bc9 2021-09-16 xhr shutdown();
227 1d916766 2021-09-01 xhr }
228 b49c8139 2021-09-06 xhr
229 af92ffb1 2021-09-15 xhr void
230 af92ffb1 2021-09-15 xhr pm(int what, const char *fmt, ...)
231 af92ffb1 2021-09-15 xhr {
232 af92ffb1 2021-09-15 xhr va_list ap;
233 af92ffb1 2021-09-15 xhr
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) {
237 af92ffb1 2021-09-15 xhr case RED:
238 af92ffb1 2021-09-15 xhr fprintf(stdout, ANSI_COLOR_RED);
239 af92ffb1 2021-09-15 xhr break;
240 af92ffb1 2021-09-15 xhr case YELLOW:
241 af92ffb1 2021-09-15 xhr fprintf(stdout, ANSI_COLOR_YELLOW);
242 af92ffb1 2021-09-15 xhr break;
243 af92ffb1 2021-09-15 xhr case GREEN:
244 af92ffb1 2021-09-15 xhr fprintf(stdout, ANSI_COLOR_GREEN);
245 af92ffb1 2021-09-15 xhr break;
246 af92ffb1 2021-09-15 xhr default:
247 af92ffb1 2021-09-15 xhr break;
248 af92ffb1 2021-09-15 xhr }
249 af92ffb1 2021-09-15 xhr }
250 af92ffb1 2021-09-15 xhr
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);
254 af92ffb1 2021-09-15 xhr va_end(ap);
255 af92ffb1 2021-09-15 xhr }
256 af92ffb1 2021-09-15 xhr
257 b49c8139 2021-09-06 xhr const char*
258 b49c8139 2021-09-06 xhr get_isscrolls_dir()
259 b49c8139 2021-09-06 xhr {
260 b49c8139 2021-09-06 xhr return isscrolls_dir;
261 b49c8139 2021-09-06 xhr }