Download
jcs
/subtext
/main_menu.c
(View History)
jcs *: Minor cleanups, remove dead variables, fix some error paths | Latest amendment: 580 on 2024-01-24 |
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 "logger.h" |
23 | #include "main_menu.h" |
24 | |
25 | struct main_menu_option *main_menu_options = NULL; |
26 | |
27 | struct main_menu_option * |
28 | main_menu_parse(char *opts, size_t len) |
29 | { |
30 | char *line = NULL, *action = NULL, *menu_key = NULL, *all_keys = NULL, |
31 | *label = NULL; |
32 | size_t n, m, linelen, lastsep, linenum, ret_size; |
33 | short actionid, ret_count; |
34 | struct main_menu_option *ret = NULL; |
35 | |
36 | ret_count = 0; |
37 | ret_size = 0; |
38 | |
39 | #define LINESIZE 1024 |
40 | line = xmalloc(LINESIZE); |
41 | if (line == NULL) |
42 | goto parse_done; |
43 | action = xmalloc(LINESIZE); |
44 | if (action == NULL) |
45 | goto parse_done; |
46 | menu_key = xmalloc(LINESIZE); |
47 | if (menu_key == NULL) |
48 | goto parse_done; |
49 | all_keys = xmalloc(LINESIZE); |
50 | if (all_keys == NULL) |
51 | goto parse_done; |
52 | label = xmalloc(LINESIZE); |
53 | if (label == NULL) |
54 | goto parse_done; |
55 | |
56 | for (n = 0, lastsep = 0, linenum = 0; n <= len; n++) { |
57 | if (!(n == len || opts[n] == '\r')) |
58 | continue; |
59 | |
60 | linenum++; |
61 | linelen = MIN(n - lastsep, LINESIZE - 1); |
62 | if (n == len && linelen) |
63 | linelen--; |
64 | memcpy(line, opts + lastsep, linelen); |
65 | line[linelen] = '\0'; |
66 | lastsep = n + 1; |
67 | |
68 | if (line[0] == '\0' || line[0] == '#' || line[0] == '\r') |
69 | continue; |
70 | |
71 | /* BOARD_SHOW_FIRST:B:Bb:Message Board */ |
72 | |
73 | /* sscanf won't match %[^:] for an empty section ("A::Aa:aa") */ |
74 | action[0] = '\0'; |
75 | for (m = 0; m < linelen; m++) { |
76 | if (line[m] == ':') { |
77 | memcpy(action, line, m); |
78 | action[m] = '\0'; |
79 | linelen -= m + 1; |
80 | memmove(line, line + m + 1, linelen + 1); |
81 | break; |
82 | } |
83 | } |
84 | if (action[0] == '\0') { |
85 | logger_printf("[views] Error parsing main_menu.txt on line " |
86 | "%ld: no action found", linenum); |
87 | ret_count = 0; |
88 | break; |
89 | } |
90 | |
91 | actionid = ACTION_NONE; |
92 | if (strcmp(action, "BOARD_LIST_BOARDS") == 0) |
93 | actionid = ACTION_BOARD_LIST_BOARDS; |
94 | else if (strcmp(action, "BOARD_LIST_FTN_AREAS") == 0) |
95 | actionid = ACTION_BOARD_LIST_FTN_AREAS; |
96 | else if (strcmp(action, "BOARD_SHOW_FIRST") == 0) |
97 | actionid = ACTION_BOARD_SHOW_FIRST; |
98 | else if (strcmp(action, "BOARD_SHOW_1") == 0) |
99 | actionid = ACTION_BOARD_SHOW_1; |
100 | else if (strcmp(action, "BOARD_SHOW_2") == 0) |
101 | actionid = ACTION_BOARD_SHOW_2; |
102 | else if (strcmp(action, "BOARD_SHOW_3") == 0) |
103 | actionid = ACTION_BOARD_SHOW_3; |
104 | else if (strcmp(action, "BOARD_SHOW_4") == 0) |
105 | actionid = ACTION_BOARD_SHOW_4; |
106 | else if (strcmp(action, "BOARD_SHOW_5") == 0) |
107 | actionid = ACTION_BOARD_SHOW_5; |
108 | else if (strcmp(action, "BOARD_SHOW_6") == 0) |
109 | actionid = ACTION_BOARD_SHOW_6; |
110 | else if (strcmp(action, "BOARD_SHOW_7") == 0) |
111 | actionid = ACTION_BOARD_SHOW_7; |
112 | else if (strcmp(action, "BOARD_SHOW_8") == 0) |
113 | actionid = ACTION_BOARD_SHOW_8; |
114 | else if (strcmp(action, "BOARD_SHOW_9") == 0) |
115 | actionid = ACTION_BOARD_SHOW_9; |
116 | else if (strcmp(action, "BOARD_SHOW_10") == 0) |
117 | actionid = ACTION_BOARD_SHOW_10; |
118 | else if (strcmp(action, "CHAT") == 0) |
119 | actionid = ACTION_CHAT; |
120 | else if (strcmp(action, "FILES_MENU") == 0) |
121 | actionid = ACTION_FILES_MENU; |
122 | else if (strcmp(action, "GOODBYE") == 0) |
123 | actionid = ACTION_GOODBYE; |
124 | else if (strcmp(action, "RECENT_LOGINS") == 0) |
125 | actionid = ACTION_RECENT_LOGINS; |
126 | else if (strcmp(action, "MAIL_COMPOSE") == 0) |
127 | actionid = ACTION_MAIL_COMPOSE; |
128 | else if (strcmp(action, "MAIL_MENU") == 0) |
129 | actionid = ACTION_MAIL_MENU; |
130 | else if (strcmp(action, "MOTD") == 0) |
131 | actionid = ACTION_MOTD; |
132 | else if (strcmp(action, "PAGE_SEND_OR_ANSWER") == 0) |
133 | actionid = ACTION_PAGE_SEND_OR_ANSWER; |
134 | else if (strcmp(action, "SETTINGS_OR_SIGNUP") == 0) |
135 | actionid = ACTION_SETTINGS_OR_SIGNUP; |
136 | else if (strcmp(action, "SHOW_MENU") == 0) |
137 | actionid = ACTION_SHOW_MENU; |
138 | else if (strcmp(action, "SYSOP_MENU") == 0) |
139 | actionid = ACTION_SYSOP_MENU; |
140 | else if (strcmp(action, "WHOS_ONLINE") == 0) |
141 | actionid = ACTION_WHOS_ONLINE; |
142 | else { |
143 | logger_printf("[views] Error parsing main_menu.txt on line " |
144 | "%ld: invalid action \"%s\"", linenum, action); |
145 | ret_count = 0; |
146 | break; |
147 | } |
148 | |
149 | menu_key[0] = '\0'; |
150 | for (m = 0; m < linelen; m++) { |
151 | if (line[m] == ':') { |
152 | memcpy(menu_key, line, m); |
153 | menu_key[m] = '\0'; |
154 | linelen -= m + 1; |
155 | memmove(line, line + m + 1, linelen + 1); |
156 | break; |
157 | } |
158 | } |
159 | /* menu_key can be 1 or 0 characters */ |
160 | if (strlen(menu_key) > 1) { |
161 | logger_printf("[views] Error parsing main_menu.txt on line " |
162 | "%ld: Menu Key can only be 1 character", linenum); |
163 | ret_count = 0; |
164 | break; |
165 | } |
166 | |
167 | all_keys[0] = '\0'; |
168 | for (m = 0; m < linelen; m++) { |
169 | if (line[m] == ':') { |
170 | memcpy(all_keys, line, m); |
171 | all_keys[m] = '\0'; |
172 | linelen -= m + 1; |
173 | memmove(line, line + m + 1, linelen + 1); |
174 | break; |
175 | } |
176 | } |
177 | if (all_keys[0] == '\0') { |
178 | logger_printf("[views] Error parsing main_menu.txt on line " |
179 | "%ld: All Keys field cannot be empty", linenum); |
180 | ret_count = 0; |
181 | break; |
182 | } |
183 | |
184 | if (line[0] == '\0') { |
185 | logger_printf("[views] Error parsing main_menu.txt on line " |
186 | "%ld: Label cannot be empty", linenum); |
187 | ret_count = 0; |
188 | break; |
189 | } |
190 | strlcpy(label, line, LINESIZE); |
191 | |
192 | if (!grow_to_fit(&ret, &ret_size, |
193 | sizeof(struct main_menu_option) * ret_count, |
194 | sizeof(struct main_menu_option), 4)) { |
195 | ret_count = 0; |
196 | break; |
197 | } |
198 | |
199 | ret[ret_count].action = actionid; |
200 | ret[ret_count].menu_key = menu_key[0]; |
201 | strlcpy(ret[ret_count].all_keys, all_keys, |
202 | sizeof(ret[ret_count].all_keys)); |
203 | strlcpy(ret[ret_count].label, label, sizeof(ret[ret_count].label)); |
204 | ret_count++; |
205 | } |
206 | |
207 | parse_done: |
208 | if (line) |
209 | xfree(&line); |
210 | if (action) |
211 | xfree(&action); |
212 | if (menu_key) |
213 | xfree(&menu_key); |
214 | if (all_keys) |
215 | xfree(&all_keys); |
216 | if (label) |
217 | xfree(&label); |
218 | |
219 | if (ret_count == 0) { |
220 | if (ret) |
221 | xfree(&ret); |
222 | return NULL; |
223 | } |
224 | |
225 | if (!grow_to_fit(&ret, &ret_size, |
226 | sizeof(struct main_menu_option) * ret_count, |
227 | sizeof(struct main_menu_option), 1)) { |
228 | if (ret) |
229 | xfree(&ret); |
230 | return NULL; |
231 | } |
232 | |
233 | ret[ret_count].action = ACTION_NONE; |
234 | ret[ret_count].menu_key = 0; |
235 | ret[ret_count].all_keys[0] = '\0'; |
236 | ret[ret_count].label[0] = '\0'; |
237 | |
238 | return ret; |
239 | #undef LINESIZE |
240 | } |