2 * Window Maker window manager
4 * Copyright (c) 2012 Christophe Curis
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 #include <WINGs/WUtil.h>
29 #include "menuparser.h"
31 static WMenuParser
menu_parser_create_new(const char *file_name
, void *file
);
32 static char *menu_parser_isolate_token(WMenuParser parser
);
35 /***** Constructor and Destructor for the Menu Parser object *****/
36 WMenuParser
WMenuParserCreate(const char *file_name
, void *file
)
40 parser
= menu_parser_create_new(file_name
, file
);
44 void WMenuParserDelete(WMenuParser parser
)
49 static WMenuParser
menu_parser_create_new(const char *file_name
, void *file
)
53 parser
= wmalloc(sizeof(*parser
));
54 parser
->file_name
= file_name
;
55 parser
->file_handle
= file
;
56 parser
->rd
= parser
->line_buffer
;
61 /***** To report helpfull messages to user *****/
62 const char *WMenuParserGetFilename(WMenuParser parser
)
64 return parser
->file_name
;
67 void WMenuParserError(WMenuParser parser
, const char *msg
, ...)
73 vsnprintf(buf
, sizeof(buf
), msg
, args
);
75 __wmessage("WMenuParser", parser
->file_name
, parser
->line_number
, WMESSAGE_TYPE_WARNING
, buf
);
78 /***** Read one line from file and split content *****/
79 /* The function returns False when the end of file is reached */
80 Bool
WMenuParserGetLine(WMenuParser top_parser
, char **title
, char **command
, char **parameter
, char **shortcut
)
82 WMenuParser cur_parser
;
83 enum { GET_TITLE
, GET_COMMAND
, GET_PARAMETERS
, GET_SHORTCUT
} scanmode
;
85 char lineparam
[MAXLINE
];
95 cur_parser
= top_parser
;
98 if (fgets(cur_parser
->line_buffer
, sizeof(cur_parser
->line_buffer
), cur_parser
->file_handle
) == NULL
) {
101 cur_parser
->line_number
++;
102 cur_parser
->rd
= cur_parser
->line_buffer
;
105 if (!menu_parser_skip_spaces_and_comments(cur_parser
)) {
106 /* We reached the end of line */
107 if (scanmode
== GET_TITLE
)
108 goto read_next_line
; // Empty line -> skip
110 break; // Finished reading current line -> return it to caller
114 token
= menu_parser_isolate_token(cur_parser
);
118 scanmode
= GET_COMMAND
;
122 if (strcmp(token
, "SHORTCUT") == 0) {
123 scanmode
= GET_SHORTCUT
;
127 scanmode
= GET_PARAMETERS
;
132 if (*shortcut
!= NULL
) {
133 WMenuParserError(top_parser
, _("multiple SHORTCUT definition not valid") );
137 scanmode
= GET_COMMAND
;
144 if (params
== NULL
) {
147 if ((params
- lineparam
) < sizeof(lineparam
)-1)
151 while ((params
- lineparam
) < sizeof(lineparam
)-1)
152 if ( (*params
= *src
++) == '\0')
162 if (params
!= NULL
) {
163 lineparam
[sizeof(lineparam
) - 1] = '\0';
164 *parameter
= wstrdup(lineparam
);
170 /* Return False when there's nothing left on the line,
171 otherwise increment parser's pointer to next token */
172 Bool
menu_parser_skip_spaces_and_comments(WMenuParser parser
)
175 while (isspace(*parser
->rd
))
178 if (*parser
->rd
== '\0')
179 return False
; // Found the end of current line
181 else if ((parser
->rd
[0] == '\\') &&
182 (parser
->rd
[1] == '\n') &&
183 (parser
->rd
[2] == '\0')) {
184 // Means that the current line is expected to be continued on next line
185 if (fgets(parser
->line_buffer
, sizeof(parser
->line_buffer
), parser
->file_handle
) == NULL
) {
186 WMenuParserError(parser
, _("premature end of file while expecting a new line after '\\'") );
189 parser
->line_number
++;
190 parser
->rd
= parser
->line_buffer
;
192 } else if (parser
->rd
[0] == '/') {
193 if (parser
->rd
[1] == '/') // Single line C comment
194 return False
; // Won't find anything more on this line
195 if (parser
->rd
[1] == '*') {
198 start_line
= parser
->line_number
;
201 /* Search end-of-comment marker */
202 while (*parser
->rd
!= '\0') {
203 if (parser
->rd
[0] == '*')
204 if (parser
->rd
[1] == '/')
205 goto found_end_of_comment
;
209 /* Marker not found -> load next line */
210 if (fgets(parser
->line_buffer
, sizeof(parser
->line_buffer
), parser
->file_handle
) == NULL
) {
211 WMenuParserError(parser
, _("reached end of file while searching '*/' for comment started at line %d"), start_line
);
214 parser
->line_number
++;
215 parser
->rd
= parser
->line_buffer
;
218 found_end_of_comment
:
219 parser
->rd
+= 2; // Skip closing mark
220 continue; // Because there may be spaces after the comment
222 return True
; // the '/' was not a comment, treat it as user data
224 return True
; // Found some data
228 /* read a token (non-spaces suite of characters)
229 the result os wmalloc's, so it needs to be free'd */
230 static char *menu_parser_isolate_token(WMenuParser parser
)
237 while (*parser
->rd
!= '\0')
238 if (isspace(*parser
->rd
))
240 else if ((parser
->rd
[0] == '/') &&
241 ((parser
->rd
[1] == '*') || (parser
->rd
[1] == '/')))
243 else if ((parser
->rd
[0] == '\\') && (parser
->rd
[1] == '\n'))
245 else if ((*parser
->rd
== '"' ) || (*parser
->rd
== '\'')) {
246 char eot
= *parser
->rd
++;
247 while ((*parser
->rd
!= '\0') && (*parser
->rd
!= '\n'))
248 if (*parser
->rd
++ == eot
)
249 goto found_end_quote
;
250 WMenuParserError(parser
, _("missing closing quote or double-quote before end-of-line") );
256 token
= wmalloc(parser
->rd
- start
+ 1);
257 strncpy(token
, start
, parser
->rd
- start
);
258 token
[parser
->rd
- start
] = '\0';