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

Contents of /lbbs/src/menu.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.85 - (show annotations)
Tue Nov 11 00:28:05 2025 UTC (4 months ago) by sysadm
Branch: MAIN
Changes since 1.84: +4 -0 lines
Content type: text/x-csrc
Use config.h

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

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