1
0
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:
Christophe CURIS
2012-06-17 23:56:34 +02:00
committed by Carlos R. Mafra
parent 7d74648fc3
commit ed9482b626
2 changed files with 157 additions and 72 deletions

View File

@@ -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;
}

View File

@@ -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 */