C-Menu
0.2.9
A User Interface Toolkit
Toggle main menu visibility
Loading...
Searching...
No Matches
parse_menu_desc.c
Go to the documentation of this file.
1
/** @file parse_menu_desc.c
2
@brief Parse menu description file and create Menu
3
@author Bill Waller
4
Copyright (c) 2025
5
MIT License
6
billxwaller@gmail.com
7
@date 2026-02-09
8
*/
9
10
/** @defgroup parse_menu Menu Parser
11
@brief Functions for parsing menu description files and creating Menu
12
structures
13
*/
14
15
#
include
<
common
.
h
>
16
#
include
<
ctype
.
h
>
17
#
include
<
stddef
.
h
>
18
#
include
<
stdlib
.
h
>
19
#
include
<
string
.
h
>
20
21
unsigned
int
parse_menu_description
(Init *);
22
unsigned
int
get_command_type
(
char
*);
23
24
/** @brief Parse menu description file and create Menu
25
@ingroup parse_menu
26
@param init Pointer to Init structure containing menu information
27
@return 0 on success, non-zero on failure
28
*/
29
unsigned
int
parse_menu_description
(Init *init) {
30
FILE *fp;
31
char
tmp_str[
MAXLEN
];
32
char
tmp_buf[
MAXLEN
];
33
char
in_buf[
MAXLEN
];
34
char
*in_buf_p;
35
int
Pos;
36
unsigned
char
ltr;
37
unsigned
char
fltr[127];
38
int
directive;
39
int
l;
40
char
*s, *d, *e;
41
int
actions = 0;
42
int
choices = 0;
43
int
in_fp_line = 0;
44
menu
= init
->
menu
;
45
fp = fopen(
menu
->
mapp_spec
,
"r"
);
46
if
(fp ==
nullptr
) {
47
strnz__cpy
(
tmp_buf
,
"file not found"
,
MAXLEN
)
;
48
abend
(
-1
,
tmp_buf
)
;
49
exit(-1);
50
}
51
while
((fgets(in_buf,
MAXLEN
, fp)) !=
nullptr
) {
52
if
(in_buf[0] ==
'\0'
)
53
continue
;
54
in_fp_line++;
55
chrep
(
in_buf
,
'\r'
,
'\0'
)
;
56
chrep
(
in_buf
,
'\n'
,
'\0'
)
;
57
chrep
(
in_buf
,
'\t'
,
' '
)
;
58
in_buf_p = in_buf;
59
directive = *in_buf_p;
60
in_buf_p++;
61
strnz__cpy
(
tmp_buf
,
in_buf_p
,
MAXLEN
)
;
62
trim
(
tmp_buf
)
;
63
l = strlen(tmp_buf);
64
if
(!l)
65
continue
;
66
if
(directive ==
'#'
)
67
continue
;
68
switch
(directive) {
69
/** '!' Command */
70
case
'!'
:
71
if
(!
menu
->
line_idx
)
72
break
;
73
if
(
menu
->
line
[
menu
->
line_idx
- 1]
->
type
!=
MT_TEXT
)
74
break
;
75
menu
->
line_idx
--;
76
l = strlen(tmp_buf);
77
if
(l + 1 >
MAXLEN
)
78
break
;
79
menu
->
line
[
menu
->
line_idx
]
->
command_str
=
80
calloc(
MAXLEN
+ 1,
sizeof
(
char
));
81
if
(!
menu
->
line
[
menu
->
line_idx
]
->
command_str
) {
82
sprintf(tmp_str,
83
"0-malloc(%d bytes) failed M-L[%d]->command_str"
,
84
MAXLEN
+ 1,
menu
->
line_idx
);
85
abend
(
-1
,
tmp_str
)
;
86
}
87
strnz__cpy
(
menu
->
line
[
menu
->
line_idx
]
->
command_str
,
tmp_buf
,
88
MAXLEN
- 1
)
;
89
menu
->
line
[
menu
->
line_idx
]
->
command_type
=
90
get_command_type
(
tmp_buf
)
;
91
s =
menu
->
line
[
menu
->
line_idx
]
->
raw_text
;
92
if
(*s ==
'-'
|| *s ==
'_'
) {
93
s++;
94
ltr = *s++;
95
}
else
96
ltr = *s;
97
l = 0;
98
while
(*s++ !=
'\0'
)
99
l++;
100
if
(l + 1 >
MAXLEN
)
101
l =
MAXLEN
- 1;
102
menu
->
line
[
menu
->
line_idx
]
->
choice_text
=
103
calloc(
MAXLEN
+ 1,
sizeof
(
char
));
104
if
(!
menu
->
line
[
menu
->
line_idx
]
->
choice_text
) {
105
sprintf(tmp_str,
106
"1-malloc(%d bytes) failed M-L[%d]->choice_text"
,
107
MAXLEN
+ 1,
menu
->
line_idx
);
108
abend
(
-1
,
tmp_str
)
;
109
}
110
d =
menu
->
line
[
menu
->
line_idx
]
->
choice_text
;
111
e = d + l;
112
s =
menu
->
line
[
menu
->
line_idx
]
->
raw_text
;
113
if
(*s ==
'-'
|| *s ==
'_'
)
114
s += 2;
115
while
(*s !=
'\0'
&& d < e)
116
*d++ = *s++;
117
*d = (
char
)
'\0'
;
118
if
(l >
menu
->
choice_max_len
)
119
menu
->
choice_max_len
= l;
120
if
(
menu
->
line
[
menu
->
line_idx
]
->
command_type
==
CT_RETURN
)
121
menu
->
line
[
menu
->
line_idx
]
->
choice_letter
=
'Q'
;
122
else
123
menu
->
line
[
menu
->
line_idx
]
->
choice_letter
= ltr;
124
menu
->
line
[
menu
->
line_idx
]
->
type
=
MT_CHOICE
;
125
menu
->
line_idx
++;
126
actions++;
127
break
;
128
/** ':' Text line, parse and add to menu */
129
case
':'
:
130
if
(choices > actions) {
131
ssnprintf
(
em0
,
MAXLEN
- 1
,
132
"More choices than actions at line %d of"
,
133
in_fp_line
)
;
134
strnz__cpy
(
em1
,
menu
->
mapp_spec
,
MAXLEN
- 1
)
;
135
strnz__cpy
(
em2
,
in_buf
,
MAXLEN
- 1
)
;
136
display_error
(
em0
,
em1
,
em2
,
nullptr
)
;
137
abend
(
-1
,
"unrecoverable error"
)
;
138
}
139
chrep
(
tmp_buf
,
'\t'
,
' '
)
;
140
l = strlen(tmp_buf);
141
if
(l >
menu
->
text_max_len
)
142
menu
->
text_max_len
= l;
143
if
(!
menu
->
title
[0]) {
/**< in_buf -> Title */
144
if
(l + 5 >
MAXLEN
)
145
l =
MAXLEN
- 5;
146
strnz__cpy
(
menu
->
title
,
tmp_buf
,
l
)
;
147
l += 4;
148
if
(l >
menu
->
text_max_len
)
149
menu
->
text_max_len
= l;
150
}
else
{
151
menu
->
line
[
menu
->
line_idx
] = calloc(1,
sizeof
(Line));
152
if
(
menu
->
line
[
menu
->
line_idx
] == (Line *)0) {
153
sprintf(tmp_str,
154
"2-malloc(%ld bytes) failed menu->line[%d]"
,
155
sizeof
(Line),
menu
->
line_idx
);
156
abend
(
-1
,
tmp_str
)
;
157
}
158
menu
->
line
[
menu
->
line_idx
]
->
type
=
MT_TEXT
;
159
menu
->
line
[
menu
->
line_idx
]
->
raw_text
= strdup(tmp_buf);
160
menu
->
line
[
menu
->
line_idx
]
->
choice_text
=
nullptr
;
161
menu
->
line
[
menu
->
line_idx
]
->
choice_letter
=
'\0'
;
162
menu
->
line
[
menu
->
line_idx
]
->
letter_pos
= 0;
163
menu
->
line
[
menu
->
line_idx
]
->
command_type
=
'\0'
;
164
menu
->
line
[
menu
->
line_idx
]
->
command_str
=
nullptr
;
165
menu
->
line_idx
++;
166
choices++;
167
}
168
break
;
169
case
'?'
:
170
break
;
/** ' ' Empty line, ignore */
171
case
' '
:
172
case
'\0'
:
173
case
'\n'
:
174
break
;
175
default
:
176
ssnprintf
(
em0
,
MAXLEN
- 1
,
"Invalid directive '%c' at line %d of"
,
177
directive
,
in_fp_line
)
;
178
strnz__cpy
(
em1
,
menu
->
mapp_spec
,
MAXLEN
- 1
)
;
179
strnz__cpy
(
em2
,
in_buf
,
MAXLEN
- 1
)
;
180
display_error
(
em0
,
em1
,
em2
,
nullptr
)
;
181
}
182
}
183
fclose(fp);
184
menu
->
item_count
=
menu
->
line_idx
;
185
for
(ltr =
'0'
; ltr <
'z'
; ltr++)
186
fltr[ltr] =
FALSE
;
187
fltr[
'Q'
] =
TRUE
;
188
for
(
menu
->
line_idx
= 0;
menu
->
line_idx
<
menu
->
item_count
;
189
menu
->
line_idx
++) {
190
ltr =
menu
->
line
[
menu
->
line_idx
]
->
choice_letter
;
191
if
(ltr <
'0'
|| ltr >
'z'
)
192
ltr =
'0'
;
193
if
(!fltr[ltr] ||
194
(
menu
->
line
[
menu
->
line_idx
]
->
command_type
==
CT_RETURN
&&
195
ltr ==
'Q'
)) {
196
fltr[ltr] =
TRUE
;
197
s =
menu
->
line
[
menu
->
line_idx
]
->
choice_text
;
198
Pos = 0;
199
while
(*s !=
'\0'
) {
200
if
(*s == ltr)
201
break
;
202
s++;
203
Pos++;
204
}
205
}
else
{
206
Pos = 0;
207
while
(ltr !=
'\0'
) {
208
Pos++;
209
ltr = toupper(
menu
->
line
[
menu
->
line_idx
]
->
choice_text
[Pos]);
210
if
(ltr >=
'0'
&& ltr <=
'Z'
)
211
if
(!fltr[ltr])
212
break
;
213
}
214
if
(ltr ==
'\0'
) {
215
for
(ltr =
'0'
; ltr <
'Z'
; ltr++)
216
if
(!fltr[ltr])
217
break
;
218
if
(ltr >
'z'
) {
219
Perror
(
"Ran out of letters"
)
;
220
return
0;
221
}
222
}
223
fltr[ltr] =
TRUE
;
224
menu
->
line
[
menu
->
line_idx
]
->
choice_letter
= ltr;
225
}
226
menu
->
line
[
menu
->
line_idx
]
->
letter_pos
= Pos;
227
}
228
menu
->
lines
=
menu
->
item_count
;
229
if
(
menu
->
text_max_len
> (
menu
->
choice_max_len
+ 6))
230
menu
->
cols
=
menu
->
text_max_len
;
231
else
232
menu
->
cols
=
menu
->
choice_max_len
+ 6;
233
if
(
menu
->
cols
>=
MAXLEN
)
234
Perror
(
"line too long"
)
;
235
for
(
menu
->
line_idx
= 0;
menu
->
line_idx
<
menu
->
item_count
;
236
menu
->
line_idx
++) {
237
strnz__cpy
(
tmp_buf
,
" x - "
,
MAXLEN
- 1
)
;
238
tmp_buf[1] =
menu
->
line
[
menu
->
line_idx
]
->
choice_letter
;
239
strnz__cat
(
tmp_buf
,
menu
->
line
[
menu
->
line_idx
]
->
choice_text
,
240
MAXLEN
- 1
)
;
241
strnz__cpy
(
menu
->
line
[
menu
->
line_idx
]
->
choice_text
,
tmp_buf
,
242
MAXLEN
- 1
)
;
243
}
244
return
0;
245
}
246
/** @brief Get command type from command string
247
@ingroup parse_menu
248
@param t Command string
249
@return Command type as an unsigned int
250
*/
251
unsigned
int
get_command_type
(
char
*t) {
252
char
*s, *p;
253
254
s = p = t;
255
while
(*s !=
' '
&& *s !=
'\0'
) {
256
if
(*s ==
'/'
)
257
p = s + 1;
258
s++;
259
}
260
*s =
'\0'
;
261
if
(!strcmp(p,
"ckeys"
))
262
return
(
CT_CKEYS
);
263
else
if
(!strcmp(p,
"exec"
))
264
return
(
CT_EXEC
);
265
else
if
(!strcmp(p,
"help"
))
266
return
(
CT_HELP
);
267
else
if
(!strcmp(p,
"about"
))
268
return
(
CT_ABOUT
);
269
else
if
(!strcmp(p,
"menu"
))
270
return
(
CT_MENU
);
271
else
if
(!strcmp(p,
"form"
))
272
return
(
CT_FORM
);
273
else
if
(!strcmp(p,
"pick"
))
274
return
(
CT_PICK
);
275
else
if
(!strcmp(p,
"return"
))
276
return
(
CT_RETURN
);
277
else
if
(!strcmp(p,
"view"
))
278
return
(
CT_VIEW
);
279
else
if
(!strcmp(p,
"?"
))
280
return
(
CT_HELP
);
281
else
if
(!strcmp(p,
"write_config"
))
282
return
(
CT_WRITE_CONFIG
);
283
return
(
CT_UNDEFINED
);
284
}
nullptr
#define nullptr
Definition
cm.h:23
MT_TEXT
@ MT_TEXT
Definition
menu.h:22
MT_CHOICE
@ MT_CHOICE
Definition
menu.h:22
menu
Menu * menu
Definition
mem.c:45
CT_PICK
@ CT_PICK
Definition
menu.h:37
CT_FORM
@ CT_FORM
Definition
menu.h:33
CT_UNDEFINED
@ CT_UNDEFINED
Definition
menu.h:43
CT_MENU
@ CT_MENU
Definition
menu.h:36
CT_RETURN
@ CT_RETURN
Definition
menu.h:40
CT_HELP
@ CT_HELP
Definition
menu.h:31
CT_WRITE_CONFIG
@ CT_WRITE_CONFIG
Definition
menu.h:42
CT_EXEC
@ CT_EXEC
Definition
menu.h:30
CT_VIEW
@ CT_VIEW
Definition
menu.h:38
CT_ABOUT
@ CT_ABOUT
Definition
menu.h:32
CT_CKEYS
@ CT_CKEYS
Definition
menu.h:39
TRUE
#define TRUE
Definition
iloan.c:19
FALSE
#define FALSE
Definition
iloan.c:18
MAXLEN
#define MAXLEN
Definition
curskeys.c:15
em1
char em1[MAXLEN]
Definition
dwin.c:133
em0
char em0[MAXLEN]
Definition
dwin.c:132
em2
char em2[MAXLEN]
Definition
dwin.c:134
Perror
int Perror(char *)
Display a simple error message window or print to stderr.
Definition
dwin.c:1110
display_error
int display_error(char *em0, char *em1, char *em2, char *em3)
Display an error message window or print to stderr.
Definition
dwin.c:1054
abend
void abend(int, char *)
Abnormal program termination.
Definition
dwin.c:1331
strnz__cpy
size_t strnz__cpy(char *, const char *, size_t)
safer alternative to strncpy
Definition
futil.c:269
trim
size_t trim(char *)
Trims leading and trailing spaces from string s in place.
Definition
futil.c:118
ssnprintf
size_t ssnprintf(char *, size_t, const char *,...)
ssnprintf was designed to be a safer alternative to snprintf.
Definition
futil.c:147
strnz__cat
size_t strnz__cat(char *, const char *, size_t)
safer alternative to strncat
Definition
futil.c:298
chrep
bool chrep(char *, char, char)
Replaces all occurrences of old_chr in s with new_chr in place.
Definition
futil.c:486
get_command_type
unsigned int get_command_type(char *)
Get command type from command string.
Definition
parse_menu_desc.c:251
parse_menu_description
unsigned int parse_menu_description(Init *)
Parse menu description file and create Menu.
Definition
parse_menu_desc.c:29
Init::menu
Menu * menu
Definition
common.h:172
Line::choice_text
char * choice_text
Definition
menu.h:54
Line::raw_text
char * raw_text
Definition
menu.h:51
Line::command_str
char * command_str
Definition
menu.h:70
Line::type
unsigned int type
Definition
menu.h:49
Line::letter_pos
int letter_pos
Definition
menu.h:60
Line::command_type
unsigned int command_type
Definition
menu.h:64
Line::choice_letter
char choice_letter
Definition
menu.h:57
Menu::cols
int cols
Definition
menu.h:92
Menu::mapp_spec
char mapp_spec[MAXLEN]
Definition
menu.h:115
Menu::line
Line * line[MAX_MENU_LINES]
Definition
menu.h:194
Menu::text_max_len
int text_max_len
Definition
menu.h:181
Menu::item_count
int item_count
Definition
menu.h:187
Menu::choice_max_len
int choice_max_len
Definition
menu.h:175
Menu::line_idx
int line_idx
Definition
menu.h:190
Menu::lines
int lines
Definition
menu.h:90
Menu::title
char title[MAXLEN]
Definition
menu.h:106
parse_menu_desc.c
Generated by
1.17.0