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

Annotation of /lbbs/src/menu.c

Parent Directory Parent Directory | Revision Log Revision Log


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

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