# HG changeset patch
# User Pantxo Diribarne <pantxo.diribarne@gmail.com>
# Date 1451811691 -3600
#      Sun Jan 03 10:01:31 2016 +0100
# Node ID 87387cfa0a6133bdbe2115264817701a0f660279
# Parent  d9f4e4961e09909955c939f7d09298d0faf64b10
Fix overflowing feedback buffers (bug #46417)

* gl2ps-renderer.h (glps_renderer::draw_axes): handle errors, warnings 
    and overflows after gl2psEndViewport.
* gl2ps-renderer.h (glps_renderer::buffer_overflow): new bool attribute.
* gl2ps-renderer.cc (glps_renderer::draw): make use of buffer_overflow to 
    detect overflows and increase buffer size by a factor of 2 instead of a 
    fixed amount of 1Mb.
* gl2ps-renderer.cc (glps_renderer::draw): pass a temporary file to gl2ps and
    copy its content to the actual pipe/file stream after successfull run
* gl2ps-renderer.cc (glps_renderer::draw): remove error checking after 
    gl2psEndPage
* bootstrap.conf: add gnulib "ftruncate", necessary to discard content of 
    the temporary file

diff -r d9f4e4961e09 -r 87387cfa0a61 bootstrap.conf
--- a/bootstrap.conf	Wed Dec 30 09:46:05 2015 +0100
+++ b/bootstrap.conf	Sun Jan 03 10:01:31 2016 +0100
@@ -47,6 +47,7 @@
   frexpf
   fseek
   ftell
+  ftruncate
   getcwd
   gethostname
   getopt-gnu
diff -r d9f4e4961e09 -r 87387cfa0a61 libinterp/corefcn/gl2ps-renderer.cc
--- a/libinterp/corefcn/gl2ps-renderer.cc	Wed Dec 30 09:46:05 2015 +0100
+++ b/libinterp/corefcn/gl2ps-renderer.cc	Sun Jan 03 10:01:31 2016 +0100
@@ -38,6 +38,7 @@
 
 #include "gl2ps.h"
 #include "sysdep.h"
+#include "unistd.h"
 
 void
 glps_renderer::draw (const graphics_object& go, const std::string& print_cmd)
@@ -80,11 +81,22 @@
       if (term.find ("is2D") != std::string::npos)
         gl2ps_sort = GL2PS_SIMPLE_SORT;
 
-      GLint state = GL2PS_OVERFLOW;
-      GLint buffsize = 0;
+      // Use a temporary file in case an overflow happens
+      FILE* tmpf = gnulib::tmpfile ();
 
-      while (state == GL2PS_OVERFLOW)
+      if (! tmpf)
+        error ("glps_renderer::draw: couldn't open temporary file for printing");
+
+      GLint buffsize = 2*1024*1024;
+      buffer_overflow = true;
+
+      while (buffer_overflow)
         {
+          buffer_overflow = false;
+          buffsize *= 2;
+          gnulib::fseek (tmpf, 0, SEEK_SET);
+          gnulib::ftruncate (fileno (tmpf), 0);
+
           // For LaTeX output the fltk print process uses 2 drawnow() commands.
           // The first one is for the pdf/ps/eps graph to be included.  The
           // print_cmd is saved as old_print_cmd.  Then the second drawnow()
@@ -111,8 +123,6 @@
           else
             include_graph = "foobar-inc";
 
-          buffsize += 1024*1024;
-
           // GL2PS_SILENT was removed to allow gl2ps printing errors on stderr
           GLint ret = gl2psBeginPage ("glps_renderer figure", "Octave", 0,
                                       gl2ps_term, gl2ps_sort,
@@ -123,31 +133,33 @@
                                        | GL2PS_NO_PS3_SHADING
                                        | GL2PS_USE_CURRENT_VIEWPORT),
                                       GL_RGBA, 0, 0, 0, 0, 0,
-                                      buffsize, fp, include_graph.c_str ());
+                                      buffsize, tmpf, include_graph.c_str ());
           if (ret == GL2PS_ERROR)
             {
               old_print_cmd.clear ();
               error ("gl2ps-renderer::draw: gl2psBeginPage returned GL2PS_ERROR");
             }
 
-          old_print_cmd = print_cmd;
-
           opengl_renderer::draw (go);
 
-          // Without glFinish () there may be primitives missing in the
-          // gl2ps output.
-          glFinish ();
+          if (! buffer_overflow)
+            old_print_cmd = print_cmd;
 
-          state = gl2psEndPage ();
+          // Don't check return value of gl2psEndPage, it is not meaningful.
+          // Errors and warnings are checked after gl2psEndViewport in 
+          // glps_renderer::draw_axes instead.
+          gl2psEndPage ();
+        }
 
-          if (state == GL2PS_ERROR)
-            {
-              old_print_cmd.clear ();
-              error ("gl2ps-renderer::draw: gl2psEndPage returned GL2PS_ERROR");
-            }
-
-          // Don't check state for GL2PS_UNINITIALIZED (should never happen)
-          // GL2PS_OVERFLOW (see while loop) or GL2PS_SUCCESS
+      // Copy temporary file to  pipe
+      gnulib::fseek (tmpf, 0, SEEK_SET);
+      char str[256];
+      int nread = 1;
+      while (! feof (tmpf) && nread)
+        {
+          nread = gnulib::fread (str, 1, 256, tmpf);
+          if (nread)
+            gnulib::fwrite (str, 1, nread, fp);
         }
     }
   else
diff -r d9f4e4961e09 -r 87387cfa0a61 libinterp/corefcn/gl2ps-renderer.h
--- a/libinterp/corefcn/gl2ps-renderer.h	Wed Dec 30 09:46:05 2015 +0100
+++ b/libinterp/corefcn/gl2ps-renderer.h	Sun Jan 03 10:01:31 2016 +0100
@@ -37,7 +37,7 @@
 public:
   glps_renderer (FILE *_fp, const std::string& _term)
     : opengl_renderer () , fp (_fp), term (_term), fontsize (),
-    fontname () { }
+    fontname (), buffer_overflow (false) { }
 
   ~glps_renderer (void) { }
 
@@ -66,7 +66,11 @@
     // Finalize viewport
     GLint state = gl2psEndViewport ();
     if (state == GL2PS_NO_FEEDBACK)
-      warning ("gl2ps-renderer::draw: empty feedback buffer and/or nothing else to print");
+      warning ("gl2ps-renderer::draw_axes: empty feedback buffer and/or nothing else to print");
+    else if (state == GL2PS_ERROR)
+      error ("gl2ps-renderer::draw_axes: gl2psEndPage returned GL2PS_ERROR");
+    
+    buffer_overflow |= (state == GL2PS_OVERFLOW);
   }
 
   void draw_text (const text::properties& props);
@@ -115,6 +119,7 @@
   caseless_str term;
   double fontsize;
   std::string fontname;
+  bool buffer_overflow;
 };
 
 #endif
