]> granicus.if.org Git - graphviz/commitdiff
gvc auto_output_filename: avoid 'strdup' when constructing file name
authorMatthew Fernandez <matthew.fernandez@gmail.com>
Sat, 9 Jul 2022 16:05:41 +0000 (09:05 -0700)
committerMatthew Fernandez <matthew.fernandez@gmail.com>
Fri, 22 Jul 2022 00:41:57 +0000 (17:41 -0700)
This block of code is scanning a string of `:`-separated entries and writing
them into `buf` in reverse order `.`-separated. We can rewrite it to avoid
dynamic allocation, thus avoiding certain failure cases and locking overhead.

Unfortunately there seems to be no variant of `strrchr` that takes a length. So
we need to write our own loop for locating the last `:` with a limit.

lib/gvc/gvdevice.c

index 8baed0f65b78aeab52eda7f709d0beedd7236fd0..5ced43c1200edfd513824c0c580386b5ae04b87e 100644 (file)
@@ -17,6 +17,7 @@
 #include <ctype.h>
 #include <stdarg.h>
 #include <stdbool.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <inttypes.h>
@@ -86,7 +87,7 @@ static void auto_output_filename(GVJ_t *job)
     static char *buf;
     static size_t bufsz;
     char gidx[100];  /* large enough for '.' plus any integer */
-    char *fn, *p, *q;
+    char *fn;
     size_t len;
 
     if (job->graph_index)
@@ -107,14 +108,23 @@ static void auto_output_filename(GVJ_t *job)
     strcpy(buf, fn);
     strcat(buf, gidx);
     strcat(buf, ".");
-    p = strdup(job->output_langname);
-    while ((q = strrchr(p, ':'))) {
-        strcat(buf, q+1);
-        strcat(buf, ".");
-       *q = '\0';
+
+    {
+        char *dst = buf + strlen(buf);
+        const char *src = job->output_langname;
+        const char *src_end = src + strlen(src);
+        for (const char *q = src_end; ; --q) {
+            if (*q == ':') {
+                sprintf(dst, "%.*s.", (int)(src_end - q - 1), q + 1);
+                dst += (size_t)(src_end - q - 1);
+                src_end = q;
+            }
+            if (q == src) {
+                sprintf(dst, "%.*s", (int)(src_end - src), src);
+                break;
+            }
+        }
     }
-    strcat(buf, p);
-    free(p);
 
     job->output_filename = buf;
 }