]> granicus.if.org Git - graphviz/commitdiff
Revert "API BREAK: change 'Agiodisc_t' output function from puts-alike to printf...
authorMatthew Fernandez <matthew.fernandez@gmail.com>
Sat, 4 Jun 2022 15:27:27 +0000 (08:27 -0700)
committerMatthew Fernandez <matthew.fernandez@gmail.com>
Sun, 5 Jun 2022 18:28:25 +0000 (11:28 -0700)
This reverts commit 4915673bd8826641c4227bb6e32e1d759f3b1df5. This also adds a
changelog entry for this.

Commit 4915673bd8826641c4227bb6e32e1d759f3b1df5 introduced a bug where
`gvprintf` was cast and stored into an incompatible pointer type, one returning
an `int` instead of `void`. On platforms like x86-64, this coincidentally works
out with no ill effects. But on platforms like Web Assembly this prevents using
plugins containing this code.

CHANGELOG.md
cmd/gvpr/gvprmain.c
lib/cgraph/cgraph.3
lib/cgraph/cgraph.h
lib/cgraph/io.c
lib/cgraph/write.c
lib/common/output.c
lib/gvpr/compile.c
plugin/core/gvrender_core_dot.c
plugin/core/gvrender_core_json.c
tclpkg/tcldot/tcldot.c

index f38cc8ff573c31152696887fafb9d5d3b29736df..4f1a127a2936da16792401a2a700a8691af83ab0 100644 (file)
@@ -6,6 +6,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ## [Unreleased (4.0.1)]
 
+### Fixed
+
+- **Breaking**: The 4.0.0 change replacing the `Agiodisc_t` struct member
+  `putstr` by `printf` has been reverted
+
 ## [4.0.0] – 2022-05-29
 
 ### Changed
index 188cfdf940e67bc0a6cf1a8e432de9700e439705..92872f8cd8d2c29b535f48fe116345a08229109b 100644 (file)
@@ -47,14 +47,17 @@ static int iofread(void *chan, char *buf, int bufsize)
   return (int)fread(buf, 1, (size_t)bufsize, chan);
 }
 
+static int ioputstr(void *chan, const char *str)
+{
+  return fputs(str, chan);
+}
+
 static int ioflush(void *chan)
 {
   return fflush(chan);
 }
 
-typedef int (*printfn)(void *chan, const char *format, ...);
-
-static Agiodisc_t gprIoDisc = { iofread, (printfn)fprintf, ioflush };
+static Agiodisc_t gprIoDisc = { iofread, ioputstr, ioflush };
 
 static Agdisc_t gprDisc = { &AgMemDisc, &AgIdDisc, &gprIoDisc };
 
index ed7392c0665dd325a96d1bf9aa6a8e77f3d69c90..67e35c2e9c59d69fa81e54d1c8babb7074f6d8a3 100644 (file)
@@ -487,14 +487,14 @@ The I/O discipline provides an abstraction for the reading and writing of graphs
 .P0
 struct Agiodisc_s {
     int        (*fread)(void *chan, char *buf, int bufsize);
-    int        (*printf)(void *chan, const char *format, ...);
+    int        (*putstr)(void *chan, char *str);
     int        (*flush)(void *chan);    /* sync */
 } ;
 .P1
 Normally, the \fBFILE\fP structure and its related functions are used for I/O. At times, though,
 an application may need to use a totally different type of character source. The associated
 state or stream information is provided by the \fIchan\fP argument to \fBagread\fP or \fBagwrite\fP.
-The discipline function \fIfread\fP and \fIprintf\fP provide the corresponding functions for
+The discipline function \fIfread\fP and \fIputstr\fP provide the corresponding functions for
 read and writing.
 
 .SH "MEMORY DISCIPLINE"
index 7b005c44246571eaeb75216b8f4d7c9bea792a82..cbec3bbe6074ba68962c615da481c5a40c78edf8 100644 (file)
@@ -169,7 +169,7 @@ struct Agiddisc_s {         /* object ID allocator */
 
 struct Agiodisc_s {
     int (*afread) (void *chan, char *buf, int bufsize);
-    int (*printf)(void *chan, const char *format, ...);
+    int (*putstr) (void *chan, const char *str);
     int (*flush) (void *chan); /* sync */
     /* error messages? */
 };
index d8b136804b7f2b3f9fbc502867b016d952c9aa7d..66c605ae685681b86e62a3352bf94eebf8b54e8f 100644 (file)
@@ -24,15 +24,17 @@ static int iofread(void *chan, char *buf, int bufsize)
 }
 
 /* default IO methods */
+static int ioputstr(void *chan, const char *str)
+{
+    return fputs(str, chan);
+}
 
 static int ioflush(void *chan)
 {
     return fflush(chan);
 }
 
-typedef int (*printfn)(void *chan, const char *format, ...);
-
-Agiodisc_t AgIoDisc = { iofread, (printfn)fprintf, ioflush };
+Agiodisc_t AgIoDisc = { iofread, ioputstr, ioflush };
 
 typedef struct {
     const char *data;
@@ -78,7 +80,7 @@ static Agraph_t *agmemread0(Agraph_t *arg_g, const char *cp)
     rdr_t rdr;
     Agdisc_t disc;
 
-    memIoDisc.printf = AgIoDisc.printf;
+    memIoDisc.putstr = AgIoDisc.putstr;
     memIoDisc.flush = AgIoDisc.flush;
     rdr.data = cp;
     rdr.len = strlen(cp);
index e14f7d8356c1584f472757cc953f5d5a121c1766..9e72d2c5c38f83f697b08490749f88398a0b23b3 100644 (file)
@@ -26,7 +26,7 @@ typedef void iochan_t;
 
 static int ioput(Agraph_t * g, iochan_t * ofile, char *str)
 {
-    return AGDISC(g, io)->printf(ofile, "%s", str);
+    return AGDISC(g, io)->putstr(ofile, str);
 
 }
 
index c91dfe41e77647bbc72169344e7775436f6e8704..648409c5a4d09f1138cadacf0e7769e4036fdc21 100644 (file)
@@ -26,15 +26,17 @@ double yDir (double y)
     return YDIR(y);
 }
 
-static int (*print)(void *chan, const char *format, ...);
+static int (*putstr) (void *chan, const char *str);
 
 static void agputs (const char* s, FILE* fp)
 {
-  print(fp, "%s", s);
+    putstr ((void*)fp, s);
 }
 static void agputc (int c, FILE* fp)
 {
-  print(fp, "%c", (char)c);
+    static char buf[2] = {'\0','\0'};
+    buf[0] = c;
+    putstr ((void*)fp, buf);
 }
 
 
@@ -117,7 +119,7 @@ void write_plain(GVJ_t *job, graph_t *g, FILE *f, bool extend) {
     char *lbl;
     char* fillcolor;
 
-    print = g->clos->disc.io->printf;
+    putstr = g->clos->disc.io->putstr;
 //    setup_graph(job, g);
     setYInvert(g);
     pt = GD_bb(g).UR;
index a7fe27bf51ef85acc73820b5e3707f7437e26bac..3704f51d9ec03dcb823aa85fc9fda6dbc590b6fb 100644 (file)
@@ -66,14 +66,17 @@ static int iofread(void *chan, char *buf, int bufsize)
     return (int)read(sffileno(chan), buf, bufsize);
 }
 
+static int ioputstr(void *chan, const char *str)
+{
+    return sfputr(chan, str, -1);
+}
+
 static int ioflush(void *chan)
 {
     return sfsync(chan);
 }
 
-typedef int (*printfn)(void *chan, const char *format, ...);
-
-static Agiodisc_t gprIoDisc = { iofread, (printfn)sfprintf, ioflush };
+static Agiodisc_t gprIoDisc = { iofread, ioputstr, ioflush };
 
 #ifdef GVDLL
 static Agdisc_t gprDisc = { 0, 0, &gprIoDisc };
index c45563460272803e51192ccb38b0024db2f03984..63eb5e5352064aae71f7ef9afc040ed60d42ad77 100644 (file)
@@ -511,7 +511,7 @@ static void xdot_end_graph(graph_t* g)
     textflags[EMIT_GLABEL] = 0;
 }
 
-typedef int (*printfn)(void *chan, const char *format, ...);
+typedef int (*putstrfn) (void *chan, const char *str);
 typedef int (*flushfn) (void *chan);
 static void dot_end_graph(GVJ_t *job)
 {
@@ -521,7 +521,7 @@ static void dot_end_graph(GVJ_t *job)
 
     if (io.afread == NULL) {
        io.afread = AgIoDisc.afread;
-       io.printf = (printfn)gvprintf;
+       io.putstr = (putstrfn)gvputs;
        io.flush = (flushfn)gvflush;
     }
 
index bab5d64afc6c6fae2ed805b96d086bacd3d3577c..88715a93a2c0cf5fe0ced8d37bf58df2fab858b9 100644 (file)
@@ -693,7 +693,7 @@ static void write_graph(Agraph_t * g, GVJ_t * job, int top, state_t* sp)
        gvputs(job, "}");
 }
 
-typedef int (*printfn)(void *chan, const char *format, ...);
+typedef int (*putstrfn) (void *chan, const char *str);
 typedef int (*flushfn) (void *chan);
 
 static void json_end_graph(GVJ_t *job)
@@ -704,7 +704,7 @@ static void json_end_graph(GVJ_t *job)
 
     if (io.afread == NULL) {
        io.afread = AgIoDisc.afread;
-       io.printf = (printfn)gvprintf;
+       io.putstr = (putstrfn)gvputs;
        io.flush = (flushfn)gvflush;
     }
 
index 335d8e4697ddec3d16bcfab2c149bd4635d35ee1..b747124cf1e78363251e823f95afd83f86fe25b3 100644 (file)
@@ -163,7 +163,7 @@ int Tcldot_Init(Tcl_Interp * interp)
     /* build disciplines dynamically so we can selectively replace functions */
 
     ictx->myioDisc.afread = NULL;            /* set in dotread() or dotstring() according to need */
-    ictx->myioDisc.printf = AgIoDisc.printf; /* no change */
+    ictx->myioDisc.putstr = AgIoDisc.putstr; /* no change */
     ictx->myioDisc.flush = AgIoDisc.flush;   /* no change */
 
     ictx->mydisc.mem = &AgMemDisc;           /* no change */