]> skyeroc.xyz Git - dgamelaunch/commitdiff
multi-arg exec and nested ${pref1:${pref2}}
authorTangles <andyrthomson@gmail.com>
Sun, 16 Feb 2020 01:47:22 +0000 (12:47 +1100)
committerTangles <andyrthomson@gmail.com>
Sun, 16 Feb 2020 01:57:59 +0000 (12:57 +1100)
exec "command" "several args separated by spaces in 1 string".
I could not figure out how to nicely deal with multiple args in the parser,
so I just left it as DGL_CMD1, and do the separation manually.
Does the separation before dgl_format_str substitutions, to prevent
relying on potentially user-supplied input not having extra spaces embedded.

nested preferences - this just fixes a bug where we assumed the token
ended on the first }.

dgamelaunch.c
dgl-common.c

index e850674f26513f442d40e8ef7d6a016357d08974..290aa2e6d3d7d86a9ab55b6bc5bfa6c0d5dfcbe5 100644 (file)
@@ -407,27 +407,16 @@ bannerstr_substprefs(char *buf, char *bufnew, int buflen)
     char *gpr = NULL;
     int isdollar = 0;
     int firstchar = 0;
+    int nest = 0;
     if (!src) return NULL;
     while (*src && dst < bufnew + buflen - 1) {
-        if (*src == '$') {
-            isdollar = 1;
-        } else if (isdollar) {
-            if (*src == '0') {
-                firstchar = 1;
-            } else {
-               isdollar = 0;
-               if (*src == '{') {
-                   varname = src + 1;
-               } else {
-                   *dst++ = '$';
-                   *dst++ = *src;
-               }
-            }
-        } else if (varname || fallback) {
-            if (*src == ':') {
+        if (varname || fallback) {
+            if (*src == ':' && !nest) {
                 *src = '\0';
                 fallback = src + 1;
-            } else if (*src == '}') {
+            } else if (*src == '{') {
+                nest++;
+            } else if (*src == '}' && !(--nest)) {
                 *src = '\0';
                 gpr = getpref(varname, fallback);
                 if (firstchar) {
@@ -439,7 +428,22 @@ bannerstr_substprefs(char *buf, char *bufnew, int buflen)
                 for (; *dst; dst++);
                 fallback = varname = NULL;
             }
-        } else
+        } else if (*src == '$') {
+            isdollar = 1;
+        } else if (isdollar) {
+            if (*src == '0') {
+                firstchar = 1;
+            } else {
+               isdollar = 0;
+               if (*src == '{') {
+                   varname = src + 1;
+                    nest++;
+               } else {
+                   *dst++ = '$';
+                   *dst++ = *src;
+               }
+            }
+         } else
             *dst++ = *src;
         src++;
     }
index 1f43fd545eec4fdc80678d26391d2c0d56f977af..4b56778f287101804b7b120df7c591f90c64545d 100644 (file)
@@ -134,6 +134,7 @@ dgl_format_str(int game, struct dg_user *me, char *str, char *plrname)
     int ispercent = 0;
     int isbackslash = 0;
     int isdollar = 0;
+    int nest = 0;
     int firstchar = 0; /* special case for returning
                           only the first char of a userpref */
 
@@ -146,11 +147,12 @@ dgl_format_str(int game, struct dg_user *me, char *str, char *plrname)
 
     while (*f) {
         if (varname || fallback) {
-           if (*f == ':') {
+           if (*f == ':' && !nest) {
                fallback = f+1;
                *f = '\0';
-           }
-           if (*f == '}') {
+           } else if (*f == '{') {
+               nest++;
+           } else if (*f == '}' && !(--nest)) {
                *f = '\0';
                gpr = getpref(varname, fallback);
                if (firstchar) {
@@ -285,7 +287,6 @@ dgl_format_str(int game, struct dg_user *me, char *str, char *plrname)
 int
 dgl_exec_cmdqueue_w(struct dg_cmdpart *queue, int game, struct dg_user *me, char *playername)
 {
-    int i;
     struct dg_cmdpart *tmp = queue;
     char *p1;
     char *p2;
@@ -296,8 +297,8 @@ dgl_exec_cmdqueue_w(struct dg_cmdpart *queue, int game, struct dg_user *me, char
     return_from_submenu = 0;
 
     while (tmp && !return_from_submenu) {
-       if (tmp->param1) p1 = dgl_format_str(game, me, tmp->param1, playername);
-       if (tmp->param2) p2 = dgl_format_str(game, me, tmp->param2, playername);
+       p1 = tmp->param1 ? dgl_format_str(game, me, tmp->param1, playername) : NULL;
+       p2 = tmp->param2 ? dgl_format_str(game, me, tmp->param2, playername) : NULL;
 
        switch (tmp->cmd) {
        default: break;
@@ -352,12 +353,33 @@ dgl_exec_cmdqueue_w(struct dg_cmdpart *queue, int game, struct dg_user *me, char
            break;
        case DGLCMD_EXEC:
            if (p1 && p2) {
+                /* split the un-formatted p2 value on whitespace and pass it
+                 * as separate args after re-formatting each part. This can
+                 * probably done better in the config parser, but this works.
+                 */
                pid_t child;
-               char *myargv[3];
+               int myargc = 0;
+               char *words[32]; /* max args - this is arbitrary */
+               char **myargv; /* allocate these when we know how many */
+               char *p; 
+               int isspace = 1;
+               int i;
+               for (p = tmp->param2; *p; p++) {
+                   if (*p == ' ') {
+                       isspace++;
+                       *p = 0;
+                   } else if (isspace) {
+                       isspace = 0;
+                       words[myargc++] = p;
+                   }
+               }
+               myargv = calloc(++myargc + 1, sizeof (char *));
 
                myargv[0] = p1;
-               myargv[1] = p2;
-               myargv[2] = 0;
+               for (i = 1; i < myargc; i++) {
+                    myargv[i] = dgl_format_str(game, me, words[i-1], playername);
+               }
+               myargv[i] = 0;
 
                clear();
                refresh();
@@ -371,8 +393,14 @@ dgl_exec_cmdqueue_w(struct dg_cmdpart *queue, int game, struct dg_user *me, char
                } else if (child == 0) {
                    execvp(p1, myargv);
                    exit(0);
-               } else
+               } else {
+                    /* argv[0] is 'p1' which gets freed later */
+                    for (i = 1; i < myargc; i++) {
+                        free(myargv[i]);
+                    }
+                    free (myargv);
                    waitpid(child, NULL, 0);
+                }
                idle_alarm_set_enabled(1);
                initcurses();
                check_retard(1);