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

Annotation of /lbbs/src/menu.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.47 - (hide annotations)
Sun May 18 08:53:21 2025 UTC (10 months ago) by sysadm
Branch: MAIN
Changes since 1.46: +21 -6 lines
Content type: text/x-csrc
Refine menu: clear screen lines before output
Truncate blank lines in menu config

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.47 strncpy(p_menu->screen_name, p, sizeof(p_menu->screen_name) - 1);
550     p_menu->screen_name[sizeof(p_menu->screen_name) - 1] = '\0';
551 sysadm 1.31
552     // Check syntax
553     q = strtok_r(NULL, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
554     if (q != NULL)
555     {
556     log_error("Unknown extra content in menu config line %d\n", fin_line);
557     return -1;
558     }
559 sysadm 1.21 }
560 sysadm 1.31 }
561     }
562     else // BEGIN of menu screen
563     {
564 sysadm 1.40 if (p_menu_set->menu_item_count >= MAX_MENUS)
565     {
566     log_error("Menu screen count (%d) exceed limit (%d)\n", p_menu_set->menu_screen_count, MAX_MENUS);
567     return -3;
568     }
569     screen_id = (MENU_SCREEN_ID)p_menu_set->menu_screen_count;
570     p_menu_set->menu_screen_count++;
571    
572     p_screen = get_menu_screen_by_id(p_menu_set, screen_id);
573    
574 sysadm 1.31 q = p;
575     while (isalnum(*q) || *q == '_')
576     {
577     q++;
578     }
579     if (*q != '\0')
580     {
581     log_error("Error menu screen name in menu config line %d\n", fin_line);
582     return -1;
583     }
584 sysadm 1.40 strncpy(p_screen->name, p, sizeof(p_screen->name) - 1);
585     p_screen->name[sizeof(p_screen->name) - 1] = '\0';
586 sysadm 1.31
587 sysadm 1.40 if (trie_dict_set(p_menu_set->p_menu_screen_dict, p_screen->name, (int64_t)screen_id) != 1)
588     {
589     log_error("Error set menu screen dict [%s]\n", p_screen->name);
590     }
591 sysadm 1.31
592     // Check syntax
593     q = strtok_r(NULL, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
594     if (q != NULL)
595     {
596     log_error("Unknown extra content in menu config line %d\n", fin_line);
597     return -1;
598     }
599    
600 sysadm 1.40 p_screen->buf_offset = p_menu_set->p_menu_screen_buf_free - p_menu_set->p_menu_screen_buf;
601     p_screen->buf_length = -1;
602    
603     // safety appending boundary
604     q = p_menu_set->p_menu_screen_buf + MAX_MENU_SCR_BUF_LENGTH * MAX_MENUS - 1;
605 sysadm 1.31
606     while (fgets(buffer, sizeof(buffer), fin))
607     {
608     fin_line++;
609    
610 sysadm 1.40 strncpy(temp, buffer, sizeof(temp) - 1); // Duplicate line for strtok_r
611     temp[sizeof(temp) - 1] = '\0';
612 sysadm 1.33 p = strtok_r(temp, MENU_CONF_DELIM_WITH_SPACE, &saveptr);
613 sysadm 1.31 if (p != NULL && *p == '%') // END of menu screen
614 sysadm 1.21 {
615 sysadm 1.40 if (p_menu_set->p_menu_screen_buf_free + 1 > q)
616     {
617     log_error("Menu screen buffer depleted (%p + 1 > %p)\n", p_menu_set->p_menu_screen_buf_free, q);
618     return -3;
619     }
620    
621     *(p_menu_set->p_menu_screen_buf_free) = '\0';
622     p_menu_set->p_menu_screen_buf_free++;
623     p_screen->buf_length = p_menu_set->p_menu_screen_buf_free - p_menu_set->p_menu_screen_buf - p_screen->buf_offset;
624 sysadm 1.31 break;
625 sysadm 1.21 }
626 sysadm 1.31
627 sysadm 1.47 // Clear line
628     if (p_menu_set->p_menu_screen_buf_free + strlen(CTRL_SEQ_CLR_LINE) > q)
629     {
630     log_error("Menu screen buffer depleted (%p + %d > %p)\n", p_menu_set->p_menu_screen_buf_free, q, strlen(CTRL_SEQ_CLR_LINE));
631     return -3;
632     }
633     p_menu_set->p_menu_screen_buf_free = stpcpy(p_menu_set->p_menu_screen_buf_free, CTRL_SEQ_CLR_LINE);
634    
635 sysadm 1.40 p = buffer;
636     while (*p != '\0')
637 sysadm 1.21 {
638 sysadm 1.40 if (p_menu_set->p_menu_screen_buf_free + 2 > q)
639     {
640     log_error("Menu screen buffer depleted (%p + 2 > %p)\n", p_menu_set->p_menu_screen_buf_free, q);
641     return -3;
642     }
643    
644     if (*p == '\n' && p > buffer && *(p - 1) != '\r')
645     {
646     *(p_menu_set->p_menu_screen_buf_free) = '\r';
647     p_menu_set->p_menu_screen_buf_free++;
648     }
649    
650     *(p_menu_set->p_menu_screen_buf_free) = *p;
651     p++;
652     p_menu_set->p_menu_screen_buf_free++;
653 sysadm 1.21 }
654     }
655 sysadm 1.31
656 sysadm 1.40 if (p_screen->buf_length == -1)
657     {
658     log_error("End of menu screen [%s] not found\n", p_screen->name);
659     }
660 sysadm 1.21 }
661 sysadm 1.31 }
662     else // Invalid prefix
663     {
664     log_error("Error in menu config line %d\n", fin_line);
665     return -1;
666 sysadm 1.10 }
667 sysadm 1.3 }
668 sysadm 1.21 fclose(fin);
669 sysadm 1.3
670 sysadm 1.47 for (menu_id = 0; menu_id < p_menu_set->menu_count; menu_id++)
671     {
672     p_menu = get_menu_by_id(p_menu_set, menu_id);
673    
674     if (trie_dict_get(p_menu_set->p_menu_screen_dict, p_menu->screen_name, (int64_t *)(&(p_menu->screen_id))) != 1)
675     {
676     log_error("Undefined menu screen [%s]\n", p);
677     return -1;
678     }
679     }
680    
681 sysadm 1.40 for (menu_item_id = 0; menu_item_id < p_menu_set->menu_item_count; menu_item_id++)
682     {
683     p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
684 sysadm 1.44
685     // Set menu_item->action_cmd_handler of each menu item pointing to bbs_cmd
686     if (p_menu_item->submenu == 0)
687     {
688     if ((p_menu_item->action_cmd_handler = get_cmd_handler(p_menu_item->action)) == NULL)
689     {
690     log_error("Undefined menu action cmd handler [%s]\n", p_menu_item->action);
691     return -1;
692     }
693     }
694     // Set menu_item->action_menu_id of each menu item pointing to a submenu to the menu_id of the corresponding submenu
695     else if (strcmp(p_menu_item->action, "..") != 0)
696 sysadm 1.40 {
697     if (trie_dict_get(p_menu_set->p_menu_name_dict, p_menu_item->action, (int64_t *)&menu_id) != 1)
698     {
699     log_error("Undefined menu action [%s]\n", p_menu_item->action);
700     return -1;
701     }
702     p_menu_item->action_menu_id = menu_id;
703     }
704     }
705    
706     // Save status varaibles into reserved memory area
707     *((int16_t *)p_menu_set->p_reserved) = p_menu_set->menu_count;
708     *(((int16_t *)p_menu_set->p_reserved) + 1) = p_menu_set->menu_item_count;
709     *(((int16_t *)p_menu_set->p_reserved) + 2) = p_menu_set->menu_screen_count;
710 sysadm 1.2
711 sysadm 1.21 return 0;
712 sysadm 1.1 }
713    
714 sysadm 1.40 static int display_menu_cursor(MENU_SET *p_menu_set, int show)
715 sysadm 1.3 {
716 sysadm 1.40 MENU_ID menu_id;
717     MENU_ITEM_ID menu_item_id;
718     MENU *p_menu;
719     MENU_ITEM *p_menu_item;
720     int16_t menu_item_pos;
721 sysadm 1.39
722 sysadm 1.40 menu_id = p_menu_set->menu_id_path[p_menu_set->choose_step];
723     p_menu = get_menu_by_id(p_menu_set, menu_id);
724     if (p_menu == NULL)
725     {
726     log_error("get_menu_by_id(%d) return NULL pointer\n", menu_id);
727     return -1;
728     }
729 sysadm 1.5
730 sysadm 1.40 menu_item_pos = p_menu_set->menu_item_pos[p_menu_set->choose_step];
731     menu_item_id = p_menu->items[menu_item_pos];
732     p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
733     if (p_menu_item == NULL)
734 sysadm 1.10 {
735 sysadm 1.40 log_error("get_menu_item_by_id(%d) return NULL pointer\n", menu_item_id);
736     return -1;
737 sysadm 1.10 }
738 sysadm 1.5
739 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);
740 sysadm 1.26 outc(show ? '>' : ' ');
741 sysadm 1.21 iflush();
742 sysadm 1.40
743     return 0;
744 sysadm 1.1 }
745    
746 sysadm 1.40 int display_menu(MENU_SET *p_menu_set)
747 sysadm 1.1 {
748 sysadm 1.40 int16_t row = 0;
749     int16_t col = 0;
750 sysadm 1.26 int menu_selectable = 0;
751 sysadm 1.40 MENU_ID menu_id;
752     MENU_ITEM_ID menu_item_id;
753     MENU *p_menu;
754     MENU_ITEM *p_menu_item;
755     MENU_SCREEN *p_menu_screen;
756     int16_t menu_item_pos;
757 sysadm 1.3
758 sysadm 1.40 menu_id = p_menu_set->menu_id_path[p_menu_set->choose_step];
759     p_menu = get_menu_by_id(p_menu_set, menu_id);
760 sysadm 1.21 if (p_menu == NULL)
761 sysadm 1.26 {
762 sysadm 1.40 log_error("get_menu_by_id(%d) return NULL pointer\n", menu_id);
763 sysadm 1.21 return -1;
764 sysadm 1.26 }
765 sysadm 1.5
766 sysadm 1.40 menu_item_pos = p_menu_set->menu_item_pos[p_menu_set->choose_step];
767     menu_item_id = p_menu->items[menu_item_pos];
768     p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
769     if (p_menu_item == NULL)
770     {
771     log_error("get_menu_item_by_id(%d) return NULL pointer\n", menu_item_id);
772     return -1;
773     }
774    
775     if (menu_item_pos > 0 &&
776     checkpriv(&BBS_priv, 0, p_menu_item->priv) != 0 &&
777     checklevel(&BBS_priv, p_menu_item->level) != 0)
778 sysadm 1.35 {
779     menu_selectable = 1;
780     }
781    
782 sysadm 1.21 if (p_menu->title.show)
783 sysadm 1.26 {
784 sysadm 1.21 show_top(p_menu->title.text);
785 sysadm 1.26 }
786 sysadm 1.3
787 sysadm 1.40 if (p_menu->screen_show)
788 sysadm 1.10 {
789 sysadm 1.40 p_menu_screen = get_menu_screen_by_id(p_menu_set, p_menu->screen_id);
790     if (p_menu_screen == NULL)
791 sysadm 1.26 {
792 sysadm 1.40 log_error("get_menu_screen_by_id(%d) return NULL pointer\n", p_menu->screen_id);
793     return -1;
794 sysadm 1.26 }
795 sysadm 1.40
796     moveto(p_menu->screen_row, p_menu->screen_col);
797     prints("%s", p_menu_set->p_menu_screen_buf + p_menu_screen->buf_offset);
798     iflush();
799 sysadm 1.10 }
800 sysadm 1.21
801 sysadm 1.41 for (menu_item_pos = 0; menu_item_pos < p_menu->item_count; menu_item_pos++)
802 sysadm 1.26 {
803 sysadm 1.41 menu_item_id = p_menu->items[menu_item_pos];
804 sysadm 1.40 p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
805    
806     if (p_menu_item->row != 0)
807 sysadm 1.26 {
808 sysadm 1.40 row = p_menu_item->row;
809 sysadm 1.26 }
810 sysadm 1.40 if (p_menu_item->col != 0)
811 sysadm 1.26 {
812 sysadm 1.40 col = p_menu_item->col;
813 sysadm 1.26 }
814 sysadm 1.21
815 sysadm 1.40 if (checkpriv(&BBS_priv, 0, p_menu_item->priv) == 0 || checklevel(&BBS_priv, p_menu_item->level) == 0)
816 sysadm 1.21 {
817 sysadm 1.41 p_menu_set->menu_item_display[menu_item_pos] = 0;
818     p_menu_set->menu_item_r_row[menu_item_pos] = 0;
819     p_menu_set->menu_item_r_col[menu_item_pos] = 0;
820 sysadm 1.21 }
821     else
822     {
823 sysadm 1.41 p_menu_set->menu_item_display[menu_item_pos] = 1;
824 sysadm 1.10
825 sysadm 1.26 if (!menu_selectable)
826     {
827 sysadm 1.41 p_menu_set->menu_item_pos[p_menu_set->choose_step] = menu_item_pos;
828 sysadm 1.26 menu_selectable = 1;
829     }
830 sysadm 1.3
831 sysadm 1.41 p_menu_set->menu_item_r_row[menu_item_pos] = row;
832     p_menu_set->menu_item_r_col[menu_item_pos] = col;
833 sysadm 1.26
834 sysadm 1.21 moveto(row, col);
835 sysadm 1.40 prints("%s", p_menu_item->text);
836 sysadm 1.26
837     row++;
838 sysadm 1.21 }
839 sysadm 1.10 }
840    
841 sysadm 1.21 if (!menu_selectable)
842 sysadm 1.26 {
843 sysadm 1.21 return -1;
844 sysadm 1.26 }
845 sysadm 1.3
846 sysadm 1.40 display_menu_cursor(p_menu_set, 1);
847 sysadm 1.1
848 sysadm 1.21 return 0;
849 sysadm 1.1 }
850    
851 sysadm 1.40 int menu_control(MENU_SET *p_menu_set, int key)
852 sysadm 1.12 {
853 sysadm 1.40 MENU_ID menu_id;
854     MENU_ITEM_ID menu_item_id;
855 sysadm 1.21 MENU *p_menu;
856 sysadm 1.40 MENU_ITEM *p_menu_item;
857     int16_t menu_item_pos;
858 sysadm 1.12
859 sysadm 1.40 if (p_menu_set->menu_count == 0)
860     {
861     return 0;
862     }
863 sysadm 1.12
864 sysadm 1.40 menu_id = p_menu_set->menu_id_path[p_menu_set->choose_step];
865     p_menu = get_menu_by_id(p_menu_set, menu_id);
866     if (p_menu == NULL)
867     {
868     log_error("get_menu_by_id(%d) return NULL pointer\n", menu_id);
869     return -1;
870     }
871 sysadm 1.12
872 sysadm 1.40 if (p_menu->item_count == 0)
873 sysadm 1.26 {
874 sysadm 1.21 return 0;
875 sysadm 1.26 }
876 sysadm 1.3
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     {
882     log_error("get_menu_item_by_id(%d) return NULL pointer\n", menu_item_id);
883     return -1;
884     }
885 sysadm 1.3
886 sysadm 1.21 switch (key)
887 sysadm 1.10 {
888 sysadm 1.21 case CR:
889 sysadm 1.40 igetch_reset();
890 sysadm 1.21 case KEY_RIGHT:
891 sysadm 1.40 if (p_menu_item->submenu)
892 sysadm 1.21 {
893 sysadm 1.40 if (strcmp(p_menu_item->action, "..") == 0)
894 sysadm 1.26 {
895 sysadm 1.21 return menu_control(p_menu_set, KEY_LEFT);
896 sysadm 1.26 }
897 sysadm 1.40 p_menu_set->choose_step++;
898     p_menu_set->menu_id_path[p_menu_set->choose_step] = p_menu_item->action_menu_id;
899     p_menu_set->menu_item_pos[p_menu_set->choose_step] = 0;
900 sysadm 1.26
901 sysadm 1.40 if (display_menu(p_menu_set) != 0)
902 sysadm 1.26 {
903 sysadm 1.21 return menu_control(p_menu_set, KEY_LEFT);
904 sysadm 1.26 }
905 sysadm 1.21 }
906     else
907     {
908 sysadm 1.44 return ((*(p_menu_item->action_cmd_handler))((void *)(p_menu_item->name)));
909 sysadm 1.21 }
910 sysadm 1.38 break;
911 sysadm 1.21 case KEY_LEFT:
912 sysadm 1.40 if (p_menu_set->choose_step > 0)
913 sysadm 1.21 {
914 sysadm 1.40 p_menu_set->choose_step--;
915     if (display_menu(p_menu_set) != 0)
916 sysadm 1.26 {
917 sysadm 1.21 return menu_control(p_menu_set, KEY_LEFT);
918 sysadm 1.26 }
919 sysadm 1.21 }
920     else
921     {
922 sysadm 1.40 display_menu_cursor(p_menu_set, 0);
923     menu_item_pos = p_menu->item_count - 1;
924     while (menu_item_pos >= 0)
925 sysadm 1.26 {
926 sysadm 1.40 menu_item_id = p_menu->items[menu_item_pos];
927     p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
928     if (p_menu_item == NULL)
929     {
930     log_error("get_menu_item_by_id(%d) return NULL pointer\n", menu_item_id);
931     return -1;
932     }
933    
934 sysadm 1.41 if (!p_menu_set->menu_item_display[menu_item_pos] || p_menu_item->priv != 0 || p_menu_item->level != 0)
935 sysadm 1.40 {
936     menu_item_pos--;
937     }
938     else
939     {
940     break;
941     }
942 sysadm 1.26 }
943 sysadm 1.40 p_menu_set->menu_item_pos[p_menu_set->choose_step] = menu_item_pos;
944     display_menu_cursor(p_menu_set, 1);
945 sysadm 1.21 }
946 sysadm 1.38 break;
947 sysadm 1.21 case KEY_UP:
948 sysadm 1.40 display_menu_cursor(p_menu_set, 0);
949 sysadm 1.21 do
950     {
951 sysadm 1.40 menu_item_pos--;
952     if (menu_item_pos < 0)
953     {
954     menu_item_pos = p_menu->item_count - 1;
955     }
956     menu_item_id = p_menu->items[menu_item_pos];
957     p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
958     if (p_menu_item == NULL)
959 sysadm 1.26 {
960 sysadm 1.40 log_error("get_menu_item_by_id(%d) return NULL pointer\n", menu_item_id);
961     return -1;
962 sysadm 1.26 }
963 sysadm 1.41 } while (!p_menu_set->menu_item_display[menu_item_pos]);
964 sysadm 1.40 p_menu_set->menu_item_pos[p_menu_set->choose_step] = menu_item_pos;
965     display_menu_cursor(p_menu_set, 1);
966 sysadm 1.21 break;
967     case KEY_DOWN:
968 sysadm 1.40 display_menu_cursor(p_menu_set, 0);
969 sysadm 1.21 do
970     {
971 sysadm 1.40 menu_item_pos++;
972     if (menu_item_pos >= p_menu->item_count)
973     {
974     menu_item_pos = 0;
975     }
976     menu_item_id = p_menu->items[menu_item_pos];
977     p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
978     if (p_menu_item == NULL)
979 sysadm 1.26 {
980 sysadm 1.40 log_error("get_menu_item_by_id(%d) return NULL pointer\n", menu_item_id);
981     return -1;
982 sysadm 1.26 }
983 sysadm 1.41 } while (!p_menu_set->menu_item_display[menu_item_pos]);
984 sysadm 1.40 p_menu_set->menu_item_pos[p_menu_set->choose_step] = menu_item_pos;
985     display_menu_cursor(p_menu_set, 1);
986 sysadm 1.21 break;
987 sysadm 1.43 case KEY_HOME:
988 sysadm 1.42 case KEY_PGUP:
989     display_menu_cursor(p_menu_set, 0);
990     menu_item_pos = 0;
991     while (menu_item_pos < p_menu->item_count - 1)
992     {
993     menu_item_id = p_menu->items[menu_item_pos];
994     p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
995     if (p_menu_item == NULL)
996     {
997     log_error("get_menu_item_by_id(%d) return NULL pointer\n", menu_item_id);
998     return -1;
999     }
1000    
1001     if (p_menu_set->menu_item_display[menu_item_pos])
1002     {
1003     break;
1004     }
1005    
1006     menu_item_pos++;
1007     }
1008     p_menu_set->menu_item_pos[p_menu_set->choose_step] = menu_item_pos;
1009     display_menu_cursor(p_menu_set, 1);
1010     break;
1011 sysadm 1.43 case KEY_END:
1012 sysadm 1.42 case KEY_PGDN:
1013     display_menu_cursor(p_menu_set, 0);
1014     menu_item_pos = p_menu->item_count - 1;
1015     while (menu_item_pos > 0)
1016     {
1017     menu_item_id = p_menu->items[menu_item_pos];
1018     p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
1019     if (p_menu_item == NULL)
1020     {
1021     log_error("get_menu_item_by_id(%d) return NULL pointer\n", menu_item_id);
1022     return -1;
1023     }
1024    
1025     if (p_menu_set->menu_item_display[menu_item_pos])
1026     {
1027     break;
1028     }
1029    
1030     menu_item_pos--;
1031     }
1032     p_menu_set->menu_item_pos[p_menu_set->choose_step] = menu_item_pos;
1033     display_menu_cursor(p_menu_set, 1);
1034     break;
1035 sysadm 1.21 default:
1036 sysadm 1.31 if (isalnum(key))
1037 sysadm 1.21 {
1038 sysadm 1.41 for (menu_item_pos = 0; menu_item_pos < p_menu->item_count; menu_item_pos++)
1039 sysadm 1.21 {
1040 sysadm 1.41 menu_item_id = p_menu->items[menu_item_pos];
1041 sysadm 1.40 p_menu_item = get_menu_item_by_id(p_menu_set, menu_item_id);
1042     if (p_menu_item == NULL)
1043     {
1044     log_error("get_menu_item_by_id(%d) return NULL pointer\n", menu_item_id);
1045     return -1;
1046     }
1047    
1048 sysadm 1.41 if (toupper(key) == toupper(p_menu_item->name[0]) && p_menu_set->menu_item_display[menu_item_pos])
1049 sysadm 1.21 {
1050 sysadm 1.40 display_menu_cursor(p_menu_set, 0);
1051 sysadm 1.41 p_menu_set->menu_item_pos[p_menu_set->choose_step] = menu_item_pos;
1052 sysadm 1.40 display_menu_cursor(p_menu_set, 1);
1053 sysadm 1.21 return 0;
1054     }
1055     }
1056 sysadm 1.16 }
1057 sysadm 1.38 break;
1058 sysadm 1.3 }
1059 sysadm 1.1
1060 sysadm 1.21 return 0;
1061 sysadm 1.1 }
1062 sysadm 1.15
1063 sysadm 1.40 int unload_menu(MENU_SET *p_menu_set)
1064 sysadm 1.15 {
1065 sysadm 1.39 if (p_menu_set->p_menu_name_dict != NULL)
1066     {
1067     trie_dict_destroy(p_menu_set->p_menu_name_dict);
1068 sysadm 1.46 p_menu_set->p_menu_name_dict = NULL;
1069 sysadm 1.39 }
1070    
1071 sysadm 1.40 if (p_menu_set->p_menu_screen_dict != NULL)
1072     {
1073     trie_dict_destroy(p_menu_set->p_menu_screen_dict);
1074 sysadm 1.46 p_menu_set->p_menu_screen_dict = NULL;
1075 sysadm 1.40 }
1076    
1077     unload_menu_shm(p_menu_set);
1078    
1079     if (shmctl(p_menu_set->shmid, IPC_RMID, NULL) == -1)
1080     {
1081     log_error("shmctl(shmid=%d, IPC_RMID) error (%d)\n", p_menu_set->shmid, errno);
1082     return -1;
1083     }
1084    
1085     return 0;
1086     }
1087    
1088     int load_menu_shm(MENU_SET *p_menu_set)
1089     {
1090     // Mount shared memory
1091 sysadm 1.45 if (p_menu_set->p_reserved == NULL)
1092 sysadm 1.41 {
1093 sysadm 1.45 p_menu_set->p_reserved = shmat(p_menu_set->shmid, NULL, SHM_RDONLY);
1094     if (p_menu_set->p_reserved == (void *)-1)
1095     {
1096     log_error("shmat() error (%d)\n", errno);
1097     return -1;
1098     }
1099 sysadm 1.41 }
1100    
1101 sysadm 1.40 p_menu_set->p_menu_pool = p_menu_set->p_reserved + MENU_SET_RESERVED_LENGTH;
1102     p_menu_set->p_menu_item_pool = p_menu_set->p_menu_pool + sizeof(MENU) * MAX_MENUS;
1103     p_menu_set->p_menu_screen_pool = p_menu_set->p_menu_item_pool + sizeof(MENU_ITEM) * MAX_MENUITEMS;
1104     p_menu_set->p_menu_screen_buf = p_menu_set->p_menu_screen_pool + sizeof(MENU_SCREEN) * MAX_MENUS;
1105     p_menu_set->p_menu_screen_buf_free = p_menu_set->p_menu_screen_buf;
1106    
1107     // Restore status varaibles into reserved memory area
1108     p_menu_set->menu_count = *((int16_t *)p_menu_set->p_reserved);
1109     p_menu_set->menu_item_count = *(((int16_t *)p_menu_set->p_reserved) + 1);
1110     p_menu_set->menu_screen_count = *(((int16_t *)p_menu_set->p_reserved) + 2);
1111    
1112     p_menu_set->choose_step = 0;
1113     p_menu_set->menu_id_path[0] = 0;
1114 sysadm 1.16
1115 sysadm 1.40 p_menu_set->p_menu_name_dict = NULL;
1116     p_menu_set->p_menu_screen_dict = NULL;
1117    
1118     return 0;
1119 sysadm 1.15 }
1120 sysadm 1.18
1121 sysadm 1.40 int unload_menu_shm(MENU_SET *p_menu_set)
1122 sysadm 1.18 {
1123 sysadm 1.40 p_menu_set->menu_count = 0;
1124     p_menu_set->menu_item_count = 0;
1125     p_menu_set->menu_screen_count = 0;
1126     p_menu_set->choose_step = 0;
1127    
1128     p_menu_set->p_menu_pool = NULL;
1129     p_menu_set->p_menu_item_pool = NULL;
1130     p_menu_set->p_menu_screen_pool = NULL;
1131     p_menu_set->p_menu_screen_buf = NULL;
1132     p_menu_set->p_menu_screen_buf_free = NULL;
1133 sysadm 1.21
1134 sysadm 1.41 if (p_menu_set->p_reserved != NULL && shmdt(p_menu_set->p_reserved) == -1)
1135 sysadm 1.40 {
1136     log_error("shmdt() error (%d)\n", errno);
1137     return -1;
1138     }
1139     p_menu_set->p_reserved = NULL;
1140 sysadm 1.18
1141 sysadm 1.40 return 0;
1142 sysadm 1.18 }

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