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

Contents of /lbbs/src/menu.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.47 - (show annotations)
Sun May 18 08:53:21 2025 UTC (10 months ago) by sysadm
Branch: MAIN
Changes since 1.46: +21 -6 lines
Content type: text/x-csrc
Refine menu: clear screen lines before output
Truncate blank lines in menu config

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 "user_priv.h"
20 #include "bbs_cmd.h"
21 #include "menu.h"
22 #include "log.h"
23 #include "io.h"
24 #include "screen.h"
25 #include "common.h"
26 #include <string.h>
27 #include <stdio.h>
28 #include <ctype.h>
29 #include <stdlib.h>
30 #include <errno.h>
31 #include <unistd.h>
32 #include <sys/shm.h>
33 #include <sys/ipc.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 MENU_SET *p_bbs_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 *saveptr = NULL;
52 MENU *p_menu = NULL;
53 MENU_ITEM *p_menu_item = NULL;
54 MENU_SCREEN *p_screen = NULL;
55 MENU_ID menu_id;
56 MENU_ITEM_ID menu_item_id;
57 MENU_SCREEN_ID screen_id;
58 int proj_id;
59 key_t key;
60 size_t size;
61
62 // Use trie_dict to search menu_id by menu name
63 p_menu_set->p_menu_name_dict = trie_dict_create();
64 if (p_menu_set->p_menu_name_dict == NULL)
65 {
66 log_error("trie_dict_create() error\n");
67 return -3;
68 }
69
70 // Use trie_dict to search screen_id by menu screen name
71 p_menu_set->p_menu_screen_dict = trie_dict_create();
72 if (p_menu_set->p_menu_screen_dict == NULL)
73 {
74 log_error("trie_dict_create() error\n");
75 return -3;
76 }
77
78 if ((fin = fopen(conf_file, "r")) == NULL)
79 {
80 log_error("Open %s failed", conf_file);
81 return -2;
82 }
83
84 // Allocate shared memory
85 proj_id = (int)(time(NULL) % getpid());
86 key = ftok(conf_file, proj_id);
87 if (key == -1)
88 {
89 log_error("ftok(%s %d) error (%d)\n", conf_file, proj_id, errno);
90 return -2;
91 }
92
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 p_menu_set->shmid = shmget(key, size, IPC_CREAT | IPC_EXCL | 0600);
99 if (p_menu_set->shmid == -1)
100 {
101 log_error("shmget(size = %d) error (%d)\n", size, errno);
102 return -3;
103 }
104 p_menu_set->p_reserved = shmat(p_menu_set->shmid, NULL, 0);
105 if (p_menu_set->p_reserved == (void *)-1)
106 {
107 log_error("shmat() error (%d)\n", errno);
108 return -3;
109 }
110 p_menu_set->p_menu_pool = p_menu_set->p_reserved + MENU_SET_RESERVED_LENGTH;
111 p_menu_set->p_menu_item_pool = p_menu_set->p_menu_pool + sizeof(MENU) * MAX_MENUS;
112 p_menu_set->p_menu_screen_pool = p_menu_set->p_menu_item_pool + sizeof(MENU_ITEM) * MAX_MENUITEMS;
113 p_menu_set->p_menu_screen_buf = p_menu_set->p_menu_screen_pool + sizeof(MENU_SCREEN) * MAX_MENUS;
114 p_menu_set->p_menu_screen_buf_free = p_menu_set->p_menu_screen_buf;
115
116 p_menu_set->menu_count = 0;
117 p_menu_set->menu_item_count = 0;
118 p_menu_set->menu_screen_count = 0;
119 p_menu_set->choose_step = 0;
120 p_menu_set->menu_id_path[0] = 0;
121
122 while (fgets(buffer, sizeof(buffer), fin))
123 {
124 fin_line++;
125
126 p = strtok_r(buffer, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
127 if (p == NULL) // Blank line
128 {
129 continue;
130 }
131
132 if (*p == '#' || *p == '\r' || *p == '\n') // Comment or blank line
133 {
134 continue;
135 }
136
137 if (*p == '%')
138 {
139 p++;
140
141 if (strcmp(p, "menu") == 0) // BEGIN of sub-menu
142 {
143 if (p_menu != NULL)
144 {
145 log_error("Incomplete menu definition in menu config line %d\n", fin_line);
146 return -1;
147 }
148
149 if (p_menu_set->menu_count >= MAX_MENUS)
150 {
151 log_error("Menu count (%d) exceed limit (%d)\n", p_menu_set->menu_count, MAX_MENUS);
152 return -3;
153 }
154 menu_id = (MENU_ID)p_menu_set->menu_count;
155 p_menu_set->menu_count++;
156
157 p_menu = get_menu_by_id(p_menu_set, menu_id);
158
159 p_menu->item_count = 0;
160 p_menu->title.show = 0;
161 p_menu->screen_show = 0;
162
163 q = strtok_r(NULL, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
164 if (q == NULL)
165 {
166 log_error("Error menu name in menu config line %d\n", fin_line);
167 return -1;
168 }
169 p = q;
170 while (isalnum(*q) || *q == '_')
171 {
172 q++;
173 }
174 if (*q != '\0')
175 {
176 log_error("Error menu name in menu config line %d\n", fin_line);
177 return -1;
178 }
179
180 if (q - p > sizeof(p_menu->name) - 1)
181 {
182 log_error("Too longer menu name in menu config line %d\n", fin_line);
183 return -1;
184 }
185 strncpy(p_menu->name, p, sizeof(p_menu->name) - 1);
186 p_menu->name[sizeof(p_menu->name) - 1] = '\0';
187
188 if (trie_dict_set(p_menu_set->p_menu_name_dict, p_menu->name, (int64_t)menu_id) != 1)
189 {
190 log_error("Error set menu dict [%s]\n", p_menu->name);
191 }
192
193 // Check syntax
194 q = strtok_r(NULL, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
195 if (q != NULL)
196 {
197 log_error("Unknown extra content in menu config line %d\n", fin_line);
198 return -1;
199 }
200
201 while (fgets(buffer, sizeof(buffer), fin))
202 {
203 fin_line++;
204
205 p = strtok_r(buffer, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
206 if (p == NULL) // Blank line
207 {
208 continue;
209 }
210
211 if (*p == '#' || *p == '\r' || *p == '\n') // Comment or blank line
212 {
213 continue;
214 }
215
216 if (*p == '%') // END of sub-menu
217 {
218 p_menu = NULL;
219 break;
220 }
221 else if (*p == '!' || *p == '@')
222 {
223 // BEGIN of menu item
224 if (p_menu->item_count >= MAX_ITEMS_PER_MENU)
225 {
226 log_error("Menuitem count per menu (%d) exceed limit (%d)\n", p_menu->item_count, MAX_ITEMS_PER_MENU);
227 return -1;
228 }
229 if (p_menu_set->menu_item_count >= MAX_MENUITEMS)
230 {
231 log_error("Menuitem count (%d) exceed limit (%d)\n", p_menu_set->menu_item_count, MAX_MENUITEMS);
232 return -3;
233 }
234 menu_item_id = (MENU_ITEM_ID)p_menu_set->menu_item_count;
235 p_menu_set->menu_item_count++;
236
237 p_menu->items[p_menu->item_count] = menu_item_id;
238 p_menu->item_count++;
239
240 p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
241
242 p_menu_item->submenu = (*p == '!' ? 1 : 0);
243
244 // Menu item action
245 p++;
246 if (strcmp(p, "..") == 0) // Return to parent menu
247 {
248 q = p + 2; // strlen("..")
249 }
250 else
251 {
252 q = p;
253 while (isalnum(*q) || *q == '_')
254 {
255 q++;
256 }
257 if (*q != '\0')
258 {
259 log_error("Error menu item action in menu config line %d\n", fin_line);
260 return -1;
261 }
262 }
263
264 if (q - p > sizeof(p_menu_item->action) - 1)
265 {
266 log_error("Too longer menu action in menu config line %d\n", fin_line);
267 return -1;
268 }
269 strncpy(p_menu_item->action, p, sizeof(p_menu_item->action) - 1);
270 p_menu_item->action[sizeof(p_menu_item->action) - 1] = '\0';
271
272 // Menu item row
273 q = strtok_r(NULL, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
274 if (q == NULL)
275 {
276 log_error("Error menu item row in menu config line %d\n", fin_line);
277 return -1;
278 }
279 p = q;
280 while (isdigit(*q))
281 {
282 q++;
283 }
284 if (*q != '\0')
285 {
286 log_error("Error menu item row in menu config line %d\n", fin_line);
287 return -1;
288 }
289 p_menu_item->row = (int16_t)atoi(p);
290
291 // Menu item col
292 q = strtok_r(NULL, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
293 if (q == NULL)
294 {
295 log_error("Error menu item col in menu config line %d\n", fin_line);
296 return -1;
297 }
298 p = q;
299 while (isdigit(*q))
300 {
301 q++;
302 }
303 if (*q != '\0')
304 {
305 log_error("Error menu item col in menu config line %d\n", fin_line);
306 return -1;
307 }
308 p_menu_item->col = (int16_t)atoi(p);
309
310 // Menu item priv
311 q = strtok_r(NULL, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
312 if (q == NULL)
313 {
314 log_error("Error menu item priv in menu config line %d\n", fin_line);
315 return -1;
316 }
317 p = q;
318 while (isdigit(*q))
319 {
320 q++;
321 }
322 if (*q != '\0')
323 {
324 log_error("Error menu item priv in menu config line %d\n", fin_line);
325 return -1;
326 }
327 p_menu_item->priv = atoi(p);
328
329 // Menu item level
330 q = strtok_r(NULL, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
331 if (q == NULL)
332 {
333 log_error("Error menu item level in menu config line %d\n", fin_line);
334 return -1;
335 }
336 p = q;
337 while (isdigit(*q))
338 {
339 q++;
340 }
341 if (*q != '\0')
342 {
343 log_error("Error menu item level in menu config line %d\n", fin_line);
344 return -1;
345 }
346 p_menu_item->level = atoi(p);
347
348 // Menu item name
349 q = strtok_r(NULL, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
350 if (q == NULL || *q != '\"')
351 {
352 log_error("Error menu item name in menu config line %d\n", fin_line);
353 return -1;
354 }
355 q++;
356 p = q;
357 while (*q != '\0' && *q != '\"')
358 {
359 q++;
360 }
361 if (*q != '\"' || *(q + 1) != '\0')
362 {
363 log_error("Error menu item name in menu config line %d\n", fin_line);
364 return -1;
365 }
366 *q = '\0';
367
368 if (q - p > sizeof(p_menu_item->name) - 1)
369 {
370 log_error("Too longer menu name in menu config line %d\n", fin_line);
371 return -1;
372 }
373 strncpy(p_menu_item->name, p, sizeof(p_menu_item->name) - 1);
374 p_menu_item->name[sizeof(p_menu_item->name) - 1] = '\0';
375
376 // Menu item text
377 q = strtok_r(NULL, MENU_CONF_DELIM_WITHOUT_SPACE, &saveptr);
378 if (q == NULL || (q = strchr(q, '\"')) == NULL)
379 {
380 log_error("Error menu item text in menu config line %d\n", fin_line);
381 return -1;
382 }
383 q++;
384 p = q;
385 while (*q != '\0' && *q != '\"')
386 {
387 q++;
388 }
389 if (*q != '\"')
390 {
391 log_error("Error menu item text in menu config line %d\n", fin_line);
392 return -1;
393 }
394 *q = '\0';
395
396 if (q - p > sizeof(p_menu_item->text) - 1)
397 {
398 log_error("Too longer menu item text in menu config line %d\n", fin_line);
399 return -1;
400 }
401 strncpy(p_menu_item->text, p, sizeof(p_menu_item->text) - 1);
402 p_menu_item->text[sizeof(p_menu_item->text) - 1] = '\0';
403
404 // Check syntax
405 q = strtok_r(q + 1, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
406 if (q != NULL)
407 {
408 log_error("Unknown extra content in menu config line %d\n", fin_line);
409 return -1;
410 }
411 }
412 else if (strcmp(p, "title") == 0)
413 {
414 p_menu->title.show = 1;
415
416 // Menu title row
417 q = strtok_r(NULL, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
418 if (q == NULL)
419 {
420 log_error("Error menu title row in menu config line %d\n", fin_line);
421 return -1;
422 }
423 p = q;
424 while (isdigit(*q))
425 {
426 q++;
427 }
428 if (*q != '\0')
429 {
430 log_error("Error menu title row in menu config line %d\n", fin_line);
431 return -1;
432 }
433 p_menu->title.row = (int16_t)atoi(p);
434
435 // Menu title col
436 q = strtok_r(NULL, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
437 if (q == NULL)
438 {
439 log_error("Error menu title col in menu config line %d\n", fin_line);
440 return -1;
441 }
442 p = q;
443 while (isdigit(*q))
444 {
445 q++;
446 }
447 if (*q != '\0')
448 {
449 log_error("Error menu title col in menu config line %d\n", fin_line);
450 return -1;
451 }
452 p_menu->title.col = (int16_t)atoi(p);
453
454 // Menu title text
455 q = strtok_r(NULL, MENU_CONF_DELIM_WITHOUT_SPACE, &saveptr);
456 if (q == NULL || (q = strchr(q, '\"')) == NULL)
457 {
458 log_error("Error menu title text in menu config line %d\n", fin_line);
459 return -1;
460 }
461 q++;
462 p = q;
463 while (*q != '\0' && *q != '\"')
464 {
465 q++;
466 }
467 if (*q != '\"')
468 {
469 log_error("Error menu title text in menu config line %d\n", fin_line);
470 return -1;
471 }
472 *q = '\0';
473
474 if (q - p > sizeof(p_menu_item->text) - 1)
475 {
476 log_error("Too longer menu title text in menu config line %d\n", fin_line);
477 return -1;
478 }
479 strncpy(p_menu->title.text, p, sizeof(p_menu->title.text) - 1);
480 p_menu->title.text[sizeof(p_menu->title.text) - 1] = '\0';
481
482 // Check syntax
483 q = strtok_r(q + 1, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
484 if (q != NULL)
485 {
486 log_error("Unknown extra content in menu config line %d\n", fin_line);
487 return -1;
488 }
489 }
490 else if (strcmp(p, "screen") == 0)
491 {
492 p_menu->screen_show = 1;
493
494 // Menu screen row
495 q = strtok_r(NULL, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
496 if (q == NULL)
497 {
498 log_error("Error menu screen row in menu config line %d\n", fin_line);
499 return -1;
500 }
501 p = q;
502 while (isdigit(*q))
503 {
504 q++;
505 }
506 if (*q != '\0')
507 {
508 log_error("Error menu screen row in menu config line %d\n", fin_line);
509 return -1;
510 }
511 p_menu->screen_row = (int16_t)atoi(p);
512
513 // Menu screen col
514 q = strtok_r(NULL, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
515 if (q == NULL)
516 {
517 log_error("Error menu screen col in menu config line %d\n", fin_line);
518 return -1;
519 }
520 p = q;
521 while (isdigit(*q))
522 {
523 q++;
524 }
525 if (*q != '\0')
526 {
527 log_error("Error menu screen col in menu config line %d\n", fin_line);
528 return -1;
529 }
530 p_menu->screen_col = (int16_t)atoi(p);
531
532 // Menu screen name
533 q = strtok_r(NULL, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
534 if (q == NULL)
535 {
536 log_error("Error menu screen name in menu config line %d\n", fin_line);
537 return -1;
538 }
539 p = q;
540 while (isalnum(*q) || *q == '_')
541 {
542 q++;
543 }
544 if (*q != '\0')
545 {
546 log_error("Error menu screen name in menu config line %d\n", fin_line);
547 return -1;
548 }
549 strncpy(p_menu->screen_name, p, sizeof(p_menu->screen_name) - 1);
550 p_menu->screen_name[sizeof(p_menu->screen_name) - 1] = '\0';
551
552 // Check syntax
553 q = strtok_r(NULL, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
554 if (q != NULL)
555 {
556 log_error("Unknown extra content in menu config line %d\n", fin_line);
557 return -1;
558 }
559 }
560 }
561 }
562 else // BEGIN of menu screen
563 {
564 if (p_menu_set->menu_item_count >= MAX_MENUS)
565 {
566 log_error("Menu screen count (%d) exceed limit (%d)\n", p_menu_set->menu_screen_count, MAX_MENUS);
567 return -3;
568 }
569 screen_id = (MENU_SCREEN_ID)p_menu_set->menu_screen_count;
570 p_menu_set->menu_screen_count++;
571
572 p_screen = get_menu_screen_by_id(p_menu_set, screen_id);
573
574 q = p;
575 while (isalnum(*q) || *q == '_')
576 {
577 q++;
578 }
579 if (*q != '\0')
580 {
581 log_error("Error menu screen name in menu config line %d\n", fin_line);
582 return -1;
583 }
584 strncpy(p_screen->name, p, sizeof(p_screen->name) - 1);
585 p_screen->name[sizeof(p_screen->name) - 1] = '\0';
586
587 if (trie_dict_set(p_menu_set->p_menu_screen_dict, p_screen->name, (int64_t)screen_id) != 1)
588 {
589 log_error("Error set menu screen dict [%s]\n", p_screen->name);
590 }
591
592 // Check syntax
593 q = strtok_r(NULL, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
594 if (q != NULL)
595 {
596 log_error("Unknown extra content in menu config line %d\n", fin_line);
597 return -1;
598 }
599
600 p_screen->buf_offset = p_menu_set->p_menu_screen_buf_free - p_menu_set->p_menu_screen_buf;
601 p_screen->buf_length = -1;
602
603 // safety appending boundary
604 q = p_menu_set->p_menu_screen_buf + MAX_MENU_SCR_BUF_LENGTH * MAX_MENUS - 1;
605
606 while (fgets(buffer, sizeof(buffer), fin))
607 {
608 fin_line++;
609
610 strncpy(temp, buffer, sizeof(temp) - 1); // Duplicate line for strtok_r
611 temp[sizeof(temp) - 1] = '\0';
612 p = strtok_r(temp, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
613 if (p != NULL && *p == '%') // END of menu screen
614 {
615 if (p_menu_set->p_menu_screen_buf_free + 1 > q)
616 {
617 log_error("Menu screen buffer depleted (%p + 1 > %p)\n", p_menu_set->p_menu_screen_buf_free, q);
618 return -3;
619 }
620
621 *(p_menu_set->p_menu_screen_buf_free) = '\0';
622 p_menu_set->p_menu_screen_buf_free++;
623 p_screen->buf_length = p_menu_set->p_menu_screen_buf_free - p_menu_set->p_menu_screen_buf - p_screen->buf_offset;
624 break;
625 }
626
627 // Clear line
628 if (p_menu_set->p_menu_screen_buf_free + strlen(CTRL_SEQ_CLR_LINE) > q)
629 {
630 log_error("Menu screen buffer depleted (%p + %d > %p)\n", p_menu_set->p_menu_screen_buf_free, q, strlen(CTRL_SEQ_CLR_LINE));
631 return -3;
632 }
633 p_menu_set->p_menu_screen_buf_free = stpcpy(p_menu_set->p_menu_screen_buf_free, CTRL_SEQ_CLR_LINE);
634
635 p = buffer;
636 while (*p != '\0')
637 {
638 if (p_menu_set->p_menu_screen_buf_free + 2 > q)
639 {
640 log_error("Menu screen buffer depleted (%p + 2 > %p)\n", p_menu_set->p_menu_screen_buf_free, q);
641 return -3;
642 }
643
644 if (*p == '\n' && p > buffer && *(p - 1) != '\r')
645 {
646 *(p_menu_set->p_menu_screen_buf_free) = '\r';
647 p_menu_set->p_menu_screen_buf_free++;
648 }
649
650 *(p_menu_set->p_menu_screen_buf_free) = *p;
651 p++;
652 p_menu_set->p_menu_screen_buf_free++;
653 }
654 }
655
656 if (p_screen->buf_length == -1)
657 {
658 log_error("End of menu screen [%s] not found\n", p_screen->name);
659 }
660 }
661 }
662 else // Invalid prefix
663 {
664 log_error("Error in menu config line %d\n", fin_line);
665 return -1;
666 }
667 }
668 fclose(fin);
669
670 for (menu_id = 0; menu_id < p_menu_set->menu_count; menu_id++)
671 {
672 p_menu = get_menu_by_id(p_menu_set, menu_id);
673
674 if (trie_dict_get(p_menu_set->p_menu_screen_dict, p_menu->screen_name, (int64_t *)(&(p_menu->screen_id))) != 1)
675 {
676 log_error("Undefined menu screen [%s]\n", p);
677 return -1;
678 }
679 }
680
681 for (menu_item_id = 0; menu_item_id < p_menu_set->menu_item_count; menu_item_id++)
682 {
683 p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
684
685 // Set menu_item->action_cmd_handler of each menu item pointing to bbs_cmd
686 if (p_menu_item->submenu == 0)
687 {
688 if ((p_menu_item->action_cmd_handler = get_cmd_handler(p_menu_item->action)) == NULL)
689 {
690 log_error("Undefined menu action cmd handler [%s]\n", p_menu_item->action);
691 return -1;
692 }
693 }
694 // Set menu_item->action_menu_id of each menu item pointing to a submenu to the menu_id of the corresponding submenu
695 else if (strcmp(p_menu_item->action, "..") != 0)
696 {
697 if (trie_dict_get(p_menu_set->p_menu_name_dict, p_menu_item->action, (int64_t *)&menu_id) != 1)
698 {
699 log_error("Undefined menu action [%s]\n", p_menu_item->action);
700 return -1;
701 }
702 p_menu_item->action_menu_id = menu_id;
703 }
704 }
705
706 // Save status varaibles into reserved memory area
707 *((int16_t *)p_menu_set->p_reserved) = p_menu_set->menu_count;
708 *(((int16_t *)p_menu_set->p_reserved) + 1) = p_menu_set->menu_item_count;
709 *(((int16_t *)p_menu_set->p_reserved) + 2) = p_menu_set->menu_screen_count;
710
711 return 0;
712 }
713
714 static int display_menu_cursor(MENU_SET *p_menu_set, int show)
715 {
716 MENU_ID menu_id;
717 MENU_ITEM_ID menu_item_id;
718 MENU *p_menu;
719 MENU_ITEM *p_menu_item;
720 int16_t menu_item_pos;
721
722 menu_id = p_menu_set->menu_id_path[p_menu_set->choose_step];
723 p_menu = get_menu_by_id(p_menu_set, menu_id);
724 if (p_menu == NULL)
725 {
726 log_error("get_menu_by_id(%d) return NULL pointer\n", menu_id);
727 return -1;
728 }
729
730 menu_item_pos = p_menu_set->menu_item_pos[p_menu_set->choose_step];
731 menu_item_id = p_menu->items[menu_item_pos];
732 p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
733 if (p_menu_item == NULL)
734 {
735 log_error("get_menu_item_by_id(%d) return NULL pointer\n", menu_item_id);
736 return -1;
737 }
738
739 moveto(p_menu_set->menu_item_r_row[menu_item_pos], p_menu_set->menu_item_r_col[menu_item_pos] - 2);
740 outc(show ? '>' : ' ');
741 iflush();
742
743 return 0;
744 }
745
746 int display_menu(MENU_SET *p_menu_set)
747 {
748 int16_t row = 0;
749 int16_t col = 0;
750 int menu_selectable = 0;
751 MENU_ID menu_id;
752 MENU_ITEM_ID menu_item_id;
753 MENU *p_menu;
754 MENU_ITEM *p_menu_item;
755 MENU_SCREEN *p_menu_screen;
756 int16_t menu_item_pos;
757
758 menu_id = p_menu_set->menu_id_path[p_menu_set->choose_step];
759 p_menu = get_menu_by_id(p_menu_set, menu_id);
760 if (p_menu == NULL)
761 {
762 log_error("get_menu_by_id(%d) return NULL pointer\n", menu_id);
763 return -1;
764 }
765
766 menu_item_pos = p_menu_set->menu_item_pos[p_menu_set->choose_step];
767 menu_item_id = p_menu->items[menu_item_pos];
768 p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
769 if (p_menu_item == NULL)
770 {
771 log_error("get_menu_item_by_id(%d) return NULL pointer\n", menu_item_id);
772 return -1;
773 }
774
775 if (menu_item_pos > 0 &&
776 checkpriv(&BBS_priv, 0, p_menu_item->priv) != 0 &&
777 checklevel(&BBS_priv, p_menu_item->level) != 0)
778 {
779 menu_selectable = 1;
780 }
781
782 if (p_menu->title.show)
783 {
784 show_top(p_menu->title.text);
785 }
786
787 if (p_menu->screen_show)
788 {
789 p_menu_screen = get_menu_screen_by_id(p_menu_set, p_menu->screen_id);
790 if (p_menu_screen == NULL)
791 {
792 log_error("get_menu_screen_by_id(%d) return NULL pointer\n", p_menu->screen_id);
793 return -1;
794 }
795
796 moveto(p_menu->screen_row, p_menu->screen_col);
797 prints("%s", p_menu_set->p_menu_screen_buf + p_menu_screen->buf_offset);
798 iflush();
799 }
800
801 for (menu_item_pos = 0; menu_item_pos < p_menu->item_count; menu_item_pos++)
802 {
803 menu_item_id = p_menu->items[menu_item_pos];
804 p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
805
806 if (p_menu_item->row != 0)
807 {
808 row = p_menu_item->row;
809 }
810 if (p_menu_item->col != 0)
811 {
812 col = p_menu_item->col;
813 }
814
815 if (checkpriv(&BBS_priv, 0, p_menu_item->priv) == 0 || checklevel(&BBS_priv, p_menu_item->level) == 0)
816 {
817 p_menu_set->menu_item_display[menu_item_pos] = 0;
818 p_menu_set->menu_item_r_row[menu_item_pos] = 0;
819 p_menu_set->menu_item_r_col[menu_item_pos] = 0;
820 }
821 else
822 {
823 p_menu_set->menu_item_display[menu_item_pos] = 1;
824
825 if (!menu_selectable)
826 {
827 p_menu_set->menu_item_pos[p_menu_set->choose_step] = menu_item_pos;
828 menu_selectable = 1;
829 }
830
831 p_menu_set->menu_item_r_row[menu_item_pos] = row;
832 p_menu_set->menu_item_r_col[menu_item_pos] = col;
833
834 moveto(row, col);
835 prints("%s", p_menu_item->text);
836
837 row++;
838 }
839 }
840
841 if (!menu_selectable)
842 {
843 return -1;
844 }
845
846 display_menu_cursor(p_menu_set, 1);
847
848 return 0;
849 }
850
851 int menu_control(MENU_SET *p_menu_set, int key)
852 {
853 MENU_ID menu_id;
854 MENU_ITEM_ID menu_item_id;
855 MENU *p_menu;
856 MENU_ITEM *p_menu_item;
857 int16_t menu_item_pos;
858
859 if (p_menu_set->menu_count == 0)
860 {
861 return 0;
862 }
863
864 menu_id = p_menu_set->menu_id_path[p_menu_set->choose_step];
865 p_menu = get_menu_by_id(p_menu_set, menu_id);
866 if (p_menu == NULL)
867 {
868 log_error("get_menu_by_id(%d) return NULL pointer\n", menu_id);
869 return -1;
870 }
871
872 if (p_menu->item_count == 0)
873 {
874 return 0;
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 switch (key)
887 {
888 case CR:
889 igetch_reset();
890 case KEY_RIGHT:
891 if (p_menu_item->submenu)
892 {
893 if (strcmp(p_menu_item->action, "..") == 0)
894 {
895 return menu_control(p_menu_set, KEY_LEFT);
896 }
897 p_menu_set->choose_step++;
898 p_menu_set->menu_id_path[p_menu_set->choose_step] = p_menu_item->action_menu_id;
899 p_menu_set->menu_item_pos[p_menu_set->choose_step] = 0;
900
901 if (display_menu(p_menu_set) != 0)
902 {
903 return menu_control(p_menu_set, KEY_LEFT);
904 }
905 }
906 else
907 {
908 return ((*(p_menu_item->action_cmd_handler))((void *)(p_menu_item->name)));
909 }
910 break;
911 case KEY_LEFT:
912 if (p_menu_set->choose_step > 0)
913 {
914 p_menu_set->choose_step--;
915 if (display_menu(p_menu_set) != 0)
916 {
917 return menu_control(p_menu_set, KEY_LEFT);
918 }
919 }
920 else
921 {
922 display_menu_cursor(p_menu_set, 0);
923 menu_item_pos = p_menu->item_count - 1;
924 while (menu_item_pos >= 0)
925 {
926 menu_item_id = p_menu->items[menu_item_pos];
927 p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
928 if (p_menu_item == NULL)
929 {
930 log_error("get_menu_item_by_id(%d) return NULL pointer\n", menu_item_id);
931 return -1;
932 }
933
934 if (!p_menu_set->menu_item_display[menu_item_pos] || p_menu_item->priv != 0 || p_menu_item->level != 0)
935 {
936 menu_item_pos--;
937 }
938 else
939 {
940 break;
941 }
942 }
943 p_menu_set->menu_item_pos[p_menu_set->choose_step] = menu_item_pos;
944 display_menu_cursor(p_menu_set, 1);
945 }
946 break;
947 case KEY_UP:
948 display_menu_cursor(p_menu_set, 0);
949 do
950 {
951 menu_item_pos--;
952 if (menu_item_pos < 0)
953 {
954 menu_item_pos = p_menu->item_count - 1;
955 }
956 menu_item_id = p_menu->items[menu_item_pos];
957 p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
958 if (p_menu_item == NULL)
959 {
960 log_error("get_menu_item_by_id(%d) return NULL pointer\n", menu_item_id);
961 return -1;
962 }
963 } while (!p_menu_set->menu_item_display[menu_item_pos]);
964 p_menu_set->menu_item_pos[p_menu_set->choose_step] = menu_item_pos;
965 display_menu_cursor(p_menu_set, 1);
966 break;
967 case KEY_DOWN:
968 display_menu_cursor(p_menu_set, 0);
969 do
970 {
971 menu_item_pos++;
972 if (menu_item_pos >= p_menu->item_count)
973 {
974 menu_item_pos = 0;
975 }
976 menu_item_id = p_menu->items[menu_item_pos];
977 p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
978 if (p_menu_item == NULL)
979 {
980 log_error("get_menu_item_by_id(%d) return NULL pointer\n", menu_item_id);
981 return -1;
982 }
983 } while (!p_menu_set->menu_item_display[menu_item_pos]);
984 p_menu_set->menu_item_pos[p_menu_set->choose_step] = menu_item_pos;
985 display_menu_cursor(p_menu_set, 1);
986 break;
987 case KEY_HOME:
988 case KEY_PGUP:
989 display_menu_cursor(p_menu_set, 0);
990 menu_item_pos = 0;
991 while (menu_item_pos < p_menu->item_count - 1)
992 {
993 menu_item_id = p_menu->items[menu_item_pos];
994 p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
995 if (p_menu_item == NULL)
996 {
997 log_error("get_menu_item_by_id(%d) return NULL pointer\n", menu_item_id);
998 return -1;
999 }
1000
1001 if (p_menu_set->menu_item_display[menu_item_pos])
1002 {
1003 break;
1004 }
1005
1006 menu_item_pos++;
1007 }
1008 p_menu_set->menu_item_pos[p_menu_set->choose_step] = menu_item_pos;
1009 display_menu_cursor(p_menu_set, 1);
1010 break;
1011 case KEY_END:
1012 case KEY_PGDN:
1013 display_menu_cursor(p_menu_set, 0);
1014 menu_item_pos = p_menu->item_count - 1;
1015 while (menu_item_pos > 0)
1016 {
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 -1;
1023 }
1024
1025 if (p_menu_set->menu_item_display[menu_item_pos])
1026 {
1027 break;
1028 }
1029
1030 menu_item_pos--;
1031 }
1032 p_menu_set->menu_item_pos[p_menu_set->choose_step] = menu_item_pos;
1033 display_menu_cursor(p_menu_set, 1);
1034 break;
1035 default:
1036 if (isalnum(key))
1037 {
1038 for (menu_item_pos = 0; menu_item_pos < p_menu->item_count; menu_item_pos++)
1039 {
1040 menu_item_id = p_menu->items[menu_item_pos];
1041 p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
1042 if (p_menu_item == NULL)
1043 {
1044 log_error("get_menu_item_by_id(%d) return NULL pointer\n", menu_item_id);
1045 return -1;
1046 }
1047
1048 if (toupper(key) == toupper(p_menu_item->name[0]) && p_menu_set->menu_item_display[menu_item_pos])
1049 {
1050 display_menu_cursor(p_menu_set, 0);
1051 p_menu_set->menu_item_pos[p_menu_set->choose_step] = menu_item_pos;
1052 display_menu_cursor(p_menu_set, 1);
1053 return 0;
1054 }
1055 }
1056 }
1057 break;
1058 }
1059
1060 return 0;
1061 }
1062
1063 int unload_menu(MENU_SET *p_menu_set)
1064 {
1065 if (p_menu_set->p_menu_name_dict != NULL)
1066 {
1067 trie_dict_destroy(p_menu_set->p_menu_name_dict);
1068 p_menu_set->p_menu_name_dict = NULL;
1069 }
1070
1071 if (p_menu_set->p_menu_screen_dict != NULL)
1072 {
1073 trie_dict_destroy(p_menu_set->p_menu_screen_dict);
1074 p_menu_set->p_menu_screen_dict = NULL;
1075 }
1076
1077 unload_menu_shm(p_menu_set);
1078
1079 if (shmctl(p_menu_set->shmid, IPC_RMID, NULL) == -1)
1080 {
1081 log_error("shmctl(shmid=%d, IPC_RMID) error (%d)\n", p_menu_set->shmid, errno);
1082 return -1;
1083 }
1084
1085 return 0;
1086 }
1087
1088 int load_menu_shm(MENU_SET *p_menu_set)
1089 {
1090 // Mount shared memory
1091 if (p_menu_set->p_reserved == NULL)
1092 {
1093 p_menu_set->p_reserved = shmat(p_menu_set->shmid, NULL, SHM_RDONLY);
1094 if (p_menu_set->p_reserved == (void *)-1)
1095 {
1096 log_error("shmat() error (%d)\n", errno);
1097 return -1;
1098 }
1099 }
1100
1101 p_menu_set->p_menu_pool = p_menu_set->p_reserved + MENU_SET_RESERVED_LENGTH;
1102 p_menu_set->p_menu_item_pool = p_menu_set->p_menu_pool + sizeof(MENU) * MAX_MENUS;
1103 p_menu_set->p_menu_screen_pool = p_menu_set->p_menu_item_pool + sizeof(MENU_ITEM) * MAX_MENUITEMS;
1104 p_menu_set->p_menu_screen_buf = p_menu_set->p_menu_screen_pool + sizeof(MENU_SCREEN) * MAX_MENUS;
1105 p_menu_set->p_menu_screen_buf_free = p_menu_set->p_menu_screen_buf;
1106
1107 // Restore status varaibles into reserved memory area
1108 p_menu_set->menu_count = *((int16_t *)p_menu_set->p_reserved);
1109 p_menu_set->menu_item_count = *(((int16_t *)p_menu_set->p_reserved) + 1);
1110 p_menu_set->menu_screen_count = *(((int16_t *)p_menu_set->p_reserved) + 2);
1111
1112 p_menu_set->choose_step = 0;
1113 p_menu_set->menu_id_path[0] = 0;
1114
1115 p_menu_set->p_menu_name_dict = NULL;
1116 p_menu_set->p_menu_screen_dict = NULL;
1117
1118 return 0;
1119 }
1120
1121 int unload_menu_shm(MENU_SET *p_menu_set)
1122 {
1123 p_menu_set->menu_count = 0;
1124 p_menu_set->menu_item_count = 0;
1125 p_menu_set->menu_screen_count = 0;
1126 p_menu_set->choose_step = 0;
1127
1128 p_menu_set->p_menu_pool = NULL;
1129 p_menu_set->p_menu_item_pool = NULL;
1130 p_menu_set->p_menu_screen_pool = NULL;
1131 p_menu_set->p_menu_screen_buf = NULL;
1132 p_menu_set->p_menu_screen_buf_free = NULL;
1133
1134 if (p_menu_set->p_reserved != NULL && shmdt(p_menu_set->p_reserved) == -1)
1135 {
1136 log_error("shmdt() error (%d)\n", errno);
1137 return -1;
1138 }
1139 p_menu_set->p_reserved = NULL;
1140
1141 return 0;
1142 }

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