From: Matthew Fernandez Date: Wed, 14 Sep 2022 00:47:29 +0000 (-0700) Subject: gvc auto_output_filename: avoid 'strdup' when constructing file name X-Git-Tag: 6.0.2~37^2 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=62a33d96e6484b2d6f4b2ca66d87d2608087c056;p=graphviz gvc auto_output_filename: avoid 'strdup' when constructing file name This is a reattempt of 4291cc769a3eeef8b1c171e5479194733a4da6cd. The first attempt introduced a bug where the separating `.` was not accounted for and accidentally truncated. It was reverted in 8d662734b6a34709d9475b120e7ce3de872339e2. The present commit takes much the same approach but ensures to account for the separating `.`. Quoting 4291cc769a3eeef8b1c171e5479194733a4da6cd: 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. --- diff --git a/lib/gvc/gvdevice.c b/lib/gvc/gvdevice.c index dfe68871d..0ab0e45b0 100644 --- a/lib/gvc/gvdevice.c +++ b/lib/gvc/gvdevice.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -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,22 @@ 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 == ':') { + dst += sprintf(dst, "%.*s.", (int)(src_end - q - 1), 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; }