AmendHub

Download

jcs

/

subtext

/

main_menu.c

 

(View History)

jcs   board+main_menu: Add ACTION_BOARD_LIST_BOARDS, fix bug in indexing Latest amendment: 464 on 2023-04-06

1 /*
2 * Copyright (c) 2022 joshua stein <jcs@jcs.org>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 #include <stdio.h>
18 #include <string.h>
19
20 #include "subtext.h"
21 #include "db.h"
22 #include "main_menu.h"
23
24 struct main_menu_option *main_menu_options = NULL;
25
26 void
27 main_menu_init(void)
28 {
29 struct main_menu_option *opts = NULL, *old_opts = NULL;
30 size_t size;
31 char *menu = NULL;
32 Handle default_menu;
33
34 size = bile_read_alloc(db->bile, DB_TEXT_TYPE, DB_TEXT_MENU_OPTIONS_ID,
35 &menu);
36 if (size == 0 || menu == NULL) {
37 /* use default menu */
38 if (menu != NULL)
39 xfree(&menu);
40 default_menu = GetResource('TEXT', MENU_DEFAULTS_ID);
41 if (default_menu == NULL)
42 panic("Failed to find TEXT resource %d", MENU_DEFAULTS_ID);
43 size = GetHandleSize(default_menu);
44 menu = xmalloc(size);
45 if (menu == NULL)
46 panic("No memory for main menu");
47 HLock(default_menu);
48 memcpy(menu, *default_menu, size);
49 HUnlock(default_menu);
50 ReleaseResource(default_menu);
51
52 bile_write(db->bile, DB_TEXT_TYPE, DB_TEXT_MENU_OPTIONS_ID,
53 menu, size);
54 }
55
56 opts = main_menu_parse(menu, size);
57 xfree(&menu);
58 if (opts == NULL) {
59 main_menu_edit();
60 return;
61 }
62
63 /* swap this atomically */
64 old_opts = main_menu_options;
65 main_menu_options = opts;
66 if (old_opts != NULL)
67 xfree(&old_opts);
68 }
69
70 void
71 main_menu_edit(void)
72 {
73 view_editor_show(DB_TEXT_MENU_OPTIONS_ID, "Edit: Main Menu options");
74 }
75
76 struct main_menu_option *
77 main_menu_parse(char *opts, size_t len)
78 {
79 char *line, *action, *menu_key, *all_keys, *label;
80 size_t n, m, linelen, lastsep, linenum, ret_size;
81 short actionid, ret_count;
82 struct main_menu_option *ret = NULL;
83
84 ret_count = 0;
85 ret_size = 0;
86
87 #define LINESIZE 1024
88 line = xmalloc(LINESIZE);
89 if (line == NULL)
90 goto parse_done;
91 action = xmalloc(LINESIZE);
92 if (action == NULL)
93 goto parse_done;
94 menu_key = xmalloc(LINESIZE);
95 if (menu_key == NULL)
96 goto parse_done;
97 all_keys = xmalloc(LINESIZE);
98 if (all_keys == NULL)
99 goto parse_done;
100 label = xmalloc(LINESIZE);
101 if (label == NULL)
102 goto parse_done;
103
104 for (n = 0, lastsep = 0, linenum = 0; n <= len; n++) {
105 if (!(n == len || opts[n] == '\r'))
106 continue;
107
108 linenum++;
109 linelen = MIN(n - lastsep, LINESIZE - 1);
110 if (n == len && linelen)
111 linelen--;
112 memcpy(line, opts + lastsep, linelen);
113 line[linelen] = '\0';
114 lastsep = n + 1;
115
116 if (line[0] == '\0' || line[0] == '#' || line[0] == '\r')
117 continue;
118
119 /* BOARD_SHOW_FIRST:B:Bb:Message Board */
120
121 /* sscanf won't match %[^:] for an empty section ("A::Aa:aa") */
122 action[0] = '\0';
123 for (m = 0; m < linelen; m++) {
124 if (line[m] == ':') {
125 memcpy(action, line, m);
126 action[m] = '\0';
127 linelen -= m + 1;
128 memmove(line, line + m + 1, linelen + 1);
129 break;
130 }
131 }
132 if (action[0] == '\0') {
133 warn("Error on line %ld: no action found", linenum);
134 ret_count = 0;
135 break;
136 }
137
138 actionid = ACTION_NONE;
139 if (strcmp(action, "BOARD_LIST_BOARDS") == 0)
140 actionid = ACTION_BOARD_LIST_BOARDS;
141 else if (strcmp(action, "BOARD_LIST_FTN_AREAS") == 0)
142 actionid = ACTION_BOARD_LIST_FTN_AREAS;
143 else if (strcmp(action, "BOARD_SHOW_FIRST") == 0)
144 actionid = ACTION_BOARD_SHOW_FIRST;
145 else if (strcmp(action, "BOARD_SHOW_1") == 0)
146 actionid = ACTION_BOARD_SHOW_1;
147 else if (strcmp(action, "BOARD_SHOW_2") == 0)
148 actionid = ACTION_BOARD_SHOW_2;
149 else if (strcmp(action, "BOARD_SHOW_3") == 0)
150 actionid = ACTION_BOARD_SHOW_3;
151 else if (strcmp(action, "BOARD_SHOW_4") == 0)
152 actionid = ACTION_BOARD_SHOW_4;
153 else if (strcmp(action, "BOARD_SHOW_5") == 0)
154 actionid = ACTION_BOARD_SHOW_5;
155 else if (strcmp(action, "BOARD_SHOW_6") == 0)
156 actionid = ACTION_BOARD_SHOW_6;
157 else if (strcmp(action, "BOARD_SHOW_7") == 0)
158 actionid = ACTION_BOARD_SHOW_7;
159 else if (strcmp(action, "BOARD_SHOW_8") == 0)
160 actionid = ACTION_BOARD_SHOW_8;
161 else if (strcmp(action, "BOARD_SHOW_9") == 0)
162 actionid = ACTION_BOARD_SHOW_9;
163 else if (strcmp(action, "BOARD_SHOW_10") == 0)
164 actionid = ACTION_BOARD_SHOW_10;
165 else if (strcmp(action, "CHAT") == 0)
166 actionid = ACTION_CHAT;
167 else if (strcmp(action, "FILES_MENU") == 0)
168 actionid = ACTION_FILES_MENU;
169 else if (strcmp(action, "GOODBYE") == 0)
170 actionid = ACTION_GOODBYE;
171 else if (strcmp(action, "RECENT_LOGINS") == 0)
172 actionid = ACTION_RECENT_LOGINS;
173 else if (strcmp(action, "MAIL_COMPOSE") == 0)
174 actionid = ACTION_MAIL_COMPOSE;
175 else if (strcmp(action, "MAIL_MENU") == 0)
176 actionid = ACTION_MAIL_MENU;
177 else if (strcmp(action, "MOTD") == 0)
178 actionid = ACTION_MOTD;
179 else if (strcmp(action, "PAGE_SEND_OR_ANSWER") == 0)
180 actionid = ACTION_PAGE_SEND_OR_ANSWER;
181 else if (strcmp(action, "SETTINGS_OR_SIGNUP") == 0)
182 actionid = ACTION_SETTINGS_OR_SIGNUP;
183 else if (strcmp(action, "SHOW_MENU") == 0)
184 actionid = ACTION_SHOW_MENU;
185 else if (strcmp(action, "SYSOP_MENU") == 0)
186 actionid = ACTION_SYSOP_MENU;
187 else if (strcmp(action, "WHOS_ONLINE") == 0)
188 actionid = ACTION_WHOS_ONLINE;
189 else {
190 warn("Error on line %ld: invalid action \"%s\"", linenum,
191 action);
192 ret_count = 0;
193 break;
194 }
195
196 menu_key[0] = '\0';
197 for (m = 0; m < linelen; m++) {
198 if (line[m] == ':') {
199 memcpy(menu_key, line, m);
200 menu_key[m] = '\0';
201 linelen -= m + 1;
202 memmove(line, line + m + 1, linelen + 1);
203 break;
204 }
205 }
206 /* menu_key can be 1 or 0 characters */
207 if (strlen(menu_key) > 1) {
208 warn("Error on line %ld: Menu Key can only be 1 character",
209 linenum);
210 ret_count = 0;
211 break;
212 }
213
214 all_keys[0] = '\0';
215 for (m = 0; m < linelen; m++) {
216 if (line[m] == ':') {
217 memcpy(all_keys, line, m);
218 all_keys[m] = '\0';
219 linelen -= m + 1;
220 memmove(line, line + m + 1, linelen + 1);
221 break;
222 }
223 }
224 if (all_keys[0] == '\0') {
225 warn("Error on line %ld: All Keys field cannot be empty",
226 linenum);
227 ret_count = 0;
228 break;
229 }
230
231 if (line[0] == '\0') {
232 warn("Error on line %ld: Label cannot be empty",
233 linenum);
234 ret_count = 0;
235 break;
236 }
237 strlcpy(label, line, LINESIZE);
238
239 if (!grow_to_fit(&ret, &ret_size,
240 sizeof(struct main_menu_option) * ret_count,
241 sizeof(struct main_menu_option), 4)) {
242 ret_count = 0;
243 break;
244 }
245
246 ret[ret_count].action = actionid;
247 ret[ret_count].menu_key = menu_key[0];
248 strlcpy(ret[ret_count].all_keys, all_keys,
249 sizeof(ret[ret_count].all_keys));
250 strlcpy(ret[ret_count].label, label, sizeof(ret[ret_count].label));
251 ret_count++;
252 }
253
254 parse_done:
255 if (line)
256 xfree(&line);
257 if (action)
258 xfree(&action);
259 if (menu_key)
260 xfree(&menu_key);
261 if (all_keys)
262 xfree(&all_keys);
263 if (label)
264 xfree(&label);
265
266 if (ret_count == 0) {
267 if (ret)
268 xfree(&ret);
269 return NULL;
270 }
271
272 if (!grow_to_fit(&ret, &ret_size,
273 sizeof(struct main_menu_option) * ret_count,
274 sizeof(struct main_menu_option), 1)) {
275 if (ret)
276 xfree(&ret);
277 return NULL;
278 }
279
280 ret[ret_count].action = ACTION_NONE;
281 ret[ret_count].menu_key = 0;
282 ret[ret_count].all_keys[0] = '\0';
283 ret[ret_count].label[0] = '\0';
284
285 return ret;
286 #undef LINESIZE
287 }