>From 4ea0f7a71413eec2ec8df86475d4fb2881128129 Mon Sep 17 00:00:00 2001
From: Tobias Stoeckmann <[email protected]>
Date: Sat, 5 May 2012 19:32:21 +0200
Subject: [PATCH] Major overhaul of rootmenu's file handling.

This diff fixes a huge amount of issues that could be triggered by using
the old-fashioned configuration files, i.e menu.  They can be activated
by using a line like "/path/to/menu".  On most systems, this file will be
parsed with cpp and the result sent through a pipe to WindowMaker.

Anyway, in the code path, memory leaks and buffer overruns await. I have
tried to fix these parts, but in the end it is more or less a rewrite,
whereas I used WINGs whenever possible.

Difference to previous implementation, beside of bugfixes:
- You are free to use single quotes and double quotes in configuration
- Linewrapping is allowed for other pipe'd data, too
- In general, line reading is unified throughout that file

Bugfixes:
- Avoid buffer overrun on lines which have line wrappings, that will happen
  ALWAYS, because wtrimspace-usage was erroneously.
- Avoid memory leak, also happened through wtrimspace usage.
- Avoid buffer overrun in separateline if a line ending happens early.
- Actually handle ferror() instead of only feof(), that would result in
  endless spinning
- A line wrapping at the end of a file is an error.
---
 src/rootmenu.c |  259 ++++++++++++++++++++++---------------------------------
 1 files changed, 104 insertions(+), 155 deletions(-)

diff --git a/src/rootmenu.c b/src/rootmenu.c
index 94d35d9..aec9ed1 100644
--- a/src/rootmenu.c
+++ b/src/rootmenu.c
@@ -882,152 +882,119 @@ static WMenuEntry *addMenuEntry(WMenu * menu, char 
*title, char *shortcut, char
 
 /*******************   Menu Configuration From File   *******************/
 
-static void separateline(char *line, char *title, char *command, char 
*parameter, char *shortcut)
+static void freeline(char *title, char *command, char *parameter, char 
*shortcut)
 {
-       int l, i;
+       wfree(title);
+       wfree(command);
+       wfree(parameter);
+       wfree(shortcut);
+}
 
-       l = strlen(line);
+static void separateline(char *line, char **title, char **command, char 
**parameter, char **shortcut)
+{
+       char *suffix, *next = line;
+
+       *title = NULL;
+       *command = NULL;
+       *parameter = NULL;
+       *shortcut = NULL;
 
-       *title = 0;
-       *command = 0;
-       *parameter = 0;
-       *shortcut = 0;
        /* get the title */
-       while (isspace(*line) && (*line != 0))
-               line++;
-       if (*line == '"') {
-               line++;
-               i = 0;
-               while (line[i] != '"' && (line[i] != 0))
-                       i++;
-               if (line[i] != '"')
-                       return;
-       } else {
-               i = 0;
-               while (!isspace(line[i]) && (line[i] != 0))
-                       i++;
-       }
-       strncpy(title, line, i);
-       title[i++] = 0;
-       line += i;
+       *title = wtokennext(line, &next);
+       if (next == NULL)
+               return;
+       line = next;
 
        /* get the command or shortcut keyword */
-       while (isspace(*line) && (*line != 0))
-               line++;
-       if (*line == 0)
+       *command = wtokennext(line, &next);
+       if (next == NULL)
                return;
-       i = 0;
-       while (!isspace(line[i]) && (line[i] != 0))
-               i++;
-       strncpy(command, line, i);
-       command[i++] = 0;
-       line += i;
-
-       if (strcmp(command, "SHORTCUT") == 0) {
-               /* get the shortcut key */
-               while (isspace(*line) && (*line != 0))
-                       line++;
-               if (*line == '"') {
-                       line++;
-                       i = 0;
-                       while (line[i] != '"' && (line[i] != 0))
-                               i++;
-                       if (line[i] != '"')
-                               return;
-               } else {
-                       i = 0;
-                       while (!isspace(line[i]) && (line[i] != 0))
-                               i++;
-               }
-               strncpy(shortcut, line, i);
-               shortcut[i++] = 0;
-               line += i;
+       line = next;
 
-               *command = 0;
+       if (*command != NULL && strcmp(*command, "SHORTCUT") == 0) {
+               /* get the shortcut */
+               *shortcut = wtokennext(line, &next);
+               if (next == NULL)
+                       return;
+               line = next;
 
                /* get the command */
-               while (isspace(*line) && (*line != 0))
-                       line++;
-               if (*line == 0)
+               *command = wtokennext(line, &next);
+               if (next == NULL)
                        return;
-               i = 0;
-               while (!isspace(line[i]) && (line[i] != 0))
-                       i++;
-               strncpy(command, line, i);
-               command[i++] = 0;
-               line += i;
+               line = next;
        }
 
        /* get the parameters */
-       while (isspace(*line) && (*line != 0))
-               line++;
-       if (*line == 0)
-               return;
+       suffix = wtrimspace(line);
 
-       if (*line == '"') {
-               line++;
-               l = 0;
-               while (line[l] != 0 && line[l] != '"') {
-                       parameter[l] = line[l];
-                       l++;
-               }
-               parameter[l] = 0;
-               return;
+       /* should we keep this weird old behavior? */
+       if (suffix[0] == '"') {
+               *parameter = wtokennext(suffix, &next);
+               wfree(suffix);
+       } else {
+               *parameter = suffix;
        }
-
-       l = strlen(line);
-       while (isspace(line[l]) && (l > 0))
-               l--;
-       strncpy(parameter, line, l);
-       parameter[l] = 0;
 }
 
-static WMenu *parseCascade(WScreen * scr, WMenu * menu, FILE * file, char 
*file_name)
+static char *getLine(FILE * file, const char *file_name)
 {
        char linebuf[MAXLINE];
-       char elinebuf[MAXLINE];
-       char title[MAXLINE];
-       char command[MAXLINE];
-       char shortcut[MAXLINE];
-       char params[MAXLINE];
-       char *line;
+       char *line = NULL, *result = NULL;
+       size_t len;
+       int done;
 
-       while (!feof(file)) {
-               int lsize, ok;
-
-               ok = 0;
-               fgets(linebuf, MAXLINE, file);
+again:
+       done = 0;
+       while (!done && fgets(linebuf, sizeof(linebuf), file) != NULL) {
                line = wtrimspace(linebuf);
-               lsize = strlen(line);
-               do {
-                       if (line[lsize - 1] == '\\') {
-                               char *line2;
-                               int lsize2;
-                               fgets(elinebuf, MAXLINE, file);
-                               line2 = wtrimspace(elinebuf);
-                               lsize2 = strlen(line2);
-                               if (lsize2 + lsize > MAXLINE) {
-                                       wwarning(_("%s:maximal line size 
exceeded in menu config: %s"),
-                                                file_name, line);
-                                       ok = 2;
-                               } else {
-                                       line[lsize - 1] = 0;
-                                       lsize += lsize2 - 1;
-                                       strcat(line, line2);
-                               }
-                       } else {
-                               ok = 1;
+               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);
                        }
-               } while (!ok && !feof(file));
-               if (ok == 2)
-                       continue;
+                       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;
+       }
 
-               if (line[0] == 0 || line[0] == '#' || (line[0] == '/' && 
line[1] == '/'))
-                       continue;
+       return result;
+}
 
-               separateline(line, title, command, params, shortcut);
+static WMenu *parseCascade(WScreen * scr, WMenu * menu, FILE * file, char 
*file_name)
+{
+       char *line;
+       char *command, *params, *shortcut, *title;
 
-               if (!command[0]) {
+       while ((line = getLine(file, file_name)) != NULL) {
+               separateline(line, &title, &command, &params, &shortcut);
+
+               if (command == NULL || !command[0]) {
+                       freeline(title, command, params, shortcut);
                        wwarning(_("%s:missing command in menu config: %s"), 
file_name, line);
                        goto error;
                }
@@ -1046,32 +1013,28 @@ 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);
                        return menu;
-
                } else {
                        /* normal items */
-                       addMenuEntry(menu, M_(title), shortcut[0] ? shortcut : 
NULL, command,
-                                    params[0] ? params : NULL, file_name);
+                       addMenuEntry(menu, M_(title), shortcut, command, 
params, file_name);
                }
+               freeline(title, command, params, shortcut);
        }
 
        wwarning(_("%s:syntax error in menu file:END declaration missing"), 
file_name);
-       return menu;
 
  error:
-       return menu;
+       return NULL;
 }
 
 static WMenu *readMenuFile(WScreen * scr, char *file_name)
 {
        WMenu *menu = NULL;
        FILE *file = NULL;
-       char linebuf[MAXLINE];
-       char title[MAXLINE];
-       char shortcut[MAXLINE];
-       char command[MAXLINE];
-       char params[MAXLINE];
        char *line;
+       char *command, *params, *shortcut, *title;
+       char cmd[MAXLINE];
 #ifdef USECPP
        char *args;
        int cpp = 0;
@@ -1083,9 +1046,9 @@ static WMenu *readMenuFile(WScreen * scr, char *file_name)
                if (!args) {
                        wwarning(_("could not make arguments for menu file 
preprocessor"));
                } else {
-                       snprintf(command, sizeof(command), "%s %s %s", 
CPP_PATH, args, file_name);
+                       snprintf(cmd, sizeof(cmd), "%s %s %s", CPP_PATH, args, 
file_name);
                        wfree(args);
-                       file = popen(command, "r");
+                       file = popen(cmd, "r");
                        if (!file) {
                                werror(_("%s:could not open/preprocess menu 
file"), file_name);
                        } else {
@@ -1103,16 +1066,10 @@ static WMenu *readMenuFile(WScreen * scr, char 
*file_name)
                }
        }
 
-       while (!feof(file)) {
-               if (!fgets(linebuf, MAXLINE, file))
-                       break;
-               line = wtrimspace(linebuf);
-               if (line[0] == 0 || line[0] == '#' || (line[0] == '/' && 
line[1] == '/'))
-                       continue;
-
-               separateline(line, title, command, params, shortcut);
+       while ((line = getLine(file, file_name)) != NULL) {
+               separateline(line, &title, &command, &params, &shortcut);
 
-               if (!command[0]) {
+               if (command == NULL || !command[0]) {
                        wwarning(_("%s:missing command in menu config: %s"), 
file_name, line);
                        break;
                }
@@ -1128,6 +1085,7 @@ static WMenu *readMenuFile(WScreen * scr, char *file_name)
                        break;
                }
        }
+       freeline(title, command, params, shortcut);
 
 #ifdef USECPP
        if (cpp) {
@@ -1150,11 +1108,7 @@ static WMenu *readMenuPipe(WScreen * scr, char 
**file_name)
 {
        WMenu *menu = NULL;
        FILE *file = NULL;
-       char linebuf[MAXLINE];
-       char title[MAXLINE];
-       char command[MAXLINE];
-       char params[MAXLINE];
-       char shortcut[MAXLINE];
+       char *command, *params, *shortcut, *title;
        char *line;
        char *filename;
        char flat_file[MAXLINE];
@@ -1197,16 +1151,10 @@ static WMenu *readMenuPipe(WScreen * scr, char 
**file_name)
                }
        }
 
-       while (!feof(file)) {
-               if (!fgets(linebuf, MAXLINE, file))
-                       break;
-               line = wtrimspace(linebuf);
-               if (line[0] == 0 || line[0] == '#' || (line[0] == '/' && 
line[1] == '/'))
-                       continue;
-
-               separateline(line, title, command, params, shortcut);
+       while ((line = getLine(file, filename)) != NULL) {
+               separateline(line, &title, &command, &params, &shortcut);
 
-               if (!command[0]) {
+               if (command == NULL || !command[0]) {
                        wwarning(_("%s:missing command in menu config: %s"), 
filename, line);
                        break;
                }
@@ -1222,6 +1170,7 @@ static WMenu *readMenuPipe(WScreen * scr, char 
**file_name)
                        break;
                }
        }
+       freeline(title, command, params, shortcut);
 
        pclose(file);
 
-- 
1.7.6


-- 
To unsubscribe, send mail to [email protected].

Reply via email to