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

Contents of /lbbs/src/menu.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.77 - (show annotations)
Wed Oct 29 05:30:05 2025 UTC (4 months, 2 weeks ago) by sysadm
Branch: MAIN
Changes since 1.76: +34 -14 lines
Content type: text/x-csrc
Retry shmget() several times to skip conflict keys

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

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