]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
tool_parsecfg: use dynbuf for quoted arguments
authorDaniel Stenberg <daniel@haxx.se>
Fri, 8 Aug 2025 15:41:30 +0000 (17:41 +0200)
committerDaniel Stenberg <daniel@haxx.se>
Fri, 8 Aug 2025 16:27:03 +0000 (18:27 +0200)
Instead of doing malloc/free every time and "manual" buffer population.
This reuses the dynbuf for this purpose for the duration of parsing the
file.

Closes #18230

src/tool_parsecfg.c
tests/data/test459

index d5303e679bf880be3983bf914aeead7faf613d11..bc22b9d5b7b5f967392ef6b3ea7108f9a33dd724 100644 (file)
    specified with an initial dash! */
 #define ISSEP(x,dash) (!dash && (((x) == '=') || ((x) == ':')))
 
-static const char *unslashquote(const char *line, char *param);
+/*
+ * Copies the string from line to the param dynbuf, unquoting backslash-quoted
+ * characters and null-terminating the output string. Stops at the first
+ * non-backslash-quoted double quote character or the end of the input string.
+ * param must be at least as long as the input string. Returns 0 on success.
+ */
+static int unslashquote(const char *line, struct dynbuf *param)
+{
+  curlx_dyn_reset(param);
+
+  while(*line && (*line != '\"')) {
+    if(*line == '\\') {
+      char out;
+      line++;
+
+      /* default is to output the letter after the backslash */
+      switch(out = *line) {
+      case '\0':
+        continue; /* this'll break out of the loop */
+      case 't':
+        out = '\t';
+        break;
+      case 'n':
+        out = '\n';
+        break;
+      case 'r':
+        out = '\r';
+        break;
+      case 'v':
+        out = '\v';
+        break;
+      }
+      if(curlx_dyn_addn(param, &out, 1))
+        return 1;
+      line++;
+    }
+    else if(curlx_dyn_addn(param, line++, 1))
+      return 1;
+  }
+  return 0; /* ok */
+}
 
 #define MAX_CONFIG_LINE_LENGTH (10*1024*1024)
 
@@ -87,13 +127,14 @@ int parseconfig(const char *filename)
     int lineno = 0;
     bool dashed_option;
     struct dynbuf buf;
+    struct dynbuf pbuf;
     bool fileerror = FALSE;
     curlx_dyn_init(&buf, MAX_CONFIG_LINE_LENGTH);
+    curlx_dyn_init(&pbuf, MAX_CONFIG_LINE_LENGTH);
     DEBUGASSERT(filename);
 
     while(!rc && my_get_line(file, &buf, &fileerror)) {
       ParameterError res;
-      bool alloced_param = FALSE;
       lineno++;
       line = curlx_dyn_ptr(&buf);
       if(!line) {
@@ -125,15 +166,10 @@ int parseconfig(const char *filename)
       /* the parameter starts here (unless quoted) */
       if(*line == '\"') {
         /* quoted parameter, do the quote dance */
-        line++;
-        param = malloc(strlen(line) + 1); /* parameter */
-        if(!param) {
-          /* out of memory */
-          rc = 1;
+        rc = unslashquote(++line, &pbuf);
+        if(rc)
           break;
-        }
-        alloced_param = TRUE;
-        (void)unslashquote(line, param);
+        param = curlx_dyn_len(&pbuf) ? curlx_dyn_ptr(&pbuf) : CURL_UNCONST("");
       }
       else {
         param = line; /* parameter starts here */
@@ -156,10 +192,9 @@ int parseconfig(const char *filename)
           case '#': /* comment */
             break;
           default:
-            warnf("%s:%d: warning: '%s' uses unquoted "
-                  "whitespace", filename, lineno, option);
-            warnf("This may cause side-effects. "
-                  "Consider using double quotes?");
+            warnf("%s:%d: warning: '%s' uses unquoted whitespace. "
+                  "This may cause side-effects. Consider double quotes.",
+                  filename, lineno, option);
           }
         }
         if(!*param)
@@ -211,11 +246,9 @@ int parseconfig(const char *filename)
           rc = (int)res;
         }
       }
-
-      if(alloced_param)
-        tool_safefree(param);
     }
     curlx_dyn_free(&buf);
+    curlx_dyn_free(&pbuf);
     if(file != stdin)
       fclose(file);
     if(fileerror)
@@ -228,46 +261,6 @@ int parseconfig(const char *filename)
   return rc;
 }
 
-/*
- * Copies the string from line to the buffer at param, unquoting
- * backslash-quoted characters and null-terminating the output string. Stops
- * at the first non-backslash-quoted double quote character or the end of the
- * input string. param must be at least as long as the input string. Returns
- * the pointer after the last handled input character.
- */
-static const char *unslashquote(const char *line, char *param)
-{
-  while(*line && (*line != '\"')) {
-    if(*line == '\\') {
-      char out;
-      line++;
-
-      /* default is to output the letter after the backslash */
-      switch(out = *line) {
-      case '\0':
-        continue; /* this'll break out of the loop */
-      case 't':
-        out = '\t';
-        break;
-      case 'n':
-        out = '\n';
-        break;
-      case 'r':
-        out = '\r';
-        break;
-      case 'v':
-        out = '\v';
-        break;
-      }
-      *param++ = out;
-      line++;
-    }
-    else
-      *param++ = *line++;
-  }
-  *param = '\0'; /* always null-terminate */
-  return line;
-}
 
 static bool get_line(FILE *input, struct dynbuf *buf, bool *error)
 {
index e46d029732cd5b0e563c59b86352de411d72b3e0..198e67d2a3e00cdc4375c4cbb86b20e978365512 100644 (file)
@@ -56,8 +56,8 @@ Content-Type: application/x-www-form-urlencoded
 arg
 </protocol>
 <stderr mode="text">
-Warning: %LOGDIR/config:1: warning: 'data' uses unquoted whitespace
-Warning: This may cause side-effects. Consider using double quotes?
+Warning: %LOGDIR/config:1: warning: 'data' uses unquoted whitespace. This may 
+Warning: cause side-effects. Consider double quotes.
 </stderr>
 </verify>
 </testcase>