This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[RFC] Add possibility to force buffering mode for stdout/stderr


This patch add
setvbuf wrapping inside ui_file structure.

This maintenance feature is 
to allow to test the effect of
changing the buffering mode on the testsuite output.

basically adding
"-ex {maint setvbuf stdout full 1000000}"
or
"-ex {maint setvbuf stdout line 80}"
should allow to test both performance differences
induced by buffering changes and possible regressions
in testsuite results.

This patch is really only of interest to developers
using the testsuite or wanting to investigate
performance issues related to buffering.

I implemented it after the thread about 
forcing the buffering mode for mingw build GDB executables.

The advantage of this patch is that:
- there are no changes in the default behavior
- any executable can be tested, not only mingw builds
like in the other thread.
- it should be a tool to understand the change between
line buffering and no buffering.

 The patch itself is probably not perfect yet
and comments are most welcome.

Pierre Muller


2013-08-21  Pierre Muller  <muller@sourceware.org>

	Implement new 'maintenance setvbuf' command.
	* ui-file.h (ui_file_setvbuf_ftype): New function type prototype.
	(set_ui_file_setvbuf): New function.
	(ui_file_setvbuf): New function.
	* ui-file.c (struct ui_file): Add to_setvbuf field.
	(ui_file_new): Add call to set_ui_file_setvbuf.
	(null_file_setvbuf): Dummy function for non stdio variants.
	(ui_file_fseek):
	(set_ui_file_setvbuf): New function.
	(struct stdio_file): Add buf field.
	(stdio_file_new): Initialize buf field and to_setvbuf.
	(stdio_file_delete): Call xfree on BUF if non NULL.
	(stdio_file_setvbuf): New function call libc setvbuf function.
	* maint.c (maintenance_setvbuf): New function.
	(_initialize_maint_cmds): Register new 'maintenance setvbuf'
command.

Index: ui-file.h
===================================================================
RCS file: /cvs/src/src/gdb/ui-file.h,v
retrieving revision 1.22
diff -u -p -r1.22 ui-file.h
--- ui-file.h	14 May 2013 20:35:24 -0000	1.22
+++ ui-file.h	21 Aug 2013 14:12:51 -0000
@@ -33,6 +33,11 @@ typedef void (ui_file_flush_ftype) (stru
 extern void set_ui_file_flush (struct ui_file *stream,
 			       ui_file_flush_ftype *flush);
 
+typedef int (ui_file_setvbuf_ftype) (struct ui_file *stream, char *buf,
+				     int mode, size_t size);
+extern void set_ui_file_setvbuf (struct ui_file *stream,
+				 ui_file_setvbuf_ftype *setvbuf);
+
 /* NOTE: Both fputs and write methods are available.  Default
    implementations that mapping one onto the other are included.  */
 typedef void (ui_file_write_ftype) (struct ui_file *stream,
@@ -120,6 +125,9 @@ extern long ui_file_read (struct ui_file
 
 extern int ui_file_fseek (struct ui_file *file, long offset, int whence);
 
+extern int ui_file_setvbuf (struct ui_file *file, char *buf,
+			    int mode, size_t size);
+
 /* Create/open a memory based file.  Can be used as a scratch buffer
    for collecting output.  */
 extern struct ui_file *mem_fileopen (void);
Index: ui-file.c
===================================================================
RCS file: /cvs/src/src/gdb/ui-file.c,v
retrieving revision 1.36
diff -u -p -r1.36 ui-file.c
--- ui-file.c	14 May 2013 20:35:24 -0000	1.36
+++ ui-file.c	21 Aug 2013 14:12:51 -0000
@@ -38,6 +38,7 @@ static ui_file_delete_ftype null_file_de
 static ui_file_rewind_ftype null_file_rewind;
 static ui_file_put_ftype null_file_put;
 static ui_file_fseek_ftype null_file_fseek;
+static ui_file_setvbuf_ftype null_file_setvbuf;
 
 struct ui_file
   {
@@ -52,6 +53,7 @@ struct ui_file
     ui_file_rewind_ftype *to_rewind;
     ui_file_put_ftype *to_put;
     ui_file_fseek_ftype *to_fseek;
+    ui_file_setvbuf_ftype * to_setvbuf;
     void *to_data;
   };
 int ui_file_magic;
@@ -64,6 +66,7 @@ ui_file_new (void)
   file->magic = &ui_file_magic;
   set_ui_file_data (file, NULL, null_file_delete);
   set_ui_file_flush (file, null_file_flush);
+  set_ui_file_setvbuf (file, null_file_setvbuf);
   set_ui_file_write (file, null_file_write);
   set_ui_file_write_async_safe (file, null_file_write_async_safe);
   set_ui_file_fputs (file, null_file_fputs);
@@ -108,6 +111,13 @@ null_file_flush (struct ui_file *file)
   return;
 }
 
+static int
+null_file_setvbuf (struct ui_file *file, char *buf, int mode, size_t size)
+{
+  /* Indicates failure as non-zero result.  */
+  return 1;
+}
+
 static void
 null_file_write (struct ui_file *file,
 		 const char *buf,
@@ -245,6 +255,12 @@ ui_file_fseek (struct ui_file *file, lon
   return file->to_fseek (file, offset, whence);
 }
 
+int
+ui_file_setvbuf (struct ui_file *file, char *buf, int mode, int size)
+{
+  return file->to_setvbuf (file, buf, mode, size);
+}
+
 void
 fputs_unfiltered (const char *buf, struct ui_file *file)
 {
@@ -258,6 +274,12 @@ set_ui_file_flush (struct ui_file *file,
 }
 
 void
+set_ui_file_setvbuf (struct ui_file *file, ui_file_setvbuf_ftype
*setvbuf_ptr)
+{
+  file->to_setvbuf = setvbuf_ptr;
+}
+
+void
 set_ui_file_isatty (struct ui_file *file, ui_file_isatty_ftype *isatty_ptr)
 {
   file->to_isatty = isatty_ptr;
@@ -493,6 +515,7 @@ static ui_file_isatty_ftype stdio_file_i
 static ui_file_delete_ftype stdio_file_delete;
 static struct ui_file *stdio_file_new (FILE *file, int close_p);
 static ui_file_flush_ftype stdio_file_flush;
+static ui_file_setvbuf_ftype stdio_file_setvbuf;
 static ui_file_fseek_ftype stdio_file_fseek;
 
 static int stdio_file_magic;
@@ -505,6 +528,9 @@ struct stdio_file
        stdio_file_write_async_safe's benefit, in case fileno isn't
async-safe.  */
     int fd;
     int close_p;
+    /* The buf that might have been assigned using to_setvbuf call.
+       This buffer should be allocated using xmalloc.  */
+    char *buf;
   };
 
 static struct ui_file *
@@ -517,8 +543,10 @@ stdio_file_new (FILE *file, int close_p)
   stdio->file = file;
   stdio->fd = fileno (file);
   stdio->close_p = close_p;
+  stdio->buf = NULL;
   set_ui_file_data (ui_file, stdio, stdio_file_delete);
   set_ui_file_flush (ui_file, stdio_file_flush);
+  set_ui_file_setvbuf (ui_file, stdio_file_setvbuf);
   set_ui_file_write (ui_file, stdio_file_write);
   set_ui_file_write_async_safe (ui_file, stdio_file_write_async_safe);
   set_ui_file_fputs (ui_file, stdio_file_fputs);
@@ -540,6 +568,8 @@ stdio_file_delete (struct ui_file *file)
     {
       fclose (stdio->file);
     }
+  if (stdio->buf)
+    xfree (stdio->buf);
   xfree (stdio);
 }
 
@@ -554,6 +584,25 @@ stdio_file_flush (struct ui_file *file)
   fflush (stdio->file);
 }
 
+static int
+stdio_file_setvbuf (struct ui_file *file, char *buf, int mode, size_t size)
+{
+  int res;
+  struct stdio_file *stdio = ui_file_data (file);
+
+  if (stdio->magic != &stdio_file_magic)
+    internal_error (__FILE__, __LINE__,
+		    _("stdio_file_setvbuf: bad magic number"));
+  res = setvbuf (stdio->file, buf, mode, size);
+  if (res == 0)
+    {
+      if (stdio->buf)
+	xfree (stdio->buf);
+      stdio->buf = buf;
+    }
+  return res;
+}
+
 static long
 stdio_file_read (struct ui_file *file, char *buf, long length_buf)
 {
@@ -577,6 +626,22 @@ stdio_file_read (struct ui_file *file, c
   return read (stdio->fd, buf, length_buf);
 }
 
+/* Force flush if same file descriptor as gdb_stderr.  */
+
+static void
+stdio_maybe_flush (struct ui_file *file)
+{
+  if (gdb_stderr && (gdb_stderr->magic == &ui_file_magic))
+    {
+      struct stdio_file *stderr_stdio = ui_file_data (gdb_stderr);
+      struct stdio_file *stdio = ui_file_data (file);
+
+      if (stderr_stdio->magic == &stdio_file_magic
+	  && stderr_stdio->fd == stdio->fd)
+	file->to_flush (file);
+    }
+}
+
 static void
 stdio_file_write (struct ui_file *file, const char *buf, long length_buf)
 {
@@ -590,6 +655,7 @@ stdio_file_write (struct ui_file *file, 
     {
       /* Nothing.  */
     }
+  stdio_maybe_flush (file);
 }
 
 static void
@@ -614,6 +680,7 @@ stdio_file_write_async_safe (struct ui_f
     {
       /* Nothing.  */
     }
+  stdio_maybe_flush (file);
 }
 
 static void
@@ -629,6 +696,7 @@ stdio_file_fputs (const char *linebuffer
     {
       /* Nothing.  */
     }
+  stdio_maybe_flush (file);
 }
 
 static int
Index: maint.c
===================================================================
RCS file: /cvs/src/src/gdb/maint.c,v
retrieving revision 1.95
diff -u -p -r1.95 maint.c
--- maint.c	8 Apr 2013 20:20:46 -0000	1.95
+++ maint.c	21 Aug 2013 14:12:52 -0000
@@ -55,6 +55,8 @@ static void maintenance_internal_error (
 
 static void maintenance_demangle (char *, int);
 
+static void maintenance_setvbuf (char *, int);
+
 static void maintenance_time_display (char *, int);
 
 static void maintenance_space_display (char *, int);
@@ -165,6 +167,88 @@ maintenance_demangle (char *args, int fr
     }
 }
 
+/* Force standard files to specific bbufferingg mode.  */
+static void
+maintenance_setvbuf (char *args, int from_tty)
+{
+  char *file;
+  char *mode;
+  char *size;
+
+  if (args == NULL || *args == '\0')
+    {
+      printf_unfiltered (_("\"maintenance setvbuf\" takes "
+			   "\"stdout/stderr\" and \"full/line/no\""
+                           " optionally followed by buffer size.\n"));
+    }
+  else
+    {
+      struct ui_file *f = NULL;
+      if (strncmp (args, "stdout ", strlen ("stdout ")) == 0)
+	{
+	  f = gdb_stdout;
+	  args += strlen ("stdout ");
+	}
+      else if (strncmp (args, "stderr ", strlen ("stderr ")) == 0)
+	{
+	  f = gdb_stderr;
+	  args += strlen ("stderr ");
+	}
+
+      if (f == NULL)
+	{
+	  printf_unfiltered (_("\"maintenance setvbuf\" accepts only "
+			       "\"stdout\" or \"stderr\" as first
argument.\n"));
+	}
+      else
+	{
+	  int mode = -1;
+
+	  if (strncmp (args, "full", strlen ("full")) == 0)
+	    {
+	      mode = _IOFBF;
+	      args += strlen ("full");
+	    }
+	  else if (strncmp (args, "line", strlen ("line")) == 0)
+	    {
+	      mode = _IOLBF;
+	      args += strlen ("line");
+	    }
+	  else if (strncmp (args, "no", strlen ("no")) == 0)
+	    {
+	      mode = _IONBF;
+	      args += strlen ("no");
+	    }
+	  if (mode == -1)
+	    {
+	      printf_unfiltered (_("\"maintenance setvbuf\" accepts only "
+				   "\"full\",\"line\" or \"no\" as second"
+				   " argument.\n"));
+	    }
+	  else
+	    {
+	      char *buf = NULL;
+	      ULONGEST size;
+	      int res;
+
+	      if (args && *args != '\0')
+		size = parse_and_eval_long (args);
+	      else
+		size = BUFSIZ;
+	      if (mode != _IONBF)
+		buf = (char *) xmalloc (size);
+	      res = ui_file_setvbuf (f, buf, mode, size);
+	      if (res != 0)
+		{
+		  if (buf)
+		    xfree (buf);
+		  printf_unfiltered (_("Call to setvbuf failed.\n"));
+		}
+	    }
+	}
+    }
+}
+
 static void
 maintenance_time_display (char *args, int from_tty)
 {
@@ -1123,6 +1207,9 @@ Takes an optional file parameter."),
 	   _("Translate a section name and address to a symbol."),
 	   &maintenancelist);
 
+  add_cmd ("setvbuf", class_maintenance, maintenance_setvbuf,
+	   _("Force stdout/stderr buffering mode."), &maintenancelist);
+
   add_cmd ("deprecate", class_maintenance, maintenance_deprecate, _("\
 Deprecate a command.  Note that this is just in here so the \n\
 testsuite can check the command deprecator. You probably shouldn't use
this,\n\z
to GDBFLAGS in site.exp for testsuite runs 


Pierre Muller
GDB pascal language maintainer


2013-08-21  Pierre Muller  <muller@sourceware.org>

	Implement new 'maintenance setvbuf' command.
	* ui-file.h (ui_file_setvbuf_ftype): New function type prototype.
	(set_ui_file_setvbuf): New function.
	(ui_file_setvbuf): New function.
	* ui-file.c (struct ui_file): Add to_setvbuf field.
	(ui_file_new): Add call to set_ui_file_setvbuf.
	(null_file_setvbuf): Dummy function for non stdio variants.
	(ui_file_fseek):
	(set_ui_file_setvbuf): New function.
	(struct stdio_file): Add buf field.
	(stdio_file_new): Initialize buf field and to_setvbuf.
	(stdio_file_delete): Call xfree on BUF if non NULL.
	(stdio_file_setvbuf): New function call libc setvbuf function.
	* maint.c (maintenance_setvbuf): New function.
	(_initialize_maint_cmds): Register new 'maintenance setvbuf'
command.

Index: ui-file.h
===================================================================
RCS file: /cvs/src/src/gdb/ui-file.h,v
retrieving revision 1.22
diff -u -p -r1.22 ui-file.h
--- ui-file.h	14 May 2013 20:35:24 -0000	1.22
+++ ui-file.h	21 Aug 2013 14:12:51 -0000
@@ -33,6 +33,11 @@ typedef void (ui_file_flush_ftype) (stru
 extern void set_ui_file_flush (struct ui_file *stream,
 			       ui_file_flush_ftype *flush);
 
+typedef int (ui_file_setvbuf_ftype) (struct ui_file *stream, char *buf,
+				     int mode, size_t size);
+extern void set_ui_file_setvbuf (struct ui_file *stream,
+				 ui_file_setvbuf_ftype *setvbuf);
+
 /* NOTE: Both fputs and write methods are available.  Default
    implementations that mapping one onto the other are included.  */
 typedef void (ui_file_write_ftype) (struct ui_file *stream,
@@ -120,6 +125,9 @@ extern long ui_file_read (struct ui_file
 
 extern int ui_file_fseek (struct ui_file *file, long offset, int whence);
 
+extern int ui_file_setvbuf (struct ui_file *file, char *buf,
+			    int mode, size_t size);
+
 /* Create/open a memory based file.  Can be used as a scratch buffer
    for collecting output.  */
 extern struct ui_file *mem_fileopen (void);
Index: ui-file.c
===================================================================
RCS file: /cvs/src/src/gdb/ui-file.c,v
retrieving revision 1.36
diff -u -p -r1.36 ui-file.c
--- ui-file.c	14 May 2013 20:35:24 -0000	1.36
+++ ui-file.c	21 Aug 2013 14:12:51 -0000
@@ -38,6 +38,7 @@ static ui_file_delete_ftype null_file_de
 static ui_file_rewind_ftype null_file_rewind;
 static ui_file_put_ftype null_file_put;
 static ui_file_fseek_ftype null_file_fseek;
+static ui_file_setvbuf_ftype null_file_setvbuf;
 
 struct ui_file
   {
@@ -52,6 +53,7 @@ struct ui_file
     ui_file_rewind_ftype *to_rewind;
     ui_file_put_ftype *to_put;
     ui_file_fseek_ftype *to_fseek;
+    ui_file_setvbuf_ftype * to_setvbuf;
     void *to_data;
   };
 int ui_file_magic;
@@ -64,6 +66,7 @@ ui_file_new (void)
   file->magic = &ui_file_magic;
   set_ui_file_data (file, NULL, null_file_delete);
   set_ui_file_flush (file, null_file_flush);
+  set_ui_file_setvbuf (file, null_file_setvbuf);
   set_ui_file_write (file, null_file_write);
   set_ui_file_write_async_safe (file, null_file_write_async_safe);
   set_ui_file_fputs (file, null_file_fputs);
@@ -108,6 +111,13 @@ null_file_flush (struct ui_file *file)
   return;
 }
 
+static int
+null_file_setvbuf (struct ui_file *file, char *buf, int mode, size_t size)
+{
+  /* Indicates failure as non-zero result.  */
+  return 1;
+}
+
 static void
 null_file_write (struct ui_file *file,
 		 const char *buf,
@@ -245,6 +255,12 @@ ui_file_fseek (struct ui_file *file, lon
   return file->to_fseek (file, offset, whence);
 }
 
+int
+ui_file_setvbuf (struct ui_file *file, char *buf, int mode, int size)
+{
+  return file->to_setvbuf (file, buf, mode, size);
+}
+
 void
 fputs_unfiltered (const char *buf, struct ui_file *file)
 {
@@ -258,6 +274,12 @@ set_ui_file_flush (struct ui_file *file,
 }
 
 void
+set_ui_file_setvbuf (struct ui_file *file, ui_file_setvbuf_ftype
*setvbuf_ptr)
+{
+  file->to_setvbuf = setvbuf_ptr;
+}
+
+void
 set_ui_file_isatty (struct ui_file *file, ui_file_isatty_ftype *isatty_ptr)
 {
   file->to_isatty = isatty_ptr;
@@ -493,6 +515,7 @@ static ui_file_isatty_ftype stdio_file_i
 static ui_file_delete_ftype stdio_file_delete;
 static struct ui_file *stdio_file_new (FILE *file, int close_p);
 static ui_file_flush_ftype stdio_file_flush;
+static ui_file_setvbuf_ftype stdio_file_setvbuf;
 static ui_file_fseek_ftype stdio_file_fseek;
 
 static int stdio_file_magic;
@@ -505,6 +528,9 @@ struct stdio_file
        stdio_file_write_async_safe's benefit, in case fileno isn't
async-safe.  */
     int fd;
     int close_p;
+    /* The buf that might have been assigned using to_setvbuf call.
+       This buffer should be allocated using xmalloc.  */
+    char *buf;
   };
 
 static struct ui_file *
@@ -517,8 +543,10 @@ stdio_file_new (FILE *file, int close_p)
   stdio->file = file;
   stdio->fd = fileno (file);
   stdio->close_p = close_p;
+  stdio->buf = NULL;
   set_ui_file_data (ui_file, stdio, stdio_file_delete);
   set_ui_file_flush (ui_file, stdio_file_flush);
+  set_ui_file_setvbuf (ui_file, stdio_file_setvbuf);
   set_ui_file_write (ui_file, stdio_file_write);
   set_ui_file_write_async_safe (ui_file, stdio_file_write_async_safe);
   set_ui_file_fputs (ui_file, stdio_file_fputs);
@@ -540,6 +568,8 @@ stdio_file_delete (struct ui_file *file)
     {
       fclose (stdio->file);
     }
+  if (stdio->buf)
+    xfree (stdio->buf);
   xfree (stdio);
 }
 
@@ -554,6 +584,25 @@ stdio_file_flush (struct ui_file *file)
   fflush (stdio->file);
 }
 
+static int
+stdio_file_setvbuf (struct ui_file *file, char *buf, int mode, size_t size)
+{
+  int res;
+  struct stdio_file *stdio = ui_file_data (file);
+
+  if (stdio->magic != &stdio_file_magic)
+    internal_error (__FILE__, __LINE__,
+		    _("stdio_file_setvbuf: bad magic number"));
+  res = setvbuf (stdio->file, buf, mode, size);
+  if (res == 0)
+    {
+      if (stdio->buf)
+	xfree (stdio->buf);
+      stdio->buf = buf;
+    }
+  return res;
+}
+
 static long
 stdio_file_read (struct ui_file *file, char *buf, long length_buf)
 {
@@ -577,6 +626,22 @@ stdio_file_read (struct ui_file *file, c
   return read (stdio->fd, buf, length_buf);
 }
 
+/* Force flush if same file descriptor as gdb_stderr.  */
+
+static void
+stdio_maybe_flush (struct ui_file *file)
+{
+  if (gdb_stderr && (gdb_stderr->magic == &ui_file_magic))
+    {
+      struct stdio_file *stderr_stdio = ui_file_data (gdb_stderr);
+      struct stdio_file *stdio = ui_file_data (file);
+
+      if (stderr_stdio->magic == &stdio_file_magic
+	  && stderr_stdio->fd == stdio->fd)
+	file->to_flush (file);
+    }
+}
+
 static void
 stdio_file_write (struct ui_file *file, const char *buf, long length_buf)
 {
@@ -590,6 +655,7 @@ stdio_file_write (struct ui_file *file, 
     {
       /* Nothing.  */
     }
+  stdio_maybe_flush (file);
 }
 
 static void
@@ -614,6 +680,7 @@ stdio_file_write_async_safe (struct ui_f
     {
       /* Nothing.  */
     }
+  stdio_maybe_flush (file);
 }
 
 static void
@@ -629,6 +696,7 @@ stdio_file_fputs (const char *linebuffer
     {
       /* Nothing.  */
     }
+  stdio_maybe_flush (file);
 }
 
 static int
Index: maint.c
===================================================================
RCS file: /cvs/src/src/gdb/maint.c,v
retrieving revision 1.95
diff -u -p -r1.95 maint.c
--- maint.c	8 Apr 2013 20:20:46 -0000	1.95
+++ maint.c	21 Aug 2013 14:12:52 -0000
@@ -55,6 +55,8 @@ static void maintenance_internal_error (
 
 static void maintenance_demangle (char *, int);
 
+static void maintenance_setvbuf (char *, int);
+
 static void maintenance_time_display (char *, int);
 
 static void maintenance_space_display (char *, int);
@@ -165,6 +167,88 @@ maintenance_demangle (char *args, int fr
     }
 }
 
+/* Force standard files to specific bbufferingg mode.  */
+static void
+maintenance_setvbuf (char *args, int from_tty)
+{
+  char *file;
+  char *mode;
+  char *size;
+
+  if (args == NULL || *args == '\0')
+    {
+      printf_unfiltered (_("\"maintenance setvbuf\" takes "
+			   "\"stdout/stderr\" and \"full/line/no\""
+                           " optionally followed by buffer size.\n"));
+    }
+  else
+    {
+      struct ui_file *f = NULL;
+      if (strncmp (args, "stdout ", strlen ("stdout ")) == 0)
+	{
+	  f = gdb_stdout;
+	  args += strlen ("stdout ");
+	}
+      else if (strncmp (args, "stderr ", strlen ("stderr ")) == 0)
+	{
+	  f = gdb_stderr;
+	  args += strlen ("stderr ");
+	}
+
+      if (f == NULL)
+	{
+	  printf_unfiltered (_("\"maintenance setvbuf\" accepts only "
+			       "\"stdout\" or \"stderr\" as first
argument.\n"));
+	}
+      else
+	{
+	  int mode = -1;
+
+	  if (strncmp (args, "full", strlen ("full")) == 0)
+	    {
+	      mode = _IOFBF;
+	      args += strlen ("full");
+	    }
+	  else if (strncmp (args, "line", strlen ("line")) == 0)
+	    {
+	      mode = _IOLBF;
+	      args += strlen ("line");
+	    }
+	  else if (strncmp (args, "no", strlen ("no")) == 0)
+	    {
+	      mode = _IONBF;
+	      args += strlen ("no");
+	    }
+	  if (mode == -1)
+	    {
+	      printf_unfiltered (_("\"maintenance setvbuf\" accepts only "
+				   "\"full\",\"line\" or \"no\" as second"
+				   " argument.\n"));
+	    }
+	  else
+	    {
+	      char *buf = NULL;
+	      ULONGEST size;
+	      int res;
+
+	      if (args && *args != '\0')
+		size = parse_and_eval_long (args);
+	      else
+		size = BUFSIZ;
+	      if (mode != _IONBF)
+		buf = (char *) xmalloc (size);
+	      res = ui_file_setvbuf (f, buf, mode, size);
+	      if (res != 0)
+		{
+		  if (buf)
+		    xfree (buf);
+		  printf_unfiltered (_("Call to setvbuf failed.\n"));
+		}
+	    }
+	}
+    }
+}
+
 static void
 maintenance_time_display (char *args, int from_tty)
 {
@@ -1123,6 +1207,9 @@ Takes an optional file parameter."),
 	   _("Translate a section name and address to a symbol."),
 	   &maintenancelist);
 
+  add_cmd ("setvbuf", class_maintenance, maintenance_setvbuf,
+	   _("Force stdout/stderr buffering mode."), &maintenancelist);
+
   add_cmd ("deprecate", class_maintenance, maintenance_deprecate, _("\
 Deprecate a command.  Note that this is just in here so the \n\
 testsuite can check the command deprecator. You probably shouldn't use
this,\n\


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]