mirror of
https://github.com/gryf/wmaker.git
synced 2026-01-08 23:04:15 +01:00
Remove dependency to CPP: new parser that handles comments
Wrote a new parsing code that is able to skip over comments. Note that because CPP is still active, you will not see any effect unless you disable CPP pre-processing.
This commit is contained in:
committed by
Carlos R. Mafra
parent
7d74648fc3
commit
ed9482b626
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Window Maker window manager
|
* Window Maker window manager
|
||||||
*
|
*
|
||||||
* Copyright (c) 1997-2003 Alfredo K. Kojima
|
* Copyright (c) 2012 Christophe Curis
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
#include <WINGs/WUtil.h>
|
#include <WINGs/WUtil.h>
|
||||||
@@ -28,7 +29,7 @@
|
|||||||
#include "menuparser.h"
|
#include "menuparser.h"
|
||||||
|
|
||||||
static WMenuParser menu_parser_create_new(const char *file_name, void *file);
|
static WMenuParser menu_parser_create_new(const char *file_name, void *file);
|
||||||
static void separateline(char *line, char **title, char **command, char **parameter, char **shortcut);
|
static char *menu_parser_isolate_token(WMenuParser parser);
|
||||||
|
|
||||||
|
|
||||||
/***** Constructor and Destructor for the Menu Parser object *****/
|
/***** Constructor and Destructor for the Menu Parser object *****/
|
||||||
@@ -75,104 +76,186 @@ void WMenuParserError(WMenuParser parser, const char *msg, ...)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/***** Read one line from file and split content *****/
|
/***** Read one line from file and split content *****/
|
||||||
|
/* The function returns False when the end of file is reached */
|
||||||
Bool WMenuParserGetLine(WMenuParser top_parser, char **title, char **command, char **parameter, char **shortcut)
|
Bool WMenuParserGetLine(WMenuParser top_parser, char **title, char **command, char **parameter, char **shortcut)
|
||||||
{
|
{
|
||||||
WMenuParser cur_parser;
|
WMenuParser cur_parser;
|
||||||
char *line = NULL, *result = NULL;
|
enum { GET_TITLE, GET_COMMAND, GET_PARAMETERS, GET_SHORTCUT } scanmode;
|
||||||
size_t len;
|
char *token;
|
||||||
int done;
|
char lineparam[MAXLINE];
|
||||||
|
char *params = NULL;
|
||||||
|
|
||||||
|
lineparam[0] = '\0';
|
||||||
*title = NULL;
|
*title = NULL;
|
||||||
*command = NULL;
|
*command = NULL;
|
||||||
*parameter = NULL;
|
*parameter = NULL;
|
||||||
*shortcut = NULL;
|
*shortcut = NULL;
|
||||||
|
scanmode = GET_TITLE;
|
||||||
|
|
||||||
cur_parser = top_parser;
|
cur_parser = top_parser;
|
||||||
|
|
||||||
again:
|
read_next_line:
|
||||||
done = 0;
|
if (fgets(cur_parser->line_buffer, sizeof(cur_parser->line_buffer), cur_parser->file_handle) == NULL) {
|
||||||
while (!done && fgets(cur_parser->line_buffer, sizeof(cur_parser->line_buffer), cur_parser->file_handle) != NULL) {
|
return False;
|
||||||
line = wtrimspace(cur_parser->line_buffer);
|
}
|
||||||
len = strlen(line);
|
cur_parser->line_number++;
|
||||||
cur_parser->line_number++;
|
cur_parser->rd = cur_parser->line_buffer;
|
||||||
|
|
||||||
/* allow line wrapping */
|
for (;;) {
|
||||||
if (len > 0 && line[len - 1] == '\\') {
|
if (!menu_parser_skip_spaces_and_comments(cur_parser)) {
|
||||||
line[len - 1] = '\0';
|
/* We reached the end of line */
|
||||||
} else {
|
if (scanmode == GET_TITLE)
|
||||||
done = 1;
|
goto read_next_line; // Empty line -> skip
|
||||||
|
else
|
||||||
|
break; // Finished reading current line -> return it to caller
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result == NULL) {
|
/* Found a word */
|
||||||
result = line;
|
token = menu_parser_isolate_token(cur_parser);
|
||||||
} else {
|
switch (scanmode) {
|
||||||
if (strlen(result) < MAXLINE) {
|
case GET_TITLE:
|
||||||
result = wstrappend(result, line);
|
*title = token;
|
||||||
|
scanmode = GET_COMMAND;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GET_COMMAND:
|
||||||
|
if (strcmp(token, "SHORTCUT") == 0) {
|
||||||
|
scanmode = GET_SHORTCUT;
|
||||||
|
wfree(token);
|
||||||
|
} else {
|
||||||
|
*command = token;
|
||||||
|
scanmode = GET_PARAMETERS;
|
||||||
}
|
}
|
||||||
wfree(line);
|
break;
|
||||||
|
|
||||||
|
case GET_SHORTCUT:
|
||||||
|
if (*shortcut != NULL) {
|
||||||
|
WMenuParserError(top_parser, _("multiple SHORTCUT definition not valid") );
|
||||||
|
wfree(*shortcut);
|
||||||
|
}
|
||||||
|
*shortcut = token;
|
||||||
|
scanmode = GET_COMMAND;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GET_PARAMETERS:
|
||||||
|
{
|
||||||
|
char *src;
|
||||||
|
|
||||||
|
if (params == NULL) {
|
||||||
|
params = lineparam;
|
||||||
|
} else {
|
||||||
|
if ((params - lineparam) < sizeof(lineparam)-1)
|
||||||
|
*params++ = ' ';
|
||||||
|
}
|
||||||
|
src = token;
|
||||||
|
while ((params - lineparam) < sizeof(lineparam)-1)
|
||||||
|
if ( (*params = *src++) == '\0')
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
params++;
|
||||||
|
wfree(token);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!done || ferror(cur_parser->file_handle)) {
|
|
||||||
wfree(result);
|
if (params != NULL) {
|
||||||
result = NULL;
|
lineparam[sizeof(lineparam) - 1] = '\0';
|
||||||
} else if (result != NULL && (result[0] == 0 || result[0] == '#' ||
|
*parameter = wstrdup(lineparam);
|
||||||
(result[0] == '/' && result[1] == '/'))) {
|
|
||||||
wfree(result);
|
|
||||||
result = NULL;
|
|
||||||
goto again;
|
|
||||||
} else if (result != NULL && strlen(result) >= MAXLINE) {
|
|
||||||
WMenuParserError(cur_parser, _("maximal line size exceeded in menu config") );
|
|
||||||
wfree(result);
|
|
||||||
result = NULL;
|
|
||||||
goto again;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result == NULL)
|
|
||||||
return False;
|
|
||||||
|
|
||||||
separateline(line, title, command, parameter, shortcut);
|
|
||||||
wfree(line);
|
|
||||||
return True;
|
return True;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void separateline(char *line, char **title, char **command, char **parameter, char **shortcut)
|
/* Return False when there's nothing left on the line,
|
||||||
|
otherwise increment parser's pointer to next token */
|
||||||
|
Bool menu_parser_skip_spaces_and_comments(WMenuParser parser)
|
||||||
{
|
{
|
||||||
char *suffix, *next = line;
|
for (;;) {
|
||||||
|
while (isspace(*parser->rd))
|
||||||
|
parser->rd++;
|
||||||
|
|
||||||
/* get the title */
|
if (*parser->rd == '\0')
|
||||||
*title = wtokennext(line, &next);
|
return False; // Found the end of current line
|
||||||
if (next == NULL)
|
|
||||||
return;
|
|
||||||
line = next;
|
|
||||||
|
|
||||||
/* get the command or shortcut keyword */
|
else if ((parser->rd[0] == '\\') &&
|
||||||
*command = wtokennext(line, &next);
|
(parser->rd[1] == '\n') &&
|
||||||
if (next == NULL)
|
(parser->rd[2] == '\0')) {
|
||||||
return;
|
// Means that the current line is expected to be continued on next line
|
||||||
line = next;
|
if (fgets(parser->line_buffer, sizeof(parser->line_buffer), parser->file_handle) == NULL) {
|
||||||
|
WMenuParserError(parser, _("premature end of file while expecting a new line after '\\'") );
|
||||||
|
return False;
|
||||||
|
}
|
||||||
|
parser->line_number++;
|
||||||
|
parser->rd = parser->line_buffer;
|
||||||
|
|
||||||
if (*command != NULL && strcmp(*command, "SHORTCUT") == 0) {
|
} else if (parser->rd[0] == '/') {
|
||||||
/* get the shortcut */
|
if (parser->rd[1] == '/') // Single line C comment
|
||||||
*shortcut = wtokennext(line, &next);
|
return False; // Won't find anything more on this line
|
||||||
if (next == NULL)
|
if (parser->rd[1] == '*') {
|
||||||
return;
|
int start_line;
|
||||||
line = next;
|
|
||||||
|
|
||||||
/* get the command */
|
start_line = parser->line_number;
|
||||||
*command = wtokennext(line, &next);
|
parser->rd += 2;
|
||||||
if (next == NULL)
|
for (;;) {
|
||||||
return;
|
/* Search end-of-comment marker */
|
||||||
line = next;
|
while (*parser->rd != '\0') {
|
||||||
}
|
if (parser->rd[0] == '*')
|
||||||
|
if (parser->rd[1] == '/')
|
||||||
|
goto found_end_of_comment;
|
||||||
|
parser->rd++;
|
||||||
|
}
|
||||||
|
|
||||||
/* get the parameters */
|
/* Marker not found -> load next line */
|
||||||
suffix = wtrimspace(line);
|
if (fgets(parser->line_buffer, sizeof(parser->line_buffer), parser->file_handle) == NULL) {
|
||||||
|
WMenuParserError(parser, _("reached end of file while searching '*/' for comment started at line %d"), start_line);
|
||||||
|
return False;
|
||||||
|
}
|
||||||
|
parser->line_number++;
|
||||||
|
parser->rd = parser->line_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
/* should we keep this weird old behavior? */
|
found_end_of_comment:
|
||||||
if (suffix[0] == '"') {
|
parser->rd += 2; // Skip closing mark
|
||||||
*parameter = wtokennext(suffix, &next);
|
continue; // Because there may be spaces after the comment
|
||||||
wfree(suffix);
|
}
|
||||||
} else {
|
return True; // the '/' was not a comment, treat it as user data
|
||||||
*parameter = suffix;
|
} else
|
||||||
|
return True; // Found some data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* read a token (non-spaces suite of characters)
|
||||||
|
the result os wmalloc's, so it needs to be free'd */
|
||||||
|
static char *menu_parser_isolate_token(WMenuParser parser)
|
||||||
|
{
|
||||||
|
char *start;
|
||||||
|
char *token;
|
||||||
|
|
||||||
|
start = parser->rd;
|
||||||
|
|
||||||
|
while (*parser->rd != '\0')
|
||||||
|
if (isspace(*parser->rd))
|
||||||
|
break;
|
||||||
|
else if ((parser->rd[0] == '/') &&
|
||||||
|
((parser->rd[1] == '*') || (parser->rd[1] == '/')))
|
||||||
|
break;
|
||||||
|
else if ((parser->rd[0] == '\\') && (parser->rd[1] == '\n'))
|
||||||
|
break;
|
||||||
|
else if ((*parser->rd == '"' ) || (*parser->rd == '\'')) {
|
||||||
|
char eot = *parser->rd++;
|
||||||
|
while ((*parser->rd != '\0') && (*parser->rd != '\n'))
|
||||||
|
if (*parser->rd++ == eot)
|
||||||
|
goto found_end_quote;
|
||||||
|
WMenuParserError(parser, _("missing closing quote or double-quote before end-of-line") );
|
||||||
|
found_end_quote:
|
||||||
|
;
|
||||||
|
} else
|
||||||
|
parser->rd++;
|
||||||
|
|
||||||
|
token = wmalloc(parser->rd - start + 1);
|
||||||
|
strncpy(token, start, parser->rd - start);
|
||||||
|
token[parser->rd - start] = '\0';
|
||||||
|
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|||||||
@@ -37,4 +37,6 @@ struct w_menu_parser {
|
|||||||
char line_buffer[MAXLINE];
|
char line_buffer[MAXLINE];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Bool menu_parser_skip_spaces_and_comments(WMenuParser parser);
|
||||||
|
|
||||||
#endif /* _MENUPARSER_H_INCLUDED */
|
#endif /* _MENUPARSER_H_INCLUDED */
|
||||||
|
|||||||
Reference in New Issue
Block a user