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

Contents of /lbbs/src/menu.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.46 - (show annotations)
Sun May 18 06:57:56 2025 UTC (10 months ago) by sysadm
Branch: MAIN
Changes since 1.45: +2 -0 lines
Content type: text/x-csrc
Refine

1 /***************************************************************************
2 menu.c - description
3 -------------------
4 Copyright : (C) 2004-2025 by Leaflet
5 Email : leaflet@leafok.com
6 ***************************************************************************/
7
8 /***************************************************************************
9 * *
10 * This program is free software; you can redistribute it and/or modify *
11 * it under the terms of the GNU General Public License as published by *
12 * the Free Software Foundation; either version 3 of the License, or *
13 * (at your option) any later version. *
14 * *
15 ***************************************************************************/
16
17 #include "bbs.h"
18 #include "bbs_cmd.h"
19 #include "user_priv.h"
20 #include "bbs_cmd.h"
21 #include "menu.h"
22 #include "log.h"
23 #include "io.h"
24 #include "screen.h"
25 #include "common.h"
26 #include <string.h>
27 #include <stdio.h>
28 #include <ctype.h>
29 #include <stdlib.h>
30 #include <errno.h>
31 #include <unistd.h>
32 #include <sys/shm.h>
33 #include <sys/ipc.h>
34
35 #define MENU_SCREEN_PATH_PREFIX "var/MENU_SCR_"
36 #define MENU_CONF_DELIM_WITH_SPACE " ,\t\r\n"
37 #define MENU_CONF_DELIM_WITHOUT_SPACE "\r\n"
38
39 #define MENU_SET_RESERVED_LENGTH (sizeof(int16_t) * 4)
40
41 MENU_SET *p_bbs_menu;
42
43 int load_menu(MENU_SET *p_menu_set, const char *conf_file)
44 {
45 FILE *fin;
46 int fin_line = 0;
47 char buffer[LINE_BUFFER_LEN];
48 char temp[LINE_BUFFER_LEN];
49 char *p = NULL;
50 char *q = NULL;
51 char *saveptr = NULL;
52 MENU *p_menu = NULL;
53 MENU_ITEM *p_menu_item = NULL;
54 MENU_SCREEN *p_screen = NULL;
55 MENU_ID menu_id;
56 MENU_ITEM_ID menu_item_id;
57 MENU_SCREEN_ID screen_id;
58 int proj_id;
59 key_t key;
60 size_t size;
61
62 // Use trie_dict to search menu_id by menu name
63 p_menu_set->p_menu_name_dict = trie_dict_create();
64 if (p_menu_set->p_menu_name_dict == NULL)
65 {
66 log_error("trie_dict_create() error\n");
67 return -3;
68 }
69
70 // Use trie_dict to search screen_id by menu screen name
71 p_menu_set->p_menu_screen_dict = trie_dict_create();
72 if (p_menu_set->p_menu_screen_dict == NULL)
73 {
74 log_error("trie_dict_create() error\n");
75 return -3;
76 }
77
78 if ((fin = fopen(conf_file, "r")) == NULL)
79 {
80 log_error("Open %s failed", conf_file);
81 return -2;
82 }
83
84 // Allocate shared memory
85 proj_id = (int)(time(NULL) % getpid());
86 key = ftok(conf_file, proj_id);
87 if (key == -1)
88 {
89 log_error("ftok(%s %d) error (%d)\n", conf_file, proj_id, errno);
90 return -2;
91 }
92
93 size = MENU_SET_RESERVED_LENGTH +
94 sizeof(MENU) * MAX_MENUS +
95 sizeof(MENU_ITEM) * MAX_MENUITEMS +
96 sizeof(MENU_SCREEN) * MAX_MENUS +
97 MAX_MENU_SCR_BUF_LENGTH * MAX_MENUS;
98 p_menu_set->shmid = shmget(key, size, IPC_CREAT | IPC_EXCL | 0600);
99 if (p_menu_set->shmid == -1)
100 {
101 log_error("shmget(size = %d) error (%d)\n", size, errno);
102 return -3;
103 }
104 p_menu_set->p_reserved = shmat(p_menu_set->shmid, NULL, 0);
105 if (p_menu_set->p_reserved == (void *)-1)
106 {
107 log_error("shmat() error (%d)\n", errno);
108 return -3;
109 }
110 p_menu_set->p_menu_pool = p_menu_set->p_reserved + MENU_SET_RESERVED_LENGTH;
111 p_menu_set->p_menu_item_pool = p_menu_set->p_menu_pool + sizeof(MENU) * MAX_MENUS;
112 p_menu_set->p_menu_screen_pool = p_menu_set->p_menu_item_pool + sizeof(MENU_ITEM) * MAX_MENUITEMS;
113 p_menu_set->p_menu_screen_buf = p_menu_set->p_menu_screen_pool + sizeof(MENU_SCREEN) * MAX_MENUS;
114 p_menu_set->p_menu_screen_buf_free = p_menu_set->p_menu_screen_buf;
115
116 p_menu_set->menu_count = 0;
117 p_menu_set->menu_item_count = 0;
118 p_menu_set->menu_screen_count = 0;
119 p_menu_set->choose_step = 0;
120 p_menu_set->menu_id_path[0] = 0;
121
122 while (fgets(buffer, sizeof(buffer), fin))
123 {
124 fin_line++;
125
126 p = strtok_r(buffer, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
127 if (p == NULL) // Blank line
128 {
129 continue;
130 }
131
132 if (*p == '#' || *p == '\r' || *p == '\n') // Comment or blank line
133 {
134 continue;
135 }
136
137 if (*p == '%')
138 {
139 p++;
140
141 if (strcmp(p, "menu") == 0) // BEGIN of sub-menu
142 {
143 if (p_menu != NULL)
144 {
145 log_error("Incomplete menu definition in menu config line %d\n", fin_line);
146 return -1;
147 }
148
149 if (p_menu_set->menu_count >= MAX_MENUS)
150 {
151 log_error("Menu count (%d) exceed limit (%d)\n", p_menu_set->menu_count, MAX_MENUS);
152 return -3;
153 }
154 menu_id = (MENU_ID)p_menu_set->menu_count;
155 p_menu_set->menu_count++;
156
157 p_menu = get_menu_by_id(p_menu_set, menu_id);
158
159 p_menu->item_count = 0;
160 p_menu->title.show = 0;
161 p_menu->screen_show = 0;
162
163 q = strtok_r(NULL, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
164 if (q == NULL)
165 {
166 log_error("Error menu name in menu config line %d\n", fin_line);
167 return -1;
168 }
169 p = q;
170 while (isalnum(*q) || *q == '_')
171 {
172 q++;
173 }
174 if (*q != '\0')
175 {
176 log_error("Error menu name in menu config line %d\n", fin_line);
177 return -1;
178 }
179
180 if (q - p > sizeof(p_menu->name) - 1)
181 {
182 log_error("Too longer menu name in menu config line %d\n", fin_line);
183 return -1;
184 }
185 strncpy(p_menu->name, p, sizeof(p_menu->name) - 1);
186 p_menu->name[sizeof(p_menu->name) - 1] = '\0';
187
188 if (trie_dict_set(p_menu_set->p_menu_name_dict, p_menu->name, (int64_t)menu_id) != 1)
189 {
190 log_error("Error set menu dict [%s]\n", p_menu->name);
191 }
192
193 // Check syntax
194 q = strtok_r(NULL, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
195 if (q != NULL)
196 {
197 log_error("Unknown extra content in menu config line %d\n", fin_line);
198 return -1;
199 }
200
201 while (fgets(buffer, sizeof(buffer), fin))
202 {
203 fin_line++;
204
205 p = strtok_r(buffer, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
206 if (p == NULL) // Blank line
207 {
208 continue;
209 }
210
211 if (*p == '#' || *p == '\r' || *p == '\n') // Comment or blank line
212 {
213 continue;
214 }
215
216 if (*p == '%') // END of sub-menu
217 {
218 p_menu = NULL;
219 break;
220 }
221 else if (*p == '!' || *p == '@')
222 {
223 // BEGIN of menu item
224 if (p_menu->item_count >= MAX_ITEMS_PER_MENU)
225 {
226 log_error("Menuitem count per menu (%d) exceed limit (%d)\n", p_menu->item_count, MAX_ITEMS_PER_MENU);
227 return -1;
228 }
229 if (p_menu_set->menu_item_count >= MAX_MENUITEMS)
230 {
231 log_error("Menuitem count (%d) exceed limit (%d)\n", p_menu_set->menu_item_count, MAX_MENUITEMS);
232 return -3;
233 }
234 menu_item_id = (MENU_ITEM_ID)p_menu_set->menu_item_count;
235 p_menu_set->menu_item_count++;
236
237 p_menu->items[p_menu->item_count] = menu_item_id;
238 p_menu->item_count++;
239
240 p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
241
242 p_menu_item->submenu = (*p == '!' ? 1 : 0);
243
244 // Menu item action
245 p++;
246 if (strcmp(p, "..") == 0) // Return to parent menu
247 {
248 q = p + 2; // strlen("..")
249 }
250 else
251 {
252 q = p;
253 while (isalnum(*q) || *q == '_')
254 {
255 q++;
256 }
257 if (*q != '\0')
258 {
259 log_error("Error menu item action in menu config line %d\n", fin_line);
260 return -1;
261 }
262 }
263
264 if (q - p > sizeof(p_menu_item->action) - 1)
265 {
266 log_error("Too longer menu action in menu config line %d\n", fin_line);
267 return -1;
268 }
269 strncpy(p_menu_item->action, p, sizeof(p_menu_item->action) - 1);
270 p_menu_item->action[sizeof(p_menu_item->action) - 1] = '\0';
271
272 // Menu item row
273 q = strtok_r(NULL, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
274 if (q == NULL)
275 {
276 log_error("Error menu item row in menu config line %d\n", fin_line);
277 return -1;
278 }
279 p = q;
280 while (isdigit(*q))
281 {
282 q++;
283 }
284 if (*q != '\0')
285 {
286 log_error("Error menu item row in menu config line %d\n", fin_line);
287 return -1;
288 }
289 p_menu_item->row = (int16_t)atoi(p);
290
291 // Menu item col
292 q = strtok_r(NULL, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
293 if (q == NULL)
294 {
295 log_error("Error menu item col in menu config line %d\n", fin_line);
296 return -1;
297 }
298 p = q;
299 while (isdigit(*q))
300 {
301 q++;
302 }
303 if (*q != '\0')
304 {
305 log_error("Error menu item col in menu config line %d\n", fin_line);
306 return -1;
307 }
308 p_menu_item->col = (int16_t)atoi(p);
309
310 // Menu item priv
311 q = strtok_r(NULL, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
312 if (q == NULL)
313 {
314 log_error("Error menu item priv in menu config line %d\n", fin_line);
315 return -1;
316 }
317 p = q;
318 while (isdigit(*q))
319 {
320 q++;
321 }
322 if (*q != '\0')
323 {
324 log_error("Error menu item priv in menu config line %d\n", fin_line);
325 return -1;
326 }
327 p_menu_item->priv = atoi(p);
328
329 // Menu item level
330 q = strtok_r(NULL, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
331 if (q == NULL)
332 {
333 log_error("Error menu item level in menu config line %d\n", fin_line);
334 return -1;
335 }
336 p = q;
337 while (isdigit(*q))
338 {
339 q++;
340 }
341 if (*q != '\0')
342 {
343 log_error("Error menu item level in menu config line %d\n", fin_line);
344 return -1;
345 }
346 p_menu_item->level = atoi(p);
347
348 // Menu item name
349 q = strtok_r(NULL, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
350 if (q == NULL || *q != '\"')
351 {
352 log_error("Error menu item name in menu config line %d\n", fin_line);
353 return -1;
354 }
355 q++;
356 p = q;
357 while (*q != '\0' && *q != '\"')
358 {
359 q++;
360 }
361 if (*q != '\"' || *(q + 1) != '\0')
362 {
363 log_error("Error menu item name in menu config line %d\n", fin_line);
364 return -1;
365 }
366 *q = '\0';
367
368 if (q - p > sizeof(p_menu_item->name) - 1)
369 {
370 log_error("Too longer menu name in menu config line %d\n", fin_line);
371 return -1;
372 }
373 strncpy(p_menu_item->name, p, sizeof(p_menu_item->name) - 1);
374 p_menu_item->name[sizeof(p_menu_item->name) - 1] = '\0';
375
376 // Menu item text
377 q = strtok_r(NULL, MENU_CONF_DELIM_WITHOUT_SPACE, &saveptr);
378 if (q == NULL || (q = strchr(q, '\"')) == NULL)
379 {
380 log_error("Error menu item text in menu config line %d\n", fin_line);
381 return -1;
382 }
383 q++;
384 p = q;
385 while (*q != '\0' && *q != '\"')
386 {
387 q++;
388 }
389 if (*q != '\"')
390 {
391 log_error("Error menu item text in menu config line %d\n", fin_line);
392 return -1;
393 }
394 *q = '\0';
395
396 if (q - p > sizeof(p_menu_item->text) - 1)
397 {
398 log_error("Too longer menu item text in menu config line %d\n", fin_line);
399 return -1;
400 }
401 strncpy(p_menu_item->text, p, sizeof(p_menu_item->text) - 1);
402 p_menu_item->text[sizeof(p_menu_item->text) - 1] = '\0';
403
404 // Check syntax
405 q = strtok_r(q + 1, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
406 if (q != NULL)
407 {
408 log_error("Unknown extra content in menu config line %d\n", fin_line);
409 return -1;
410 }
411 }
412 else if (strcmp(p, "title") == 0)
413 {
414 p_menu->title.show = 1;
415
416 // Menu title row
417 q = strtok_r(NULL, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
418 if (q == NULL)
419 {
420 log_error("Error menu title row in menu config line %d\n", fin_line);
421 return -1;
422 }
423 p = q;
424 while (isdigit(*q))
425 {
426 q++;
427 }
428 if (*q != '\0')
429 {
430 log_error("Error menu title row in menu config line %d\n", fin_line);
431 return -1;
432 }
433 p_menu->title.row = (int16_t)atoi(p);
434
435 // Menu title col
436 q = strtok_r(NULL, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
437 if (q == NULL)
438 {
439 log_error("Error menu title col in menu config line %d\n", fin_line);
440 return -1;
441 }
442 p = q;
443 while (isdigit(*q))
444 {
445 q++;
446 }
447 if (*q != '\0')
448 {
449 log_error("Error menu title col in menu config line %d\n", fin_line);
450 return -1;
451 }
452 p_menu->title.col = (int16_t)atoi(p);
453
454 // Menu title text
455 q = strtok_r(NULL, MENU_CONF_DELIM_WITHOUT_SPACE, &saveptr);
456 if (q == NULL || (q = strchr(q, '\"')) == NULL)
457 {
458 log_error("Error menu title text in menu config line %d\n", fin_line);
459 return -1;
460 }
461 q++;
462 p = q;
463 while (*q != '\0' && *q != '\"')
464 {
465 q++;
466 }
467 if (*q != '\"')
468 {
469 log_error("Error menu title text in menu config line %d\n", fin_line);
470 return -1;
471 }
472 *q = '\0';
473
474 if (q - p > sizeof(p_menu_item->text) - 1)
475 {
476 log_error("Too longer menu title text in menu config line %d\n", fin_line);
477 return -1;
478 }
479 strncpy(p_menu->title.text, p, sizeof(p_menu->title.text) - 1);
480 p_menu->title.text[sizeof(p_menu->title.text) - 1] = '\0';
481
482 // Check syntax
483 q = strtok_r(q + 1, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
484 if (q != NULL)
485 {
486 log_error("Unknown extra content in menu config line %d\n", fin_line);
487 return -1;
488 }
489 }
490 else if (strcmp(p, "screen") == 0)
491 {
492 p_menu->screen_show = 1;
493
494 // Menu screen row
495 q = strtok_r(NULL, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
496 if (q == NULL)
497 {
498 log_error("Error menu screen row in menu config line %d\n", fin_line);
499 return -1;
500 }
501 p = q;
502 while (isdigit(*q))
503 {
504 q++;
505 }
506 if (*q != '\0')
507 {
508 log_error("Error menu screen row in menu config line %d\n", fin_line);
509 return -1;
510 }
511 p_menu->screen_row = (int16_t)atoi(p);
512
513 // Menu screen col
514 q = strtok_r(NULL, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
515 if (q == NULL)
516 {
517 log_error("Error menu screen col in menu config line %d\n", fin_line);
518 return -1;
519 }
520 p = q;
521 while (isdigit(*q))
522 {
523 q++;
524 }
525 if (*q != '\0')
526 {
527 log_error("Error menu screen col in menu config line %d\n", fin_line);
528 return -1;
529 }
530 p_menu->screen_col = (int16_t)atoi(p);
531
532 // Menu screen name
533 q = strtok_r(NULL, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
534 if (q == NULL)
535 {
536 log_error("Error menu screen name in menu config line %d\n", fin_line);
537 return -1;
538 }
539 p = q;
540 while (isalnum(*q) || *q == '_')
541 {
542 q++;
543 }
544 if (*q != '\0')
545 {
546 log_error("Error menu screen name in menu config line %d\n", fin_line);
547 return -1;
548 }
549 if (trie_dict_get(p_menu_set->p_menu_screen_dict, p, (int64_t *)&screen_id) != 1)
550 {
551 log_error("Undefined menu screen [%s]\n", p);
552 return -1;
553 }
554 p_menu->screen_id = screen_id;
555
556 // Check syntax
557 q = strtok_r(NULL, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
558 if (q != NULL)
559 {
560 log_error("Unknown extra content in menu config line %d\n", fin_line);
561 return -1;
562 }
563 }
564 }
565 }
566 else // BEGIN of menu screen
567 {
568 if (p_menu_set->menu_item_count >= MAX_MENUS)
569 {
570 log_error("Menu screen count (%d) exceed limit (%d)\n", p_menu_set->menu_screen_count, MAX_MENUS);
571 return -3;
572 }
573 screen_id = (MENU_SCREEN_ID)p_menu_set->menu_screen_count;
574 p_menu_set->menu_screen_count++;
575
576 p_screen = get_menu_screen_by_id(p_menu_set, screen_id);
577
578 q = p;
579 while (isalnum(*q) || *q == '_')
580 {
581 q++;
582 }
583 if (*q != '\0')
584 {
585 log_error("Error menu screen name in menu config line %d\n", fin_line);
586 return -1;
587 }
588 strncpy(p_screen->name, p, sizeof(p_screen->name) - 1);
589 p_screen->name[sizeof(p_screen->name) - 1] = '\0';
590
591 if (trie_dict_set(p_menu_set->p_menu_screen_dict, p_screen->name, (int64_t)screen_id) != 1)
592 {
593 log_error("Error set menu screen dict [%s]\n", p_screen->name);
594 }
595
596 // Check syntax
597 q = strtok_r(NULL, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
598 if (q != NULL)
599 {
600 log_error("Unknown extra content in menu config line %d\n", fin_line);
601 return -1;
602 }
603
604 p_screen->buf_offset = p_menu_set->p_menu_screen_buf_free - p_menu_set->p_menu_screen_buf;
605 p_screen->buf_length = -1;
606
607 // safety appending boundary
608 q = p_menu_set->p_menu_screen_buf + MAX_MENU_SCR_BUF_LENGTH * MAX_MENUS - 1;
609
610 while (fgets(buffer, sizeof(buffer), fin))
611 {
612 fin_line++;
613
614 strncpy(temp, buffer, sizeof(temp) - 1); // Duplicate line for strtok_r
615 temp[sizeof(temp) - 1] = '\0';
616 p = strtok_r(temp, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
617 if (p != NULL && *p == '%') // END of menu screen
618 {
619 if (p_menu_set->p_menu_screen_buf_free + 1 > q)
620 {
621 log_error("Menu screen buffer depleted (%p + 1 > %p)\n", p_menu_set->p_menu_screen_buf_free, q);
622 return -3;
623 }
624
625 *(p_menu_set->p_menu_screen_buf_free) = '\0';
626 p_menu_set->p_menu_screen_buf_free++;
627 p_screen->buf_length = p_menu_set->p_menu_screen_buf_free - p_menu_set->p_menu_screen_buf - p_screen->buf_offset;
628 break;
629 }
630
631 p = buffer;
632 while (*p != '\0')
633 {
634 if (p_menu_set->p_menu_screen_buf_free + 2 > q)
635 {
636 log_error("Menu screen buffer depleted (%p + 2 > %p)\n", p_menu_set->p_menu_screen_buf_free, q);
637 return -3;
638 }
639
640 if (*p == '\n' && p > buffer && *(p - 1) != '\r')
641 {
642 *(p_menu_set->p_menu_screen_buf_free) = '\r';
643 p_menu_set->p_menu_screen_buf_free++;
644 }
645
646 *(p_menu_set->p_menu_screen_buf_free) = *p;
647 p++;
648 p_menu_set->p_menu_screen_buf_free++;
649 }
650 }
651
652 if (p_screen->buf_length == -1)
653 {
654 log_error("End of menu screen [%s] not found\n", p_screen->name);
655 }
656 }
657 }
658 else // Invalid prefix
659 {
660 log_error("Error in menu config line %d\n", fin_line);
661 return -1;
662 }
663 }
664 fclose(fin);
665
666 for (menu_item_id = 0; menu_item_id < p_menu_set->menu_item_count; menu_item_id++)
667 {
668 p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
669
670 // Set menu_item->action_cmd_handler of each menu item pointing to bbs_cmd
671 if (p_menu_item->submenu == 0)
672 {
673 if ((p_menu_item->action_cmd_handler = get_cmd_handler(p_menu_item->action)) == NULL)
674 {
675 log_error("Undefined menu action cmd handler [%s]\n", p_menu_item->action);
676 return -1;
677 }
678 }
679 // Set menu_item->action_menu_id of each menu item pointing to a submenu to the menu_id of the corresponding submenu
680 else if (strcmp(p_menu_item->action, "..") != 0)
681 {
682 if (trie_dict_get(p_menu_set->p_menu_name_dict, p_menu_item->action, (int64_t *)&menu_id) != 1)
683 {
684 log_error("Undefined menu action [%s]\n", p_menu_item->action);
685 return -1;
686 }
687 p_menu_item->action_menu_id = menu_id;
688 }
689 }
690
691 // Save status varaibles into reserved memory area
692 *((int16_t *)p_menu_set->p_reserved) = p_menu_set->menu_count;
693 *(((int16_t *)p_menu_set->p_reserved) + 1) = p_menu_set->menu_item_count;
694 *(((int16_t *)p_menu_set->p_reserved) + 2) = p_menu_set->menu_screen_count;
695
696 return 0;
697 }
698
699 static int display_menu_cursor(MENU_SET *p_menu_set, int show)
700 {
701 MENU_ID menu_id;
702 MENU_ITEM_ID menu_item_id;
703 MENU *p_menu;
704 MENU_ITEM *p_menu_item;
705 int16_t menu_item_pos;
706
707 menu_id = p_menu_set->menu_id_path[p_menu_set->choose_step];
708 p_menu = get_menu_by_id(p_menu_set, menu_id);
709 if (p_menu == NULL)
710 {
711 log_error("get_menu_by_id(%d) return NULL pointer\n", menu_id);
712 return -1;
713 }
714
715 menu_item_pos = p_menu_set->menu_item_pos[p_menu_set->choose_step];
716 menu_item_id = p_menu->items[menu_item_pos];
717 p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
718 if (p_menu_item == NULL)
719 {
720 log_error("get_menu_item_by_id(%d) return NULL pointer\n", menu_item_id);
721 return -1;
722 }
723
724 moveto(p_menu_set->menu_item_r_row[menu_item_pos], p_menu_set->menu_item_r_col[menu_item_pos] - 2);
725 outc(show ? '>' : ' ');
726 iflush();
727
728 return 0;
729 }
730
731 int display_menu(MENU_SET *p_menu_set)
732 {
733 int16_t row = 0;
734 int16_t col = 0;
735 int menu_selectable = 0;
736 MENU_ID menu_id;
737 MENU_ITEM_ID menu_item_id;
738 MENU *p_menu;
739 MENU_ITEM *p_menu_item;
740 MENU_SCREEN *p_menu_screen;
741 int16_t menu_item_pos;
742
743 menu_id = p_menu_set->menu_id_path[p_menu_set->choose_step];
744 p_menu = get_menu_by_id(p_menu_set, menu_id);
745 if (p_menu == NULL)
746 {
747 log_error("get_menu_by_id(%d) return NULL pointer\n", menu_id);
748 return -1;
749 }
750
751 menu_item_pos = p_menu_set->menu_item_pos[p_menu_set->choose_step];
752 menu_item_id = p_menu->items[menu_item_pos];
753 p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
754 if (p_menu_item == NULL)
755 {
756 log_error("get_menu_item_by_id(%d) return NULL pointer\n", menu_item_id);
757 return -1;
758 }
759
760 if (menu_item_pos > 0 &&
761 checkpriv(&BBS_priv, 0, p_menu_item->priv) != 0 &&
762 checklevel(&BBS_priv, p_menu_item->level) != 0)
763 {
764 menu_selectable = 1;
765 }
766
767 if (p_menu->title.show)
768 {
769 show_top(p_menu->title.text);
770 }
771
772 if (p_menu->screen_show)
773 {
774 p_menu_screen = get_menu_screen_by_id(p_menu_set, p_menu->screen_id);
775 if (p_menu_screen == NULL)
776 {
777 log_error("get_menu_screen_by_id(%d) return NULL pointer\n", p_menu->screen_id);
778 return -1;
779 }
780
781 moveto(p_menu->screen_row, p_menu->screen_col);
782 prints("%s", p_menu_set->p_menu_screen_buf + p_menu_screen->buf_offset);
783 iflush();
784 }
785
786 for (menu_item_pos = 0; menu_item_pos < p_menu->item_count; menu_item_pos++)
787 {
788 menu_item_id = p_menu->items[menu_item_pos];
789 p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
790
791 if (p_menu_item->row != 0)
792 {
793 row = p_menu_item->row;
794 }
795 if (p_menu_item->col != 0)
796 {
797 col = p_menu_item->col;
798 }
799
800 if (checkpriv(&BBS_priv, 0, p_menu_item->priv) == 0 || checklevel(&BBS_priv, p_menu_item->level) == 0)
801 {
802 p_menu_set->menu_item_display[menu_item_pos] = 0;
803 p_menu_set->menu_item_r_row[menu_item_pos] = 0;
804 p_menu_set->menu_item_r_col[menu_item_pos] = 0;
805 }
806 else
807 {
808 p_menu_set->menu_item_display[menu_item_pos] = 1;
809
810 if (!menu_selectable)
811 {
812 p_menu_set->menu_item_pos[p_menu_set->choose_step] = menu_item_pos;
813 menu_selectable = 1;
814 }
815
816 p_menu_set->menu_item_r_row[menu_item_pos] = row;
817 p_menu_set->menu_item_r_col[menu_item_pos] = col;
818
819 moveto(row, col);
820 prints("%s", p_menu_item->text);
821
822 row++;
823 }
824 }
825
826 if (!menu_selectable)
827 {
828 return -1;
829 }
830
831 display_menu_cursor(p_menu_set, 1);
832
833 return 0;
834 }
835
836 int menu_control(MENU_SET *p_menu_set, int key)
837 {
838 MENU_ID menu_id;
839 MENU_ITEM_ID menu_item_id;
840 MENU *p_menu;
841 MENU_ITEM *p_menu_item;
842 int16_t menu_item_pos;
843
844 if (p_menu_set->menu_count == 0)
845 {
846 return 0;
847 }
848
849 menu_id = p_menu_set->menu_id_path[p_menu_set->choose_step];
850 p_menu = get_menu_by_id(p_menu_set, menu_id);
851 if (p_menu == NULL)
852 {
853 log_error("get_menu_by_id(%d) return NULL pointer\n", menu_id);
854 return -1;
855 }
856
857 if (p_menu->item_count == 0)
858 {
859 return 0;
860 }
861
862 menu_item_pos = p_menu_set->menu_item_pos[p_menu_set->choose_step];
863 menu_item_id = p_menu->items[menu_item_pos];
864 p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
865 if (p_menu_item == NULL)
866 {
867 log_error("get_menu_item_by_id(%d) return NULL pointer\n", menu_item_id);
868 return -1;
869 }
870
871 switch (key)
872 {
873 case CR:
874 igetch_reset();
875 case KEY_RIGHT:
876 if (p_menu_item->submenu)
877 {
878 if (strcmp(p_menu_item->action, "..") == 0)
879 {
880 return menu_control(p_menu_set, KEY_LEFT);
881 }
882 p_menu_set->choose_step++;
883 p_menu_set->menu_id_path[p_menu_set->choose_step] = p_menu_item->action_menu_id;
884 p_menu_set->menu_item_pos[p_menu_set->choose_step] = 0;
885
886 if (display_menu(p_menu_set) != 0)
887 {
888 return menu_control(p_menu_set, KEY_LEFT);
889 }
890 }
891 else
892 {
893 return ((*(p_menu_item->action_cmd_handler))((void *)(p_menu_item->name)));
894 }
895 break;
896 case KEY_LEFT:
897 if (p_menu_set->choose_step > 0)
898 {
899 p_menu_set->choose_step--;
900 if (display_menu(p_menu_set) != 0)
901 {
902 return menu_control(p_menu_set, KEY_LEFT);
903 }
904 }
905 else
906 {
907 display_menu_cursor(p_menu_set, 0);
908 menu_item_pos = p_menu->item_count - 1;
909 while (menu_item_pos >= 0)
910 {
911 menu_item_id = p_menu->items[menu_item_pos];
912 p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
913 if (p_menu_item == NULL)
914 {
915 log_error("get_menu_item_by_id(%d) return NULL pointer\n", menu_item_id);
916 return -1;
917 }
918
919 if (!p_menu_set->menu_item_display[menu_item_pos] || p_menu_item->priv != 0 || p_menu_item->level != 0)
920 {
921 menu_item_pos--;
922 }
923 else
924 {
925 break;
926 }
927 }
928 p_menu_set->menu_item_pos[p_menu_set->choose_step] = menu_item_pos;
929 display_menu_cursor(p_menu_set, 1);
930 }
931 break;
932 case KEY_UP:
933 display_menu_cursor(p_menu_set, 0);
934 do
935 {
936 menu_item_pos--;
937 if (menu_item_pos < 0)
938 {
939 menu_item_pos = p_menu->item_count - 1;
940 }
941 menu_item_id = p_menu->items[menu_item_pos];
942 p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
943 if (p_menu_item == NULL)
944 {
945 log_error("get_menu_item_by_id(%d) return NULL pointer\n", menu_item_id);
946 return -1;
947 }
948 } while (!p_menu_set->menu_item_display[menu_item_pos]);
949 p_menu_set->menu_item_pos[p_menu_set->choose_step] = menu_item_pos;
950 display_menu_cursor(p_menu_set, 1);
951 break;
952 case KEY_DOWN:
953 display_menu_cursor(p_menu_set, 0);
954 do
955 {
956 menu_item_pos++;
957 if (menu_item_pos >= p_menu->item_count)
958 {
959 menu_item_pos = 0;
960 }
961 menu_item_id = p_menu->items[menu_item_pos];
962 p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
963 if (p_menu_item == NULL)
964 {
965 log_error("get_menu_item_by_id(%d) return NULL pointer\n", menu_item_id);
966 return -1;
967 }
968 } while (!p_menu_set->menu_item_display[menu_item_pos]);
969 p_menu_set->menu_item_pos[p_menu_set->choose_step] = menu_item_pos;
970 display_menu_cursor(p_menu_set, 1);
971 break;
972 case KEY_HOME:
973 case KEY_PGUP:
974 display_menu_cursor(p_menu_set, 0);
975 menu_item_pos = 0;
976 while (menu_item_pos < p_menu->item_count - 1)
977 {
978 menu_item_id = p_menu->items[menu_item_pos];
979 p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
980 if (p_menu_item == NULL)
981 {
982 log_error("get_menu_item_by_id(%d) return NULL pointer\n", menu_item_id);
983 return -1;
984 }
985
986 if (p_menu_set->menu_item_display[menu_item_pos])
987 {
988 break;
989 }
990
991 menu_item_pos++;
992 }
993 p_menu_set->menu_item_pos[p_menu_set->choose_step] = menu_item_pos;
994 display_menu_cursor(p_menu_set, 1);
995 break;
996 case KEY_END:
997 case KEY_PGDN:
998 display_menu_cursor(p_menu_set, 0);
999 menu_item_pos = p_menu->item_count - 1;
1000 while (menu_item_pos > 0)
1001 {
1002 menu_item_id = p_menu->items[menu_item_pos];
1003 p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
1004 if (p_menu_item == NULL)
1005 {
1006 log_error("get_menu_item_by_id(%d) return NULL pointer\n", menu_item_id);
1007 return -1;
1008 }
1009
1010 if (p_menu_set->menu_item_display[menu_item_pos])
1011 {
1012 break;
1013 }
1014
1015 menu_item_pos--;
1016 }
1017 p_menu_set->menu_item_pos[p_menu_set->choose_step] = menu_item_pos;
1018 display_menu_cursor(p_menu_set, 1);
1019 break;
1020 default:
1021 if (isalnum(key))
1022 {
1023 for (menu_item_pos = 0; menu_item_pos < p_menu->item_count; menu_item_pos++)
1024 {
1025 menu_item_id = p_menu->items[menu_item_pos];
1026 p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
1027 if (p_menu_item == NULL)
1028 {
1029 log_error("get_menu_item_by_id(%d) return NULL pointer\n", menu_item_id);
1030 return -1;
1031 }
1032
1033 if (toupper(key) == toupper(p_menu_item->name[0]) && p_menu_set->menu_item_display[menu_item_pos])
1034 {
1035 display_menu_cursor(p_menu_set, 0);
1036 p_menu_set->menu_item_pos[p_menu_set->choose_step] = menu_item_pos;
1037 display_menu_cursor(p_menu_set, 1);
1038 return 0;
1039 }
1040 }
1041 }
1042 break;
1043 }
1044
1045 return 0;
1046 }
1047
1048 int unload_menu(MENU_SET *p_menu_set)
1049 {
1050 if (p_menu_set->p_menu_name_dict != NULL)
1051 {
1052 trie_dict_destroy(p_menu_set->p_menu_name_dict);
1053 p_menu_set->p_menu_name_dict = NULL;
1054 }
1055
1056 if (p_menu_set->p_menu_screen_dict != NULL)
1057 {
1058 trie_dict_destroy(p_menu_set->p_menu_screen_dict);
1059 p_menu_set->p_menu_screen_dict = NULL;
1060 }
1061
1062 unload_menu_shm(p_menu_set);
1063
1064 if (shmctl(p_menu_set->shmid, IPC_RMID, NULL) == -1)
1065 {
1066 log_error("shmctl(shmid=%d, IPC_RMID) error (%d)\n", p_menu_set->shmid, errno);
1067 return -1;
1068 }
1069
1070 return 0;
1071 }
1072
1073 int load_menu_shm(MENU_SET *p_menu_set)
1074 {
1075 // Mount shared memory
1076 if (p_menu_set->p_reserved == NULL)
1077 {
1078 p_menu_set->p_reserved = shmat(p_menu_set->shmid, NULL, SHM_RDONLY);
1079 if (p_menu_set->p_reserved == (void *)-1)
1080 {
1081 log_error("shmat() error (%d)\n", errno);
1082 return -1;
1083 }
1084 }
1085
1086 p_menu_set->p_menu_pool = p_menu_set->p_reserved + MENU_SET_RESERVED_LENGTH;
1087 p_menu_set->p_menu_item_pool = p_menu_set->p_menu_pool + sizeof(MENU) * MAX_MENUS;
1088 p_menu_set->p_menu_screen_pool = p_menu_set->p_menu_item_pool + sizeof(MENU_ITEM) * MAX_MENUITEMS;
1089 p_menu_set->p_menu_screen_buf = p_menu_set->p_menu_screen_pool + sizeof(MENU_SCREEN) * MAX_MENUS;
1090 p_menu_set->p_menu_screen_buf_free = p_menu_set->p_menu_screen_buf;
1091
1092 // Restore status varaibles into reserved memory area
1093 p_menu_set->menu_count = *((int16_t *)p_menu_set->p_reserved);
1094 p_menu_set->menu_item_count = *(((int16_t *)p_menu_set->p_reserved) + 1);
1095 p_menu_set->menu_screen_count = *(((int16_t *)p_menu_set->p_reserved) + 2);
1096
1097 p_menu_set->choose_step = 0;
1098 p_menu_set->menu_id_path[0] = 0;
1099
1100 p_menu_set->p_menu_name_dict = NULL;
1101 p_menu_set->p_menu_screen_dict = NULL;
1102
1103 return 0;
1104 }
1105
1106 int unload_menu_shm(MENU_SET *p_menu_set)
1107 {
1108 p_menu_set->menu_count = 0;
1109 p_menu_set->menu_item_count = 0;
1110 p_menu_set->menu_screen_count = 0;
1111 p_menu_set->choose_step = 0;
1112
1113 p_menu_set->p_menu_pool = NULL;
1114 p_menu_set->p_menu_item_pool = NULL;
1115 p_menu_set->p_menu_screen_pool = NULL;
1116 p_menu_set->p_menu_screen_buf = NULL;
1117 p_menu_set->p_menu_screen_buf_free = NULL;
1118
1119 if (p_menu_set->p_reserved != NULL && shmdt(p_menu_set->p_reserved) == -1)
1120 {
1121 log_error("shmdt() error (%d)\n", errno);
1122 return -1;
1123 }
1124 p_menu_set->p_reserved = NULL;
1125
1126 return 0;
1127 }

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