/[LeafOK_CVS]/lbbs/src/menu.c
ViewVC logotype

Contents of /lbbs/src/menu.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.29 - (show annotations)
Mon May 5 14:27:57 2025 UTC (10 months, 1 week ago) by sysadm
Branch: MAIN
Changes since 1.28: +22 -22 lines
Content type: text/x-csrc
Refine for strict GCC error check

1 /***************************************************************************
2 menu.c - description
3 -------------------
4 begin : Wed Mar 16 2004
5 copyright : (C) 2005 by Leaflet
6 email : leaflet@leafok.com
7 ***************************************************************************/
8
9 /***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
18 #include "bbs.h"
19 #include "bbs_cmd.h"
20 #include "user_priv.h"
21 #include "reg_ex.h"
22 #include "bbs_cmd.h"
23 #include "menu.h"
24 #include "log.h"
25 #include "io.h"
26 #include "screen.h"
27 #include "common.h"
28 #include <string.h>
29 #include <stdio.h>
30 #include <ctype.h>
31 #include <regex.h>
32 #include <stdlib.h>
33
34 #define MENU_TEMP_DIR "var"
35
36 MENU_SET bbs_menu;
37
38 int load_menu(MENU_SET *p_menu_set, const char *conf_file)
39 {
40 FILE *fin, *fout;
41 int i = 0, j;
42 char buffer[LINE_BUFFER_LEN];
43 char screen_filename[FILE_PATH_LEN];
44 char temp[LINE_BUFFER_LEN];
45 regmatch_t pmatch[10];
46
47 if ((fin = fopen(conf_file, "r")) == NULL)
48 {
49 log_error("Open %s failed", conf_file);
50 return -1;
51 }
52
53 strncpy(p_menu_set->conf_file, conf_file, sizeof(p_menu_set->conf_file) - 1);
54 p_menu_set->conf_file[sizeof(p_menu_set->conf_file) - 1] = '\0';
55
56 while (fgets(buffer, sizeof(buffer), fin))
57 {
58 switch (buffer[0])
59 {
60 case '#':
61 break;
62 case '%':
63 if (ireg("^%S_([A-Za-z0-9_]+)", buffer, 2, pmatch) == 0)
64 {
65 strncpy(temp, buffer + pmatch[1].rm_so,
66 (size_t)(pmatch[1].rm_eo - pmatch[1].rm_so));
67 temp[pmatch[1].rm_eo - pmatch[1].rm_so] = '\0';
68 snprintf(screen_filename, sizeof(screen_filename), "%s/MENU_SCR_%s", MENU_TEMP_DIR, temp);
69
70 if ((fout = fopen(screen_filename, "w")) == NULL)
71 {
72 log_error("Open %s failed", screen_filename);
73 return -2;
74 }
75
76 while (fgets(buffer, sizeof(buffer), fin))
77 {
78 if (buffer[0] != '%')
79 fputs(buffer, fout);
80 else
81 break;
82 }
83
84 fclose(fout);
85 break;
86 }
87
88 if (ireg("^%menu ([A-Za-z0-9_]+)", buffer, 2, pmatch) == 0)
89 {
90 p_menu_set->p_menu[i] = malloc(sizeof(MENU));
91 p_menu_set->p_menu[i]->title.show = 0;
92 p_menu_set->p_menu[i]->screen.show = 0;
93
94 strncpy(p_menu_set->p_menu[i]->name,
95 buffer + pmatch[1].rm_so,
96 (size_t)(pmatch[1].rm_eo - pmatch[1].rm_so));
97 p_menu_set->p_menu[i]->name[pmatch[1].rm_eo - pmatch[1].rm_so] =
98 '\0';
99
100 j = 0;
101
102 while (fgets(buffer, sizeof(buffer), fin))
103 {
104 if (buffer[0] == '#')
105 {
106 continue;
107 }
108 if (buffer[0] == '%')
109 {
110 p_menu_set->p_menu[i]->item_count = j;
111 p_menu_set->p_menu[i]->item_cur_pos = 0;
112 i++;
113 break;
114 }
115 if (ireg("^!([A-Za-z0-9_.]+)[[:space:]]*([0-9]+),"
116 "[[:space:]]*([0-9]+),[[:space:]]*([0-9]+),"
117 "[[:space:]]*([0-9]+),[[:space:]]*\"([^\"]+)\","
118 "[[:space:]]*\"([^\"]+)\"",
119 buffer, 8, pmatch) == 0)
120 {
121 p_menu_set->p_menu[i]->items[j] =
122 malloc(sizeof(MENU_ITEM));
123 p_menu_set->p_menu[i]->items[j]->submenu = 1;
124 strncpy(p_menu_set->p_menu[i]->items[j]->action,
125 buffer + pmatch[1].rm_so,
126 (size_t)(pmatch[1].rm_eo - pmatch[1].rm_so));
127 p_menu_set->p_menu[i]->items[j]->action[pmatch[1].rm_eo -
128 pmatch[1].rm_so] = '\0';
129 strncpy(temp, buffer + pmatch[2].rm_so,
130 (size_t)(pmatch[2].rm_eo - pmatch[2].rm_so));
131 temp[pmatch[2].rm_eo - pmatch[2].rm_so] = '\0';
132 p_menu_set->p_menu[i]->items[j]->row = atoi(temp);
133 strncpy(temp,
134 buffer + pmatch[3].rm_so,
135 (size_t)(pmatch[3].rm_eo - pmatch[3].rm_so));
136 temp[pmatch[3].rm_eo - pmatch[3].rm_so] = '\0';
137 p_menu_set->p_menu[i]->items[j]->col = atoi(temp);
138 strncpy(temp,
139 buffer + pmatch[4].rm_so,
140 (size_t)(pmatch[4].rm_eo - pmatch[4].rm_so));
141 temp[pmatch[4].rm_eo - pmatch[4].rm_so] = '\0';
142 p_menu_set->p_menu[i]->items[j]->priv = atoi(temp);
143 strncpy(temp,
144 buffer + pmatch[5].rm_so,
145 (size_t)(pmatch[5].rm_eo - pmatch[5].rm_so));
146 temp[pmatch[5].rm_eo - pmatch[5].rm_so] = '\0';
147 p_menu_set->p_menu[i]->items[j]->level = atoi(temp);
148 strncpy(p_menu_set->p_menu[i]->items[j]->name,
149 buffer + pmatch[6].rm_so,
150 (size_t)(pmatch[6].rm_eo - pmatch[6].rm_so));
151 p_menu_set->p_menu[i]->items[j]->name[pmatch[6].rm_eo -
152 pmatch[6].rm_so] =
153 '\0';
154 strncpy(p_menu_set->p_menu[i]->items[j]->text,
155 buffer + pmatch[7].rm_so,
156 (size_t)(pmatch[7].rm_eo - pmatch[7].rm_so));
157 p_menu_set->p_menu[i]->items[j]->text[pmatch[7].rm_eo -
158 pmatch[7].rm_so] =
159 '\0';
160 j++;
161 continue;
162 }
163 if (ireg("^@([A-Za-z0-9_]+)[[:space:]]*([0-9]+),"
164 "[[:space:]]*([0-9]+),[[:space:]]*([0-9]+),"
165 "[[:space:]]*([0-9]+),[[:space:]]*\"([^\"]+)\","
166 "[[:space:]]*\"([^\"]+)\"",
167 buffer, 8, pmatch) == 0)
168 {
169 p_menu_set->p_menu[i]->items[j] =
170 malloc(sizeof(MENU_ITEM));
171 p_menu_set->p_menu[i]->items[j]->submenu = 0;
172 strncpy(p_menu_set->p_menu[i]->items[j]->action,
173 buffer + pmatch[1].rm_so,
174 (size_t)(pmatch[1].rm_eo - pmatch[1].rm_so));
175 p_menu_set->p_menu[i]->items[j]->action[pmatch[1].rm_eo -
176 pmatch[1].rm_so] = '\0';
177 strncpy(temp, buffer + pmatch[2].rm_so,
178 (size_t)(pmatch[2].rm_eo - pmatch[2].rm_so));
179 temp[pmatch[2].rm_eo - pmatch[2].rm_so] = '\0';
180 p_menu_set->p_menu[i]->items[j]->row = atoi(temp);
181 strncpy(temp,
182 buffer + pmatch[3].rm_so,
183 (size_t)(pmatch[3].rm_eo - pmatch[3].rm_so));
184 temp[pmatch[3].rm_eo - pmatch[3].rm_so] = '\0';
185 p_menu_set->p_menu[i]->items[j]->col = atoi(temp);
186 strncpy(temp,
187 buffer + pmatch[4].rm_so,
188 (size_t)(pmatch[4].rm_eo - pmatch[4].rm_so));
189 temp[pmatch[4].rm_eo - pmatch[4].rm_so] = '\0';
190 p_menu_set->p_menu[i]->items[j]->priv = atoi(temp);
191 strncpy(temp,
192 buffer + pmatch[5].rm_so,
193 (size_t)(pmatch[5].rm_eo - pmatch[5].rm_so));
194 temp[pmatch[5].rm_eo - pmatch[5].rm_so] = '\0';
195 p_menu_set->p_menu[i]->items[j]->level = atoi(temp);
196 strncpy(p_menu_set->p_menu[i]->items[j]->name,
197 buffer + pmatch[6].rm_so,
198 (size_t)(pmatch[6].rm_eo - pmatch[6].rm_so));
199 p_menu_set->p_menu[i]->items[j]->name[pmatch[6].rm_eo -
200 pmatch[6].rm_so] =
201 '\0';
202 strncpy(p_menu_set->p_menu[i]->items[j]->text,
203 buffer + pmatch[7].rm_so,
204 (size_t)(pmatch[7].rm_eo - pmatch[7].rm_so));
205 p_menu_set->p_menu[i]->items[j]->text[pmatch[7].rm_eo -
206 pmatch[7].rm_so] =
207 '\0';
208 j++;
209 continue;
210 }
211 if (ireg("^title[[:space:]]*([0-9]+),"
212 "[[:space:]]*([0-9]+),[[:space:]]*\"([^\"]+)\"",
213 buffer, 4, pmatch) == 0)
214 {
215 p_menu_set->p_menu[i]->title.show = 1;
216 strncpy(temp,
217 buffer + pmatch[1].rm_so,
218 (size_t)(pmatch[1].rm_eo - pmatch[1].rm_so));
219 temp[pmatch[1].rm_eo - pmatch[1].rm_so] = '\0';
220 p_menu_set->p_menu[i]->title.row = atoi(temp);
221 strncpy(temp,
222 buffer + pmatch[2].rm_so,
223 (size_t)(pmatch[2].rm_eo - pmatch[2].rm_so));
224 temp[pmatch[2].rm_eo - pmatch[2].rm_so] = '\0';
225 p_menu_set->p_menu[i]->title.col = atoi(temp);
226 strncpy(p_menu_set->p_menu[i]->title.text,
227 buffer + pmatch[3].rm_so,
228 (size_t)(pmatch[3].rm_eo - pmatch[3].rm_so));
229 p_menu_set->p_menu[i]->title.text[pmatch[3].rm_eo -
230 pmatch[3].rm_so] =
231 '\0';
232 continue;
233 }
234 if (ireg("^screen[[:space:]]*([0-9]+),"
235 "[[:space:]]*([0-9]+),[[:space:]]*S_([A-Za-z0-9_]+)",
236 buffer, 4, pmatch) == 0)
237 {
238 p_menu_set->p_menu[i]->screen.show = 1;
239 strncpy(temp,
240 buffer + pmatch[1].rm_so,
241 (size_t)(pmatch[1].rm_eo - pmatch[1].rm_so));
242 temp[pmatch[1].rm_eo - pmatch[1].rm_so] = '\0';
243 p_menu_set->p_menu[i]->screen.row = atoi(temp);
244 strncpy(temp,
245 buffer + pmatch[2].rm_so,
246 (size_t)(pmatch[2].rm_eo - pmatch[2].rm_so));
247 temp[pmatch[2].rm_eo - pmatch[2].rm_so] = '\0';
248 p_menu_set->p_menu[i]->screen.col = atoi(temp);
249 strncpy(temp,
250 buffer + pmatch[3].rm_so,
251 (size_t)(pmatch[3].rm_eo - pmatch[3].rm_so));
252 temp[pmatch[3].rm_eo - pmatch[3].rm_so] = '\0';
253 snprintf(p_menu_set->p_menu[i]->screen.filename,
254 sizeof(p_menu_set->p_menu[i]->screen.filename),
255 "%s/MENU_SCR_%s", MENU_TEMP_DIR, temp);
256 continue;
257 }
258 }
259 }
260 break;
261 }
262 }
263 fclose(fin);
264
265 p_menu_set->menu_count = i;
266 p_menu_set->menu_select_depth = 0;
267 p_menu_set->p_menu_select[p_menu_set->menu_select_depth] = (i == 0 ? NULL : p_menu_set->p_menu[0]);
268
269 return 0;
270 }
271
272 MENU *
273 get_menu(MENU_SET *p_menu_set, const char *menu_name)
274 {
275 int i;
276
277 for (i = 0; i < p_menu_set->menu_count; i++)
278 {
279 if (strcmp(p_menu_set->p_menu[i]->name, menu_name) == 0)
280 {
281 return p_menu_set->p_menu[i];
282 }
283 }
284
285 return NULL;
286 }
287
288 static void display_menu_cursor(MENU *p_menu, int show)
289 {
290 moveto((p_menu->items[p_menu->item_cur_pos])->r_row,
291 (p_menu->items[p_menu->item_cur_pos])->r_col - 2);
292 outc(show ? '>' : ' ');
293 iflush();
294 }
295
296 int display_menu(MENU *p_menu)
297 {
298 int row = 0;
299 int col = 0;
300 int menu_selectable = 0;
301
302 if (p_menu == NULL)
303 {
304 return -1;
305 }
306
307 if (p_menu->title.show)
308 {
309 show_top(p_menu->title.text);
310 }
311
312 if (p_menu->screen.show)
313 {
314 moveto(p_menu->screen.row, p_menu->screen.col);
315 if (display_file(p_menu->screen.filename) != 0)
316 {
317 log_error("Display menu screen <%s> failed!\n",
318 p_menu->screen.filename);
319 }
320 }
321
322 for (int i = 0; i < p_menu->item_count; i++)
323 {
324 if (p_menu->items[i]->row != 0)
325 {
326 row = p_menu->items[i]->row;
327 }
328 if (p_menu->items[i]->col != 0)
329 {
330 col = p_menu->items[i]->col;
331 }
332
333 if (checkpriv(&BBS_priv, 0, p_menu->items[i]->priv) == 0 || checklevel(&BBS_priv, p_menu->items[i]->level) == 0)
334 {
335 p_menu->items[i]->display = 0;
336 p_menu->items[i]->r_row = 0;
337 p_menu->items[i]->r_col = 0;
338 }
339 else
340 {
341 p_menu->items[i]->display = 1;
342
343 if (!menu_selectable)
344 {
345 p_menu->item_cur_pos = i;
346 menu_selectable = 1;
347 }
348
349 p_menu->items[i]->r_row = row;
350 p_menu->items[i]->r_col = col;
351
352 moveto(row, col);
353 prints("%s", p_menu->items[i]->text);
354
355 row++;
356 }
357 }
358
359 if (!menu_selectable)
360 {
361 return -1;
362 }
363
364 display_menu_cursor(p_menu, 1);
365
366 return 0;
367 }
368
369 int display_current_menu(MENU_SET *p_menu_set)
370 {
371 MENU *p_menu;
372
373 p_menu = p_menu_set->p_menu_select[p_menu_set->menu_select_depth];
374
375 return display_menu(p_menu);
376 }
377
378 int menu_control(MENU_SET *p_menu_set, int key)
379 {
380 int i;
381 MENU *p_menu;
382
383 if (p_menu_set->menu_count == 0)
384 {
385 return 0;
386 }
387
388 p_menu = p_menu_set->p_menu_select[p_menu_set->menu_select_depth];
389
390 switch (key)
391 {
392 case CR:
393 igetch(1); // Cleanup remaining '\n' in the buffer
394 case KEY_RIGHT:
395 if (p_menu->items[p_menu->item_cur_pos]->submenu)
396 {
397 if (strcmp(p_menu->items[p_menu->item_cur_pos]->action, "..") == 0)
398 {
399 return menu_control(p_menu_set, KEY_LEFT);
400 }
401 p_menu_set->menu_select_depth++;
402 p_menu = get_menu(p_menu_set, p_menu->items[p_menu->item_cur_pos]->action);
403 p_menu_set->p_menu_select[p_menu_set->menu_select_depth] = p_menu;
404
405 if (display_menu(p_menu) != 0)
406 {
407 return menu_control(p_menu_set, KEY_LEFT);
408 }
409 break;
410 }
411 else
412 {
413 return (exec_cmd(p_menu->items[p_menu->item_cur_pos]->action,
414 p_menu->items[p_menu->item_cur_pos]->name));
415 }
416 case KEY_LEFT:
417 if (p_menu_set->menu_select_depth > 0)
418 {
419 p_menu_set->menu_select_depth--;
420 if (display_current_menu(p_menu_set) != 0)
421 {
422 return menu_control(p_menu_set, KEY_LEFT);
423 }
424 break;
425 }
426 else
427 {
428 display_menu_cursor(p_menu, 0);
429 p_menu->item_cur_pos = p_menu->item_count - 1;
430 while (!p_menu->items[p_menu->item_cur_pos]->display ||
431 p_menu->items[p_menu->item_cur_pos]->priv != 0 ||
432 p_menu->items[p_menu->item_cur_pos]->level != 0)
433 {
434 p_menu->item_cur_pos--;
435 }
436 display_menu_cursor(p_menu, 1);
437 break;
438 }
439 case KEY_UP:
440 display_menu_cursor(p_menu, 0);
441 do
442 {
443 p_menu->item_cur_pos--;
444 if (p_menu->item_cur_pos < 0)
445 {
446 p_menu->item_cur_pos = p_menu->item_count - 1;
447 }
448 } while (!p_menu->items[p_menu->item_cur_pos]->display);
449 display_menu_cursor(p_menu, 1);
450 break;
451 case KEY_DOWN:
452 display_menu_cursor(p_menu, 0);
453 do
454 {
455 p_menu->item_cur_pos++;
456 if (p_menu->item_cur_pos >= p_menu->item_count)
457 {
458 p_menu->item_cur_pos = 0;
459 }
460 } while (!p_menu->items[p_menu->item_cur_pos]->display);
461 display_menu_cursor(p_menu, 1);
462 break;
463 default:
464 for (i = 0; i < p_menu->item_count; i++)
465 {
466 if (key == p_menu->items[i]->name[0] &&
467 p_menu->items[i]->display)
468 {
469 display_menu_cursor(p_menu, 0);
470 p_menu->item_cur_pos = i;
471 display_menu_cursor(p_menu, 1);
472 return 0;
473 }
474 }
475 if (isalpha(key))
476 {
477 for (i = 0; i < p_menu->item_count; i++)
478 {
479 if (toupper(key) == toupper(p_menu->items[i]->name[0]) &&
480 p_menu->items[i]->display)
481 {
482 display_menu_cursor(p_menu, 0);
483 p_menu->item_cur_pos = i;
484 display_menu_cursor(p_menu, 1);
485 return 0;
486 }
487 }
488 }
489 }
490
491 return 0;
492 }
493
494 void unload_menu(MENU_SET *p_menu_set)
495 {
496 MENU *p_menu;
497 int i, j;
498
499 for (i = 0; i < p_menu_set->menu_count; i++)
500 {
501 p_menu = p_menu_set->p_menu[i];
502 for (j = 0; j < p_menu->item_count; j++)
503 {
504 free(p_menu->items[j]);
505 }
506 remove(p_menu->screen.filename);
507 free(p_menu);
508 }
509
510 p_menu_set->menu_count = 0;
511 p_menu_set->menu_select_depth = 0;
512 }
513
514 int reload_menu(MENU_SET *p_menu_set)
515 {
516 int result;
517 char conf_file[FILE_PATH_LEN];
518
519 strncpy(conf_file, p_menu_set->conf_file, sizeof(conf_file) - 1);
520 conf_file[sizeof(conf_file) - 1] = '\0';
521
522 unload_menu(p_menu_set);
523 result = load_menu(p_menu_set, conf_file);
524
525 return result;
526 }

webmaster@leafok.com
ViewVC Help
Powered by ViewVC 1.3.0-beta1