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

Contents of /lbbs/src/menu.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.81 - (show annotations)
Tue Nov 4 14:15:49 2025 UTC (4 months, 1 week ago) by sysadm
Branch: MAIN
Changes since 1.80: +3 -4 lines
Content type: text/x-csrc
Refine

1 /* SPDX-License-Identifier: GPL-3.0-or-later */
2 /*
3 * menu
4 * - configurable user interactive menu feature
5 *
6 * Copyright (C) 2004-2025 by Leaflet <leaflet@leafok.com>
7 */
8
9 #include "bbs.h"
10 #include "bbs_cmd.h"
11 #include "bbs_cmd.h"
12 #include "common.h"
13 #include "io.h"
14 #include "log.h"
15 #include "menu.h"
16 #include "screen.h"
17 #include "user_priv.h"
18 #include <ctype.h>
19 #include <errno.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <unistd.h>
24 #include <sys/ipc.h>
25 #include <sys/shm.h>
26
27 #define MENU_SCREEN_PATH_PREFIX "var/MENU_SCR_"
28 #define MENU_CONF_DELIM_WITH_SPACE " ,\t\r\n"
29 #define MENU_CONF_DELIM_WITHOUT_SPACE "\r\n"
30
31 #define MENU_SET_RESERVED_LENGTH (sizeof(int16_t) * 4)
32
33 #define MENU_SHMGET_RETRY_LIMIT 10
34
35 MENU_SET bbs_menu;
36 MENU_SET top10_menu;
37
38 int load_menu(MENU_SET *p_menu_set, const char *conf_file)
39 {
40 FILE *fin;
41 int fin_line = 0;
42 char buffer[LINE_BUFFER_LEN];
43 char temp[LINE_BUFFER_LEN];
44 char *p = NULL;
45 char *q = NULL;
46 char *r = NULL;
47 char *saveptr = NULL;
48 MENU *p_menu = NULL;
49 MENU_ITEM *p_menu_item = NULL;
50 MENU_SCREEN *p_screen = NULL;
51 MENU_ID menu_id;
52 MENU_ITEM_ID menu_item_id;
53 MENU_SCREEN_ID screen_id;
54 int proj_id;
55 key_t key;
56 size_t size;
57 int retry_cnt;
58
59 // Initialize the data structure
60 memset(p_menu_set, 0, sizeof(*p_menu_set));
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\n", conf_file);
81 return -2;
82 }
83
84 // Allocate shared memory
85 size = MENU_SET_RESERVED_LENGTH +
86 sizeof(MENU) * MAX_MENUS +
87 sizeof(MENU_ITEM) * MAX_MENUITEMS +
88 sizeof(MENU_SCREEN) * MAX_MENUS +
89 MAX_MENU_SCR_BUF_LENGTH * MAX_MENUS;
90
91 proj_id = (int)(time(NULL) % getpid());
92 retry_cnt = 0;
93
94 do
95 {
96 key = ftok(conf_file, proj_id + retry_cnt);
97 if (key == -1)
98 {
99 log_error("ftok(%s %d) error (%d)\n", conf_file, proj_id + retry_cnt, errno);
100 return -3;
101 }
102
103 p_menu_set->shmid = shmget(key, size, IPC_CREAT | IPC_EXCL | 0600);
104 if (p_menu_set->shmid == -1)
105 {
106 if (errno != EEXIST || retry_cnt + 1 >= MENU_SHMGET_RETRY_LIMIT)
107 {
108 log_error("shmget(conf_file=%s, size=%d) error (%d) %d times\n",
109 conf_file, size, errno, retry_cnt + 1);
110 return -3;
111 }
112 log_error("shmget(conf_file=%s, proj_id=%d, key=0x%x, size=%d) error (%d), retry ...\n",
113 conf_file, proj_id + retry_cnt, key, size, errno);
114 retry_cnt++;
115 }
116 } while (p_menu_set->shmid == -1);
117
118 p_menu_set->p_reserved = shmat(p_menu_set->shmid, NULL, 0);
119 if (p_menu_set->p_reserved == (void *)-1)
120 {
121 log_error("shmat() error (%d)\n", errno);
122 return -3;
123 }
124
125 p_menu_set->p_menu_pool = (char *)(p_menu_set->p_reserved) + MENU_SET_RESERVED_LENGTH;
126 p_menu_set->p_menu_item_pool = (char *)(p_menu_set->p_menu_pool) + sizeof(MENU) * MAX_MENUS;
127 p_menu_set->p_menu_screen_pool = (char *)(p_menu_set->p_menu_item_pool) + sizeof(MENU_ITEM) * MAX_MENUITEMS;
128 p_menu_set->p_menu_screen_buf = (char *)(p_menu_set->p_menu_screen_pool) + sizeof(MENU_SCREEN) * MAX_MENUS;
129 p_menu_set->p_menu_screen_buf_free = p_menu_set->p_menu_screen_buf;
130
131 p_menu_set->menu_count = 0;
132 p_menu_set->menu_item_count = 0;
133 p_menu_set->menu_screen_count = 0;
134 p_menu_set->choose_step = 0;
135 p_menu_set->menu_id_path[0] = 0;
136 p_menu_set->menu_item_pos[0] = 0;
137 p_menu_set->allow_exit = 0;
138
139 while (fgets(buffer, sizeof(buffer), fin))
140 {
141 fin_line++;
142
143 p = strtok_r(buffer, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
144 if (p == NULL) // Blank line
145 {
146 continue;
147 }
148
149 if (*p == '#' || *p == '\r' || *p == '\n') // Comment or blank line
150 {
151 continue;
152 }
153
154 if (*p == '%')
155 {
156 p++;
157
158 if (strcmp(p, "menu") == 0) // BEGIN of sub-menu
159 {
160 if (p_menu != NULL)
161 {
162 log_error("Incomplete menu definition in menu config line %d\n", fin_line);
163 return -1;
164 }
165
166 if (p_menu_set->menu_count >= MAX_MENUS)
167 {
168 log_error("Menu count (%d) exceed limit (%d)\n", p_menu_set->menu_count, MAX_MENUS);
169 return -3;
170 }
171 menu_id = (MENU_ID)p_menu_set->menu_count;
172 p_menu_set->menu_count++;
173
174 p_menu = get_menu_by_id(p_menu_set, menu_id);
175
176 p_menu->item_count = 0;
177 p_menu->title.show = 0;
178 p_menu->screen_show = 0;
179 p_menu->page_item_limit = 0;
180 p_menu->use_filter = 0;
181 p_menu->filter_handler = NULL;
182
183 q = strtok_r(NULL, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
184 if (q == NULL)
185 {
186 log_error("Error menu name in menu config line %d\n", fin_line);
187 return -1;
188 }
189 p = q;
190 while (isalnum(*q) || *q == '_' || *q == '-')
191 {
192 q++;
193 }
194 if (*q != '\0')
195 {
196 log_error("Error menu name in menu config line %d\n", fin_line);
197 return -1;
198 }
199
200 if (q - p > sizeof(p_menu->name) - 1)
201 {
202 log_error("Too longer menu name in menu config line %d\n", fin_line);
203 return -1;
204 }
205 strncpy(p_menu->name, p, sizeof(p_menu->name) - 1);
206 p_menu->name[sizeof(p_menu->name) - 1] = '\0';
207
208 if (trie_dict_set(p_menu_set->p_menu_name_dict, p_menu->name, (int64_t)menu_id) != 1)
209 {
210 log_error("Error set menu dict [%s]\n", p_menu->name);
211 }
212
213 // Check syntax
214 q = strtok_r(NULL, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
215 if (q != NULL)
216 {
217 log_error("Unknown extra content in menu config line %d\n", fin_line);
218 return -1;
219 }
220
221 while (fgets(buffer, sizeof(buffer), fin))
222 {
223 fin_line++;
224
225 p = strtok_r(buffer, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
226 if (p == NULL) // Blank line
227 {
228 continue;
229 }
230
231 if (*p == '#' || *p == '\r' || *p == '\n') // Comment or blank line
232 {
233 continue;
234 }
235
236 if (*p == '%') // END of sub-menu
237 {
238 p_menu = NULL;
239 break;
240 }
241 else if (*p == '!' || *p == '@')
242 {
243 // BEGIN of menu item
244 if (p_menu->item_count >= MAX_ITEMS_PER_MENU)
245 {
246 log_error("Menuitem count per menu (%d) exceed limit (%d)\n", p_menu->item_count, MAX_ITEMS_PER_MENU);
247 return -1;
248 }
249 if (p_menu_set->menu_item_count >= MAX_MENUITEMS)
250 {
251 log_error("Menuitem count (%d) exceed limit (%d)\n", p_menu_set->menu_item_count, MAX_MENUITEMS);
252 return -3;
253 }
254 menu_item_id = (MENU_ITEM_ID)p_menu_set->menu_item_count;
255 p_menu_set->menu_item_count++;
256
257 p_menu->items[p_menu->item_count] = menu_item_id;
258 p_menu->item_count++;
259
260 p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
261
262 p_menu_item->submenu = (*p == '!' ? 1 : 0);
263
264 // Menu item action
265 p++;
266 if (strcmp(p, "..") == 0) // Return to parent menu
267 {
268 q = p + 2; // strlen("..")
269 }
270 else
271 {
272 q = p;
273 while (isalnum(*q) || *q == '_' || *q == '-')
274 {
275 q++;
276 }
277 if (*q != '\0')
278 {
279 log_error("Error menu item action in menu config line %d\n", fin_line);
280 return -1;
281 }
282 }
283
284 if (q - p > sizeof(p_menu_item->action) - 1)
285 {
286 log_error("Too longer menu action in menu config line %d\n", fin_line);
287 return -1;
288 }
289 strncpy(p_menu_item->action, p, sizeof(p_menu_item->action) - 1);
290 p_menu_item->action[sizeof(p_menu_item->action) - 1] = '\0';
291
292 // Menu item row
293 q = strtok_r(NULL, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
294 if (q == NULL)
295 {
296 log_error("Error menu item row in menu config line %d\n", fin_line);
297 return -1;
298 }
299 p = q;
300 while (isdigit(*q))
301 {
302 q++;
303 }
304 if (*q != '\0')
305 {
306 log_error("Error menu item row in menu config line %d\n", fin_line);
307 return -1;
308 }
309 p_menu_item->row = (int16_t)atoi(p);
310
311 // Menu item col
312 q = strtok_r(NULL, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
313 if (q == NULL)
314 {
315 log_error("Error menu item col in menu config line %d\n", fin_line);
316 return -1;
317 }
318 p = q;
319 while (isdigit(*q))
320 {
321 q++;
322 }
323 if (*q != '\0')
324 {
325 log_error("Error menu item col in menu config line %d\n", fin_line);
326 return -1;
327 }
328 p_menu_item->col = (int16_t)atoi(p);
329
330 // Menu item priv
331 q = strtok_r(NULL, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
332 if (q == NULL)
333 {
334 log_error("Error menu item priv in menu config line %d\n", fin_line);
335 return -1;
336 }
337 p = q;
338 while (isdigit(*q))
339 {
340 q++;
341 }
342 if (*q != '\0')
343 {
344 log_error("Error menu item priv in menu config line %d\n", fin_line);
345 return -1;
346 }
347 p_menu_item->priv = atoi(p);
348
349 // Menu item level
350 q = strtok_r(NULL, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
351 if (q == NULL)
352 {
353 log_error("Error menu item level in menu config line %d\n", fin_line);
354 return -1;
355 }
356 p = q;
357 while (isdigit(*q))
358 {
359 q++;
360 }
361 if (*q != '\0')
362 {
363 log_error("Error menu item level in menu config line %d\n", fin_line);
364 return -1;
365 }
366 p_menu_item->level = atoi(p);
367
368 // Menu item name
369 q = strtok_r(NULL, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
370 if (q == NULL || *q != '\"')
371 {
372 log_error("Error menu item name in menu config line %d\n", fin_line);
373 return -1;
374 }
375 q++;
376 p = q;
377 while (*q != '\0' && *q != '\"')
378 {
379 if (*q == '\\')
380 {
381 r = q;
382 while (*r != '\0')
383 {
384 *r = *(r + 1);
385 r++;
386 }
387 }
388 q++;
389 }
390 if (*q != '\"' || *(q + 1) != '\0')
391 {
392 log_error("Error menu item name in menu config line %d\n", fin_line);
393 return -1;
394 }
395 *q = '\0';
396
397 if (q - p > sizeof(p_menu_item->name) - 1)
398 {
399 log_error("Too longer menu name in menu config line %d\n", fin_line);
400 return -1;
401 }
402 strncpy(p_menu_item->name, p, sizeof(p_menu_item->name) - 1);
403 p_menu_item->name[sizeof(p_menu_item->name) - 1] = '\0';
404
405 // Menu item text
406 q = strtok_r(NULL, MENU_CONF_DELIM_WITHOUT_SPACE, &saveptr);
407 if (q == NULL || (q = strchr(q, '\"')) == NULL)
408 {
409 log_error("Error menu item text in menu config line %d\n", fin_line);
410 return -1;
411 }
412 q++;
413 p = q;
414 while (*q != '\0' && *q != '\"')
415 {
416 if (*q == '\\')
417 {
418 r = q;
419 while (*r != '\0')
420 {
421 *r = *(r + 1);
422 r++;
423 }
424 }
425 q++;
426 }
427 if (*q != '\"')
428 {
429 log_error("Error menu item text in menu config line %d\n", fin_line);
430 return -1;
431 }
432 *q = '\0';
433
434 if (q - p > sizeof(p_menu_item->text) - 1)
435 {
436 log_error("Too longer menu item text in menu config line %d\n", fin_line);
437 return -1;
438 }
439 strncpy(p_menu_item->text, p, sizeof(p_menu_item->text) - 1);
440 p_menu_item->text[sizeof(p_menu_item->text) - 1] = '\0';
441
442 // Check syntax
443 q = strtok_r(q + 1, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
444 if (q != NULL)
445 {
446 log_error("Unknown extra content in menu config line %d\n", fin_line);
447 return -1;
448 }
449 }
450 else if (strcmp(p, "title") == 0)
451 {
452 p_menu->title.show = 1;
453
454 // Menu title row
455 q = strtok_r(NULL, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
456 if (q == NULL)
457 {
458 log_error("Error menu title row in menu config line %d\n", fin_line);
459 return -1;
460 }
461 p = q;
462 while (isdigit(*q))
463 {
464 q++;
465 }
466 if (*q != '\0')
467 {
468 log_error("Error menu title row in menu config line %d\n", fin_line);
469 return -1;
470 }
471 p_menu->title.row = (int16_t)atoi(p);
472
473 // Menu title col
474 q = strtok_r(NULL, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
475 if (q == NULL)
476 {
477 log_error("Error menu title col in menu config line %d\n", fin_line);
478 return -1;
479 }
480 p = q;
481 while (isdigit(*q))
482 {
483 q++;
484 }
485 if (*q != '\0')
486 {
487 log_error("Error menu title col in menu config line %d\n", fin_line);
488 return -1;
489 }
490 p_menu->title.col = (int16_t)atoi(p);
491
492 // Menu title text
493 q = strtok_r(NULL, MENU_CONF_DELIM_WITHOUT_SPACE, &saveptr);
494 if (q == NULL || (q = strchr(q, '\"')) == NULL)
495 {
496 log_error("Error menu title text in menu config line %d\n", fin_line);
497 return -1;
498 }
499 q++;
500 p = q;
501 while (*q != '\0' && *q != '\"')
502 {
503 if (*q == '\\')
504 {
505 r = q;
506 while (*r != '\0')
507 {
508 *r = *(r + 1);
509 r++;
510 }
511 }
512 q++;
513 }
514 if (*q != '\"')
515 {
516 log_error("Error menu title text in menu config line %d\n", fin_line);
517 return -1;
518 }
519 *q = '\0';
520
521 if (q - p > sizeof(p_menu->title.text) - 1)
522 {
523 log_error("Too longer menu title text in menu config line %d\n", fin_line);
524 return -1;
525 }
526 strncpy(p_menu->title.text, p, sizeof(p_menu->title.text) - 1);
527 p_menu->title.text[sizeof(p_menu->title.text) - 1] = '\0';
528
529 // Check syntax
530 q = strtok_r(q + 1, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
531 if (q != NULL)
532 {
533 log_error("Unknown extra content in menu config line %d\n", fin_line);
534 return -1;
535 }
536 }
537 else if (strcmp(p, "screen") == 0)
538 {
539 p_menu->screen_show = 1;
540
541 // Menu screen row
542 q = strtok_r(NULL, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
543 if (q == NULL)
544 {
545 log_error("Error menu screen row in menu config line %d\n", fin_line);
546 return -1;
547 }
548 p = q;
549 while (isdigit(*q))
550 {
551 q++;
552 }
553 if (*q != '\0')
554 {
555 log_error("Error menu screen row in menu config line %d\n", fin_line);
556 return -1;
557 }
558 p_menu->screen_row = (int16_t)atoi(p);
559
560 // Menu screen col
561 q = strtok_r(NULL, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
562 if (q == NULL)
563 {
564 log_error("Error menu screen col in menu config line %d\n", fin_line);
565 return -1;
566 }
567 p = q;
568 while (isdigit(*q))
569 {
570 q++;
571 }
572 if (*q != '\0')
573 {
574 log_error("Error menu screen col in menu config line %d\n", fin_line);
575 return -1;
576 }
577 p_menu->screen_col = (int16_t)atoi(p);
578
579 // Menu screen name
580 q = strtok_r(NULL, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
581 if (q == NULL)
582 {
583 log_error("Error menu screen name in menu config line %d\n", fin_line);
584 return -1;
585 }
586 p = q;
587 while (isalnum(*q) || *q == '_' || *q == '-')
588 {
589 q++;
590 }
591 if (*q != '\0')
592 {
593 log_error("Error menu screen name in menu config line %d\n", fin_line);
594 return -1;
595 }
596 strncpy(p_menu->screen_name, p, sizeof(p_menu->screen_name) - 1);
597 p_menu->screen_name[sizeof(p_menu->screen_name) - 1] = '\0';
598
599 // Check syntax
600 q = strtok_r(NULL, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
601 if (q != NULL)
602 {
603 log_error("Unknown extra content in menu config line %d\n", fin_line);
604 return -1;
605 }
606 }
607 else if (strcmp(p, "page") == 0)
608 {
609 // Menu page row
610 q = strtok_r(NULL, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
611 if (q == NULL)
612 {
613 log_error("Error menu page row in menu config line %d\n", fin_line);
614 return -1;
615 }
616 p = q;
617 while (isdigit(*q))
618 {
619 q++;
620 }
621 if (*q != '\0')
622 {
623 log_error("Error menu page row in menu config line %d\n", fin_line);
624 return -1;
625 }
626 p_menu->page_row = (int16_t)atoi(p);
627
628 // Menu page col
629 q = strtok_r(NULL, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
630 if (q == NULL)
631 {
632 log_error("Error menu page col in menu config line %d\n", fin_line);
633 return -1;
634 }
635 p = q;
636 while (isdigit(*q))
637 {
638 q++;
639 }
640 if (*q != '\0')
641 {
642 log_error("Error menu page col in menu config line %d\n", fin_line);
643 return -1;
644 }
645 p_menu->page_col = (int16_t)atoi(p);
646
647 // Menu page item limit
648 q = strtok_r(NULL, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
649 if (q == NULL)
650 {
651 log_error("Error menu page item limit in menu config line %d\n", fin_line);
652 return -1;
653 }
654 p = q;
655 while (isdigit(*q))
656 {
657 q++;
658 }
659 if (*q != '\0')
660 {
661 log_error("Error menu page item limit in menu config line %d\n", fin_line);
662 return -1;
663 }
664 p_menu->page_item_limit = (int16_t)atoi(p);
665
666 // Check syntax
667 q = strtok_r(NULL, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
668 if (q != NULL)
669 {
670 log_error("Unknown extra content in menu config line %d\n", fin_line);
671 return -1;
672 }
673 }
674 else if (strcmp(p, "use_filter") == 0)
675 {
676 p_menu->use_filter = 1;
677
678 // Check syntax
679 q = strtok_r(NULL, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
680 if (q != NULL)
681 {
682 log_error("Unknown extra content in menu config line %d\n", fin_line);
683 return -1;
684 }
685 }
686 }
687 }
688 else // BEGIN of menu screen
689 {
690 if (p_menu_set->menu_item_count >= MAX_MENUS)
691 {
692 log_error("Menu screen count (%d) exceed limit (%d)\n", p_menu_set->menu_screen_count, MAX_MENUS);
693 return -3;
694 }
695 screen_id = (MENU_SCREEN_ID)p_menu_set->menu_screen_count;
696 p_menu_set->menu_screen_count++;
697
698 p_screen = get_menu_screen_by_id(p_menu_set, screen_id);
699
700 q = p;
701 while (isalnum(*q) || *q == '_' || *q == '-')
702 {
703 q++;
704 }
705 if (*q != '\0')
706 {
707 log_error("Error menu screen name in menu config line %d\n", fin_line);
708 return -1;
709 }
710 strncpy(p_screen->name, p, sizeof(p_screen->name) - 1);
711 p_screen->name[sizeof(p_screen->name) - 1] = '\0';
712
713 if (trie_dict_set(p_menu_set->p_menu_screen_dict, p_screen->name, (int64_t)screen_id) != 1)
714 {
715 log_error("Error set menu screen dict [%s]\n", p_screen->name);
716 }
717
718 // Check syntax
719 q = strtok_r(NULL, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
720 if (q != NULL)
721 {
722 log_error("Unknown extra content in menu config line %d\n", fin_line);
723 return -1;
724 }
725
726 p_screen->buf_offset = p_menu_set->p_menu_screen_buf_free - p_menu_set->p_menu_screen_buf;
727 p_screen->buf_length = -1;
728
729 // safety appending boundary
730 q = p_menu_set->p_menu_screen_buf + MAX_MENU_SCR_BUF_LENGTH * MAX_MENUS - 1;
731
732 while (fgets(buffer, sizeof(buffer), fin))
733 {
734 fin_line++;
735
736 strncpy(temp, buffer, sizeof(temp) - 1); // Duplicate line for strtok_r
737 temp[sizeof(temp) - 1] = '\0';
738 p = strtok_r(temp, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
739 if (p != NULL && *p == '%') // END of menu screen
740 {
741 if (p_menu_set->p_menu_screen_buf_free + 1 > q)
742 {
743 log_error("Menu screen buffer depleted (%p + 1 > %p)\n", p_menu_set->p_menu_screen_buf_free, q);
744 return -3;
745 }
746
747 *(p_menu_set->p_menu_screen_buf_free) = '\0';
748 p_menu_set->p_menu_screen_buf_free++;
749 p_screen->buf_length = p_menu_set->p_menu_screen_buf_free - p_menu_set->p_menu_screen_buf - p_screen->buf_offset;
750 break;
751 }
752
753 // Clear line
754 if (p_menu_set->p_menu_screen_buf_free + strlen(CTRL_SEQ_CLR_LINE) > q)
755 {
756 log_error("Menu screen buffer depleted (%p + %d > %p)\n", p_menu_set->p_menu_screen_buf_free, q, strlen(CTRL_SEQ_CLR_LINE));
757 return -3;
758 }
759 p_menu_set->p_menu_screen_buf_free = stpcpy(p_menu_set->p_menu_screen_buf_free, CTRL_SEQ_CLR_LINE);
760
761 p = buffer;
762 while (*p != '\0')
763 {
764 if (p_menu_set->p_menu_screen_buf_free + 2 > q)
765 {
766 log_error("Menu screen buffer depleted (%p + 2 > %p)\n", p_menu_set->p_menu_screen_buf_free, q);
767 return -3;
768 }
769
770 if (*p == '\n' && p > buffer && *(p - 1) != '\r')
771 {
772 *(p_menu_set->p_menu_screen_buf_free) = '\r';
773 p_menu_set->p_menu_screen_buf_free++;
774 }
775
776 *(p_menu_set->p_menu_screen_buf_free) = *p;
777 p++;
778 p_menu_set->p_menu_screen_buf_free++;
779 }
780 }
781
782 if (p_screen->buf_length == -1)
783 {
784 log_error("End of menu screen [%s] not found\n", p_screen->name);
785 }
786 }
787 }
788 else // Invalid prefix
789 {
790 log_error("Error in menu config line %d\n", fin_line);
791 return -1;
792 }
793 }
794 fclose(fin);
795
796 for (menu_id = 0; menu_id < p_menu_set->menu_count; menu_id++)
797 {
798 p_menu = get_menu_by_id(p_menu_set, menu_id);
799
800 if (trie_dict_get(p_menu_set->p_menu_screen_dict, p_menu->screen_name, (int64_t *)(&(p_menu->screen_id))) != 1)
801 {
802 log_error("Undefined menu screen [%s]\n", p);
803 return -1;
804 }
805
806 // Set menu->filter_handler of each menu pointing to filter
807 if (p_menu->use_filter == 1)
808 {
809 if ((p_menu->filter_handler = get_cmd_handler(p_menu->name)) == NULL)
810 {
811 log_error("Undefined menu filter handler [%s]\n", p_menu->name);
812 return -1;
813 }
814 }
815 }
816
817 for (menu_item_id = 0; menu_item_id < p_menu_set->menu_item_count; menu_item_id++)
818 {
819 p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
820
821 // Set menu_item->action_cmd_handler of each menu item pointing to bbs_cmd
822 if (p_menu_item->submenu == 0)
823 {
824 if ((p_menu_item->action_cmd_handler = get_cmd_handler(p_menu_item->action)) == NULL)
825 {
826 log_error("Undefined menu action cmd handler [%s]\n", p_menu_item->action);
827 return -1;
828 }
829 }
830 // Set menu_item->action_menu_id of each menu item pointing to a submenu to the menu_id of the corresponding submenu
831 else if (strcmp(p_menu_item->action, "..") != 0)
832 {
833 if (trie_dict_get(p_menu_set->p_menu_name_dict, p_menu_item->action, (int64_t *)&menu_id) != 1)
834 {
835 log_error("Undefined sub menu id [%s]\n", p_menu_item->action);
836 return -1;
837 }
838 p_menu_item->action_menu_id = menu_id;
839 }
840 }
841
842 // Save status varaibles into reserved memory area
843 *((int16_t *)p_menu_set->p_reserved) = p_menu_set->menu_count;
844 *(((int16_t *)p_menu_set->p_reserved) + 1) = p_menu_set->menu_item_count;
845 *(((int16_t *)p_menu_set->p_reserved) + 2) = p_menu_set->menu_screen_count;
846
847 return 0;
848 }
849
850 int display_menu_cursor(MENU_SET *p_menu_set, int show)
851 {
852 MENU_ID menu_id;
853 MENU_ITEM_ID menu_item_id;
854 MENU *p_menu;
855 MENU_ITEM *p_menu_item;
856 int16_t menu_item_pos;
857
858 menu_id = p_menu_set->menu_id_path[p_menu_set->choose_step];
859 p_menu = get_menu_by_id(p_menu_set, menu_id);
860 if (p_menu == NULL)
861 {
862 log_error("get_menu_by_id(%d) return NULL pointer\n", menu_id);
863 return -1;
864 }
865
866 menu_item_pos = p_menu_set->menu_item_pos[p_menu_set->choose_step];
867 menu_item_id = p_menu->items[menu_item_pos];
868 p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
869 if (p_menu_item == NULL)
870 {
871 log_error("get_menu_item_by_id(%d) return NULL pointer\n", menu_item_id);
872 return -1;
873 }
874
875 moveto(p_menu_set->menu_item_r_row[menu_item_pos], p_menu_set->menu_item_r_col[menu_item_pos] - 2);
876 outc(show ? '>' : ' ');
877
878 return 0;
879 }
880
881 static int display_menu_current_page(MENU_SET *p_menu_set)
882 {
883 int16_t row = 0;
884 int16_t col = 0;
885 MENU_ID menu_id;
886 MENU_ITEM_ID menu_item_id;
887 MENU *p_menu;
888 MENU_ITEM *p_menu_item;
889 int16_t menu_item_pos;
890 int16_t page_id = 0;
891 MENU_SCREEN *p_menu_screen;
892
893 menu_id = p_menu_set->menu_id_path[p_menu_set->choose_step];
894 p_menu = get_menu_by_id(p_menu_set, menu_id);
895 if (p_menu == NULL)
896 {
897 log_error("get_menu_by_id(%d) return NULL pointer\n", menu_id);
898 return -1;
899 }
900
901 clrline(p_menu->page_row, p_menu->page_row + p_menu->page_item_limit - 1);
902
903 if (p_menu->title.show)
904 {
905 if (p_menu->title.row == 0 && p_menu->title.col == 0)
906 {
907 show_top(p_menu->title.text, BBS_name, "");
908 }
909 else
910 {
911 moveto(p_menu->title.row, p_menu->title.col);
912 prints("%s", p_menu->title.text);
913 }
914 }
915
916 if (p_menu->screen_show)
917 {
918 p_menu_screen = get_menu_screen_by_id(p_menu_set, p_menu->screen_id);
919 if (p_menu_screen == NULL)
920 {
921 log_error("get_menu_screen_by_id(%d) return NULL pointer\n", p_menu->screen_id);
922 return -1;
923 }
924
925 row = p_menu->screen_row;
926 col = p_menu->screen_col;
927
928 moveto(row, col);
929 prints("%s", p_menu_set->p_menu_screen_buf + p_menu_screen->buf_offset);
930 }
931
932 menu_item_pos = p_menu_set->menu_item_pos[p_menu_set->choose_step];
933 page_id = p_menu_set->menu_item_page_id[menu_item_pos];
934
935 while (menu_item_pos >= 0)
936 {
937 if (p_menu_set->menu_item_page_id[menu_item_pos] != page_id)
938 {
939 menu_item_pos++;
940 break;
941 }
942
943 if (menu_item_pos == 0)
944 {
945 break;
946 }
947
948 menu_item_pos--;
949 }
950
951 for (; menu_item_pos < p_menu->item_count; menu_item_pos++)
952 {
953 if (p_menu_set->menu_item_page_id[menu_item_pos] != page_id)
954 {
955 break;
956 }
957
958 menu_item_id = p_menu->items[menu_item_pos];
959 p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
960
961 if (p_menu_set->menu_item_display[menu_item_pos] == 0)
962 {
963 continue;
964 }
965
966 row = p_menu_set->menu_item_r_row[menu_item_pos];
967 col = p_menu_set->menu_item_r_col[menu_item_pos];
968
969 moveto(row, col);
970 prints("%s", p_menu_item->text);
971 }
972
973 return 0;
974 }
975
976 int display_menu(MENU_SET *p_menu_set)
977 {
978 int16_t row = 0;
979 int16_t col = 0;
980 int menu_selectable = 0;
981 MENU_ID menu_id;
982 MENU_ITEM_ID menu_item_id;
983 MENU *p_menu;
984 MENU_ITEM *p_menu_item;
985 int16_t menu_item_pos;
986 int16_t page_id = 0;
987 int page_item_count = 0;
988
989 menu_id = p_menu_set->menu_id_path[p_menu_set->choose_step];
990 p_menu = get_menu_by_id(p_menu_set, menu_id);
991 if (p_menu == NULL)
992 {
993 log_error("get_menu_by_id(%d) return NULL pointer\n", menu_id);
994 if (p_menu_set->choose_step > 0)
995 {
996 p_menu_set->choose_step--;
997 return REDRAW;
998 }
999 return EXITMENU;
1000 }
1001
1002 if (p_menu->item_count <= 0) // empty menu
1003 {
1004 moveto(p_menu->screen_row, p_menu->screen_col);
1005 clrtoeol();
1006 prints("没有可选项");
1007 press_any_key();
1008 return -1;
1009 }
1010
1011 menu_item_pos = p_menu_set->menu_item_pos[p_menu_set->choose_step];
1012 menu_item_id = p_menu->items[menu_item_pos];
1013 p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
1014 if (p_menu_item == NULL)
1015 {
1016 log_error("get_menu_item_by_id(%d) return NULL pointer\n", menu_item_id);
1017 return EXITMENU;
1018 }
1019
1020 if (menu_item_pos > 0 &&
1021 !(p_menu->use_filter ? (p_menu->filter_handler((void *)p_menu_item) == 0)
1022 : (checkpriv(&BBS_priv, 0, p_menu_item->priv) == 0 ||
1023 checklevel2(&BBS_priv, p_menu_item->level) == 0)))
1024 {
1025 menu_selectable = 1;
1026 }
1027
1028 for (menu_item_pos = 0; menu_item_pos < p_menu->item_count; menu_item_pos++)
1029 {
1030 menu_item_id = p_menu->items[menu_item_pos];
1031 p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
1032
1033 if (p_menu_item->row != 0)
1034 {
1035 row = p_menu_item->row;
1036 }
1037 if (p_menu_item->col != 0)
1038 {
1039 col = p_menu_item->col;
1040 }
1041
1042 p_menu_set->menu_item_page_id[menu_item_pos] = page_id;
1043
1044 if (p_menu->use_filter ? (p_menu->filter_handler((void *)p_menu_item) == 0)
1045 : (checkpriv(&BBS_priv, 0, p_menu_item->priv) == 0 ||
1046 checklevel2(&BBS_priv, p_menu_item->level) == 0))
1047 {
1048 p_menu_set->menu_item_display[menu_item_pos] = 0;
1049 p_menu_set->menu_item_r_row[menu_item_pos] = 0;
1050 p_menu_set->menu_item_r_col[menu_item_pos] = 0;
1051 }
1052 else
1053 {
1054 p_menu_set->menu_item_display[menu_item_pos] = 1;
1055
1056 if (!menu_selectable)
1057 {
1058 p_menu_set->menu_item_pos[p_menu_set->choose_step] = menu_item_pos;
1059 menu_selectable = 1;
1060 }
1061
1062 p_menu_set->menu_item_r_row[menu_item_pos] = row;
1063 p_menu_set->menu_item_r_col[menu_item_pos] = col;
1064
1065 row++;
1066
1067 page_item_count++;
1068 if (p_menu->page_item_limit > 0 && page_item_count >= p_menu->page_item_limit)
1069 {
1070 page_id++;
1071 page_item_count = 0;
1072 row = p_menu->page_row;
1073 col = p_menu->page_col;
1074 }
1075 }
1076 }
1077
1078 if (!menu_selectable)
1079 {
1080 moveto(p_menu->screen_row, p_menu->screen_col);
1081 clrtoeol();
1082 prints("没有可选项");
1083 press_any_key();
1084 return -1;
1085 }
1086
1087 if (display_menu_current_page(p_menu_set) != 0)
1088 {
1089 return -1;
1090 }
1091
1092 display_menu_cursor(p_menu_set, 1);
1093
1094 return 0;
1095 }
1096
1097 int menu_control(MENU_SET *p_menu_set, int key)
1098 {
1099 MENU_ID menu_id;
1100 MENU_ITEM_ID menu_item_id;
1101 MENU *p_menu;
1102 MENU_ITEM *p_menu_item;
1103 int16_t menu_item_pos;
1104 int16_t page_id;
1105 int require_page_change = 0;
1106
1107 if (p_menu_set->menu_count == 0)
1108 {
1109 log_error("Empty menu set\n");
1110 return EXITBBS;
1111 }
1112
1113 menu_id = p_menu_set->menu_id_path[p_menu_set->choose_step];
1114 p_menu = get_menu_by_id(p_menu_set, menu_id);
1115 if (p_menu == NULL)
1116 {
1117 log_error("get_menu_by_id(%d) return NULL pointer\n", menu_id);
1118 if (p_menu_set->choose_step > 0)
1119 {
1120 p_menu_set->choose_step--;
1121 return REDRAW;
1122 }
1123 return EXITBBS;
1124 }
1125
1126 if (p_menu->item_count == 0)
1127 {
1128 #ifdef _DEBUG
1129 log_error("Empty menu (%s)\n", p_menu->name);
1130 #endif
1131 if (p_menu_set->choose_step > 0)
1132 {
1133 p_menu_set->choose_step--;
1134 return REDRAW;
1135 }
1136 return EXITBBS;
1137 }
1138
1139 menu_item_pos = p_menu_set->menu_item_pos[p_menu_set->choose_step];
1140 page_id = p_menu_set->menu_item_page_id[menu_item_pos];
1141
1142 menu_item_id = p_menu->items[menu_item_pos];
1143 p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
1144 if (p_menu_item == NULL)
1145 {
1146 log_error("get_menu_item_by_id(%d) return NULL pointer\n", menu_item_id);
1147 p_menu_set->menu_item_pos[p_menu_set->choose_step] = 0;
1148 return REDRAW;
1149 }
1150
1151 switch (key)
1152 {
1153 case CR:
1154 case KEY_RIGHT:
1155 if (p_menu_item->submenu)
1156 {
1157 if (strcmp(p_menu_item->action, "..") == 0)
1158 {
1159 return menu_control(p_menu_set, KEY_LEFT);
1160 }
1161 p_menu_set->choose_step++;
1162 p_menu_set->menu_id_path[p_menu_set->choose_step] = p_menu_item->action_menu_id;
1163 p_menu_set->menu_item_pos[p_menu_set->choose_step] = 0;
1164
1165 if (display_menu(p_menu_set) != 0)
1166 {
1167 return menu_control(p_menu_set, KEY_LEFT);
1168 }
1169 }
1170 else
1171 {
1172 return ((*(p_menu_item->action_cmd_handler))((void *)(p_menu_item->name)));
1173 }
1174 break;
1175 case KEY_ESC:
1176 case KEY_LEFT:
1177 if (p_menu_set->choose_step > 0)
1178 {
1179 p_menu_set->choose_step--;
1180 return REDRAW;
1181 }
1182 else
1183 {
1184 if (p_menu_set->allow_exit)
1185 {
1186 return EXITMENU;
1187 }
1188
1189 display_menu_cursor(p_menu_set, 0);
1190 menu_item_pos = p_menu->item_count - 1;
1191 while (menu_item_pos >= 0)
1192 {
1193 menu_item_id = p_menu->items[menu_item_pos];
1194 p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
1195 if (p_menu_item == NULL)
1196 {
1197 log_error("get_menu_item_by_id(%d) return NULL pointer\n", menu_item_id);
1198 return -1;
1199 }
1200
1201 if (!p_menu_set->menu_item_display[menu_item_pos] || p_menu_item->priv != 0 || p_menu_item->level != 0)
1202 {
1203 menu_item_pos--;
1204 }
1205 else
1206 {
1207 break;
1208 }
1209 }
1210 p_menu_set->menu_item_pos[p_menu_set->choose_step] = menu_item_pos;
1211 display_menu_cursor(p_menu_set, 1);
1212 }
1213 break;
1214 case KEY_PGUP:
1215 require_page_change = 1;
1216 case KEY_UP:
1217 display_menu_cursor(p_menu_set, 0);
1218 do
1219 {
1220 menu_item_pos--;
1221 if (menu_item_pos < 0)
1222 {
1223 menu_item_pos = p_menu->item_count - 1;
1224 require_page_change = 0;
1225 }
1226 menu_item_id = p_menu->items[menu_item_pos];
1227 p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
1228 if (p_menu_item == NULL)
1229 {
1230 log_error("get_menu_item_by_id(%d) return NULL pointer\n", menu_item_id);
1231 return -1;
1232 }
1233 if (require_page_change && p_menu_set->menu_item_page_id[menu_item_pos] != page_id)
1234 {
1235 require_page_change = 0;
1236 }
1237 } while (require_page_change || !p_menu_set->menu_item_display[menu_item_pos]);
1238 p_menu_set->menu_item_pos[p_menu_set->choose_step] = menu_item_pos;
1239 if (p_menu_set->menu_item_page_id[menu_item_pos] != page_id)
1240 {
1241 display_menu_current_page(p_menu_set);
1242 }
1243 display_menu_cursor(p_menu_set, 1);
1244 break;
1245 case KEY_PGDN:
1246 require_page_change = 1;
1247 case KEY_DOWN:
1248 display_menu_cursor(p_menu_set, 0);
1249 do
1250 {
1251 menu_item_pos++;
1252 if (menu_item_pos >= p_menu->item_count)
1253 {
1254 menu_item_pos = 0;
1255 require_page_change = 0;
1256 }
1257 menu_item_id = p_menu->items[menu_item_pos];
1258 p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
1259 if (p_menu_item == NULL)
1260 {
1261 log_error("get_menu_item_by_id(%d) return NULL pointer\n", menu_item_id);
1262 return -1;
1263 }
1264 if (require_page_change && p_menu_set->menu_item_page_id[menu_item_pos] != page_id)
1265 {
1266 require_page_change = 0;
1267 }
1268 } while (require_page_change || !p_menu_set->menu_item_display[menu_item_pos]);
1269 p_menu_set->menu_item_pos[p_menu_set->choose_step] = menu_item_pos;
1270 if (p_menu_set->menu_item_page_id[menu_item_pos] != page_id)
1271 {
1272 display_menu_current_page(p_menu_set);
1273 }
1274 display_menu_cursor(p_menu_set, 1);
1275 break;
1276 case KEY_HOME:
1277 display_menu_cursor(p_menu_set, 0);
1278 menu_item_pos = 0;
1279 while (menu_item_pos < p_menu->item_count - 1)
1280 {
1281 menu_item_id = p_menu->items[menu_item_pos];
1282 p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
1283 if (p_menu_item == NULL)
1284 {
1285 log_error("get_menu_item_by_id(%d) return NULL pointer\n", menu_item_id);
1286 return -1;
1287 }
1288
1289 if (p_menu_set->menu_item_display[menu_item_pos])
1290 {
1291 break;
1292 }
1293
1294 menu_item_pos++;
1295 }
1296 p_menu_set->menu_item_pos[p_menu_set->choose_step] = menu_item_pos;
1297 if (p_menu_set->menu_item_page_id[menu_item_pos] != page_id)
1298 {
1299 display_menu_current_page(p_menu_set);
1300 }
1301 display_menu_cursor(p_menu_set, 1);
1302 break;
1303 case KEY_END:
1304 display_menu_cursor(p_menu_set, 0);
1305 menu_item_pos = p_menu->item_count - 1;
1306 while (menu_item_pos > 0)
1307 {
1308 menu_item_id = p_menu->items[menu_item_pos];
1309 p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
1310 if (p_menu_item == NULL)
1311 {
1312 log_error("get_menu_item_by_id(%d) return NULL pointer\n", menu_item_id);
1313 return -1;
1314 }
1315
1316 if (p_menu_set->menu_item_display[menu_item_pos])
1317 {
1318 break;
1319 }
1320
1321 menu_item_pos--;
1322 }
1323 p_menu_set->menu_item_pos[p_menu_set->choose_step] = menu_item_pos;
1324 if (p_menu_set->menu_item_page_id[menu_item_pos] != page_id)
1325 {
1326 display_menu_current_page(p_menu_set);
1327 }
1328 display_menu_cursor(p_menu_set, 1);
1329 break;
1330 default:
1331 if (isalnum(key))
1332 {
1333 for (menu_item_pos = 0; menu_item_pos < p_menu->item_count; menu_item_pos++)
1334 {
1335 menu_item_id = p_menu->items[menu_item_pos];
1336 p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
1337 if (p_menu_item == NULL)
1338 {
1339 log_error("get_menu_item_by_id(%d) return NULL pointer\n", menu_item_id);
1340 return -1;
1341 }
1342
1343 if (toupper(key) == toupper(p_menu_item->name[0]) && p_menu_set->menu_item_display[menu_item_pos])
1344 {
1345 display_menu_cursor(p_menu_set, 0);
1346 p_menu_set->menu_item_pos[p_menu_set->choose_step] = menu_item_pos;
1347 if (p_menu_set->menu_item_page_id[menu_item_pos] != page_id)
1348 {
1349 display_menu_current_page(p_menu_set);
1350 }
1351 display_menu_cursor(p_menu_set, 1);
1352 break;
1353 }
1354 }
1355 }
1356 break;
1357 }
1358
1359 return NOREDRAW;
1360 }
1361
1362 int unload_menu(MENU_SET *p_menu_set)
1363 {
1364 int shmid;
1365
1366 if (p_menu_set == NULL)
1367 {
1368 return -1;
1369 }
1370
1371 if (p_menu_set->p_menu_name_dict != NULL)
1372 {
1373 trie_dict_destroy(p_menu_set->p_menu_name_dict);
1374 p_menu_set->p_menu_name_dict = NULL;
1375 }
1376
1377 if (p_menu_set->p_menu_screen_dict != NULL)
1378 {
1379 trie_dict_destroy(p_menu_set->p_menu_screen_dict);
1380 p_menu_set->p_menu_screen_dict = NULL;
1381 }
1382
1383 shmid = p_menu_set->shmid;
1384
1385 detach_menu_shm(p_menu_set);
1386
1387 if (shmctl(shmid, IPC_RMID, NULL) == -1)
1388 {
1389 log_error("shmctl(shmid=%d, IPC_RMID) error (%d)\n", shmid, errno);
1390 return -1;
1391 }
1392
1393 return 0;
1394 }
1395
1396 int get_menu_shm_readonly(MENU_SET *p_menu_set)
1397 {
1398 void *p_shm;
1399
1400 p_shm = shmat(p_menu_set->shmid, NULL, SHM_RDONLY);
1401 if (p_shm == (void *)-1)
1402 {
1403 log_error("shmat(menu_shm shmid = %d) error (%d)\n", p_menu_set->shmid, errno);
1404 return -1;
1405 }
1406
1407 p_menu_set->p_reserved = p_shm;
1408 p_menu_set->p_menu_pool = (char *)(p_menu_set->p_reserved) + MENU_SET_RESERVED_LENGTH;
1409 p_menu_set->p_menu_item_pool = (char *)(p_menu_set->p_menu_pool) + sizeof(MENU) * MAX_MENUS;
1410 p_menu_set->p_menu_screen_pool = (char *)(p_menu_set->p_menu_item_pool) + sizeof(MENU_ITEM) * MAX_MENUITEMS;
1411 p_menu_set->p_menu_screen_buf = (char *)(p_menu_set->p_menu_screen_pool) + sizeof(MENU_SCREEN) * MAX_MENUS;
1412 p_menu_set->p_menu_screen_buf_free = p_menu_set->p_menu_screen_buf;
1413
1414 p_menu_set->choose_step = 0;
1415 p_menu_set->menu_id_path[0] = 0;
1416 p_menu_set->menu_item_pos[0] = 0;
1417
1418 return 0;
1419 }
1420
1421 int set_menu_shm_readonly(MENU_SET *p_menu_set)
1422 {
1423 void *p_shm;
1424
1425 // Remap shared memory in read-only mode
1426 p_shm = shmat(p_menu_set->shmid, p_menu_set->p_reserved, SHM_RDONLY | SHM_REMAP);
1427 if (p_shm == (void *)-1)
1428 {
1429 log_error("shmat(menu_shm shmid = %d) error (%d)\n", p_menu_set->shmid, errno);
1430 return -1;
1431 }
1432
1433 p_menu_set->p_reserved = p_shm;
1434
1435 return 0;
1436 }
1437
1438 int detach_menu_shm(MENU_SET *p_menu_set)
1439 {
1440 p_menu_set->menu_count = 0;
1441 p_menu_set->menu_item_count = 0;
1442 p_menu_set->menu_screen_count = 0;
1443 p_menu_set->choose_step = 0;
1444
1445 p_menu_set->p_menu_pool = NULL;
1446 p_menu_set->p_menu_item_pool = NULL;
1447 p_menu_set->p_menu_screen_pool = NULL;
1448 p_menu_set->p_menu_screen_buf = NULL;
1449 p_menu_set->p_menu_screen_buf_free = NULL;
1450
1451 p_menu_set->p_menu_name_dict = NULL;
1452 p_menu_set->p_menu_screen_dict = NULL;
1453
1454 if (p_menu_set->p_reserved != NULL && shmdt(p_menu_set->p_reserved) == -1)
1455 {
1456 log_error("shmdt() error (%d)\n", errno);
1457 return -1;
1458 }
1459
1460 p_menu_set->p_reserved = NULL;
1461
1462 return 0;
1463 }

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