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

Annotation of /lbbs/src/menu.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.43 - (hide annotations)
Thu May 15 09:15:52 2025 UTC (10 months ago) by sysadm
Branch: MAIN
Changes since 1.42: +2 -0 lines
Content type: text/x-csrc
Add HOME/END handling for menu

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 // Set menu_item->action_menu_id of each menu item pointing to a submenu to the menu_id of the corresponding submenu
667     for (menu_item_id = 0; menu_item_id < p_menu_set->menu_item_count; menu_item_id++)
668     {
669     p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
670     if (p_menu_item->submenu == 1 && strcmp(p_menu_item->action, "..") != 0)
671     {
672     if (trie_dict_get(p_menu_set->p_menu_name_dict, p_menu_item->action, (int64_t *)&menu_id) != 1)
673     {
674     log_error("Undefined menu action [%s]\n", p_menu_item->action);
675     return -1;
676     }
677     p_menu_item->action_menu_id = menu_id;
678     }
679     }
680    
681     // Save status varaibles into reserved memory area
682     *((int16_t *)p_menu_set->p_reserved) = p_menu_set->menu_count;
683     *(((int16_t *)p_menu_set->p_reserved) + 1) = p_menu_set->menu_item_count;
684     *(((int16_t *)p_menu_set->p_reserved) + 2) = p_menu_set->menu_screen_count;
685 sysadm 1.2
686 sysadm 1.21 return 0;
687 sysadm 1.1 }
688    
689 sysadm 1.40 static int display_menu_cursor(MENU_SET *p_menu_set, int show)
690 sysadm 1.3 {
691 sysadm 1.40 MENU_ID menu_id;
692     MENU_ITEM_ID menu_item_id;
693     MENU *p_menu;
694     MENU_ITEM *p_menu_item;
695     int16_t menu_item_pos;
696 sysadm 1.39
697 sysadm 1.40 menu_id = p_menu_set->menu_id_path[p_menu_set->choose_step];
698     p_menu = get_menu_by_id(p_menu_set, menu_id);
699     if (p_menu == NULL)
700     {
701     log_error("get_menu_by_id(%d) return NULL pointer\n", menu_id);
702     return -1;
703     }
704 sysadm 1.5
705 sysadm 1.40 menu_item_pos = p_menu_set->menu_item_pos[p_menu_set->choose_step];
706     menu_item_id = p_menu->items[menu_item_pos];
707     p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
708     if (p_menu_item == NULL)
709 sysadm 1.10 {
710 sysadm 1.40 log_error("get_menu_item_by_id(%d) return NULL pointer\n", menu_item_id);
711     return -1;
712 sysadm 1.10 }
713 sysadm 1.5
714 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);
715 sysadm 1.26 outc(show ? '>' : ' ');
716 sysadm 1.21 iflush();
717 sysadm 1.40
718     return 0;
719 sysadm 1.1 }
720    
721 sysadm 1.40 int display_menu(MENU_SET *p_menu_set)
722 sysadm 1.1 {
723 sysadm 1.40 int16_t row = 0;
724     int16_t col = 0;
725 sysadm 1.26 int menu_selectable = 0;
726 sysadm 1.40 MENU_ID menu_id;
727     MENU_ITEM_ID menu_item_id;
728     MENU *p_menu;
729     MENU_ITEM *p_menu_item;
730     MENU_SCREEN *p_menu_screen;
731     int16_t menu_item_pos;
732 sysadm 1.3
733 sysadm 1.40 menu_id = p_menu_set->menu_id_path[p_menu_set->choose_step];
734     p_menu = get_menu_by_id(p_menu_set, menu_id);
735 sysadm 1.21 if (p_menu == NULL)
736 sysadm 1.26 {
737 sysadm 1.40 log_error("get_menu_by_id(%d) return NULL pointer\n", menu_id);
738 sysadm 1.21 return -1;
739 sysadm 1.26 }
740 sysadm 1.5
741 sysadm 1.40 menu_item_pos = p_menu_set->menu_item_pos[p_menu_set->choose_step];
742     menu_item_id = p_menu->items[menu_item_pos];
743     p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
744     if (p_menu_item == NULL)
745     {
746     log_error("get_menu_item_by_id(%d) return NULL pointer\n", menu_item_id);
747     return -1;
748     }
749    
750     if (menu_item_pos > 0 &&
751     checkpriv(&BBS_priv, 0, p_menu_item->priv) != 0 &&
752     checklevel(&BBS_priv, p_menu_item->level) != 0)
753 sysadm 1.35 {
754     menu_selectable = 1;
755     }
756    
757 sysadm 1.21 if (p_menu->title.show)
758 sysadm 1.26 {
759 sysadm 1.21 show_top(p_menu->title.text);
760 sysadm 1.26 }
761 sysadm 1.3
762 sysadm 1.40 if (p_menu->screen_show)
763 sysadm 1.10 {
764 sysadm 1.40 p_menu_screen = get_menu_screen_by_id(p_menu_set, p_menu->screen_id);
765     if (p_menu_screen == NULL)
766 sysadm 1.26 {
767 sysadm 1.40 log_error("get_menu_screen_by_id(%d) return NULL pointer\n", p_menu->screen_id);
768     return -1;
769 sysadm 1.26 }
770 sysadm 1.40
771     moveto(p_menu->screen_row, p_menu->screen_col);
772     prints("%s", p_menu_set->p_menu_screen_buf + p_menu_screen->buf_offset);
773     iflush();
774 sysadm 1.10 }
775 sysadm 1.21
776 sysadm 1.41 for (menu_item_pos = 0; menu_item_pos < p_menu->item_count; menu_item_pos++)
777 sysadm 1.26 {
778 sysadm 1.41 menu_item_id = p_menu->items[menu_item_pos];
779 sysadm 1.40 p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
780    
781     if (p_menu_item->row != 0)
782 sysadm 1.26 {
783 sysadm 1.40 row = p_menu_item->row;
784 sysadm 1.26 }
785 sysadm 1.40 if (p_menu_item->col != 0)
786 sysadm 1.26 {
787 sysadm 1.40 col = p_menu_item->col;
788 sysadm 1.26 }
789 sysadm 1.21
790 sysadm 1.40 if (checkpriv(&BBS_priv, 0, p_menu_item->priv) == 0 || checklevel(&BBS_priv, p_menu_item->level) == 0)
791 sysadm 1.21 {
792 sysadm 1.41 p_menu_set->menu_item_display[menu_item_pos] = 0;
793     p_menu_set->menu_item_r_row[menu_item_pos] = 0;
794     p_menu_set->menu_item_r_col[menu_item_pos] = 0;
795 sysadm 1.21 }
796     else
797     {
798 sysadm 1.41 p_menu_set->menu_item_display[menu_item_pos] = 1;
799 sysadm 1.10
800 sysadm 1.26 if (!menu_selectable)
801     {
802 sysadm 1.41 p_menu_set->menu_item_pos[p_menu_set->choose_step] = menu_item_pos;
803 sysadm 1.26 menu_selectable = 1;
804     }
805 sysadm 1.3
806 sysadm 1.41 p_menu_set->menu_item_r_row[menu_item_pos] = row;
807     p_menu_set->menu_item_r_col[menu_item_pos] = col;
808 sysadm 1.26
809 sysadm 1.21 moveto(row, col);
810 sysadm 1.40 prints("%s", p_menu_item->text);
811 sysadm 1.26
812     row++;
813 sysadm 1.21 }
814 sysadm 1.10 }
815    
816 sysadm 1.21 if (!menu_selectable)
817 sysadm 1.26 {
818 sysadm 1.21 return -1;
819 sysadm 1.26 }
820 sysadm 1.3
821 sysadm 1.40 display_menu_cursor(p_menu_set, 1);
822 sysadm 1.1
823 sysadm 1.21 return 0;
824 sysadm 1.1 }
825    
826 sysadm 1.40 int menu_control(MENU_SET *p_menu_set, int key)
827 sysadm 1.12 {
828 sysadm 1.40 MENU_ID menu_id;
829     MENU_ITEM_ID menu_item_id;
830 sysadm 1.21 MENU *p_menu;
831 sysadm 1.40 MENU_ITEM *p_menu_item;
832     int16_t menu_item_pos;
833 sysadm 1.12
834 sysadm 1.40 if (p_menu_set->menu_count == 0)
835     {
836     return 0;
837     }
838 sysadm 1.12
839 sysadm 1.40 menu_id = p_menu_set->menu_id_path[p_menu_set->choose_step];
840     p_menu = get_menu_by_id(p_menu_set, menu_id);
841     if (p_menu == NULL)
842     {
843     log_error("get_menu_by_id(%d) return NULL pointer\n", menu_id);
844     return -1;
845     }
846 sysadm 1.12
847 sysadm 1.40 if (p_menu->item_count == 0)
848 sysadm 1.26 {
849 sysadm 1.21 return 0;
850 sysadm 1.26 }
851 sysadm 1.3
852 sysadm 1.40 menu_item_pos = p_menu_set->menu_item_pos[p_menu_set->choose_step];
853     menu_item_id = p_menu->items[menu_item_pos];
854     p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
855     if (p_menu_item == NULL)
856     {
857     log_error("get_menu_item_by_id(%d) return NULL pointer\n", menu_item_id);
858     return -1;
859     }
860 sysadm 1.3
861 sysadm 1.21 switch (key)
862 sysadm 1.10 {
863 sysadm 1.21 case CR:
864 sysadm 1.40 igetch_reset();
865 sysadm 1.21 case KEY_RIGHT:
866 sysadm 1.40 if (p_menu_item->submenu)
867 sysadm 1.21 {
868 sysadm 1.40 if (strcmp(p_menu_item->action, "..") == 0)
869 sysadm 1.26 {
870 sysadm 1.21 return menu_control(p_menu_set, KEY_LEFT);
871 sysadm 1.26 }
872 sysadm 1.40 p_menu_set->choose_step++;
873     p_menu_set->menu_id_path[p_menu_set->choose_step] = p_menu_item->action_menu_id;
874     p_menu_set->menu_item_pos[p_menu_set->choose_step] = 0;
875 sysadm 1.26
876 sysadm 1.40 if (display_menu(p_menu_set) != 0)
877 sysadm 1.26 {
878 sysadm 1.21 return menu_control(p_menu_set, KEY_LEFT);
879 sysadm 1.26 }
880 sysadm 1.21 }
881     else
882     {
883 sysadm 1.40 return (exec_cmd(p_menu_item->action, p_menu_item->name));
884 sysadm 1.21 }
885 sysadm 1.38 break;
886 sysadm 1.21 case KEY_LEFT:
887 sysadm 1.40 if (p_menu_set->choose_step > 0)
888 sysadm 1.21 {
889 sysadm 1.40 p_menu_set->choose_step--;
890     if (display_menu(p_menu_set) != 0)
891 sysadm 1.26 {
892 sysadm 1.21 return menu_control(p_menu_set, KEY_LEFT);
893 sysadm 1.26 }
894 sysadm 1.21 }
895     else
896     {
897 sysadm 1.40 display_menu_cursor(p_menu_set, 0);
898     menu_item_pos = p_menu->item_count - 1;
899     while (menu_item_pos >= 0)
900 sysadm 1.26 {
901 sysadm 1.40 menu_item_id = p_menu->items[menu_item_pos];
902     p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
903     if (p_menu_item == NULL)
904     {
905     log_error("get_menu_item_by_id(%d) return NULL pointer\n", menu_item_id);
906     return -1;
907     }
908    
909 sysadm 1.41 if (!p_menu_set->menu_item_display[menu_item_pos] || p_menu_item->priv != 0 || p_menu_item->level != 0)
910 sysadm 1.40 {
911     menu_item_pos--;
912     }
913     else
914     {
915     break;
916     }
917 sysadm 1.26 }
918 sysadm 1.40 p_menu_set->menu_item_pos[p_menu_set->choose_step] = menu_item_pos;
919     display_menu_cursor(p_menu_set, 1);
920 sysadm 1.21 }
921 sysadm 1.38 break;
922 sysadm 1.21 case KEY_UP:
923 sysadm 1.40 display_menu_cursor(p_menu_set, 0);
924 sysadm 1.21 do
925     {
926 sysadm 1.40 menu_item_pos--;
927     if (menu_item_pos < 0)
928     {
929     menu_item_pos = p_menu->item_count - 1;
930     }
931     menu_item_id = p_menu->items[menu_item_pos];
932     p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
933     if (p_menu_item == NULL)
934 sysadm 1.26 {
935 sysadm 1.40 log_error("get_menu_item_by_id(%d) return NULL pointer\n", menu_item_id);
936     return -1;
937 sysadm 1.26 }
938 sysadm 1.41 } while (!p_menu_set->menu_item_display[menu_item_pos]);
939 sysadm 1.40 p_menu_set->menu_item_pos[p_menu_set->choose_step] = menu_item_pos;
940     display_menu_cursor(p_menu_set, 1);
941 sysadm 1.21 break;
942     case KEY_DOWN:
943 sysadm 1.40 display_menu_cursor(p_menu_set, 0);
944 sysadm 1.21 do
945     {
946 sysadm 1.40 menu_item_pos++;
947     if (menu_item_pos >= p_menu->item_count)
948     {
949     menu_item_pos = 0;
950     }
951     menu_item_id = p_menu->items[menu_item_pos];
952     p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
953     if (p_menu_item == NULL)
954 sysadm 1.26 {
955 sysadm 1.40 log_error("get_menu_item_by_id(%d) return NULL pointer\n", menu_item_id);
956     return -1;
957 sysadm 1.26 }
958 sysadm 1.41 } while (!p_menu_set->menu_item_display[menu_item_pos]);
959 sysadm 1.40 p_menu_set->menu_item_pos[p_menu_set->choose_step] = menu_item_pos;
960     display_menu_cursor(p_menu_set, 1);
961 sysadm 1.21 break;
962 sysadm 1.43 case KEY_HOME:
963 sysadm 1.42 case KEY_PGUP:
964     display_menu_cursor(p_menu_set, 0);
965     menu_item_pos = 0;
966     while (menu_item_pos < p_menu->item_count - 1)
967     {
968     menu_item_id = p_menu->items[menu_item_pos];
969     p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
970     if (p_menu_item == NULL)
971     {
972     log_error("get_menu_item_by_id(%d) return NULL pointer\n", menu_item_id);
973     return -1;
974     }
975    
976     if (p_menu_set->menu_item_display[menu_item_pos])
977     {
978     break;
979     }
980    
981     menu_item_pos++;
982     }
983     p_menu_set->menu_item_pos[p_menu_set->choose_step] = menu_item_pos;
984     display_menu_cursor(p_menu_set, 1);
985     break;
986 sysadm 1.43 case KEY_END:
987 sysadm 1.42 case KEY_PGDN:
988     display_menu_cursor(p_menu_set, 0);
989     menu_item_pos = p_menu->item_count - 1;
990     while (menu_item_pos > 0)
991     {
992     menu_item_id = p_menu->items[menu_item_pos];
993     p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
994     if (p_menu_item == NULL)
995     {
996     log_error("get_menu_item_by_id(%d) return NULL pointer\n", menu_item_id);
997     return -1;
998     }
999    
1000     if (p_menu_set->menu_item_display[menu_item_pos])
1001     {
1002     break;
1003     }
1004    
1005     menu_item_pos--;
1006     }
1007     p_menu_set->menu_item_pos[p_menu_set->choose_step] = menu_item_pos;
1008     display_menu_cursor(p_menu_set, 1);
1009     break;
1010 sysadm 1.21 default:
1011 sysadm 1.31 if (isalnum(key))
1012 sysadm 1.21 {
1013 sysadm 1.41 for (menu_item_pos = 0; menu_item_pos < p_menu->item_count; menu_item_pos++)
1014 sysadm 1.21 {
1015 sysadm 1.41 menu_item_id = p_menu->items[menu_item_pos];
1016 sysadm 1.40 p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
1017     if (p_menu_item == NULL)
1018     {
1019     log_error("get_menu_item_by_id(%d) return NULL pointer\n", menu_item_id);
1020     return -1;
1021     }
1022    
1023 sysadm 1.41 if (toupper(key) == toupper(p_menu_item->name[0]) && p_menu_set->menu_item_display[menu_item_pos])
1024 sysadm 1.21 {
1025 sysadm 1.40 display_menu_cursor(p_menu_set, 0);
1026 sysadm 1.41 p_menu_set->menu_item_pos[p_menu_set->choose_step] = menu_item_pos;
1027 sysadm 1.40 display_menu_cursor(p_menu_set, 1);
1028 sysadm 1.21 return 0;
1029     }
1030     }
1031 sysadm 1.16 }
1032 sysadm 1.38 break;
1033 sysadm 1.3 }
1034 sysadm 1.1
1035 sysadm 1.21 return 0;
1036 sysadm 1.1 }
1037 sysadm 1.15
1038 sysadm 1.40 int unload_menu(MENU_SET *p_menu_set)
1039 sysadm 1.15 {
1040 sysadm 1.39 if (p_menu_set->p_menu_name_dict != NULL)
1041     {
1042     trie_dict_destroy(p_menu_set->p_menu_name_dict);
1043     p_menu_set->p_menu_name_dict = NULL;
1044     }
1045    
1046 sysadm 1.40 if (p_menu_set->p_menu_screen_dict != NULL)
1047     {
1048     trie_dict_destroy(p_menu_set->p_menu_screen_dict);
1049     p_menu_set->p_menu_screen_dict = NULL;
1050     }
1051    
1052     unload_menu_shm(p_menu_set);
1053    
1054     if (shmctl(p_menu_set->shmid, IPC_RMID, NULL) == -1)
1055     {
1056     log_error("shmctl(shmid=%d, IPC_RMID) error (%d)\n", p_menu_set->shmid, errno);
1057     return -1;
1058     }
1059    
1060     return 0;
1061     }
1062    
1063     int load_menu_shm(MENU_SET *p_menu_set)
1064     {
1065     // Mount shared memory
1066 sysadm 1.41 if (p_menu_set->p_reserved != NULL)
1067     {
1068     log_error("Menu is already loaded\n");
1069     return -1;
1070     }
1071    
1072 sysadm 1.40 p_menu_set->p_reserved = shmat(p_menu_set->shmid, NULL, SHM_RDONLY);
1073     if (p_menu_set->p_reserved == (void *)-1)
1074 sysadm 1.16 {
1075 sysadm 1.40 log_error("shmat() error (%d)\n", errno);
1076 sysadm 1.41 return -2;
1077 sysadm 1.16 }
1078 sysadm 1.40 p_menu_set->p_menu_pool = p_menu_set->p_reserved + MENU_SET_RESERVED_LENGTH;
1079     p_menu_set->p_menu_item_pool = p_menu_set->p_menu_pool + sizeof(MENU) * MAX_MENUS;
1080     p_menu_set->p_menu_screen_pool = p_menu_set->p_menu_item_pool + sizeof(MENU_ITEM) * MAX_MENUITEMS;
1081     p_menu_set->p_menu_screen_buf = p_menu_set->p_menu_screen_pool + sizeof(MENU_SCREEN) * MAX_MENUS;
1082     p_menu_set->p_menu_screen_buf_free = p_menu_set->p_menu_screen_buf;
1083    
1084     // Restore status varaibles into reserved memory area
1085     p_menu_set->menu_count = *((int16_t *)p_menu_set->p_reserved);
1086     p_menu_set->menu_item_count = *(((int16_t *)p_menu_set->p_reserved) + 1);
1087     p_menu_set->menu_screen_count = *(((int16_t *)p_menu_set->p_reserved) + 2);
1088    
1089     p_menu_set->choose_step = 0;
1090     p_menu_set->menu_id_path[0] = 0;
1091 sysadm 1.16
1092 sysadm 1.40 p_menu_set->p_menu_name_dict = NULL;
1093     p_menu_set->p_menu_screen_dict = NULL;
1094    
1095     return 0;
1096 sysadm 1.15 }
1097 sysadm 1.18
1098 sysadm 1.40 int unload_menu_shm(MENU_SET *p_menu_set)
1099 sysadm 1.18 {
1100 sysadm 1.40 p_menu_set->menu_count = 0;
1101     p_menu_set->menu_item_count = 0;
1102     p_menu_set->menu_screen_count = 0;
1103     p_menu_set->choose_step = 0;
1104    
1105     p_menu_set->p_menu_pool = NULL;
1106     p_menu_set->p_menu_item_pool = NULL;
1107     p_menu_set->p_menu_screen_pool = NULL;
1108     p_menu_set->p_menu_screen_buf = NULL;
1109     p_menu_set->p_menu_screen_buf_free = NULL;
1110 sysadm 1.21
1111 sysadm 1.41 if (p_menu_set->p_reserved != NULL && shmdt(p_menu_set->p_reserved) == -1)
1112 sysadm 1.40 {
1113     log_error("shmdt() error (%d)\n", errno);
1114     return -1;
1115     }
1116     p_menu_set->p_reserved = NULL;
1117 sysadm 1.18
1118 sysadm 1.40 return 0;
1119 sysadm 1.18 }

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