[PATCH 8/9] reports: don't escape the labels

Akim Demaille <[email protected]>
Newsgroups gmane.comp.parsers.bison.patches
Message-ID <[email protected]>
Currently we use "quotearg" to escape the strings output in Dot.  As a
result, if the user's locale is C for instance, all the non-ASCII are
escaped.  Unfortunately graphviz does not interpret this style of
escaping.

For instance:

    5 -> 2 [style=solid label="\"\303\221\303\271\341\271\203\303\251\342\204\235\303\264\""]

was displayed as a sequence of numbers.  We now output:

    5 -> 2 [style=solid label="\"Ñùṃéℝô\""]

independently of the user's locale.

* src/system.h (obstack_backslash): New.
* src/graphviz.h, src/graphviz.c (escape): Remove, use
obstack_backslash instead.
* src/print-graph.c: Likewise.
* tests/report.at: Adjust.
---
 src/graphviz.c    | 22 ++++++++++++----------
 src/graphviz.h    |  6 ------
 src/print-graph.c | 19 ++++++++++++++-----
 src/system.h      | 17 +++++++++++++++++
 tests/report.at   | 32 ++++++++++++++++----------------
 5 files changed, 59 insertions(+), 37 deletions(-)

diff --git a/src/graphviz.c b/src/graphviz.c
index 80a2ff99..34d80b03 100644
--- a/src/graphviz.c
+++ b/src/graphviz.c
@@ -72,18 +72,20 @@ output_edge (int source, int destination, char const *label,
 {
   fprintf (fout, "  %d -> %d [style=%s", source, destination, style);
   if (label)
-    fprintf (fout, " label=%s", quote (label));
+    {
+      fputs (" label=\"", fout);
+      for (const char *cp = label; *cp; ++cp)
+        switch (*cp)
+        {
+        case '"':  fputs ("\\\"", fout); break;
+        case '\\': fputs ("\\\\", fout); break;
+        default:   fputc (*cp,    fout); break;
+        }
+      fputc ('"', fout);
+    }
   fputs ("]\n", fout);
 }
 
-char const *
-escape (char const *name)
-{
-  char *q = quote (name);
-  q[strlen (q) - 1] = '\0';
-  return q + 1;
-}
-
 static void
 no_reduce_bitset_init (state const *s, bitset *no_reduce_set)
 {
@@ -149,7 +151,7 @@ print_token (struct obstack *out, bool first, char const *tok)
 {
   if (! first)
     obstack_sgrow (out, ", ");
-  obstack_sgrow (out, escape (tok));
+  obstack_backslash (out, tok);
   return false;
 }
 
diff --git a/src/graphviz.h b/src/graphviz.h
index 06b42358..ead22ffd 100644
--- a/src/graphviz.h
+++ b/src/graphviz.h
@@ -63,10 +63,4 @@ void output_red (state const *s, reductions const *reds, FILE *fout);
  */
 void finish_graph (FILE *fout);
 
-/** Escape a lookahead token.
- *
- * \param name         the token.
- */
-char const *escape (char const *name);
-
 #endif /* ! GRAPHVIZ_H_ */
diff --git a/src/print-graph.c b/src/print-graph.c
index 5691c6d8..adaa8bed 100644
--- a/src/print-graph.c
+++ b/src/print-graph.c
@@ -72,19 +72,28 @@ print_core (struct obstack *oout, state *s)
         obstack_printf (oout, "%*s| ",
                         (int) strlen (previous_lhs->symbol->tag), "");
       else
-        obstack_printf (oout, "%s: ", escape (r->lhs->symbol->tag));
+        {
+          obstack_backslash (oout, r->lhs->symbol->tag);
+          obstack_printf (oout, ": ");
+        }
       previous_lhs = r->lhs;
 
       for (item_number const *sp = r->rhs; sp < sp1; sp++)
-        obstack_printf (oout, "%s ", escape (symbols[*sp]->tag));
+        {
+          obstack_backslash (oout, symbols[*sp]->tag);
+          obstack_1grow (oout, ' ');
+        }
 
       obstack_1grow (oout, '.');
 
       if (0 <= *r->rhs)
         for (item_number const *sp = sp1; 0 <= *sp; ++sp)
-          obstack_printf (oout, " %s", escape (symbols[*sp]->tag));
+          {
+            obstack_1grow (oout, ' ');
+            obstack_backslash (oout, symbols[*sp]->tag);
+          }
       else
-        obstack_printf (oout, " %%empty");
+        obstack_sgrow (oout, " %empty");
 
       /* Experimental feature: display the lookahead tokens. */
       if (report_flag & report_lookahead_tokens
@@ -104,7 +113,7 @@ print_core (struct obstack *oout, state *s)
               BITSET_FOR_EACH (biter, reds->lookahead_tokens[redno], k, 0)
                 {
                   obstack_sgrow (oout, sep);
-                  obstack_sgrow (oout, escape (symbols[k]->tag));
+                  obstack_backslash (oout, symbols[k]->tag);
                   sep = ", ";
                 }
               obstack_1grow (oout, ']');
diff --git a/src/system.h b/src/system.h
index 33986069..eac89c27 100644
--- a/src/system.h
+++ b/src/system.h
@@ -171,6 +171,23 @@ typedef size_t uintptr_t;
 # define obstack_sgrow(Obs, Str) \
   obstack_grow (Obs, Str, strlen (Str))
 
+/* Output Str escaped to be a string.
+
+   For instance "\"foo\"" -> "\\\"foo\\\"".  */
+
+# define obstack_backslash(Obs, Str)                    \
+  do {                                                  \
+    char const *p__;                                    \
+    for (p__ = Str; *p__; p__++)                        \
+      switch (*p__)                                     \
+        {                                               \
+        case '"':  obstack_sgrow (Obs, "\\\""); break;  \
+        case '\\': obstack_sgrow (Obs, "\\\\"); break;  \
+        default:   obstack_1grow (Obs, *p__);   break;  \
+        }                                               \
+  } while (0)
+
+
 /* Output Str escaped for our postprocessing (i.e., escape M4 special
    characters).
 
diff --git a/tests/report.at b/tests/report.at
index c83d1704..27d4e7b8 100644
--- a/tests/report.at
+++ b/tests/report.at
@@ -1338,43 +1338,43 @@ digraph "input.y"
   node [fontname = courier, shape = box, colorscheme = paired6]
   edge [fontname = courier]
 
-  0 [label="State 0\n\l  0 $accept: . exp $end\l  1 exp: . exp \"\342\212\225\" exp\l  2    | . exp \"+\" exp\l  3    | . exp \"+\" exp\l  4    | . \"number\"\l  5    | . \"\303\221\303\271\341\271\203\303\251\342\204\235\303\264\"\l"]
+  0 [label="State 0\n\l  0 $accept: . exp $end\l  1 exp: . exp \"⊕\" exp\l  2    | . exp \"+\" exp\l  3    | . exp \"+\" exp\l  4    | . \"number\"\l  5    | . \"Ñùṃéℝô\"\l"]
   0 -> 1 [style=solid label="\"number\""]
-  0 -> 2 [style=solid label="\"\303\221\303\271\341\271\203\303\251\342\204\235\303\264\""]
+  0 -> 2 [style=solid label="\"Ñùṃéℝô\""]
   0 -> 3 [style=dashed label="exp"]
   1 [label="State 1\n\l  4 exp: \"number\" .\l"]
   1 -> "1R4" [style=solid]
  "1R4" [label="R4", fillcolor=3, shape=diamond, style=filled]
-  2 [label="State 2\n\l  5 exp: \"\303\221\303\271\341\271\203\303\251\342\204\235\303\264\" .\l"]
+  2 [label="State 2\n\l  5 exp: \"Ñùṃéℝô\" .\l"]
   2 -> "2R5" [style=solid]
  "2R5" [label="R5", fillcolor=3, shape=diamond, style=filled]
-  3 [label="State 3\n\l  0 $accept: exp . $end\l  1 exp: exp . \"\342\212\225\" exp\l  2    | exp . \"+\" exp\l  3    | exp . \"+\" exp\l"]
+  3 [label="State 3\n\l  0 $accept: exp . $end\l  1 exp: exp . \"⊕\" exp\l  2    | exp . \"+\" exp\l  3    | exp . \"+\" exp\l"]
   3 -> 4 [style=solid label="$end"]
   3 -> 5 [style=solid label="\"+\""]
-  3 -> 6 [style=solid label="\"\342\212\225\""]
+  3 -> 6 [style=solid label="\"⊕\""]
   4 [label="State 4\n\l  0 $accept: exp $end .\l"]
   4 -> "4R0" [style=solid]
  "4R0" [label="Acc", fillcolor=1, shape=diamond, style=filled]
-  5 [label="State 5\n\l  1 exp: . exp \"\342\212\225\" exp\l  2    | . exp \"+\" exp\l  2    | exp \"+\" . exp\l  3    | . exp \"+\" exp\l  3    | exp \"+\" . exp\l  4    | . \"number\"\l  5    | . \"\303\221\303\271\341\271\203\303\251\342\204\235\303\264\"\l"]
+  5 [label="State 5\n\l  1 exp: . exp \"⊕\" exp\l  2    | . exp \"+\" exp\l  2    | exp \"+\" . exp\l  3    | . exp \"+\" exp\l  3    | exp \"+\" . exp\l  4    | . \"number\"\l  5    | . \"Ñùṃéℝô\"\l"]
   5 -> 1 [style=solid label="\"number\""]
-  5 -> 2 [style=solid label="\"\303\221\303\271\341\271\203\303\251\342\204\235\303\264\""]
+  5 -> 2 [style=solid label="\"Ñùṃéℝô\""]
   5 -> 7 [style=dashed label="exp"]
-  6 [label="State 6\n\l  1 exp: . exp \"\342\212\225\" exp\l  1    | exp \"\342\212\225\" . exp\l  2    | . exp \"+\" exp\l  3    | . exp \"+\" exp\l  4    | . \"number\"\l  5    | . \"\303\221\303\271\341\271\203\303\251\342\204\235\303\264\"\l"]
+  6 [label="State 6\n\l  1 exp: . exp \"⊕\" exp\l  1    | exp \"⊕\" . exp\l  2    | . exp \"+\" exp\l  3    | . exp \"+\" exp\l  4    | . \"number\"\l  5    | . \"Ñùṃéℝô\"\l"]
   6 -> 1 [style=solid label="\"number\""]
-  6 -> 2 [style=solid label="\"\303\221\303\271\341\271\203\303\251\342\204\235\303\264\""]
+  6 -> 2 [style=solid label="\"Ñùṃéℝô\""]
   6 -> 8 [style=dashed label="exp"]
-  7 [label="State 7\n\l  1 exp: exp . \"\342\212\225\" exp\l  2    | exp . \"+\" exp\l  2    | exp \"+\" exp .  [$end, \"+\", \"\342\212\225\"]\l  3    | exp . \"+\" exp\l  3    | exp \"+\" exp .  [$end, \"+\", \"\342\212\225\"]\l"]
-  7 -> 6 [style=solid label="\"\342\212\225\""]
-  7 -> "7R2d" [label="[\"\342\212\225\"]", style=solid]
+  7 [label="State 7\n\l  1 exp: exp . \"⊕\" exp\l  2    | exp . \"+\" exp\l  2    | exp \"+\" exp .  [$end, \"+\", \"⊕\"]\l  3    | exp . \"+\" exp\l  3    | exp \"+\" exp .  [$end, \"+\", \"⊕\"]\l"]
+  7 -> 6 [style=solid label="\"⊕\""]
+  7 -> "7R2d" [label="[\"⊕\"]", style=solid]
  "7R2d" [label="R2", fillcolor=5, shape=diamond, style=filled]
   7 -> "7R2" [style=solid]
  "7R2" [label="R2", fillcolor=3, shape=diamond, style=filled]
-  7 -> "7R3d" [label="[$end, \"+\", \"\342\212\225\"]", style=solid]
+  7 -> "7R3d" [label="[$end, \"+\", \"⊕\"]", style=solid]
  "7R3d" [label="R3", fillcolor=5, shape=diamond, style=filled]
-  8 [label="State 8\n\l  1 exp: exp . \"\342\212\225\" exp\l  1    | exp \"\342\212\225\" exp .  [$end, \"+\", \"\342\212\225\"]\l  2    | exp . \"+\" exp\l  3    | exp . \"+\" exp\l"]
+  8 [label="State 8\n\l  1 exp: exp . \"⊕\" exp\l  1    | exp \"⊕\" exp .  [$end, \"+\", \"⊕\"]\l  2    | exp . \"+\" exp\l  3    | exp . \"+\" exp\l"]
   8 -> 5 [style=solid label="\"+\""]
-  8 -> 6 [style=solid label="\"\342\212\225\""]
-  8 -> "8R1d" [label="[\"+\", \"\342\212\225\"]", style=solid]
+  8 -> 6 [style=solid label="\"⊕\""]
+  8 -> "8R1d" [label="[\"+\", \"⊕\"]", style=solid]
  "8R1d" [label="R1", fillcolor=5, shape=diamond, style=filled]
   8 -> "8R1" [style=solid]
  "8R1" [label="R1", fillcolor=3, shape=diamond, style=filled]
-- 
2.27.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.