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

Annotation of /lbbs/src/menu.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.46 - (hide annotations)
Sun May 18 06:57:56 2025 UTC (10 months ago) by sysadm
Branch: MAIN
Changes since 1.45: +2 -0 lines
Content type: text/x-csrc
Refine

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 "user_priv.h"
20     #include "bbs_cmd.h"
21 sysadm 1.1 #include "menu.h"
22 sysadm 1.22 #include "log.h"
23 sysadm 1.1 #include "io.h"
24 sysadm 1.22 #include "screen.h"
25 sysadm 1.2 #include "common.h"
26 sysadm 1.22 #include <string.h>
27 sysadm 1.1 #include <stdio.h>
28     #include <ctype.h>
29 sysadm 1.6 #include <stdlib.h>
30 sysadm 1.40 #include <errno.h>
31     #include <unistd.h>
32     #include <sys/shm.h>
33     #include <sys/ipc.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     MENU_SET *p_bbs_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     char *saveptr = NULL;
52     MENU *p_menu = NULL;
53 sysadm 1.40 MENU_ITEM *p_menu_item = NULL;
54     MENU_SCREEN *p_screen = NULL;
55     MENU_ID menu_id;
56     MENU_ITEM_ID menu_item_id;
57     MENU_SCREEN_ID screen_id;
58     int proj_id;
59     key_t key;
60     size_t size;
61 sysadm 1.31
62 sysadm 1.40 // Use trie_dict to search menu_id by menu name
63 sysadm 1.39 p_menu_set->p_menu_name_dict = trie_dict_create();
64 sysadm 1.40 if (p_menu_set->p_menu_name_dict == NULL)
65     {
66     log_error("trie_dict_create() error\n");
67     return -3;
68     }
69    
70     // Use trie_dict to search screen_id by menu screen name
71     p_menu_set->p_menu_screen_dict = trie_dict_create();
72     if (p_menu_set->p_menu_screen_dict == NULL)
73     {
74     log_error("trie_dict_create() error\n");
75     return -3;
76     }
77 sysadm 1.21
78     if ((fin = fopen(conf_file, "r")) == NULL)
79     {
80     log_error("Open %s failed", conf_file);
81 sysadm 1.31 return -2;
82 sysadm 1.21 }
83    
84 sysadm 1.40 // Allocate shared memory
85     proj_id = (int)(time(NULL) % getpid());
86     key = ftok(conf_file, proj_id);
87     if (key == -1)
88     {
89     log_error("ftok(%s %d) error (%d)\n", conf_file, proj_id, errno);
90     return -2;
91     }
92    
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     p_menu_set->shmid = shmget(key, size, IPC_CREAT | IPC_EXCL | 0600);
99     if (p_menu_set->shmid == -1)
100     {
101     log_error("shmget(size = %d) error (%d)\n", size, errno);
102     return -3;
103     }
104     p_menu_set->p_reserved = shmat(p_menu_set->shmid, NULL, 0);
105     if (p_menu_set->p_reserved == (void *)-1)
106     {
107     log_error("shmat() error (%d)\n", errno);
108     return -3;
109     }
110     p_menu_set->p_menu_pool = p_menu_set->p_reserved + MENU_SET_RESERVED_LENGTH;
111     p_menu_set->p_menu_item_pool = p_menu_set->p_menu_pool + sizeof(MENU) * MAX_MENUS;
112     p_menu_set->p_menu_screen_pool = p_menu_set->p_menu_item_pool + sizeof(MENU_ITEM) * MAX_MENUITEMS;
113     p_menu_set->p_menu_screen_buf = p_menu_set->p_menu_screen_pool + sizeof(MENU_SCREEN) * MAX_MENUS;
114     p_menu_set->p_menu_screen_buf_free = p_menu_set->p_menu_screen_buf;
115    
116     p_menu_set->menu_count = 0;
117     p_menu_set->menu_item_count = 0;
118     p_menu_set->menu_screen_count = 0;
119     p_menu_set->choose_step = 0;
120     p_menu_set->menu_id_path[0] = 0;
121 sysadm 1.21
122 sysadm 1.23 while (fgets(buffer, sizeof(buffer), fin))
123 sysadm 1.3 {
124 sysadm 1.31 fin_line++;
125    
126     p = strtok_r(buffer, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
127     if (p == NULL) // Blank line
128 sysadm 1.21 {
129 sysadm 1.31 continue;
130     }
131    
132     if (*p == '#' || *p == '\r' || *p == '\n') // Comment or blank line
133     {
134     continue;
135     }
136    
137     if (*p == '%')
138     {
139     p++;
140    
141     if (strcmp(p, "menu") == 0) // BEGIN of sub-menu
142 sysadm 1.21 {
143 sysadm 1.31 if (p_menu != NULL)
144     {
145 sysadm 1.33 log_error("Incomplete menu definition in menu config line %d\n", fin_line);
146 sysadm 1.31 return -1;
147     }
148 sysadm 1.40
149     if (p_menu_set->menu_count >= MAX_MENUS)
150 sysadm 1.31 {
151 sysadm 1.40 log_error("Menu count (%d) exceed limit (%d)\n", p_menu_set->menu_count, MAX_MENUS);
152 sysadm 1.31 return -3;
153     }
154 sysadm 1.40 menu_id = (MENU_ID)p_menu_set->menu_count;
155     p_menu_set->menu_count++;
156    
157     p_menu = get_menu_by_id(p_menu_set, menu_id);
158 sysadm 1.21
159 sysadm 1.31 p_menu->item_count = 0;
160     p_menu->title.show = 0;
161 sysadm 1.40 p_menu->screen_show = 0;
162 sysadm 1.31
163     q = strtok_r(NULL, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
164     if (q == NULL)
165     {
166     log_error("Error menu name in menu config line %d\n", fin_line);
167     return -1;
168     }
169     p = q;
170     while (isalnum(*q) || *q == '_')
171     {
172     q++;
173     }
174     if (*q != '\0')
175 sysadm 1.21 {
176 sysadm 1.31 log_error("Error menu name in menu config line %d\n", fin_line);
177     return -1;
178 sysadm 1.21 }
179    
180 sysadm 1.31 if (q - p > sizeof(p_menu->name) - 1)
181 sysadm 1.21 {
182 sysadm 1.31 log_error("Too longer menu name in menu config line %d\n", fin_line);
183     return -1;
184 sysadm 1.21 }
185 sysadm 1.31 strncpy(p_menu->name, p, sizeof(p_menu->name) - 1);
186     p_menu->name[sizeof(p_menu->name) - 1] = '\0';
187 sysadm 1.40
188     if (trie_dict_set(p_menu_set->p_menu_name_dict, p_menu->name, (int64_t)menu_id) != 1)
189 sysadm 1.39 {
190     log_error("Error set menu dict [%s]\n", p_menu->name);
191     }
192 sysadm 1.21
193 sysadm 1.31 // Check syntax
194     q = strtok_r(NULL, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
195     if (q != NULL)
196     {
197     log_error("Unknown extra content in menu config line %d\n", fin_line);
198     return -1;
199     }
200 sysadm 1.21
201 sysadm 1.31 while (fgets(buffer, sizeof(buffer), fin))
202     {
203     fin_line++;
204 sysadm 1.21
205 sysadm 1.31 p = strtok_r(buffer, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
206     if (p == NULL) // Blank line
207     {
208     continue;
209     }
210 sysadm 1.21
211 sysadm 1.31 if (*p == '#' || *p == '\r' || *p == '\n') // Comment or blank line
212 sysadm 1.21 {
213     continue;
214     }
215 sysadm 1.31
216     if (*p == '%') // END of sub-menu
217 sysadm 1.21 {
218 sysadm 1.31 p_menu = NULL;
219 sysadm 1.21 break;
220     }
221 sysadm 1.31 else if (*p == '!' || *p == '@')
222 sysadm 1.21 {
223 sysadm 1.31 // BEGIN of menu item
224 sysadm 1.40 if (p_menu->item_count >= MAX_ITEMS_PER_MENU)
225     {
226     log_error("Menuitem count per menu (%d) exceed limit (%d)\n", p_menu->item_count, MAX_ITEMS_PER_MENU);
227     return -1;
228     }
229     if (p_menu_set->menu_item_count >= MAX_MENUITEMS)
230 sysadm 1.31 {
231 sysadm 1.40 log_error("Menuitem count (%d) exceed limit (%d)\n", p_menu_set->menu_item_count, MAX_MENUITEMS);
232 sysadm 1.31 return -3;
233     }
234 sysadm 1.40 menu_item_id = (MENU_ITEM_ID)p_menu_set->menu_item_count;
235     p_menu_set->menu_item_count++;
236 sysadm 1.31
237 sysadm 1.40 p_menu->items[p_menu->item_count] = menu_item_id;
238     p_menu->item_count++;
239    
240     p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
241    
242     p_menu_item->submenu = (*p == '!' ? 1 : 0);
243 sysadm 1.31
244     // Menu item action
245     p++;
246     if (strcmp(p, "..") == 0) // Return to parent menu
247     {
248     q = p + 2; // strlen("..")
249     }
250     else
251     {
252     q = p;
253     while (isalnum(*q) || *q == '_')
254     {
255     q++;
256     }
257     if (*q != '\0')
258     {
259     log_error("Error menu item action in menu config line %d\n", fin_line);
260     return -1;
261     }
262     }
263    
264 sysadm 1.40 if (q - p > sizeof(p_menu_item->action) - 1)
265 sysadm 1.31 {
266     log_error("Too longer menu action in menu config line %d\n", fin_line);
267     return -1;
268     }
269 sysadm 1.40 strncpy(p_menu_item->action, p, sizeof(p_menu_item->action) - 1);
270     p_menu_item->action[sizeof(p_menu_item->action) - 1] = '\0';
271 sysadm 1.31
272     // Menu item row
273     q = strtok_r(NULL, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
274     if (q == NULL)
275     {
276     log_error("Error menu item row in menu config line %d\n", fin_line);
277     return -1;
278     }
279     p = q;
280     while (isdigit(*q))
281     {
282     q++;
283     }
284     if (*q != '\0')
285     {
286     log_error("Error menu item row in menu config line %d\n", fin_line);
287     return -1;
288     }
289 sysadm 1.40 p_menu_item->row = (int16_t)atoi(p);
290 sysadm 1.31
291     // Menu item col
292     q = strtok_r(NULL, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
293     if (q == NULL)
294     {
295     log_error("Error menu item col in menu config line %d\n", fin_line);
296     return -1;
297     }
298     p = q;
299     while (isdigit(*q))
300     {
301     q++;
302     }
303     if (*q != '\0')
304     {
305     log_error("Error menu item col in menu config line %d\n", fin_line);
306     return -1;
307     }
308 sysadm 1.40 p_menu_item->col = (int16_t)atoi(p);
309 sysadm 1.31
310     // Menu item priv
311     q = strtok_r(NULL, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
312     if (q == NULL)
313     {
314     log_error("Error menu item priv in menu config line %d\n", fin_line);
315     return -1;
316     }
317     p = q;
318     while (isdigit(*q))
319     {
320     q++;
321     }
322     if (*q != '\0')
323     {
324     log_error("Error menu item priv in menu config line %d\n", fin_line);
325     return -1;
326     }
327 sysadm 1.40 p_menu_item->priv = atoi(p);
328 sysadm 1.31
329     // Menu item level
330     q = strtok_r(NULL, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
331     if (q == NULL)
332     {
333     log_error("Error menu item level in menu config line %d\n", fin_line);
334     return -1;
335     }
336     p = q;
337     while (isdigit(*q))
338     {
339     q++;
340     }
341     if (*q != '\0')
342     {
343     log_error("Error menu item level in menu config line %d\n", fin_line);
344     return -1;
345     }
346 sysadm 1.40 p_menu_item->level = atoi(p);
347 sysadm 1.31
348     // Menu item name
349     q = strtok_r(NULL, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
350     if (q == NULL || *q != '\"')
351     {
352     log_error("Error menu item name in menu config line %d\n", fin_line);
353     return -1;
354     }
355     q++;
356     p = q;
357     while (*q != '\0' && *q != '\"')
358     {
359     q++;
360     }
361     if (*q != '\"' || *(q + 1) != '\0')
362     {
363     log_error("Error menu item name in menu config line %d\n", fin_line);
364     return -1;
365     }
366     *q = '\0';
367    
368 sysadm 1.40 if (q - p > sizeof(p_menu_item->name) - 1)
369 sysadm 1.31 {
370     log_error("Too longer menu name in menu config line %d\n", fin_line);
371     return -1;
372     }
373 sysadm 1.40 strncpy(p_menu_item->name, p, sizeof(p_menu_item->name) - 1);
374     p_menu_item->name[sizeof(p_menu_item->name) - 1] = '\0';
375 sysadm 1.31
376     // Menu item text
377     q = strtok_r(NULL, MENU_CONF_DELIM_WITHOUT_SPACE, &saveptr);
378     if (q == NULL || (q = strchr(q, '\"')) == NULL)
379     {
380 sysadm 1.32 log_error("Error menu item text in menu config line %d\n", fin_line);
381 sysadm 1.31 return -1;
382     }
383     q++;
384     p = q;
385     while (*q != '\0' && *q != '\"')
386     {
387     q++;
388     }
389     if (*q != '\"')
390     {
391     log_error("Error menu item text in menu config line %d\n", fin_line);
392     return -1;
393     }
394     *q = '\0';
395    
396 sysadm 1.40 if (q - p > sizeof(p_menu_item->text) - 1)
397 sysadm 1.31 {
398     log_error("Too longer menu item text in menu config line %d\n", fin_line);
399     return -1;
400     }
401 sysadm 1.40 strncpy(p_menu_item->text, p, sizeof(p_menu_item->text) - 1);
402     p_menu_item->text[sizeof(p_menu_item->text) - 1] = '\0';
403 sysadm 1.31
404     // Check syntax
405     q = strtok_r(q + 1, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
406     if (q != NULL)
407     {
408     log_error("Unknown extra content in menu config line %d\n", fin_line);
409     return -1;
410     }
411     }
412     else if (strcmp(p, "title") == 0)
413     {
414     p_menu->title.show = 1;
415    
416     // Menu title row
417     q = strtok_r(NULL, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
418     if (q == NULL)
419     {
420     log_error("Error menu title row in menu config line %d\n", fin_line);
421     return -1;
422     }
423     p = q;
424     while (isdigit(*q))
425     {
426     q++;
427     }
428     if (*q != '\0')
429     {
430     log_error("Error menu title row in menu config line %d\n", fin_line);
431     return -1;
432     }
433 sysadm 1.40 p_menu->title.row = (int16_t)atoi(p);
434 sysadm 1.31
435     // Menu title col
436     q = strtok_r(NULL, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
437     if (q == NULL)
438     {
439     log_error("Error menu title col in menu config line %d\n", fin_line);
440     return -1;
441     }
442     p = q;
443     while (isdigit(*q))
444     {
445     q++;
446     }
447     if (*q != '\0')
448     {
449     log_error("Error menu title col in menu config line %d\n", fin_line);
450     return -1;
451     }
452 sysadm 1.40 p_menu->title.col = (int16_t)atoi(p);
453 sysadm 1.31
454     // Menu title text
455     q = strtok_r(NULL, MENU_CONF_DELIM_WITHOUT_SPACE, &saveptr);
456     if (q == NULL || (q = strchr(q, '\"')) == NULL)
457     {
458     log_error("Error menu title text in menu config line %d\n", fin_line);
459     return -1;
460     }
461     q++;
462     p = q;
463     while (*q != '\0' && *q != '\"')
464     {
465     q++;
466     }
467     if (*q != '\"')
468     {
469     log_error("Error menu title text in menu config line %d\n", fin_line);
470     return -1;
471     }
472     *q = '\0';
473    
474 sysadm 1.40 if (q - p > sizeof(p_menu_item->text) - 1)
475 sysadm 1.31 {
476     log_error("Too longer menu title text in menu config line %d\n", fin_line);
477     return -1;
478     }
479     strncpy(p_menu->title.text, p, sizeof(p_menu->title.text) - 1);
480     p_menu->title.text[sizeof(p_menu->title.text) - 1] = '\0';
481    
482     // Check syntax
483     q = strtok_r(q + 1, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
484     if (q != NULL)
485     {
486     log_error("Unknown extra content in menu config line %d\n", fin_line);
487     return -1;
488     }
489 sysadm 1.21 }
490 sysadm 1.31 else if (strcmp(p, "screen") == 0)
491 sysadm 1.21 {
492 sysadm 1.40 p_menu->screen_show = 1;
493 sysadm 1.31
494     // Menu screen row
495     q = strtok_r(NULL, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
496     if (q == NULL)
497     {
498     log_error("Error menu screen row in menu config line %d\n", fin_line);
499     return -1;
500     }
501     p = q;
502     while (isdigit(*q))
503     {
504     q++;
505     }
506     if (*q != '\0')
507     {
508     log_error("Error menu screen row in menu config line %d\n", fin_line);
509     return -1;
510     }
511 sysadm 1.40 p_menu->screen_row = (int16_t)atoi(p);
512 sysadm 1.31
513     // Menu screen col
514     q = strtok_r(NULL, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
515     if (q == NULL)
516     {
517     log_error("Error menu screen col in menu config line %d\n", fin_line);
518     return -1;
519     }
520     p = q;
521     while (isdigit(*q))
522     {
523     q++;
524     }
525     if (*q != '\0')
526     {
527     log_error("Error menu screen col in menu config line %d\n", fin_line);
528     return -1;
529     }
530 sysadm 1.40 p_menu->screen_col = (int16_t)atoi(p);
531 sysadm 1.31
532     // Menu screen name
533     q = strtok_r(NULL, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
534     if (q == NULL)
535     {
536     log_error("Error menu screen name in menu config line %d\n", fin_line);
537     return -1;
538     }
539     p = q;
540     while (isalnum(*q) || *q == '_')
541     {
542     q++;
543     }
544     if (*q != '\0')
545     {
546     log_error("Error menu screen name in menu config line %d\n", fin_line);
547     return -1;
548     }
549 sysadm 1.40 if (trie_dict_get(p_menu_set->p_menu_screen_dict, p, (int64_t *)&screen_id) != 1)
550     {
551     log_error("Undefined menu screen [%s]\n", p);
552     return -1;
553     }
554     p_menu->screen_id = screen_id;
555 sysadm 1.31
556     // Check syntax
557     q = strtok_r(NULL, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
558     if (q != NULL)
559     {
560     log_error("Unknown extra content in menu config line %d\n", fin_line);
561     return -1;
562     }
563 sysadm 1.21 }
564 sysadm 1.31 }
565     }
566     else // BEGIN of menu screen
567     {
568 sysadm 1.40 if (p_menu_set->menu_item_count >= MAX_MENUS)
569     {
570     log_error("Menu screen count (%d) exceed limit (%d)\n", p_menu_set->menu_screen_count, MAX_MENUS);
571     return -3;
572     }
573     screen_id = (MENU_SCREEN_ID)p_menu_set->menu_screen_count;
574     p_menu_set->menu_screen_count++;
575    
576     p_screen = get_menu_screen_by_id(p_menu_set, screen_id);
577    
578 sysadm 1.31 q = p;
579     while (isalnum(*q) || *q == '_')
580     {
581     q++;
582     }
583     if (*q != '\0')
584     {
585     log_error("Error menu screen name in menu config line %d\n", fin_line);
586     return -1;
587     }
588 sysadm 1.40 strncpy(p_screen->name, p, sizeof(p_screen->name) - 1);
589     p_screen->name[sizeof(p_screen->name) - 1] = '\0';
590 sysadm 1.31
591 sysadm 1.40 if (trie_dict_set(p_menu_set->p_menu_screen_dict, p_screen->name, (int64_t)screen_id) != 1)
592     {
593     log_error("Error set menu screen dict [%s]\n", p_screen->name);
594     }
595 sysadm 1.31
596     // Check syntax
597     q = strtok_r(NULL, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
598     if (q != NULL)
599     {
600     log_error("Unknown extra content in menu config line %d\n", fin_line);
601     return -1;
602     }
603    
604 sysadm 1.40 p_screen->buf_offset = p_menu_set->p_menu_screen_buf_free - p_menu_set->p_menu_screen_buf;
605     p_screen->buf_length = -1;
606    
607     // safety appending boundary
608     q = p_menu_set->p_menu_screen_buf + MAX_MENU_SCR_BUF_LENGTH * MAX_MENUS - 1;
609 sysadm 1.31
610     while (fgets(buffer, sizeof(buffer), fin))
611     {
612     fin_line++;
613    
614 sysadm 1.40 strncpy(temp, buffer, sizeof(temp) - 1); // Duplicate line for strtok_r
615     temp[sizeof(temp) - 1] = '\0';
616 sysadm 1.33 p = strtok_r(temp, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
617 sysadm 1.31 if (p != NULL && *p == '%') // END of menu screen
618 sysadm 1.21 {
619 sysadm 1.40 if (p_menu_set->p_menu_screen_buf_free + 1 > q)
620     {
621     log_error("Menu screen buffer depleted (%p + 1 > %p)\n", p_menu_set->p_menu_screen_buf_free, q);
622     return -3;
623     }
624    
625     *(p_menu_set->p_menu_screen_buf_free) = '\0';
626     p_menu_set->p_menu_screen_buf_free++;
627     p_screen->buf_length = p_menu_set->p_menu_screen_buf_free - p_menu_set->p_menu_screen_buf - p_screen->buf_offset;
628 sysadm 1.31 break;
629 sysadm 1.21 }
630 sysadm 1.31
631 sysadm 1.40 p = buffer;
632     while (*p != '\0')
633 sysadm 1.21 {
634 sysadm 1.40 if (p_menu_set->p_menu_screen_buf_free + 2 > q)
635     {
636     log_error("Menu screen buffer depleted (%p + 2 > %p)\n", p_menu_set->p_menu_screen_buf_free, q);
637     return -3;
638     }
639    
640     if (*p == '\n' && p > buffer && *(p - 1) != '\r')
641     {
642     *(p_menu_set->p_menu_screen_buf_free) = '\r';
643     p_menu_set->p_menu_screen_buf_free++;
644     }
645    
646     *(p_menu_set->p_menu_screen_buf_free) = *p;
647     p++;
648     p_menu_set->p_menu_screen_buf_free++;
649 sysadm 1.21 }
650     }
651 sysadm 1.31
652 sysadm 1.40 if (p_screen->buf_length == -1)
653     {
654     log_error("End of menu screen [%s] not found\n", p_screen->name);
655     }
656 sysadm 1.21 }
657 sysadm 1.31 }
658     else // Invalid prefix
659     {
660     log_error("Error in menu config line %d\n", fin_line);
661     return -1;
662 sysadm 1.10 }
663 sysadm 1.3 }
664 sysadm 1.21 fclose(fin);
665 sysadm 1.3
666 sysadm 1.40 for (menu_item_id = 0; menu_item_id < p_menu_set->menu_item_count; menu_item_id++)
667     {
668     p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
669 sysadm 1.44
670     // Set menu_item->action_cmd_handler of each menu item pointing to bbs_cmd
671     if (p_menu_item->submenu == 0)
672     {
673     if ((p_menu_item->action_cmd_handler = get_cmd_handler(p_menu_item->action)) == NULL)
674     {
675     log_error("Undefined menu action cmd handler [%s]\n", p_menu_item->action);
676     return -1;
677     }
678     }
679     // Set menu_item->action_menu_id of each menu item pointing to a submenu to the menu_id of the corresponding submenu
680     else if (strcmp(p_menu_item->action, "..") != 0)
681 sysadm 1.40 {
682     if (trie_dict_get(p_menu_set->p_menu_name_dict, p_menu_item->action, (int64_t *)&menu_id) != 1)
683     {
684     log_error("Undefined menu action [%s]\n", p_menu_item->action);
685     return -1;
686     }
687     p_menu_item->action_menu_id = menu_id;
688     }
689     }
690    
691     // Save status varaibles into reserved memory area
692     *((int16_t *)p_menu_set->p_reserved) = p_menu_set->menu_count;
693     *(((int16_t *)p_menu_set->p_reserved) + 1) = p_menu_set->menu_item_count;
694     *(((int16_t *)p_menu_set->p_reserved) + 2) = p_menu_set->menu_screen_count;
695 sysadm 1.2
696 sysadm 1.21 return 0;
697 sysadm 1.1 }
698    
699 sysadm 1.40 static int display_menu_cursor(MENU_SET *p_menu_set, int show)
700 sysadm 1.3 {
701 sysadm 1.40 MENU_ID menu_id;
702     MENU_ITEM_ID menu_item_id;
703     MENU *p_menu;
704     MENU_ITEM *p_menu_item;
705     int16_t menu_item_pos;
706 sysadm 1.39
707 sysadm 1.40 menu_id = p_menu_set->menu_id_path[p_menu_set->choose_step];
708     p_menu = get_menu_by_id(p_menu_set, menu_id);
709     if (p_menu == NULL)
710     {
711     log_error("get_menu_by_id(%d) return NULL pointer\n", menu_id);
712     return -1;
713     }
714 sysadm 1.5
715 sysadm 1.40 menu_item_pos = p_menu_set->menu_item_pos[p_menu_set->choose_step];
716     menu_item_id = p_menu->items[menu_item_pos];
717     p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
718     if (p_menu_item == NULL)
719 sysadm 1.10 {
720 sysadm 1.40 log_error("get_menu_item_by_id(%d) return NULL pointer\n", menu_item_id);
721     return -1;
722 sysadm 1.10 }
723 sysadm 1.5
724 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);
725 sysadm 1.26 outc(show ? '>' : ' ');
726 sysadm 1.21 iflush();
727 sysadm 1.40
728     return 0;
729 sysadm 1.1 }
730    
731 sysadm 1.40 int display_menu(MENU_SET *p_menu_set)
732 sysadm 1.1 {
733 sysadm 1.40 int16_t row = 0;
734     int16_t col = 0;
735 sysadm 1.26 int menu_selectable = 0;
736 sysadm 1.40 MENU_ID menu_id;
737     MENU_ITEM_ID menu_item_id;
738     MENU *p_menu;
739     MENU_ITEM *p_menu_item;
740     MENU_SCREEN *p_menu_screen;
741     int16_t menu_item_pos;
742 sysadm 1.3
743 sysadm 1.40 menu_id = p_menu_set->menu_id_path[p_menu_set->choose_step];
744     p_menu = get_menu_by_id(p_menu_set, menu_id);
745 sysadm 1.21 if (p_menu == NULL)
746 sysadm 1.26 {
747 sysadm 1.40 log_error("get_menu_by_id(%d) return NULL pointer\n", menu_id);
748 sysadm 1.21 return -1;
749 sysadm 1.26 }
750 sysadm 1.5
751 sysadm 1.40 menu_item_pos = p_menu_set->menu_item_pos[p_menu_set->choose_step];
752     menu_item_id = p_menu->items[menu_item_pos];
753     p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
754     if (p_menu_item == NULL)
755     {
756     log_error("get_menu_item_by_id(%d) return NULL pointer\n", menu_item_id);
757     return -1;
758     }
759    
760     if (menu_item_pos > 0 &&
761     checkpriv(&BBS_priv, 0, p_menu_item->priv) != 0 &&
762     checklevel(&BBS_priv, p_menu_item->level) != 0)
763 sysadm 1.35 {
764     menu_selectable = 1;
765     }
766    
767 sysadm 1.21 if (p_menu->title.show)
768 sysadm 1.26 {
769 sysadm 1.21 show_top(p_menu->title.text);
770 sysadm 1.26 }
771 sysadm 1.3
772 sysadm 1.40 if (p_menu->screen_show)
773 sysadm 1.10 {
774 sysadm 1.40 p_menu_screen = get_menu_screen_by_id(p_menu_set, p_menu->screen_id);
775     if (p_menu_screen == NULL)
776 sysadm 1.26 {
777 sysadm 1.40 log_error("get_menu_screen_by_id(%d) return NULL pointer\n", p_menu->screen_id);
778     return -1;
779 sysadm 1.26 }
780 sysadm 1.40
781     moveto(p_menu->screen_row, p_menu->screen_col);
782     prints("%s", p_menu_set->p_menu_screen_buf + p_menu_screen->buf_offset);
783     iflush();
784 sysadm 1.10 }
785 sysadm 1.21
786 sysadm 1.41 for (menu_item_pos = 0; menu_item_pos < p_menu->item_count; menu_item_pos++)
787 sysadm 1.26 {
788 sysadm 1.41 menu_item_id = p_menu->items[menu_item_pos];
789 sysadm 1.40 p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
790    
791     if (p_menu_item->row != 0)
792 sysadm 1.26 {
793 sysadm 1.40 row = p_menu_item->row;
794 sysadm 1.26 }
795 sysadm 1.40 if (p_menu_item->col != 0)
796 sysadm 1.26 {
797 sysadm 1.40 col = p_menu_item->col;
798 sysadm 1.26 }
799 sysadm 1.21
800 sysadm 1.40 if (checkpriv(&BBS_priv, 0, p_menu_item->priv) == 0 || checklevel(&BBS_priv, p_menu_item->level) == 0)
801 sysadm 1.21 {
802 sysadm 1.41 p_menu_set->menu_item_display[menu_item_pos] = 0;
803     p_menu_set->menu_item_r_row[menu_item_pos] = 0;
804     p_menu_set->menu_item_r_col[menu_item_pos] = 0;
805 sysadm 1.21 }
806     else
807     {
808 sysadm 1.41 p_menu_set->menu_item_display[menu_item_pos] = 1;
809 sysadm 1.10
810 sysadm 1.26 if (!menu_selectable)
811     {
812 sysadm 1.41 p_menu_set->menu_item_pos[p_menu_set->choose_step] = menu_item_pos;
813 sysadm 1.26 menu_selectable = 1;
814     }
815 sysadm 1.3
816 sysadm 1.41 p_menu_set->menu_item_r_row[menu_item_pos] = row;
817     p_menu_set->menu_item_r_col[menu_item_pos] = col;
818 sysadm 1.26
819 sysadm 1.21 moveto(row, col);
820 sysadm 1.40 prints("%s", p_menu_item->text);
821 sysadm 1.26
822     row++;
823 sysadm 1.21 }
824 sysadm 1.10 }
825    
826 sysadm 1.21 if (!menu_selectable)
827 sysadm 1.26 {
828 sysadm 1.21 return -1;
829 sysadm 1.26 }
830 sysadm 1.3
831 sysadm 1.40 display_menu_cursor(p_menu_set, 1);
832 sysadm 1.1
833 sysadm 1.21 return 0;
834 sysadm 1.1 }
835    
836 sysadm 1.40 int menu_control(MENU_SET *p_menu_set, int key)
837 sysadm 1.12 {
838 sysadm 1.40 MENU_ID menu_id;
839     MENU_ITEM_ID menu_item_id;
840 sysadm 1.21 MENU *p_menu;
841 sysadm 1.40 MENU_ITEM *p_menu_item;
842     int16_t menu_item_pos;
843 sysadm 1.12
844 sysadm 1.40 if (p_menu_set->menu_count == 0)
845     {
846     return 0;
847     }
848 sysadm 1.12
849 sysadm 1.40 menu_id = p_menu_set->menu_id_path[p_menu_set->choose_step];
850     p_menu = get_menu_by_id(p_menu_set, menu_id);
851     if (p_menu == NULL)
852     {
853     log_error("get_menu_by_id(%d) return NULL pointer\n", menu_id);
854     return -1;
855     }
856 sysadm 1.12
857 sysadm 1.40 if (p_menu->item_count == 0)
858 sysadm 1.26 {
859 sysadm 1.21 return 0;
860 sysadm 1.26 }
861 sysadm 1.3
862 sysadm 1.40 menu_item_pos = p_menu_set->menu_item_pos[p_menu_set->choose_step];
863     menu_item_id = p_menu->items[menu_item_pos];
864     p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
865     if (p_menu_item == NULL)
866     {
867     log_error("get_menu_item_by_id(%d) return NULL pointer\n", menu_item_id);
868     return -1;
869     }
870 sysadm 1.3
871 sysadm 1.21 switch (key)
872 sysadm 1.10 {
873 sysadm 1.21 case CR:
874 sysadm 1.40 igetch_reset();
875 sysadm 1.21 case KEY_RIGHT:
876 sysadm 1.40 if (p_menu_item->submenu)
877 sysadm 1.21 {
878 sysadm 1.40 if (strcmp(p_menu_item->action, "..") == 0)
879 sysadm 1.26 {
880 sysadm 1.21 return menu_control(p_menu_set, KEY_LEFT);
881 sysadm 1.26 }
882 sysadm 1.40 p_menu_set->choose_step++;
883     p_menu_set->menu_id_path[p_menu_set->choose_step] = p_menu_item->action_menu_id;
884     p_menu_set->menu_item_pos[p_menu_set->choose_step] = 0;
885 sysadm 1.26
886 sysadm 1.40 if (display_menu(p_menu_set) != 0)
887 sysadm 1.26 {
888 sysadm 1.21 return menu_control(p_menu_set, KEY_LEFT);
889 sysadm 1.26 }
890 sysadm 1.21 }
891     else
892     {
893 sysadm 1.44 return ((*(p_menu_item->action_cmd_handler))((void *)(p_menu_item->name)));
894 sysadm 1.21 }
895 sysadm 1.38 break;
896 sysadm 1.21 case KEY_LEFT:
897 sysadm 1.40 if (p_menu_set->choose_step > 0)
898 sysadm 1.21 {
899 sysadm 1.40 p_menu_set->choose_step--;
900     if (display_menu(p_menu_set) != 0)
901 sysadm 1.26 {
902 sysadm 1.21 return menu_control(p_menu_set, KEY_LEFT);
903 sysadm 1.26 }
904 sysadm 1.21 }
905     else
906     {
907 sysadm 1.40 display_menu_cursor(p_menu_set, 0);
908     menu_item_pos = p_menu->item_count - 1;
909     while (menu_item_pos >= 0)
910 sysadm 1.26 {
911 sysadm 1.40 menu_item_id = p_menu->items[menu_item_pos];
912     p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
913     if (p_menu_item == NULL)
914     {
915     log_error("get_menu_item_by_id(%d) return NULL pointer\n", menu_item_id);
916     return -1;
917     }
918    
919 sysadm 1.41 if (!p_menu_set->menu_item_display[menu_item_pos] || p_menu_item->priv != 0 || p_menu_item->level != 0)
920 sysadm 1.40 {
921     menu_item_pos--;
922     }
923     else
924     {
925     break;
926     }
927 sysadm 1.26 }
928 sysadm 1.40 p_menu_set->menu_item_pos[p_menu_set->choose_step] = menu_item_pos;
929     display_menu_cursor(p_menu_set, 1);
930 sysadm 1.21 }
931 sysadm 1.38 break;
932 sysadm 1.21 case KEY_UP:
933 sysadm 1.40 display_menu_cursor(p_menu_set, 0);
934 sysadm 1.21 do
935     {
936 sysadm 1.40 menu_item_pos--;
937     if (menu_item_pos < 0)
938     {
939     menu_item_pos = p_menu->item_count - 1;
940     }
941     menu_item_id = p_menu->items[menu_item_pos];
942     p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
943     if (p_menu_item == NULL)
944 sysadm 1.26 {
945 sysadm 1.40 log_error("get_menu_item_by_id(%d) return NULL pointer\n", menu_item_id);
946     return -1;
947 sysadm 1.26 }
948 sysadm 1.41 } while (!p_menu_set->menu_item_display[menu_item_pos]);
949 sysadm 1.40 p_menu_set->menu_item_pos[p_menu_set->choose_step] = menu_item_pos;
950     display_menu_cursor(p_menu_set, 1);
951 sysadm 1.21 break;
952     case KEY_DOWN:
953 sysadm 1.40 display_menu_cursor(p_menu_set, 0);
954 sysadm 1.21 do
955     {
956 sysadm 1.40 menu_item_pos++;
957     if (menu_item_pos >= p_menu->item_count)
958     {
959     menu_item_pos = 0;
960     }
961     menu_item_id = p_menu->items[menu_item_pos];
962     p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
963     if (p_menu_item == NULL)
964 sysadm 1.26 {
965 sysadm 1.40 log_error("get_menu_item_by_id(%d) return NULL pointer\n", menu_item_id);
966     return -1;
967 sysadm 1.26 }
968 sysadm 1.41 } while (!p_menu_set->menu_item_display[menu_item_pos]);
969 sysadm 1.40 p_menu_set->menu_item_pos[p_menu_set->choose_step] = menu_item_pos;
970     display_menu_cursor(p_menu_set, 1);
971 sysadm 1.21 break;
972 sysadm 1.43 case KEY_HOME:
973 sysadm 1.42 case KEY_PGUP:
974     display_menu_cursor(p_menu_set, 0);
975     menu_item_pos = 0;
976     while (menu_item_pos < p_menu->item_count - 1)
977     {
978     menu_item_id = p_menu->items[menu_item_pos];
979     p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
980     if (p_menu_item == NULL)
981     {
982     log_error("get_menu_item_by_id(%d) return NULL pointer\n", menu_item_id);
983     return -1;
984     }
985    
986     if (p_menu_set->menu_item_display[menu_item_pos])
987     {
988     break;
989     }
990    
991     menu_item_pos++;
992     }
993     p_menu_set->menu_item_pos[p_menu_set->choose_step] = menu_item_pos;
994     display_menu_cursor(p_menu_set, 1);
995     break;
996 sysadm 1.43 case KEY_END:
997 sysadm 1.42 case KEY_PGDN:
998     display_menu_cursor(p_menu_set, 0);
999     menu_item_pos = p_menu->item_count - 1;
1000     while (menu_item_pos > 0)
1001     {
1002     menu_item_id = p_menu->items[menu_item_pos];
1003     p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
1004     if (p_menu_item == NULL)
1005     {
1006     log_error("get_menu_item_by_id(%d) return NULL pointer\n", menu_item_id);
1007     return -1;
1008     }
1009    
1010     if (p_menu_set->menu_item_display[menu_item_pos])
1011     {
1012     break;
1013     }
1014    
1015     menu_item_pos--;
1016     }
1017     p_menu_set->menu_item_pos[p_menu_set->choose_step] = menu_item_pos;
1018     display_menu_cursor(p_menu_set, 1);
1019     break;
1020 sysadm 1.21 default:
1021 sysadm 1.31 if (isalnum(key))
1022 sysadm 1.21 {
1023 sysadm 1.41 for (menu_item_pos = 0; menu_item_pos < p_menu->item_count; menu_item_pos++)
1024 sysadm 1.21 {
1025 sysadm 1.41 menu_item_id = p_menu->items[menu_item_pos];
1026 sysadm 1.40 p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
1027     if (p_menu_item == NULL)
1028     {
1029     log_error("get_menu_item_by_id(%d) return NULL pointer\n", menu_item_id);
1030     return -1;
1031     }
1032    
1033 sysadm 1.41 if (toupper(key) == toupper(p_menu_item->name[0]) && p_menu_set->menu_item_display[menu_item_pos])
1034 sysadm 1.21 {
1035 sysadm 1.40 display_menu_cursor(p_menu_set, 0);
1036 sysadm 1.41 p_menu_set->menu_item_pos[p_menu_set->choose_step] = menu_item_pos;
1037 sysadm 1.40 display_menu_cursor(p_menu_set, 1);
1038 sysadm 1.21 return 0;
1039     }
1040     }
1041 sysadm 1.16 }
1042 sysadm 1.38 break;
1043 sysadm 1.3 }
1044 sysadm 1.1
1045 sysadm 1.21 return 0;
1046 sysadm 1.1 }
1047 sysadm 1.15
1048 sysadm 1.40 int unload_menu(MENU_SET *p_menu_set)
1049 sysadm 1.15 {
1050 sysadm 1.39 if (p_menu_set->p_menu_name_dict != NULL)
1051     {
1052     trie_dict_destroy(p_menu_set->p_menu_name_dict);
1053 sysadm 1.46 p_menu_set->p_menu_name_dict = NULL;
1054 sysadm 1.39 }
1055    
1056 sysadm 1.40 if (p_menu_set->p_menu_screen_dict != NULL)
1057     {
1058     trie_dict_destroy(p_menu_set->p_menu_screen_dict);
1059 sysadm 1.46 p_menu_set->p_menu_screen_dict = NULL;
1060 sysadm 1.40 }
1061    
1062     unload_menu_shm(p_menu_set);
1063    
1064     if (shmctl(p_menu_set->shmid, IPC_RMID, NULL) == -1)
1065     {
1066     log_error("shmctl(shmid=%d, IPC_RMID) error (%d)\n", p_menu_set->shmid, errno);
1067     return -1;
1068     }
1069    
1070     return 0;
1071     }
1072    
1073     int load_menu_shm(MENU_SET *p_menu_set)
1074     {
1075     // Mount shared memory
1076 sysadm 1.45 if (p_menu_set->p_reserved == NULL)
1077 sysadm 1.41 {
1078 sysadm 1.45 p_menu_set->p_reserved = shmat(p_menu_set->shmid, NULL, SHM_RDONLY);
1079     if (p_menu_set->p_reserved == (void *)-1)
1080     {
1081     log_error("shmat() error (%d)\n", errno);
1082     return -1;
1083     }
1084 sysadm 1.41 }
1085    
1086 sysadm 1.40 p_menu_set->p_menu_pool = p_menu_set->p_reserved + MENU_SET_RESERVED_LENGTH;
1087     p_menu_set->p_menu_item_pool = p_menu_set->p_menu_pool + sizeof(MENU) * MAX_MENUS;
1088     p_menu_set->p_menu_screen_pool = p_menu_set->p_menu_item_pool + sizeof(MENU_ITEM) * MAX_MENUITEMS;
1089     p_menu_set->p_menu_screen_buf = p_menu_set->p_menu_screen_pool + sizeof(MENU_SCREEN) * MAX_MENUS;
1090     p_menu_set->p_menu_screen_buf_free = p_menu_set->p_menu_screen_buf;
1091    
1092     // Restore status varaibles into reserved memory area
1093     p_menu_set->menu_count = *((int16_t *)p_menu_set->p_reserved);
1094     p_menu_set->menu_item_count = *(((int16_t *)p_menu_set->p_reserved) + 1);
1095     p_menu_set->menu_screen_count = *(((int16_t *)p_menu_set->p_reserved) + 2);
1096    
1097     p_menu_set->choose_step = 0;
1098     p_menu_set->menu_id_path[0] = 0;
1099 sysadm 1.16
1100 sysadm 1.40 p_menu_set->p_menu_name_dict = NULL;
1101     p_menu_set->p_menu_screen_dict = NULL;
1102    
1103     return 0;
1104 sysadm 1.15 }
1105 sysadm 1.18
1106 sysadm 1.40 int unload_menu_shm(MENU_SET *p_menu_set)
1107 sysadm 1.18 {
1108 sysadm 1.40 p_menu_set->menu_count = 0;
1109     p_menu_set->menu_item_count = 0;
1110     p_menu_set->menu_screen_count = 0;
1111     p_menu_set->choose_step = 0;
1112    
1113     p_menu_set->p_menu_pool = NULL;
1114     p_menu_set->p_menu_item_pool = NULL;
1115     p_menu_set->p_menu_screen_pool = NULL;
1116     p_menu_set->p_menu_screen_buf = NULL;
1117     p_menu_set->p_menu_screen_buf_free = NULL;
1118 sysadm 1.21
1119 sysadm 1.41 if (p_menu_set->p_reserved != NULL && shmdt(p_menu_set->p_reserved) == -1)
1120 sysadm 1.40 {
1121     log_error("shmdt() error (%d)\n", errno);
1122     return -1;
1123     }
1124     p_menu_set->p_reserved = NULL;
1125 sysadm 1.18
1126 sysadm 1.40 return 0;
1127 sysadm 1.18 }

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