mirror of
https://github.com/gryf/wmaker.git
synced 2026-02-17 23:05:50 +01:00
Remove dependency to CPP: add support for conditional directives
It is now possible to use #ifdef/#ifndef to exclude some part of the file. The implementation uses a stack to track conditionals so it is possible to use nested constructs.
This commit is contained in:
committed by
Carlos R. Mafra
parent
9b792369cb
commit
4658f4f9a1
@@ -33,6 +33,9 @@ static WMenuParser menu_parser_create_new(const char *file_name, void *file,
|
|||||||
static char *menu_parser_isolate_token(WMenuParser parser, WParserMacro *list_macros);
|
static char *menu_parser_isolate_token(WMenuParser parser, WParserMacro *list_macros);
|
||||||
static void menu_parser_get_directive(WMenuParser parser);
|
static void menu_parser_get_directive(WMenuParser parser);
|
||||||
static Bool menu_parser_include_file(WMenuParser parser);
|
static Bool menu_parser_include_file(WMenuParser parser);
|
||||||
|
static void menu_parser_condition_ifmacro(WMenuParser parser, Bool check_exists);
|
||||||
|
static void menu_parser_condition_else(WMenuParser parser);
|
||||||
|
static void menu_parser_condition_end(WMenuParser parser);
|
||||||
|
|
||||||
|
|
||||||
/***** Constructor and Destructor for the Menu Parser object *****/
|
/***** Constructor and Destructor for the Menu Parser object *****/
|
||||||
@@ -131,6 +134,14 @@ Bool WMenuParserGetLine(WMenuParser top_parser, char **title, char **command, ch
|
|||||||
|
|
||||||
read_next_line:
|
read_next_line:
|
||||||
if (fgets(cur_parser->line_buffer, sizeof(cur_parser->line_buffer), cur_parser->file_handle) == NULL) {
|
if (fgets(cur_parser->line_buffer, sizeof(cur_parser->line_buffer), cur_parser->file_handle) == NULL) {
|
||||||
|
if (cur_parser->cond.depth > 0) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < cur_parser->cond.depth; i++)
|
||||||
|
WMenuParserError(cur_parser, _("missing #endif to match #%s at line %d"),
|
||||||
|
cur_parser->cond.stack[i].name, cur_parser->cond.stack[i].line);
|
||||||
|
}
|
||||||
|
|
||||||
if (cur_parser->parent_file == NULL)
|
if (cur_parser->parent_file == NULL)
|
||||||
/* Not inside an included file -> we have reached the end */
|
/* Not inside an included file -> we have reached the end */
|
||||||
return False;
|
return False;
|
||||||
@@ -159,6 +170,8 @@ Bool WMenuParserGetLine(WMenuParser top_parser, char **title, char **command, ch
|
|||||||
menu_parser_get_directive(cur_parser);
|
menu_parser_get_directive(cur_parser);
|
||||||
goto read_next_line_with_filechange;
|
goto read_next_line_with_filechange;
|
||||||
}
|
}
|
||||||
|
if (cur_parser->cond.stack[0].skip)
|
||||||
|
goto read_next_line;
|
||||||
|
|
||||||
/* Found a word */
|
/* Found a word */
|
||||||
token = menu_parser_isolate_token(cur_parser, top_parser->macros);
|
token = menu_parser_isolate_token(cur_parser, top_parser->macros);
|
||||||
@@ -368,6 +381,18 @@ static void menu_parser_get_directive(WMenuParser parser)
|
|||||||
} else if (strcmp(command, "define") == 0) {
|
} else if (strcmp(command, "define") == 0) {
|
||||||
menu_parser_define_macro(parser);
|
menu_parser_define_macro(parser);
|
||||||
|
|
||||||
|
} else if (strcmp(command, "ifdef") == 0) {
|
||||||
|
menu_parser_condition_ifmacro(parser, 1);
|
||||||
|
|
||||||
|
} else if (strcmp(command, "ifndef") == 0) {
|
||||||
|
menu_parser_condition_ifmacro(parser, 0);
|
||||||
|
|
||||||
|
} else if (strcmp(command, "else") == 0) {
|
||||||
|
menu_parser_condition_else(parser);
|
||||||
|
|
||||||
|
} else if (strcmp(command, "endif") == 0) {
|
||||||
|
menu_parser_condition_end(parser);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
WMenuParserError(parser, _("unknow directive '#%s'"), command);
|
WMenuParserError(parser, _("unknow directive '#%s'"), command);
|
||||||
return;
|
return;
|
||||||
@@ -409,6 +434,11 @@ static Bool menu_parser_include_file(WMenuParser parser)
|
|||||||
return False;
|
return False;
|
||||||
found_end_define_fname:
|
found_end_define_fname:
|
||||||
|
|
||||||
|
/* If we're inside a #if sequence, we abort now, but not sooner in
|
||||||
|
order to keep the syntax check */
|
||||||
|
if (parser->cond.stack[0].skip)
|
||||||
|
return False;
|
||||||
|
|
||||||
{ /* Check we are not nesting too many includes */
|
{ /* Check we are not nesting too many includes */
|
||||||
WMenuParser p;
|
WMenuParser p;
|
||||||
int count;
|
int count;
|
||||||
@@ -475,3 +505,74 @@ static Bool menu_parser_include_file(WMenuParser parser)
|
|||||||
parser->include_file->parent_file = parser;
|
parser->include_file->parent_file = parser;
|
||||||
return True;
|
return True;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check wether a macro exists or not, and marks the parser to ignore the
|
||||||
|
following data accordingly */
|
||||||
|
static void menu_parser_condition_ifmacro(WMenuParser parser, Bool check_exists)
|
||||||
|
{
|
||||||
|
WParserMacro *macro;
|
||||||
|
int idx;
|
||||||
|
const char *cmd_name, *macro_name;
|
||||||
|
|
||||||
|
cmd_name = check_exists?"ifdef":"ifndef";
|
||||||
|
if (!menu_parser_skip_spaces_and_comments(parser)) {
|
||||||
|
WMenuParserError(parser, _("missing macro name argument to #%s"), cmd_name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* jump to end of provided name for later checks that no extra stuff is following */
|
||||||
|
macro_name = parser->rd;
|
||||||
|
while (isnamechr(*parser->rd))
|
||||||
|
parser->rd++;
|
||||||
|
|
||||||
|
/* Add this condition to the stack of conditions */
|
||||||
|
if (parser->cond.depth >= sizeof(parser->cond.stack) / sizeof(parser->cond.stack[0])) {
|
||||||
|
WMenuParserError(parser, _("too many nested #if sequences") );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (idx = parser->cond.depth - 1; idx >= 0; idx--)
|
||||||
|
parser->cond.stack[idx + 1] = parser->cond.stack[idx];
|
||||||
|
parser->cond.depth++;
|
||||||
|
|
||||||
|
if (parser->cond.stack[1].skip)
|
||||||
|
parser->cond.stack[0].skip = True;
|
||||||
|
else {
|
||||||
|
macro = menu_parser_find_macro(parser, macro_name);
|
||||||
|
parser->cond.stack[0].skip =
|
||||||
|
((check_exists) && (macro == NULL)) ||
|
||||||
|
((!check_exists) && (macro != NULL)) ;
|
||||||
|
}
|
||||||
|
strcpy(parser->cond.stack[0].name, cmd_name);
|
||||||
|
parser->cond.stack[0].line = parser->line_number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Swap the 'data ignore' flag because a #else condition was found */
|
||||||
|
static void menu_parser_condition_else(WMenuParser parser)
|
||||||
|
{
|
||||||
|
if (parser->cond.depth <= 0) {
|
||||||
|
WMenuParserError(parser, _("found #%s but have no matching #if"), "else" );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ((parser->cond.depth > 1) && (parser->cond.stack[1].skip))
|
||||||
|
// The containing #if is false, so we continue skipping anyway
|
||||||
|
parser->cond.stack[0].skip = True;
|
||||||
|
else
|
||||||
|
parser->cond.stack[0].skip = !parser->cond.stack[0].skip;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Closes the current conditional, removing it from the stack */
|
||||||
|
static void menu_parser_condition_end(WMenuParser parser)
|
||||||
|
{
|
||||||
|
int idx;
|
||||||
|
|
||||||
|
if (parser->cond.depth <= 0) {
|
||||||
|
WMenuParserError(parser, _("found #%s but have no matching #if"), "endif" );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (--parser->cond.depth > 0)
|
||||||
|
for (idx = 0; idx < parser->cond.depth; idx++)
|
||||||
|
parser->cond.stack[idx] = parser->cond.stack[idx + 1];
|
||||||
|
else
|
||||||
|
parser->cond.stack[0].skip = False;
|
||||||
|
}
|
||||||
|
|||||||
@@ -44,6 +44,16 @@ struct w_menu_parser {
|
|||||||
FILE *file_handle;
|
FILE *file_handle;
|
||||||
int line_number;
|
int line_number;
|
||||||
WParserMacro *macros;
|
WParserMacro *macros;
|
||||||
|
struct {
|
||||||
|
/* Conditional text parsing is implemented using a stack of the
|
||||||
|
skip states for each nested #if */
|
||||||
|
int depth;
|
||||||
|
struct {
|
||||||
|
Bool skip;
|
||||||
|
char name[8];
|
||||||
|
int line;
|
||||||
|
} stack[32];
|
||||||
|
} cond;
|
||||||
char *rd;
|
char *rd;
|
||||||
char line_buffer[MAXLINE];
|
char line_buffer[MAXLINE];
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -229,6 +229,14 @@ void menu_parser_define_macro(WMenuParser parser)
|
|||||||
} else
|
} else
|
||||||
macro->arg_count = -1; // Means no parenthesis at all to expect
|
macro->arg_count = -1; // Means no parenthesis at all to expect
|
||||||
|
|
||||||
|
/* If we're inside a #if sequence, we abort now, but not sooner in
|
||||||
|
order to keep the syntax check */
|
||||||
|
if (parser->cond.stack[0].skip) {
|
||||||
|
wfree(macro);
|
||||||
|
*parser->rd = '\0'; // Ignore macro content
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* Get the macro's definition */
|
/* Get the macro's definition */
|
||||||
menu_parser_skip_spaces_and_comments(parser);
|
menu_parser_skip_spaces_and_comments(parser);
|
||||||
if (!menu_parser_read_macro_def(parser, macro, arg_name)) {
|
if (!menu_parser_read_macro_def(parser, macro, arg_name)) {
|
||||||
|
|||||||
Reference in New Issue
Block a user