From 9eb9701c9490a5008b183db8558bd2fd12172fdf Mon Sep 17 00:00:00 2001
From: Christophe CURIS <[email protected]>
Date: Sun, 17 Jun 2012 23:20:33 +0200
Subject: [PATCH 1/7] Remove dependency to CPP: Moving parser functions to a
 dedicated file

Due to the tasks to take in charge, the internal parser will grow, so
it is a good idea to start by moving the current functions into a
dedicated file.
The parser now uses a structure used to keep track of what's going on.

Took opportunity to de-CamelCase function 'parseCascade'
---
 src/Makefile.am      |    1 +
 src/rootmenu.c       |  152 +++++++-------------------------------------
 src/rootmenu.h       |   26 ++++++++
 src/rootmenuparser.c |  173 ++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 223 insertions(+), 129 deletions(-)
 create mode 100644 src/rootmenuparser.c

diff --git a/src/Makefile.am b/src/Makefile.am
index 0521d11..7af56ec 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -59,6 +59,7 @@ wmaker_SOURCES = 	\
 	resources.h \
 	rootmenu.c \
 	rootmenu.h \
+	rootmenuparser.c \
 	screen.c \
 	screen.h \
 	session.h \
diff --git a/src/rootmenu.c b/src/rootmenu.c
index c32411d..5b384ad 100644
--- a/src/rootmenu.c
+++ b/src/rootmenu.c
@@ -50,6 +50,7 @@
 #include "framewin.h"
 #include "session.h"
 #include "xmodifier.h"
+#include "rootmenu.h"
 
 #include <WINGs/WUtil.h>
 
@@ -409,7 +410,7 @@ static void removeShortcutsForMenu(WMenu * menu)
 	menu->menu->screen_ptr->flags.root_menu_changed_shortcuts = 1;
 }
 
-static Bool addShortcut(char *file, char *shortcutDefinition, WMenu * menu, WMenuEntry * entry)
+static Bool addShortcut(const char *file, char *shortcutDefinition, WMenu * menu, WMenuEntry * entry)
 {
 	Shortcut *ptr;
 	KeySym ksym;
@@ -758,7 +759,7 @@ static WMenuEntry *addWindowsMenu(WScreen * scr, WMenu * menu, char *title)
 }
 
 static WMenuEntry *addMenuEntry(WMenu * menu, char *title, char *shortcut, char *command,
-				char *params, char *file_name)
+				char *params, const char *file_name)
 {
 	WScreen *scr;
 	WMenuEntry *entry = NULL;
@@ -890,113 +891,15 @@ static void freeline(char *title, char *command, char *parameter, char *shortcut
 	wfree(shortcut);
 }
 
-static void separateline(char *line, char **title, char **command, char **parameter, char **shortcut)
+static WMenu *menu_parse_cascade(WScreen * scr, WMenu * menu, WMenuParser parser)
 {
-	char *suffix, *next = line;
-
-	*title = NULL;
-	*command = NULL;
-	*parameter = NULL;
-	*shortcut = NULL;
-
-	/* get the title */
-	*title = wtokennext(line, &next);
-	if (next == NULL)
-		return;
-	line = next;
-
-	/* get the command or shortcut keyword */
-	*command = wtokennext(line, &next);
-	if (next == NULL)
-		return;
-	line = next;
-
-	if (*command != NULL && strcmp(*command, "SHORTCUT") == 0) {
-		/* get the shortcut */
-		*shortcut = wtokennext(line, &next);
-		if (next == NULL)
-			return;
-		line = next;
-
-		/* get the command */
-		*command = wtokennext(line, &next);
-		if (next == NULL)
-			return;
-		line = next;
-	}
-
-	/* get the parameters */
-	suffix = wtrimspace(line);
-
-	/* should we keep this weird old behavior? */
-	if (suffix[0] == '"') {
-		*parameter = wtokennext(suffix, &next);
-		wfree(suffix);
-	} else {
-		*parameter = suffix;
-	}
-}
-
-static char *getLine(FILE * file, const char *file_name)
-{
-	char linebuf[MAXLINE];
-	char *line = NULL, *result = NULL;
-	size_t len;
-	int done;
-
-again:
-	done = 0;
-	while (!done && fgets(linebuf, sizeof(linebuf), file) != NULL) {
-		line = wtrimspace(linebuf);
-		len = strlen(line);
-
-		/* allow line wrapping */
-		if (len > 0 && line[len - 1] == '\\') {
-			line[len - 1] = '\0';
-		} else {
-			done = 1;
-		}
-
-		if (result == NULL) {
-			result = line;
-		} else {
-			if (strlen(result) < MAXLINE) {
-				result = wstrappend(result, line);
-			}
-			wfree(line);
-		}
-	}
-	if (!done || ferror(file)) {
-		wfree(result);
-		result = NULL;
-	} else if (result != NULL && (result[0] == 0 || result[0] == '#' ||
-		   (result[0] == '/' && result[1] == '/'))) {
-		wfree(result);
-		result = NULL;
-		goto again;
-	} else if (result != NULL && strlen(result) >= MAXLINE) {
-		wwarning(_("%s:maximal line size exceeded in menu config: %s"),
-			 file_name, line);
-		wfree(result);
-		result = NULL;
-		goto again;
-	}
-
-	return result;
-}
-
-static WMenu *parseCascade(WScreen * scr, WMenu * menu, FILE * file, char *file_name)
-{
-	char *line;
 	char *command, *params, *shortcut, *title;
 
-	while ((line = getLine(file, file_name)) != NULL) {
-		separateline(line, &title, &command, &params, &shortcut);
+	while (menu_parser_get_line(parser, &title, &command, &params, &shortcut)) {
 
 		if (command == NULL || !command[0]) {
-			wwarning(_("%s:missing command in menu config: %s"), file_name, line);
+			menu_parser_warning(parser, _("missing command in menu config") );
 			freeline(title, command, params, shortcut);
-			wfree(line);
 			goto error;
 		}
 
@@ -1007,7 +910,7 @@ static WMenu *parseCascade(WScreen * scr, WMenu * menu, FILE * file, char *file_
 
 			cascade = wMenuCreate(scr, M_(title), False);
 			cascade->on_destroy = removeShortcutsForMenu;
-			if (!parseCascade(scr, cascade, file, file_name)) {
+			if (!menu_parse_cascade(scr, cascade, parser)) {
 				wMenuDestroy(cascade, True);
 			} else {
 				wMenuEntrySetCascade(menu, wMenuAddCallback(menu, M_(title), NULL, NULL), cascade);
@@ -1015,17 +918,15 @@ static WMenu *parseCascade(WScreen * scr, WMenu * menu, FILE * file, char *file_
 		} else if (strcasecmp(command, "END") == 0) {
 			/* end of menu */
 			freeline(title, command, params, shortcut);
-			wfree(line);
 			return menu;
 		} else {
 			/* normal items */
-			addMenuEntry(menu, M_(title), shortcut, command, params, file_name);
+			addMenuEntry(menu, M_(title), shortcut, command, params, menu_parser_get_filename(parser));
 		}
 		freeline(title, command, params, shortcut);
-		wfree(line);
 	}
 
-	wwarning(_("%s:syntax error in menu file:END declaration missing"), file_name);
+	menu_parser_warning(parser, _("syntax error in menu file:END declaration missing") );
 
  error:
 	return NULL;
@@ -1035,7 +936,7 @@ static WMenu *readMenuFile(WScreen * scr, char *file_name)
 {
 	WMenu *menu = NULL;
 	FILE *file = NULL;
-	char *line;
+	WMenuParser parser;
 	char *command, *params, *shortcut, *title;
 	char cmd[MAXLINE];
 #ifdef USECPP
@@ -1068,36 +969,33 @@ static WMenu *readMenuFile(WScreen * scr, char *file_name)
 			return NULL;
 		}
 	}
+	parser = menu_parser_create(file_name, file);
 
-	while ((line = getLine(file, file_name)) != NULL) {
-		separateline(line, &title, &command, &params, &shortcut);
+	while (menu_parser_get_line(parser, &title, &command, &params, &shortcut)) {
 
 		if (command == NULL || !command[0]) {
-			wwarning(_("%s:missing command in menu config: %s"), file_name, line);
+			menu_parser_warning(parser, _("missing command in menu config") );
 			freeline(title, command, params, shortcut);
-			wfree(line);
 			break;
 		}
 		if (strcasecmp(command, "MENU") == 0) {
 			menu = wMenuCreate(scr, M_(title), True);
 			menu->on_destroy = removeShortcutsForMenu;
-			if (!parseCascade(scr, menu, file, file_name)) {
+			if (!menu_parse_cascade(scr, menu, parser)) {
 				wMenuDestroy(menu, True);
 				menu = NULL;
 			}
 			freeline(title, command, params, shortcut);
-			wfree(line);
 			break;
 		} else {
-			wwarning(_("%s:invalid menu file. MENU command is missing"), file_name);
+			menu_parser_warning(parser, _("invalid menu file. MENU command is missing") );
 			freeline(title, command, params, shortcut);
-			wfree(line);
 			break;
 		}
 		freeline(title, command, params, shortcut);
-		wfree(line);
 	}
 
+	menu_parser_delete(parser);
 #ifdef USECPP
 	if (cpp) {
 		if (pclose(file) == -1) {
@@ -1119,8 +1017,8 @@ static WMenu *readMenuPipe(WScreen * scr, char **file_name)
 {
 	WMenu *menu = NULL;
 	FILE *file = NULL;
+	WMenuParser parser;
 	char *command, *params, *shortcut, *title;
-	char *line;
 	char *filename;
 	char flat_file[MAXLINE];
 	char cmd[MAXLINE];
@@ -1156,43 +1054,39 @@ static WMenu *readMenuPipe(WScreen * scr, char **file_name)
 
 	if (!file) {
 		file = popen(filename, "rb");
-
 		if (!file) {
 			werror(_("%s:could not open menu file"), filename);
 			return NULL;
 		}
 	}
+	parser = menu_parser_create(flat_file, file);
 
-	while ((line = getLine(file, filename)) != NULL) {
-		separateline(line, &title, &command, &params, &shortcut);
+	while (menu_parser_get_line(parser, &title, &command, &params, &shortcut)) {
 
 		if (command == NULL || !command[0]) {
-			wwarning(_("%s:missing command in menu config: %s"), filename, line);
+			menu_parser_warning(parser, _("missing command in menu config") );
 			freeline(title, command, params, shortcut);
-			wfree(line);
 			break;
 		}
 		if (strcasecmp(command, "MENU") == 0) {
 			menu = wMenuCreate(scr, M_(title), True);
 			menu->on_destroy = removeShortcutsForMenu;
-			if (!parseCascade(scr, menu, file, filename)) {
+			if (!menu_parse_cascade(scr, menu, parser)) {
 				wMenuDestroy(menu, True);
 				menu = NULL;
 			}
 			freeline(title, command, params, shortcut);
-			wfree(line);
 			break;
 		} else {
-			wwarning(_("%s:no title given for the root menu"), filename);
+			menu_parser_warning(parser, _("no title given for the root menu") );
 			freeline(title, command, params, shortcut);
-			wfree(line);
 			break;
 		}
 
 		freeline(title, command, params, shortcut);
-		wfree(line);
 	}
 
+	menu_parser_delete(parser);
 	pclose(file);
 
 	return menu;
diff --git a/src/rootmenu.h b/src/rootmenu.h
index e7ed855..0b4a5b3 100644
--- a/src/rootmenu.h
+++ b/src/rootmenu.h
@@ -41,4 +41,30 @@ typedef struct _WRootMenuReader {
     void (*closeMenuFile)(WRootMenuData *data);
 } WRootMenuReader;
 
+/****** Parsing of menu files ******/
+typedef struct menu_parser *WMenuParser;
+
+WMenuParser menu_parser_create(const char *file_name, FILE *file);
+Bool menu_parser_get_line(WMenuParser parser, char **title, char **command, char **parameter, char **shortcut);
+const char * menu_parser_get_filename(WMenuParser parser);
+void menu_parser_delete(WMenuParser parser);
+
+#define menu_parser_warning(parser, fmt, args...)  \
+  __menu_parser_warning( parser, __func__, __FILE__, __LINE__, fmt, ## args)
+
+void __menu_parser_warning(WMenuParser parser, const char *src_func, const char *src_file, int src_line, const char *msg, ...)
+	__attribute__((__format__(printf,5,6)));
+
+#ifdef MENU_PARSER_INTERNALS
+
+struct menu_parser {
+	const char *file_name;
+	FILE *file_handle;
+	int num_line;
+	char *rd;
+	char line_buffer[MAXLINE];
+};
+
+#endif /* MENU_PARSER_INTERNALS */
+
 #endif /* WMROOTMENU_H */
diff --git a/src/rootmenuparser.c b/src/rootmenuparser.c
new file mode 100644
index 0000000..32ff514
--- /dev/null
+++ b/src/rootmenuparser.c
@@ -0,0 +1,173 @@
+/*
+ *  Window Maker window manager
+ *
+ *  Copyright (c) 1997-2003 Alfredo K. Kojima
+ *
+ *  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
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include "wconfig.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+
+#define MENU_PARSER_INTERNALS
+#include "WindowMaker.h"
+#include "rootmenu.h"
+
+
+/***** Root parser functions *****/
+WMenuParser menu_parser_create(const char *file_name, FILE *file)
+{
+	WMenuParser parser;
+
+	parser = wmalloc(sizeof(*parser));
+	parser->file_name = file_name;
+	parser->file_handle = file;
+	parser->rd = parser->line_buffer;
+
+	return parser;
+}
+
+void menu_parser_delete(WMenuParser parser)
+{
+	wfree(parser);
+}
+
+/***** Reporting problems to user *****/
+const char * menu_parser_get_filename(WMenuParser parser)
+{
+	return parser->file_name;
+}
+
+void __menu_parser_warning(WMenuParser parser, const char *src_func, const char *src_file, int src_line, const char *msg, ...)
+{
+	char buf[256];
+	int pos;
+	va_list args;
+
+	va_start(args, msg);
+	snprintf(buf, sizeof(buf), "%s:%d: ", parser->file_name, parser->num_line);
+	for (pos=0; buf[pos] != '\0'; pos++) ;
+	vsnprintf(buf+pos, sizeof(buf)-pos, msg, args);
+	va_end(args);
+	__wmessage(src_func, src_file, src_line, WMESSAGE_TYPE_WARNING, buf);
+}
+
+/***** Reading from the file *****/
+static void separateline(char *line, char **title, char **command, char **parameter, char **shortcut);
+
+/***** Main parsing from the file *****/
+Bool menu_parser_get_line(WMenuParser top_parser, char **title, char **command, char **parameter, char **shortcut)
+{
+	WMenuParser cur_parser;
+	char *line = NULL, *result = NULL;
+	size_t len;
+	int done;
+
+	*title = NULL;
+	*command = NULL;
+	*parameter = NULL;
+	*shortcut = NULL;
+
+	cur_parser = top_parser;
+
+again:
+	done = 0;
+	while (!done && fgets(cur_parser->line_buffer, sizeof(cur_parser->line_buffer), cur_parser->file_handle) != NULL) {
+		line = wtrimspace(cur_parser->line_buffer);
+		len = strlen(line);
+		cur_parser->num_line++;
+
+		/* allow line wrapping */
+		if (len > 0 && line[len - 1] == '\\') {
+			line[len - 1] = '\0';
+		} else {
+			done = 1;
+		}
+
+		if (result == NULL) {
+			result = line;
+		} else {
+			if (strlen(result) < MAXLINE) {
+				result = wstrappend(result, line);
+			}
+			wfree(line);
+		}
+	}
+	if (!done || ferror(cur_parser->file_handle)) {
+		wfree(result);
+		result = NULL;
+	} else if (result != NULL && (result[0] == 0 || result[0] == '#' ||
+		   (result[0] == '/' && result[1] == '/'))) {
+		wfree(result);
+		result = NULL;
+		goto again;
+	} else if (result != NULL && strlen(result) >= MAXLINE) {
+		menu_parser_warning(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;
+}
+
+static void separateline(char *line, char **title, char **command, char **parameter, char **shortcut)
+{
+	char *suffix, *next = line;
+
+	/* get the title */
+	*title = wtokennext(line, &next);
+	if (next == NULL)
+		return;
+	line = next;
+
+	/* get the command or shortcut keyword */
+	*command = wtokennext(line, &next);
+	if (next == NULL)
+		return;
+	line = next;
+
+	if (*command != NULL && strcmp(*command, "SHORTCUT") == 0) {
+		/* get the shortcut */
+		*shortcut = wtokennext(line, &next);
+		if (next == NULL)
+			return;
+		line = next;
+
+		/* get the command */
+		*command = wtokennext(line, &next);
+		if (next == NULL)
+			return;
+		line = next;
+	}
+
+	/* get the parameters */
+	suffix = wtrimspace(line);
+
+	/* should we keep this weird old behavior? */
+	if (suffix[0] == '"') {
+		*parameter = wtokennext(suffix, &next);
+		wfree(suffix);
+	} else {
+		*parameter = suffix;
+	}
+}
-- 
1.7.10

Reply via email to