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

Annotation of /lbbs/src/menu.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.77 - (hide annotations)
Wed Oct 29 05:30:05 2025 UTC (4 months, 2 weeks ago) by sysadm
Branch: MAIN
Changes since 1.76: +34 -14 lines
Content type: text/x-csrc
Retry shmget() several times to skip conflict keys

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

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