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

Contents of /lbbs/src/menu.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.27 - (show annotations)
Mon May 5 11:11:06 2025 UTC (10 months, 1 week ago) by sysadm
Branch: MAIN
Changes since 1.26: +5 -2 lines
Content type: text/x-csrc
Refine

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 pmatch[1].rm_eo - pmatch[1].rm_so);
67 temp[pmatch[1].rm_eo - pmatch[1].rm_so] = '\0';
68 sprintf(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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 pmatch[3].rm_eo - pmatch[3].rm_so);
252 temp[pmatch[3].rm_eo - pmatch[3].rm_so] = '\0';
253 sprintf(p_menu_set->p_menu[i]->screen.filename,
254 "%s/MENU_SCR_%s", MENU_TEMP_DIR, temp);
255 continue;
256 }
257 }
258 }
259 break;
260 }
261 }
262 fclose(fin);
263
264 p_menu_set->menu_count = i;
265 p_menu_set->menu_select_depth = 0;
266 p_menu_set->p_menu_select[p_menu_set->menu_select_depth] = (i == 0 ? NULL : p_menu_set->p_menu[0]);
267
268 return 0;
269 }
270
271 MENU *
272 get_menu(MENU_SET *p_menu_set, const char *menu_name)
273 {
274 int i;
275
276 for (i = 0; i < p_menu_set->menu_count; i++)
277 {
278 if (strcmp(p_menu_set->p_menu[i]->name, menu_name) == 0)
279 {
280 return p_menu_set->p_menu[i];
281 }
282 }
283
284 return NULL;
285 }
286
287 static void display_menu_cursor(MENU *p_menu, int show)
288 {
289 moveto((p_menu->items[p_menu->item_cur_pos])->r_row,
290 (p_menu->items[p_menu->item_cur_pos])->r_col - 2);
291 outc(show ? '>' : ' ');
292 iflush();
293 }
294
295 int display_menu(MENU *p_menu)
296 {
297 int row = 0;
298 int col = 0;
299 int menu_selectable = 0;
300
301 if (p_menu == NULL)
302 {
303 return -1;
304 }
305
306 if (p_menu->title.show)
307 {
308 show_top(p_menu->title.text);
309 }
310
311 if (p_menu->screen.show)
312 {
313 moveto(p_menu->screen.row, p_menu->screen.col);
314 if (display_file(p_menu->screen.filename) != 0)
315 {
316 log_error("Display menu screen <%s> failed!\n",
317 p_menu->screen.filename);
318 }
319 }
320
321 for (int i = 0; i < p_menu->item_count; i++)
322 {
323 if (p_menu->items[i]->row != 0)
324 {
325 row = p_menu->items[i]->row;
326 }
327 if (p_menu->items[i]->col != 0)
328 {
329 col = p_menu->items[i]->col;
330 }
331
332 if (checkpriv(&BBS_priv, 0, p_menu->items[i]->priv) == 0 || checklevel(&BBS_priv, p_menu->items[i]->level) == 0)
333 {
334 p_menu->items[i]->display = 0;
335 p_menu->items[i]->r_row = 0;
336 p_menu->items[i]->r_col = 0;
337 }
338 else
339 {
340 p_menu->items[i]->display = 1;
341
342 if (!menu_selectable)
343 {
344 p_menu->item_cur_pos = i;
345 menu_selectable = 1;
346 }
347
348 p_menu->items[i]->r_row = row;
349 p_menu->items[i]->r_col = col;
350
351 moveto(row, col);
352 prints("%s", p_menu->items[i]->text);
353
354 row++;
355 }
356 }
357
358 if (!menu_selectable)
359 {
360 return -1;
361 }
362
363 display_menu_cursor(p_menu, 1);
364
365 return 0;
366 }
367
368 int display_current_menu(MENU_SET *p_menu_set)
369 {
370 MENU *p_menu;
371
372 p_menu = p_menu_set->p_menu_select[p_menu_set->menu_select_depth];
373
374 return display_menu(p_menu);
375 }
376
377 int menu_control(MENU_SET *p_menu_set, int key)
378 {
379 int i;
380 MENU *p_menu;
381
382 if (p_menu_set->menu_count == 0)
383 {
384 return 0;
385 }
386
387 p_menu = p_menu_set->p_menu_select[p_menu_set->menu_select_depth];
388
389 switch (key)
390 {
391 case CR:
392 igetch(1); // Cleanup remaining '\n' in the buffer
393 case KEY_RIGHT:
394 if (p_menu->items[p_menu->item_cur_pos]->submenu)
395 {
396 if (strcmp(p_menu->items[p_menu->item_cur_pos]->action, "..") == 0)
397 {
398 return menu_control(p_menu_set, KEY_LEFT);
399 }
400 p_menu_set->menu_select_depth++;
401 p_menu = get_menu(p_menu_set, p_menu->items[p_menu->item_cur_pos]->action);
402 p_menu_set->p_menu_select[p_menu_set->menu_select_depth] = p_menu;
403
404 if (display_menu(p_menu) != 0)
405 {
406 return menu_control(p_menu_set, KEY_LEFT);
407 }
408 break;
409 }
410 else
411 {
412 return (exec_cmd(p_menu->items[p_menu->item_cur_pos]->action,
413 p_menu->items[p_menu->item_cur_pos]->name));
414 }
415 case KEY_LEFT:
416 if (p_menu_set->menu_select_depth > 0)
417 {
418 p_menu_set->menu_select_depth--;
419 if (display_current_menu(p_menu_set) != 0)
420 {
421 return menu_control(p_menu_set, KEY_LEFT);
422 }
423 break;
424 }
425 else
426 {
427 display_menu_cursor(p_menu, 0);
428 p_menu->item_cur_pos = p_menu->item_count - 1;
429 while (!p_menu->items[p_menu->item_cur_pos]->display ||
430 p_menu->items[p_menu->item_cur_pos]->priv != 0 ||
431 p_menu->items[p_menu->item_cur_pos]->level != 0)
432 {
433 p_menu->item_cur_pos--;
434 }
435 display_menu_cursor(p_menu, 1);
436 break;
437 }
438 case KEY_UP:
439 display_menu_cursor(p_menu, 0);
440 do
441 {
442 p_menu->item_cur_pos--;
443 if (p_menu->item_cur_pos < 0)
444 {
445 p_menu->item_cur_pos = p_menu->item_count - 1;
446 }
447 } while (!p_menu->items[p_menu->item_cur_pos]->display);
448 display_menu_cursor(p_menu, 1);
449 break;
450 case KEY_DOWN:
451 display_menu_cursor(p_menu, 0);
452 do
453 {
454 p_menu->item_cur_pos++;
455 if (p_menu->item_cur_pos >= p_menu->item_count)
456 {
457 p_menu->item_cur_pos = 0;
458 }
459 } while (!p_menu->items[p_menu->item_cur_pos]->display);
460 display_menu_cursor(p_menu, 1);
461 break;
462 default:
463 for (i = 0; i < p_menu->item_count; i++)
464 {
465 if (key == p_menu->items[i]->name[0] &&
466 p_menu->items[i]->display)
467 {
468 display_menu_cursor(p_menu, 0);
469 p_menu->item_cur_pos = i;
470 display_menu_cursor(p_menu, 1);
471 return 0;
472 }
473 }
474 if (isalpha(key))
475 {
476 for (i = 0; i < p_menu->item_count; i++)
477 {
478 if (toupper(key) == toupper(p_menu->items[i]->name[0]) &&
479 p_menu->items[i]->display)
480 {
481 display_menu_cursor(p_menu, 0);
482 p_menu->item_cur_pos = i;
483 display_menu_cursor(p_menu, 1);
484 return 0;
485 }
486 }
487 }
488 }
489
490 return 0;
491 }
492
493 void unload_menu(MENU_SET *p_menu_set)
494 {
495 MENU *p_menu;
496 int i, j;
497
498 for (i = 0; i < p_menu_set->menu_count; i++)
499 {
500 p_menu = p_menu_set->p_menu[i];
501 for (j = 0; j < p_menu->item_count; j++)
502 {
503 free(p_menu->items[j]);
504 }
505 remove(p_menu->screen.filename);
506 free(p_menu);
507 }
508
509 p_menu_set->menu_count = 0;
510 p_menu_set->menu_select_depth = 0;
511 }
512
513 int reload_menu(MENU_SET *p_menu_set)
514 {
515 int result;
516 char conf_file[FILE_PATH_LEN];
517
518 strncpy(conf_file, p_menu_set->conf_file, sizeof(conf_file) - 1);
519 conf_file[sizeof(conf_file) - 1] = '\0';
520
521 unload_menu(p_menu_set);
522 result = load_menu(p_menu_set, conf_file);
523
524 return result;
525 }

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