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

Annotation of /lbbs/src/menu.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.92 - (hide annotations)
Thu Dec 18 02:56:00 2025 UTC (2 months, 4 weeks ago) by sysadm
Branch: MAIN
Changes since 1.91: +1 -3 lines
Content type: text/x-csrc
Refine with log_debug()

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

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