]> granicus.if.org Git - graphviz/commitdiff
core plugin: remove 'GVPUTS' optimization
authorMatthew Fernandez <matthew.fernandez@gmail.com>
Mon, 18 Apr 2022 04:31:41 +0000 (21:31 -0700)
committerMatthew Fernandez <matthew.fernandez@gmail.com>
Thu, 21 Apr 2022 00:01:40 +0000 (17:01 -0700)
This macro was implemented to optimize the case of calling `gvputs` with a
string literal. It has since proven error prone to use.¹ The sharp edge is that
it is possible to call the macro with something that is not a string literal:

  const char *hello = "hello world";
  GVPUTS(job, hello);

This will pass through the compiler with no warnings, but on e.g. x86-64 will
result in a `gvputs` of `"hello wo"`. For safety, we remove it.

This effectively reverts commit 1764f50bcbdf944e003fe475aba2c26e2fd370ff. The
`GVPUTS` macro was originally introduced to optimize I/O resulting in a ~1%
runtime improvement on tests/regression_tests/large/long_chain. That example
should probably no longer be considered “expensive.” I/O is typically an
insignificant fraction of the computation done by currently known expensive
inputs that spend most of their time in layout or cycle resolution. If I/O _is_
a factor in an expensive graph, we could consider providing a vectorized
interface in future in the style of `writev`.

¹ E.g. https://gitlab.com/graphviz/graphviz/-/merge_requests/2472#note_861834540

plugin/core/gvrender_core_svg.c

index 85e748b7eb1986e04ccbf50c5cf8fc80d096da02..97d9204b7c7491e7a5204dc8fe3e51ad40fc7c96 100644 (file)
@@ -43,9 +43,6 @@
   #define EDGEALIGN 0
 #endif
 
-// optimized gvputs for string literals
-#define GVPUTS(job, str) gvwrite((job), (str), sizeof(str) - 1)
-
 typedef enum { FORMAT_SVG, FORMAT_SVGZ, } format_type;
 
 /* SVG dash array */
@@ -65,7 +62,7 @@ static void svg_bzptarray(GVJ_t * job, pointf * A, int n)
        for (i = 0; i < n; i++) {
            gvwrite(job, &c, 1);
             gvprintdouble(job, A[i].x);
-            GVPUTS(job, ",");
+            gvputc(job, ',');
             gvprintdouble(job, -A[i].y);
            if (i == 0)
                c = 'C';                /* second point */
@@ -77,7 +74,7 @@ static void svg_bzptarray(GVJ_t * job, pointf * A, int n)
        for (i = n-1; i >= 0; i--) {
            gvwrite(job, &c, 1);
             gvprintdouble(job, A[i].x);
-            GVPUTS(job, ",");
+            gvputc(job, ',');
             gvprintdouble(job, -A[i].y);
            if (i == 0)
                c = 'C';                /* second point */
@@ -92,18 +89,18 @@ static void svg_print_id_class(GVJ_t * job, char* id, char* idx, char* kind, voi
 {
     char* str;
 
-    GVPUTS(job, "<g id=\"");
+    gvputs(job, "<g id=\"");
     gvputs_xml(job, id);
     if (idx) {
-       GVPUTS(job, "_");
+       gvputc(job, '_');
        gvputs_xml(job, idx);
     }
     gvprintf(job, "\" class=\"%s", kind);
     if ((str = agget(obj, "class")) && *str) {
-       GVPUTS(job, " ");
+       gvputc(job, ' ');
        gvputs_xml(job, str);
     }
-    GVPUTS(job, "\"");
+    gvputc(job, '"');
 }
 
 static void svg_print_color(GVJ_t * job, gvcolor_t color)
@@ -114,7 +111,7 @@ static void svg_print_color(GVJ_t * job, gvcolor_t color)
        break;
     case RGBA_BYTE:
        if (color.u.rgba[3] == 0)       /* transparent */
-           GVPUTS(job, "transparent");
+           gvputs(job, "transparent");
        else
            gvprintf(job, "#%02x%02x%02x",
                     color.u.rgba[0], color.u.rgba[1], color.u.rgba[2]);
@@ -128,7 +125,7 @@ static void svg_grstyle(GVJ_t * job, int filled, int gid)
 {
     obj_state_t *obj = job->obj;
 
-    GVPUTS(job, " fill=\"");
+    gvputs(job, " fill=\"");
     if (filled == GRADIENT) {
        gvprintf(job, "url(#l_%d)", gid);
     } else if (filled == RGRADIENT) {
@@ -141,12 +138,12 @@ static void svg_grstyle(GVJ_t * job, int filled, int gid)
            gvprintf(job, "\" fill-opacity=\"%f",
                     ((float) obj->fillcolor.u.rgba[3] / 255.0));
     } else {
-       GVPUTS(job, "none");
+       gvputs(job, "none");
     }
-    GVPUTS(job, "\" stroke=\"");
+    gvputs(job, "\" stroke=\"");
     svg_print_color(job, obj->pencolor);
     if (obj->penwidth != PENWIDTH_NORMAL) {
-       GVPUTS(job, "\" stroke-width=\"");
+       gvputs(job, "\" stroke-width=\"");
         gvprintdouble(job, obj->penwidth);
     }
     if (obj->pen == PEN_DASHED) {
@@ -159,36 +156,36 @@ static void svg_grstyle(GVJ_t * job, int filled, int gid)
        gvprintf(job, "\" stroke-opacity=\"%f",
                 ((float) obj->pencolor.u.rgba[3] / 255.0));
 
-    GVPUTS(job, "\"");
+    gvputc(job, '"');
 }
 
 static void svg_comment(GVJ_t * job, char *str)
 {
-    GVPUTS(job, "<!-- ");
+    gvputs(job, "<!-- ");
     gvputs_xml(job, str);
-    GVPUTS(job, " -->\n");
+    gvputs(job, " -->\n");
 }
 
 static void svg_begin_job(GVJ_t * job)
 {
     char *s;
-    GVPUTS(job,
+    gvputs(job,
           "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n");
     if ((s = agget(job->gvc->g, "stylesheet")) && s[0]) {
-       GVPUTS(job, "<?xml-stylesheet href=\"");
+       gvputs(job, "<?xml-stylesheet href=\"");
        gvputs(job, s);
-       GVPUTS(job, "\" type=\"text/css\"?>\n");
+       gvputs(job, "\" type=\"text/css\"?>\n");
     }
-    GVPUTS(job, "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n"
+    gvputs(job, "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n"
                 " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n"
 
                 "<!-- Generated by ");
     gvputs_xml(job, job->common->info[0]);
-    GVPUTS(job, " version ");
+    gvputs(job, " version ");
     gvputs_xml(job, job->common->info[1]);
-    GVPUTS(job, " (");
+    gvputs(job, " (");
     gvputs_xml(job, job->common->info[2]);
-    GVPUTS(job, ")\n"
+    gvputs(job, ")\n"
                 " -->\n");
 }
 
@@ -196,9 +193,9 @@ static void svg_begin_graph(GVJ_t * job)
 {
     obj_state_t *obj = job->obj;
 
-    GVPUTS(job, "<!--");
+    gvputs(job, "<!--");
     if (agnameof(obj->u.g)[0] && agnameof(obj->u.g)[0] != LOCALNAMEPREFIX) {
-       GVPUTS(job, " Title: ");
+       gvputs(job, " Title: ");
        gvputs_xml(job, agnameof(obj->u.g));
     }
     gvprintf(job, " Pages: %d -->\n",
@@ -212,7 +209,7 @@ static void svg_begin_graph(GVJ_t * job)
        job->canvasBox.UR.x,
        job->canvasBox.UR.y);
     /* namespace of svg */
-    GVPUTS(job, " xmlns=\"http://www.w3.org/2000/svg\""
+    gvputs(job, " xmlns=\"http://www.w3.org/2000/svg\""
     /* namespace of xlink */
                 " xmlns:xlink=\"http://www.w3.org/1999/xlink\""
                 ">\n");
@@ -220,7 +217,7 @@ static void svg_begin_graph(GVJ_t * job)
 
 static void svg_end_graph(GVJ_t * job)
 {
-    GVPUTS(job, "</svg>\n");
+    gvputs(job, "</svg>\n");
 }
 
 static void svg_begin_layer(GVJ_t * job, char *layername, int layerNum,
@@ -232,12 +229,12 @@ static void svg_begin_layer(GVJ_t * job, char *layername, int layerNum,
     obj_state_t *obj = job->obj;
 
     svg_print_id_class(job, layername, NULL, "layer", obj->u.g);
-    GVPUTS(job, ">\n");
+    gvputs(job, ">\n");
 }
 
 static void svg_end_layer(GVJ_t * job)
 {
-    GVPUTS(job, "</g>\n");
+    gvputs(job, "</g>\n");
 }
 
 /* svg_begin_page:
@@ -251,25 +248,25 @@ static void svg_begin_page(GVJ_t * job)
     /* its really just a page of the graph, but its still a graph,
      * and it is the entire graph if we're not currently paging */
     svg_print_id_class(job, obj->id, NULL, "graph", obj->u.g);
-    GVPUTS(job, " transform=\"scale(");
+    gvputs(job, " transform=\"scale(");
     // cannot be gvprintdouble because 2 digits precision insufficient
     gvprintf(job, "%g %g", job->scale.x, job->scale.y);
     gvprintf(job, ") rotate(%d) translate(", -job->rotation);
     gvprintdouble(job, job->translation.x);
-    GVPUTS(job, " ");
+    gvputc(job, ' ');
     gvprintdouble(job, -job->translation.y);
-    GVPUTS(job, ")\">\n");
+    gvputs(job, ")\">\n");
     /* default style */
     if (agnameof(obj->u.g)[0] && agnameof(obj->u.g)[0] != LOCALNAMEPREFIX) {
-       GVPUTS(job, "<title>");
+       gvputs(job, "<title>");
        gvputs_xml(job, agnameof(obj->u.g));
-       GVPUTS(job, "</title>\n");
+       gvputs(job, "</title>\n");
     }
 }
 
 static void svg_end_page(GVJ_t * job)
 {
-    GVPUTS(job, "</g>\n");
+    gvputs(job, "</g>\n");
 }
 
 static void svg_begin_cluster(GVJ_t * job)
@@ -277,15 +274,15 @@ static void svg_begin_cluster(GVJ_t * job)
     obj_state_t *obj = job->obj;
 
     svg_print_id_class(job, obj->id, NULL, "cluster", obj->u.sg);
-    GVPUTS(job, ">\n"
+    gvputs(job, ">\n"
                 "<title>");
     gvputs_xml(job, agnameof(obj->u.g));
-    GVPUTS(job, "</title>\n");
+    gvputs(job, "</title>\n");
 }
 
 static void svg_end_cluster(GVJ_t * job)
 {
-    GVPUTS(job, "</g>\n");
+    gvputs(job, "</g>\n");
 }
 
 static void svg_begin_node(GVJ_t * job)
@@ -298,15 +295,15 @@ static void svg_begin_node(GVJ_t * job)
     else
        idx = NULL;
     svg_print_id_class(job, obj->id, idx, "node", obj->u.n);
-    GVPUTS(job, ">\n"
+    gvputs(job, ">\n"
                 "<title>");
     gvputs_xml(job, agnameof(obj->u.n));
-    GVPUTS(job, "</title>\n");
+    gvputs(job, "</title>\n");
 }
 
 static void svg_end_node(GVJ_t * job)
 {
-    GVPUTS(job, "</g>\n");
+    gvputs(job, "</g>\n");
 }
 
 static void svg_begin_edge(GVJ_t * job)
@@ -315,56 +312,56 @@ static void svg_begin_edge(GVJ_t * job)
     char *ename;
 
     svg_print_id_class(job, obj->id, NULL, "edge", obj->u.e);
-    GVPUTS(job, ">\n"
+    gvputs(job, ">\n"
 
                 "<title>");
     ename = strdup_and_subst_obj("\\E", obj->u.e);
     gvputs_xml(job, ename);
     free(ename);
-    GVPUTS(job, "</title>\n");
+    gvputs(job, "</title>\n");
 }
 
 static void svg_end_edge(GVJ_t * job)
 {
-    GVPUTS(job, "</g>\n");
+    gvputs(job, "</g>\n");
 }
 
 static void
 svg_begin_anchor(GVJ_t * job, char *href, char *tooltip, char *target,
                 char *id)
 {
-    GVPUTS(job, "<g");
+    gvputs(job, "<g");
     if (id) {
-       GVPUTS(job, " id=\"a_");
+       gvputs(job, " id=\"a_");
         gvputs_xml(job, id);
-        GVPUTS(job, "\"");
+        gvputc(job, '"');
     }
-    GVPUTS(job, ">"
+    gvputs(job, ">"
 
                 "<a");
     if (href && href[0]) {
-       GVPUTS(job, " xlink:href=\"");
+       gvputs(job, " xlink:href=\"");
        const xml_flags_t flags = {0};
        xml_escape(href, flags, (int(*)(void*, const char*))gvputs, job);
-       GVPUTS(job, "\"");
+       gvputc(job, '"');
     }
     if (tooltip && tooltip[0]) {
-       GVPUTS(job, " xlink:title=\"");
+       gvputs(job, " xlink:title=\"");
        const xml_flags_t flags = {.raw = 1, .dash = 1, .nbsp = 1};
        xml_escape(tooltip, flags, (int(*)(void*, const char*))gvputs, job);
-       GVPUTS(job, "\"");
+       gvputc(job, '"');
     }
     if (target && target[0]) {
-       GVPUTS(job, " target=\"");
+       gvputs(job, " target=\"");
        gvputs_xml(job, target);
-       GVPUTS(job, "\"");
+       gvputc(job, '"');
     }
-    GVPUTS(job, ">\n");
+    gvputs(job, ">\n");
 }
 
 static void svg_end_anchor(GVJ_t * job)
 {
-    GVPUTS(job, "</a>\n"
+    gvputs(job, "</a>\n"
                 "</g>\n");
 }
 
@@ -375,26 +372,26 @@ static void svg_textspan(GVJ_t * job, pointf p, textspan_t * span)
     char *family = NULL, *weight = NULL, *stretch = NULL, *style = NULL;
     unsigned int flags;
 
-    GVPUTS(job, "<text");
+    gvputs(job, "<text");
     switch (span->just) {
     case 'l':
-       GVPUTS(job, " text-anchor=\"start\"");
+       gvputs(job, " text-anchor=\"start\"");
        break;
     case 'r':
-       GVPUTS(job, " text-anchor=\"end\"");
+       gvputs(job, " text-anchor=\"end\"");
        break;
     default:
     case 'n':
-       GVPUTS(job, " text-anchor=\"middle\"");
+       gvputs(job, " text-anchor=\"middle\"");
        break;
     }
     p.y += span->yoffset_centerline;
     if (!obj->labeledgealigned) {
-       GVPUTS(job, " x=\"");
+       gvputs(job, " x=\"");
         gvprintdouble(job, p.x);
-        GVPUTS(job, "\" y=\"");
+        gvputs(job, "\" y=\"");
         gvprintdouble(job, -p.y);
-        GVPUTS(job, "\"");
+        gvputs(job, "\"");
     }
     pA = span->font->postscript_alias;
     if (pA) {
@@ -421,7 +418,7 @@ static void svg_textspan(GVJ_t * job, pointf p, textspan_t * span)
        gvprintf(job, " font-family=\"%s", family);
        if (pA->svg_font_family)
            gvprintf(job, ",%s", pA->svg_font_family);
-       GVPUTS(job, "\"");
+       gvputc(job, '"');
        if (weight)
            gvprintf(job, " font-weight=\"%s\"", weight);
        if (stretch)
@@ -432,14 +429,14 @@ static void svg_textspan(GVJ_t * job, pointf p, textspan_t * span)
        gvprintf(job, " font-family=\"%s\"", span->font->name);
     if ((span->font) && (flags = span->font->flags)) {
        if ((flags & HTML_BF) && !weight)
-           GVPUTS(job, " font-weight=\"bold\"");
+           gvputs(job, " font-weight=\"bold\"");
        if ((flags & HTML_IF) && !style)
-           GVPUTS(job, " font-style=\"italic\"");
+           gvputs(job, " font-style=\"italic\"");
        if ((flags & (HTML_UL|HTML_S|HTML_OL))) {
            int comma = 0;
-           GVPUTS(job, " text-decoration=\"");
+           gvputs(job, " text-decoration=\"");
            if ((flags & HTML_UL)) {
-               GVPUTS(job, "underline");
+               gvputs(job, "underline");
                comma = 1;
            }
            if ((flags & HTML_OL)) {
@@ -448,12 +445,12 @@ static void svg_textspan(GVJ_t * job, pointf p, textspan_t * span)
            }
            if ((flags & HTML_S))
                gvprintf(job, "%sline-through", (comma?",":""));
-           GVPUTS(job, "\"");
+           gvputc(job, '"');
        }
        if ((flags & HTML_SUP))
-           GVPUTS(job, " baseline-shift=\"super\"");
+           gvputs(job, " baseline-shift=\"super\"");
        if ((flags & HTML_SUB))
-           GVPUTS(job, " baseline-shift=\"sub\"");
+           gvputs(job, " baseline-shift=\"sub\"");
     }
 
     gvprintf(job, " font-size=\"%.2f\"", span->font->size);
@@ -472,19 +469,19 @@ static void svg_textspan(GVJ_t * job, pointf p, textspan_t * span)
     default:
        assert(0);              /* internal error */
     }
-    GVPUTS(job, ">");
+    gvputc(job, '>');
     if (obj->labeledgealigned) {
-       GVPUTS(job, "<textPath xlink:href=\"#");
+       gvputs(job, "<textPath xlink:href=\"#");
        gvputs_xml(job, obj->id);
-       GVPUTS(job, "_p\" startOffset=\"50%\"><tspan x=\"0\" dy=\"");
+       gvputs(job, "_p\" startOffset=\"50%\"><tspan x=\"0\" dy=\"");
         gvprintdouble(job, -p.y);
-        GVPUTS(job, "\">");
+        gvputs(job, "\">");
     }
     const xml_flags_t xml_flags = {.raw = 1, .dash = 1, .nbsp = 1};
     xml_escape(span->str, xml_flags, (int(*)(void*, const char*))gvputs, job);
     if (obj->labeledgealigned)
-       GVPUTS(job, "</tspan></textPath>");
-    GVPUTS(job, "</text>\n");
+       gvputs(job, "</tspan></textPath>");
+    gvputs(job, "</text>\n");
 }
 
 /* svg_gradstyle
@@ -503,39 +500,39 @@ static int svg_gradstyle(GVJ_t * job, pointf * A, int n)
 
     gvprintf(job,
             "<defs>\n<linearGradient id=\"l_%d\" gradientUnits=\"userSpaceOnUse\" ", id);
-    GVPUTS(job, "x1=\"");
+    gvputs(job, "x1=\"");
     gvprintdouble(job, G[0].x);
-    GVPUTS(job, "\" y1=\"");
+    gvputs(job, "\" y1=\"");
     gvprintdouble(job, G[0].y);
-    GVPUTS(job, "\" x2=\"");
+    gvputs(job, "\" x2=\"");
     gvprintdouble(job, G[1].x);
-    GVPUTS(job, "\" y2=\"");
+    gvputs(job, "\" y2=\"");
     gvprintdouble(job, G[1].y);
-    GVPUTS(job, "\" >\n");
+    gvputs(job, "\" >\n");
     if (obj->gradient_frac > 0)
        gvprintf(job, "<stop offset=\"%.03f\" style=\"stop-color:", obj->gradient_frac - 0.001);
     else
-       GVPUTS(job, "<stop offset=\"0\" style=\"stop-color:");
+       gvputs(job, "<stop offset=\"0\" style=\"stop-color:");
     svg_print_color(job, obj->fillcolor);
-    GVPUTS(job, ";stop-opacity:");
+    gvputs(job, ";stop-opacity:");
     if (obj->fillcolor.type == RGBA_BYTE && obj->fillcolor.u.rgba[3] > 0
        && obj->fillcolor.u.rgba[3] < 255)
        gvprintf(job, "%f", ((float) obj->fillcolor.u.rgba[3] / 255.0));
     else
-       GVPUTS(job, "1.");
-    GVPUTS(job, ";\"/>\n");
+       gvputs(job, "1.");
+    gvputs(job, ";\"/>\n");
     if (obj->gradient_frac > 0)
        gvprintf(job, "<stop offset=\"%.03f\" style=\"stop-color:", obj->gradient_frac);
     else
-       GVPUTS(job, "<stop offset=\"1\" style=\"stop-color:");
+       gvputs(job, "<stop offset=\"1\" style=\"stop-color:");
     svg_print_color(job, obj->stopcolor);
-    GVPUTS(job, ";stop-opacity:");
+    gvputs(job, ";stop-opacity:");
     if (obj->stopcolor.type == RGBA_BYTE && obj->stopcolor.u.rgba[3] > 0
        && obj->stopcolor.u.rgba[3] < 255)
        gvprintf(job, "%f", ((float) obj->stopcolor.u.rgba[3] / 255.0));
     else
-       GVPUTS(job, "1.");
-    GVPUTS(job, ";\"/>\n</linearGradient>\n</defs>\n");
+       gvputs(job, "1.");
+    gvputs(job, ";\"/>\n</linearGradient>\n</defs>\n");
     return id;
 }
 
@@ -560,24 +557,24 @@ static int svg_rgradstyle(GVJ_t * job)
             "<defs>\n<radialGradient id=\"r_%d\" cx=\"50%%\" cy=\"50%%\" r=\"75%%\" "
             "fx=\"%.0f%%\" fy=\"%.0f%%\">\n",
             id, ifx, ify);
-    GVPUTS(job, "<stop offset=\"0\" style=\"stop-color:");
+    gvputs(job, "<stop offset=\"0\" style=\"stop-color:");
     svg_print_color(job, obj->fillcolor);
-    GVPUTS(job, ";stop-opacity:");
+    gvputs(job, ";stop-opacity:");
     if (obj->fillcolor.type == RGBA_BYTE && obj->fillcolor.u.rgba[3] > 0
        && obj->fillcolor.u.rgba[3] < 255)
        gvprintf(job, "%f", ((float) obj->fillcolor.u.rgba[3] / 255.0));
     else
-       GVPUTS(job, "1.");
-    GVPUTS(job, ";\"/>\n"
+       gvputs(job, "1.");
+    gvputs(job, ";\"/>\n"
                 "<stop offset=\"1\" style=\"stop-color:");
     svg_print_color(job, obj->stopcolor);
-    GVPUTS(job, ";stop-opacity:");
+    gvputs(job, ";stop-opacity:");
     if (obj->stopcolor.type == RGBA_BYTE && obj->stopcolor.u.rgba[3] > 0
        && obj->stopcolor.u.rgba[3] < 255)
        gvprintf(job, "%f", ((float) obj->stopcolor.u.rgba[3] / 255.0));
     else
-       GVPUTS(job, "1.");
-    GVPUTS(job, ";\"/>\n</radialGradient>\n</defs>\n");
+       gvputs(job, "1.");
+    gvputs(job, ";\"/>\n</radialGradient>\n</defs>\n");
     return id;
 }
 
@@ -592,17 +589,17 @@ static void svg_ellipse(GVJ_t * job, pointf * A, int filled)
     } else if (filled == (RGRADIENT)) {
        gid = svg_rgradstyle(job);
     }
-    GVPUTS(job, "<ellipse");
+    gvputs(job, "<ellipse");
     svg_grstyle(job, filled, gid);
-    GVPUTS(job, " cx=\"");
+    gvputs(job, " cx=\"");
     gvprintdouble(job, A[0].x);
-    GVPUTS(job, "\" cy=\"");
+    gvputs(job, "\" cy=\"");
     gvprintdouble(job, -A[0].y);
-    GVPUTS(job, "\" rx=\"");
+    gvputs(job, "\" rx=\"");
     gvprintdouble(job, A[1].x - A[0].x);
-    GVPUTS(job, "\" ry=\"");
+    gvputs(job, "\" ry=\"");
     gvprintdouble(job, A[1].y - A[0].y);
-    GVPUTS(job, "\"/>\n");
+    gvputs(job, "\"/>\n");
 }
 
 static void
@@ -620,16 +617,16 @@ svg_bezier(GVJ_t * job, pointf * A, int n, int arrow_at_start,
     } else if (filled == (RGRADIENT)) {
        gid = svg_rgradstyle(job);
     }
-    GVPUTS(job, "<path");
+    gvputs(job, "<path");
     if (obj->labeledgealigned) {
-       GVPUTS(job, " id=\"");
+       gvputs(job, " id=\"");
        gvputs_xml(job, obj->id);
-       GVPUTS(job, "_p\" ");
+       gvputs(job, "_p\" ");
     } 
     svg_grstyle(job, filled, gid);
-    GVPUTS(job, " d=\"");
+    gvputs(job, " d=\"");
     svg_bzptarray(job, A, n);
-    GVPUTS(job, "\"/>\n");
+    gvputs(job, "\"/>\n");
 }
 
 static void svg_polygon(GVJ_t * job, pointf * A, int n, int filled)
@@ -640,36 +637,36 @@ static void svg_polygon(GVJ_t * job, pointf * A, int n, int filled)
     } else if (filled == (RGRADIENT)) {
        gid = svg_rgradstyle(job);
     }
-    GVPUTS(job, "<polygon");
+    gvputs(job, "<polygon");
     svg_grstyle(job, filled, gid);
-    GVPUTS(job, " points=\"");
+    gvputs(job, " points=\"");
     for (i = 0; i < n; i++) {
         gvprintdouble(job, A[i].x);
-        GVPUTS(job, ",");
+        gvputc(job, ',');
         gvprintdouble(job, -A[i].y);
-        GVPUTS(job, " ");
+        gvputc(job, ' ');
     }
     /* repeat the first point because Adobe SVG is broken */
     gvprintdouble(job, A[0].x);
-    GVPUTS(job, ",");
+    gvputc(job, ',');
     gvprintdouble(job, -A[0].y);
-    GVPUTS(job, "\"/>\n");
+    gvputs(job, "\"/>\n");
 }
 
 static void svg_polyline(GVJ_t * job, pointf * A, int n)
 {
     int i;
 
-    GVPUTS(job, "<polyline");
+    gvputs(job, "<polyline");
     svg_grstyle(job, 0, 0);
-    GVPUTS(job, " points=\"");
+    gvputs(job, " points=\"");
     for (i = 0; i < n; i++) {
         gvprintdouble(job, A[i].x);
-        GVPUTS(job, ",");
+        gvputc(job, ',');
         gvprintdouble(job, -A[i].y);
-        GVPUTS(job, " ");
+        gvputc(job, ' ');
     }
-    GVPUTS(job, "\"/>\n");
+    gvputs(job, "\"/>\n");
 }
 
 /* color names from http://www.w3.org/TR/SVG/types.html */