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

Annotation of /lbbs/src/menu.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.86 - (hide annotations)
Mon Nov 17 12:16:48 2025 UTC (3 months, 4 weeks ago) by sysadm
Branch: MAIN
Changes since 1.85: +24 -15 lines
Content type: text/x-csrc
Add alternative implementation of shmat(..., SHM_REMAP) under MSYS2
Fix error reported by gcc under MSYS2

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

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