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

Annotation of /lbbs/src/menu.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.80 - (hide annotations)
Tue Nov 4 13:49:51 2025 UTC (4 months, 1 week ago) by sysadm
Branch: MAIN
Changes since 1.79: +7 -15 lines
Content type: text/x-csrc
Update file header information comments

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

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