From 5a095b38c1d1c91d91e95f9f7bc303c62b2fdf25 Mon Sep 17 00:00:00 2001
From: Christophe CURIS <[email protected]>
Date: Sat, 23 Jun 2012 15:21:43 +0200
Subject: [PATCH 08/10] Remove dependency to CPP: added pre-defined macros

A number of macros are pre-defined by WindowMaker for CPP in the
function 'MakeCPPArgs', they are now available in the internal
parser too. CPP also had some predefined macros, a subset of them
have been added.
The definition have been split in two parts:
 - the macro that are dependant on WindowMaker parameters are
defined by WindowMaker (src/rootmenu.c)
 - those that are independant, which can be defined by the parser
itself (WINGs/menuparser_macros.c)
---
 WINGs/WINGs/WUtil.h       |    2 +
 WINGs/menuparser.c        |    1 +
 WINGs/menuparser.h        |    2 +
 WINGs/menuparser_macros.c |  190 +++++++++++++++++++++++++++++++++++++++++++++
 src/rootmenu.c            |   31 ++++++++
 5 files changed, 226 insertions(+)

diff --git a/WINGs/WINGs/WUtil.h b/WINGs/WINGs/WUtil.h
index 0d3343c..30476e0 100644
--- a/WINGs/WINGs/WUtil.h
+++ b/WINGs/WINGs/WUtil.h
@@ -874,6 +874,8 @@ typedef struct w_menu_parser *WMenuParser;
 
 WMenuParser WMenuParserCreate(const char *file_name, void *file, const char *include_default_paths);
 
+void WMenuParserRegisterSimpleMacro(WMenuParser parser, const char *name, const char *value);
+
 void WMenuParserError(WMenuParser parser, const char *msg, ...)
 	__attribute__ ((format (printf, 2, 3)));
 
diff --git a/WINGs/menuparser.c b/WINGs/menuparser.c
index b39b3b1..6c74144 100644
--- a/WINGs/menuparser.c
+++ b/WINGs/menuparser.c
@@ -42,6 +42,7 @@ WMenuParser WMenuParserCreate(const char *file_name, void *file,
 	WMenuParser parser;
 
 	parser = menu_parser_create_new(file_name, file, include_default_paths);
+	menu_parser_register_preset_macros(parser);
 	return parser;
 }
 
diff --git a/WINGs/menuparser.h b/WINGs/menuparser.h
index e7d101d..4407fc9 100644
--- a/WINGs/menuparser.h
+++ b/WINGs/menuparser.h
@@ -61,6 +61,8 @@ struct w_parser_macro {
 
 Bool menu_parser_skip_spaces_and_comments(WMenuParser parser);
 
+void menu_parser_register_preset_macros(WMenuParser parser);
+
 void menu_parser_define_macro(WMenuParser parser);
 
 void menu_parser_free_macros(WMenuParser parser);
diff --git a/WINGs/menuparser_macros.c b/WINGs/menuparser_macros.c
index 05cb9c7..12e7548 100644
--- a/WINGs/menuparser_macros.c
+++ b/WINGs/menuparser_macros.c
@@ -23,6 +23,8 @@
 #include <stdio.h>
 #include <string.h>
 #include <ctype.h>
+#include <unistd.h>
+#include <pwd.h>
 
 #include <WINGs/WUtil.h>
 
@@ -32,6 +34,7 @@
  This file contains the functions related to macros:
   - parse a macro being defined
   - handle single macro expansion
+  - pre-defined parser's macros
 
  Some design notes for macro internal storage:
 
@@ -56,6 +59,21 @@
   This structure allows to store any number and combination
    of text/parameter and still provide very fast generation
    at macro replacement time.
+
+ Predefined macros are using a call-back function mechanism
+   to generate the value on-demand. This value is generated
+   in the 'value' buffer of the structure.
+ Most of these call-backs will actually cache the value:
+   they generate it on the first use (inside a parser,
+   not globally) and reuse that value on next call(s).
+
+ Because none of these macros take parameters, the call-back
+   mechanism does not include passing of user arguments; the
+   complex storage mechanism for argument replacement being
+   not necessary the macro->value parameter is used as a
+   plain C string to be copied, this fact being recognised
+   by macro->function being non-null. It was chosen that the
+   call-back function would not have the possibility to fail.
 */
 
 static Bool menu_parser_read_macro_def(WMenuParser parser, WParserMacro *macro, char **argname);
@@ -512,3 +530,175 @@ static Bool menu_parser_read_macro_args(WMenuParser parser, WParserMacro *macro,
 							  macro->name);
 	return True;
 }
+
+/******************************************************************************/
+/* Definition of pre-defined macros */
+/******************************************************************************/
+
+void WMenuParserRegisterSimpleMacro(WMenuParser parser, const char *name, const char *value)
+{
+	WParserMacro *macro;
+	size_t len;
+	unsigned char *wr;
+
+	macro = wmalloc(sizeof(*macro));
+	strncpy(macro->name, name, sizeof(macro->name)-1);
+	macro->arg_count = -1;
+	len = strlen(value);
+	if (len > sizeof(macro->value) - 3) {
+		wwarning(_("size of value for macro '%s' is too big, truncated"), name);
+		len = sizeof(macro->value) - 3;
+	}
+	macro->value[0] = (len >> 8) & 0xFF;
+	macro->value[1] =  len       & 0xFF;
+	wr = &macro->value[2];
+	while (len-- > 0)
+		*wr++ = *value++;
+	*wr = 0xFF;
+	macro->next = parser->macros;
+	parser->macros = macro;
+}
+
+/* Name of the originally loaded file (before #includes) */
+static void mpm_base_file(WParserMacro *this, WMenuParser parser)
+{
+	unsigned char *src, *dst;
+
+	if (this->value[0] != '\0') return; // Value already evaluated, re-use previous
+
+	while (parser->parent_file != NULL)
+		parser = parser->parent_file;
+
+	dst = this->value;
+	src = (unsigned char *) parser->file_name;
+	*dst++ = '\"';
+	while (*src != '\0')
+		if (dst < this->value + sizeof(this->value) - 2)
+			*dst++ = *src++;
+		else
+			break;
+	*dst++ = '\"';
+	*dst   = '\0';
+}
+
+/* Number of #include currently nested */
+static void mpm_include_level(WParserMacro *this, WMenuParser parser)
+{
+	int level = 0;
+	while (parser->parent_file != NULL) {
+		parser = parser->parent_file;
+		level++;
+	}
+	snprintf((char *) this->value, sizeof(this->value), "%d", level);
+}
+
+/* Name of current file */
+static void mpm_current_file(WParserMacro *this, WMenuParser parser)
+{
+	unsigned char *src, *dst;
+
+	dst = this->value;
+	src = (unsigned char *) parser->file_name;
+	*dst++ = '\"';
+	while (*src != '\0')
+		if (dst < this->value + sizeof(this->value) - 2)
+			*dst++ = *src++;
+		else
+			break;
+	*dst++ = '\"';
+	*dst   = '\0';
+}
+
+/* Number of current line */
+static void mpm_current_line(WParserMacro *this, WMenuParser parser)
+{
+	snprintf((char *) this->value, sizeof(this->value), "%d", parser->line_number);
+}
+
+/* Name of host on which we are running, not necessarily displaying */
+static void mpm_get_hostname(WParserMacro *this, WMenuParser parser)
+{
+	char *h;
+
+	if (this->value[0] != '\0') return; // Value already evaluated, re-use previous
+
+	h = getenv("HOSTNAME");
+	if (h == NULL) {
+		h = getenv("HOST");
+		if (h == NULL) {
+			if (gethostname((char *) this->value, sizeof(this->value) ) != 0) {
+				WMenuParserError(parser, _("could not determine %s"), "HOSTNAME");
+				this->value[0] = '?';
+				this->value[1] = '?';
+				this->value[2] = '?';
+				this->value[3] = '\0';
+			}
+			return;
+		}
+	}
+	wstrlcpy((char *) this->value, h, sizeof(this->value) );
+}
+
+/* Name of the current user */
+static void mpm_get_user_name(WParserMacro *this, WMenuParser parser)
+{
+	char *user;
+
+	if (this->value[0] != '\0') return; // Value already evaluated, re-use previous
+
+	user = getlogin();
+	if (user == NULL) {
+		struct passwd *pw_user;
+
+		pw_user = getpwuid(getuid());
+		if (pw_user == NULL) {
+		error_no_username:
+			WMenuParserError(parser, _("could not determine %s"), "USER" );
+			/* Fall back on numeric id - better than nothing */
+			snprintf((char *) this->value, sizeof(this->value), "%d", getuid() );
+			return;
+		}
+		user = pw_user->pw_name;
+		if (user == NULL) goto error_no_username;
+	}
+	wstrlcpy((char *) this->value, user, sizeof(this->value) );
+}
+
+/* Number id of the user under which we are running */
+static void mpm_get_user_id(WParserMacro *this, WMenuParser parser)
+{
+	if (this->value[0] != '\0') return; // Already evaluated, re-use previous
+	snprintf((char *) this->value, sizeof(this->value), "%d", getuid() );
+}
+
+/* Small helper to automate creation of one pre-defined macro in the parser */
+static void w_create_macro(WMenuParser parser, const char *name, WParserMacroFunction *handler)
+{
+	WParserMacro *macro;
+
+	macro = wmalloc(sizeof(*macro));
+	strcpy(macro->name, name);
+	macro->function = handler;
+	macro->arg_count = -1;
+	macro->next = parser->macros;
+	parser->macros = macro;
+}
+
+/***** Register all the pre-defined macros in the parser *****/
+void menu_parser_register_preset_macros(WMenuParser parser)
+{
+	/* Defined by CPP: common predefined macros (GNU C extension) */
+	w_create_macro(parser, "__BASE_FILE__", mpm_base_file);
+	w_create_macro(parser, "__INCLUDE_LEVEL__", mpm_include_level);
+
+	/* Defined by CPP: standard predefined macros */
+	w_create_macro(parser, "__FILE__", mpm_current_file);
+	w_create_macro(parser, "__LINE__", mpm_current_line);
+	// w_create_macro(parser, "__DATE__", NULL);  [will be implemented only per user request]
+	// w_create_macro(parser, "__TIME__", NULL);  [will be implemented only per user request]
+
+	/* Historically defined by WindowMaker */
+	w_create_macro(parser, "HOST", mpm_get_hostname);
+	w_create_macro(parser, "UID", mpm_get_user_id);
+	w_create_macro(parser, "USER", mpm_get_user_name);
+}
diff --git a/src/rootmenu.c b/src/rootmenu.c
index 165ab92..7e1b2ea 100644
--- a/src/rootmenu.c
+++ b/src/rootmenu.c
@@ -65,6 +65,7 @@ static WMenu *readMenuPipe(WScreen * scr, char **file_name);
 static WMenu *readMenuFile(WScreen * scr, char *file_name);
 static WMenu *readMenuDirectory(WScreen * scr, char *title, char **file_name, char *command);
 static WMenu *configureMenu(WScreen * scr, WMPropList * definition, Bool includeGlobals);
+static void menu_parser_register_macros(WMenuParser parser);
 
 typedef struct Shortcut {
 	struct Shortcut *next;
@@ -970,6 +971,7 @@ static WMenu *readMenuFile(WScreen * scr, char *file_name)
 		}
 	}
 	parser = WMenuParserCreate(file_name, file, DEF_CONFIG_PATHS);
+	menu_parser_register_macros(parser);
 
 	while (WMenuParserGetLine(parser, &title, &command, &params, &shortcut)) {
 
@@ -1061,6 +1063,7 @@ static WMenu *readMenuPipe(WScreen * scr, char **file_name)
 		}
 	}
 	parser = WMenuParserCreate(flat_file, file, DEF_CONFIG_PATHS);
+	menu_parser_register_macros(parser);
 
 	while (WMenuParserGetLine(parser, &title, &command, &params, &shortcut)) {
 
@@ -1106,6 +1109,34 @@ static int myCompare(const void *d1, const void *d2)
 	return strcmp(p1->name, p2->name);
 }
 
+/***** Preset some macro for file parser *****/
+static void menu_parser_register_macros(WMenuParser parser)
+{
+	Visual *visual;
+	char buf[32];
+
+	// Used to return CPP verion, now returns wmaker's version
+	WMenuParserRegisterSimpleMacro(parser, "__VERSION__", VERSION);
+
+	// All macros below were historically defined by WindowMaker
+	visual = DefaultVisual(dpy, DefaultScreen(dpy));
+	snprintf(buf, sizeof(buf), "%d", visual->class);
+	WMenuParserRegisterSimpleMacro(parser, "VISUAL", buf);
+
+	snprintf(buf, sizeof(buf), "%d", DefaultDepth(dpy, DefaultScreen(dpy)) );
+	WMenuParserRegisterSimpleMacro(parser, "DEPTH", buf);
+
+	snprintf(buf, sizeof(buf), "%d", WidthOfScreen(DefaultScreenOfDisplay(dpy)) );
+	WMenuParserRegisterSimpleMacro(parser, "SCR_WIDTH", buf);
+
+	snprintf(buf, sizeof(buf), "%d", HeightOfScreen(DefaultScreenOfDisplay(dpy)) );
+	WMenuParserRegisterSimpleMacro(parser, "SCR_HEIGHT", buf);
+
+	WMenuParserRegisterSimpleMacro(parser, "DISPLAY", XDisplayName(DisplayString(dpy)) );
+
+	WMenuParserRegisterSimpleMacro(parser, "WM_VERSION", "\"" VERSION "\"");
+}
+
 /************  Menu Configuration From Directory   *************/
 
 static Bool isFilePackage(char *file)
-- 
1.7.10.4

Reply via email to