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

Contents of /lbbs/src/menu.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.96 - (show annotations)
Fri Feb 13 12:38:09 2026 UTC (4 weeks, 4 days ago) by sysadm
Branch: MAIN
CVS Tags: HEAD
Changes since 1.95: +6 -0 lines
Content type: text/x-csrc
Fix build error caused by inline function under Debug mode with CMake

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

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