Blob


1 /*
2 * Most of this file is copied from the official GNU readline
3 * documentation: https://tiswww.case.edu/php/chet/readline/readline.html
4 *
5 * The documenation was written by
6 * Lionel Cons <Lionel.Cons@cern.ch> (original author)
7 * Karl Berry <karl@freefriends.org>
8 * Olaf Bachmann <obachman@mathematik.uni-kl.de>
9 * and many others.
10 *
11 * LICENSE: GNU GPL v2
12 */
14 #include <ctype.h>
15 #include <limits.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
20 #include <readline/readline.h>
21 #include <readline/history.h>
23 #include "isscrolls.h"
25 static struct command commands[] = {
26 { "cd", cmd_cd, "Switch to or from a character", 0 },
27 { "help", cmd_usage, "Show help", 0 },
28 { "ls", cmd_ls, "List all characters", 0 },
29 { "quit", cmd_quit, "Quit the program", 0 },
30 { "q", cmd_quit, "Quit the program", 1 },
31 { "--- DICE ROLLS ---", NULL, "", 0 },
32 { "action", cmd_roll_action_dice, "Perform an action roll", 0 },
33 { "challenge", cmd_roll_challenge_die, "Roll a challenge die", 0 },
34 { "oracle", cmd_roll_oracle_die, "Roll two challenge dice as oracle", 0 },
35 { "yesorno", cmd_yes_or_no, "Roll oracle to answer a yes/no question", 0 },
36 { "actionoracle", cmd_show_action, "Show a random action oracle", 0 },
37 { "--- CHARACTER COMMANDS ---", NULL, "", 0 },
38 { "create", cmd_create_character, "Create a new character", 0 },
39 { "delete", cmd_delete_character, "Delete currently loaded character", 0 },
40 { "print", cmd_print_current_character, "Print current character sheet", 0 },
41 { "decrease", cmd_decrease_value, "Decrease a character's value", 0 },
42 { "increase", cmd_increase_value, "Increase a character's value", 0 },
43 { "toggle", cmd_toogle, "Toggle character's stats", 0 },
44 { "--- GAME MOVES ---", NULL, "", 0 },
45 { "battle", cmd_battle, "Roll a 'battle' move", 0 },
46 { "clash", cmd_clash, "Roll a 'clash' move", 0 },
47 { "compel", cmd_compel, "Roll a 'compel' move", 0 },
48 { "drawthecircle", cmd_draw_the_circle, "Roll a 'draw the circle' move", 0 },
49 { "enterthefray", cmd_enter_the_fray, "Roll a 'enter the fray' move", 0 },
50 { "facedanger", cmd_face_danger, "Roll a 'face danger' move", 0 },
51 { "forgeabond", cmd_forge_a_bond, "Roll a 'forge a bond' move", 0 },
52 { "gatherinformation", cmd_gather_information, "Roll a 'gather information' move", 0 },
53 { "makecamp", cmd_make_camp, "Roll a 'make camp' move", 0 },
54 { "heal", cmd_heal, "Roll a 'heal' move", 0 },
55 { "resupply", cmd_resupply, "Roll a 'resupply' move", 0 },
56 { "sojourn", cmd_sojourn, "Roll a 'sojourn' move", 0 },
57 { "strike", cmd_strike, "Roll a 'strike' move", 0 },
58 { "endthefight", cmd_end_the_fight, "Roll a 'end the fight' move", 0 },
59 { "swearanironvow", cmd_swear_an_iron_vow, "Roll a 'swear an iron vow' move", 0 },
60 { "undertakeajourney", cmd_undertake_a_journey, "Roll a 'undertake a journey' move", 0 },
61 { "reachyourdestination", cmd_reach_your_destination, "Roll a 'reach your destination' move", 0 },
62 { "secureanadvantage", cmd_secure_an_advantage, "Roll a 'secure an advantage' move", 0 },
63 { "testyourbond", cmd_test_your_bond, "Roll a 'test your bond' move", 0 },
64 { "endureharm", cmd_endure_harm, "Roll a 'endure harm' move", 0 },
65 { "endurestress", cmd_endure_stress, "Roll a 'endure stress' move", 0 },
66 { "facedeath", cmd_face_death, "Roll a 'face death' move", 0 },
67 { "--- ORACLE TABLE ROLLS ---", NULL, "", 0 },
68 { "coastalwaterlocation", cmd_show_coastal_location, "Show a random coastal water location", 0 },
69 { "combataction", cmd_show_combat_action, "Show a random combat action move", 0 },
70 { "elfname", cmd_show_elf_name, "Show a random Elf name", 0 },
71 { "giantname", cmd_show_giant_name, "Show a random Giant name", 0 },
72 { "ironlandername", cmd_show_iron_name, "Show a random Ironlander name", 0 },
73 { "location", cmd_show_location, "Show a random location", 0 },
74 { "locationdescription", cmd_show_location_description, "Show a random location description", 0 },
75 { "mysticbackslash", cmd_show_mystic_backshlash, "Show a random mystic backlash", 0 },
76 { "paytheprice", cmd_show_pay_the_price, "Show a random pay the price result", 0 },
77 { "plottwist", cmd_show_plot_twist, "Show a random major plot twist", 0 },
78 { "rank", cmd_show_rank, "Show a random challenge rank", 0 },
79 { "region", cmd_show_region, "Show a random region", 0 },
80 { "theme", cmd_show_theme, "Show a random theme oracle", 0 },
81 { "trollname", cmd_show_troll_name, "Show a random Troll name", 0 },
82 { "varouname", cmd_show_varou_name, "Show a random Varou name", 0 },
83 { (char *)NULL, NULL, (char *)NULL, 0 }
84 };
86 void
87 cmd_usage(__attribute__((unused)) char *unused)
88 {
89 int i;
91 printf("%-20s %s\n", "COMMAND", "DESCRIPTION");
92 for (i=0; commands[i].doc; i++)
93 if (commands[i].alias == 0)
94 printf("%-20s %s\n", commands[i].name, commands[i].doc);
95 else
96 printf("%-20s\n", commands[i].name);
98 printf("\nFor more detailed information check the man page: $ man isscrolls\n");
99 }
101 char *
102 stripwhite (char *string)
104 register char *s, *t;
106 for (s = string; isspace (*s); s++)
109 if (*s == 0)
110 return (s);
112 t = s + strlen (s) - 1;
113 while (t > s && isspace (*t))
114 t--;
116 *++t = '\0';
118 return s;
121 struct command *
122 find_command(char *line)
124 int i;
126 for (i=0; commands[i].name; i++) {
127 /* Skip over --- which is a separator for the cmd_usage() */
128 if (strncasecmp(line, "---", 3) == 0)
129 continue;
130 if (strcasecmp(line, commands[i].name) == 0)
131 return &commands[i];
134 return NULL;
137 void
138 initialize_readline(const char *base_path)
140 char hist_path[_POSIX_PATH_MAX];
142 rl_readline_name = "issrolls";
144 rl_attempted_completion_function = my_completion;
146 using_history();
148 snprintf(hist_path, _POSIX_PATH_MAX, "%s/history", base_path);
150 log_debug("Reading history from %s\n", hist_path);
151 read_history(hist_path);
154 char **
155 my_completion(const char *text, int start, int end)
157 char **matches;
159 matches = (char **)NULL;
161 if (start == 0)
162 matches = rl_completion_matches(text, command_generator);
164 return matches;
167 char *
168 command_generator(const char *text, int state)
170 const char *name;
171 static int list_index, len;
173 if (!state) {
174 list_index = 0;
175 len = strlen(text);
178 while ((name = commands[list_index].name)) {
179 list_index++;
180 if (strncmp(name, text, len) == 0) {
181 return strdup(name);
185 return (char *)NULL;
188 void
189 execute_command(char *line)
191 struct command *cmd;
192 char *word;
193 int i = 0;
195 /* Skip over white spaces */
196 while (line[i] && isspace(line[i]))
197 i++;
199 /* Set to char array after last whitespace */
200 word = line + i;
202 /* Skip over all non-isspace characters */
203 while (line[i] && !isspace(line[i]))
204 i++;
206 /* If line, is still valid, NUL terminate command word */
207 if (line[i])
208 line[i++] = '\0';
210 cmd = find_command(word);
212 if (cmd == NULL) {
213 printf("Command not found\n");
214 return;
217 /* Skip over white spaces after command line */
218 while (isspace(line[i]))
219 i++;
221 word = line + i;
223 ((*(cmd->cmd)) (word));
224 return;