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

Contents of /lbbs/src/menu.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.84 - (show annotations)
Wed Nov 5 04:19:21 2025 UTC (4 months, 1 week ago) by sysadm
Branch: MAIN
Changes since 1.83: +7 -6 lines
Content type: text/x-csrc
Use enum / const int instead of macro define constant integers
Use const char * instead of macro define for constant strings

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

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