198944Sobrien/* UI_FILE - a generic STDIO like output stream.
298944Sobrien
3130803Smarcel   Copyright 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
4130803Smarcel
598944Sobrien   This file is part of GDB.
698944Sobrien
798944Sobrien   This program is free software; you can redistribute it and/or modify
898944Sobrien   it under the terms of the GNU General Public License as published by
998944Sobrien   the Free Software Foundation; either version 2 of the License, or
1098944Sobrien   (at your option) any later version.
1198944Sobrien
1298944Sobrien   This program is distributed in the hope that it will be useful,
1398944Sobrien   but WITHOUT ANY WARRANTY; without even the implied warranty of
1498944Sobrien   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1598944Sobrien   GNU General Public License for more details.
1698944Sobrien
1798944Sobrien   You should have received a copy of the GNU General Public License
1898944Sobrien   along with this program; if not, write to the Free Software
1998944Sobrien   Foundation, Inc., 59 Temple Place - Suite 330,
2098944Sobrien   Boston, MA 02111-1307, USA.  */
2198944Sobrien
2298944Sobrien/* Implement the ``struct ui_file'' object. */
2398944Sobrien
2498944Sobrien#include "defs.h"
2598944Sobrien#include "ui-file.h"
2698944Sobrien#include "gdb_string.h"
2798944Sobrien
28130803Smarcel#include <errno.h>
2998944Sobrien
3098944Sobrienstatic ui_file_isatty_ftype null_file_isatty;
3198944Sobrienstatic ui_file_write_ftype null_file_write;
3298944Sobrienstatic ui_file_fputs_ftype null_file_fputs;
33130803Smarcelstatic ui_file_read_ftype null_file_read;
3498944Sobrienstatic ui_file_flush_ftype null_file_flush;
3598944Sobrienstatic ui_file_delete_ftype null_file_delete;
3698944Sobrienstatic ui_file_rewind_ftype null_file_rewind;
3798944Sobrienstatic ui_file_put_ftype null_file_put;
3898944Sobrien
3998944Sobrienstruct ui_file
4098944Sobrien  {
4198944Sobrien    int *magic;
4298944Sobrien    ui_file_flush_ftype *to_flush;
4398944Sobrien    ui_file_write_ftype *to_write;
4498944Sobrien    ui_file_fputs_ftype *to_fputs;
45130803Smarcel    ui_file_read_ftype *to_read;
4698944Sobrien    ui_file_delete_ftype *to_delete;
4798944Sobrien    ui_file_isatty_ftype *to_isatty;
4898944Sobrien    ui_file_rewind_ftype *to_rewind;
4998944Sobrien    ui_file_put_ftype *to_put;
5098944Sobrien    void *to_data;
5198944Sobrien  };
5298944Sobrienint ui_file_magic;
5398944Sobrien
5498944Sobrienstruct ui_file *
5598944Sobrienui_file_new (void)
5698944Sobrien{
5798944Sobrien  struct ui_file *file = xmalloc (sizeof (struct ui_file));
5898944Sobrien  file->magic = &ui_file_magic;
5998944Sobrien  set_ui_file_data (file, NULL, null_file_delete);
6098944Sobrien  set_ui_file_flush (file, null_file_flush);
6198944Sobrien  set_ui_file_write (file, null_file_write);
6298944Sobrien  set_ui_file_fputs (file, null_file_fputs);
63130803Smarcel  set_ui_file_read (file, null_file_read);
6498944Sobrien  set_ui_file_isatty (file, null_file_isatty);
6598944Sobrien  set_ui_file_rewind (file, null_file_rewind);
6698944Sobrien  set_ui_file_put (file, null_file_put);
6798944Sobrien  return file;
6898944Sobrien}
6998944Sobrien
7098944Sobrienvoid
7198944Sobrienui_file_delete (struct ui_file *file)
7298944Sobrien{
7398944Sobrien  file->to_delete (file);
7498944Sobrien  xfree (file);
7598944Sobrien}
7698944Sobrien
7798944Sobrienstatic int
7898944Sobriennull_file_isatty (struct ui_file *file)
7998944Sobrien{
8098944Sobrien  return 0;
8198944Sobrien}
8298944Sobrien
8398944Sobrienstatic void
8498944Sobriennull_file_rewind (struct ui_file *file)
8598944Sobrien{
8698944Sobrien  return;
8798944Sobrien}
8898944Sobrien
8998944Sobrienstatic void
9098944Sobriennull_file_put (struct ui_file *file,
9198944Sobrien	       ui_file_put_method_ftype *write,
9298944Sobrien	       void *dest)
9398944Sobrien{
9498944Sobrien  return;
9598944Sobrien}
9698944Sobrien
9798944Sobrienstatic void
9898944Sobriennull_file_flush (struct ui_file *file)
9998944Sobrien{
10098944Sobrien  return;
10198944Sobrien}
10298944Sobrien
10398944Sobrienstatic void
10498944Sobriennull_file_write (struct ui_file *file,
10598944Sobrien		 const char *buf,
10698944Sobrien		 long sizeof_buf)
10798944Sobrien{
10898944Sobrien  if (file->to_fputs == null_file_fputs)
10998944Sobrien    /* Both the write and fputs methods are null. Discard the
11098944Sobrien       request. */
11198944Sobrien    return;
11298944Sobrien  else
11398944Sobrien    {
11498944Sobrien      /* The fputs method isn't null, slowly pass the write request
11598944Sobrien         onto that.  FYI, this isn't as bad as it may look - the
11698944Sobrien         current (as of 1999-11-07) printf_* function calls fputc and
11798944Sobrien         fputc does exactly the below.  By having a write function it
11898944Sobrien         is possible to clean up that code.  */
11998944Sobrien      int i;
12098944Sobrien      char b[2];
12198944Sobrien      b[1] = '\0';
12298944Sobrien      for (i = 0; i < sizeof_buf; i++)
12398944Sobrien	{
12498944Sobrien	  b[0] = buf[i];
12598944Sobrien	  file->to_fputs (b, file);
12698944Sobrien	}
12798944Sobrien      return;
12898944Sobrien    }
12998944Sobrien}
13098944Sobrien
131130803Smarcelstatic long
132130803Smarcelnull_file_read (struct ui_file *file,
133130803Smarcel		char *buf,
134130803Smarcel		long sizeof_buf)
135130803Smarcel{
136130803Smarcel  errno = EBADF;
137130803Smarcel  return 0;
138130803Smarcel}
139130803Smarcel
14098944Sobrienstatic void
14198944Sobriennull_file_fputs (const char *buf, struct ui_file *file)
14298944Sobrien{
14398944Sobrien  if (file->to_write == null_file_write)
14498944Sobrien    /* Both the write and fputs methods are null. Discard the
14598944Sobrien       request. */
14698944Sobrien    return;
14798944Sobrien  else
14898944Sobrien    {
14998944Sobrien      /* The write method was implemented, use that. */
15098944Sobrien      file->to_write (file, buf, strlen (buf));
15198944Sobrien    }
15298944Sobrien}
15398944Sobrien
15498944Sobrienstatic void
15598944Sobriennull_file_delete (struct ui_file *file)
15698944Sobrien{
15798944Sobrien  return;
15898944Sobrien}
15998944Sobrien
16098944Sobrienvoid *
16198944Sobrienui_file_data (struct ui_file *file)
16298944Sobrien{
16398944Sobrien  if (file->magic != &ui_file_magic)
16498944Sobrien    internal_error (__FILE__, __LINE__,
16598944Sobrien		    "ui_file_data: bad magic number");
16698944Sobrien  return file->to_data;
16798944Sobrien}
16898944Sobrien
16998944Sobrienvoid
17098944Sobriengdb_flush (struct ui_file *file)
17198944Sobrien{
17298944Sobrien  file->to_flush (file);
17398944Sobrien}
17498944Sobrien
17598944Sobrienint
17698944Sobrienui_file_isatty (struct ui_file *file)
17798944Sobrien{
17898944Sobrien  return file->to_isatty (file);
17998944Sobrien}
18098944Sobrien
18198944Sobrienvoid
18298944Sobrienui_file_rewind (struct ui_file *file)
18398944Sobrien{
18498944Sobrien  file->to_rewind (file);
18598944Sobrien}
18698944Sobrien
18798944Sobrienvoid
18898944Sobrienui_file_put (struct ui_file *file,
18998944Sobrien	      ui_file_put_method_ftype *write,
19098944Sobrien	      void *dest)
19198944Sobrien{
19298944Sobrien  file->to_put (file, write, dest);
19398944Sobrien}
19498944Sobrien
19598944Sobrienvoid
19698944Sobrienui_file_write (struct ui_file *file,
19798944Sobrien		const char *buf,
19898944Sobrien		long length_buf)
19998944Sobrien{
20098944Sobrien  file->to_write (file, buf, length_buf);
20198944Sobrien}
20298944Sobrien
203130803Smarcellong
204130803Smarcelui_file_read (struct ui_file *file, char *buf, long length_buf)
205130803Smarcel{
206130803Smarcel  return file->to_read (file, buf, length_buf);
207130803Smarcel}
208130803Smarcel
20998944Sobrienvoid
21098944Sobrienfputs_unfiltered (const char *buf, struct ui_file *file)
21198944Sobrien{
21298944Sobrien  file->to_fputs (buf, file);
21398944Sobrien}
21498944Sobrien
21598944Sobrienvoid
21698944Sobrienset_ui_file_flush (struct ui_file *file, ui_file_flush_ftype *flush)
21798944Sobrien{
21898944Sobrien  file->to_flush = flush;
21998944Sobrien}
22098944Sobrien
22198944Sobrienvoid
22298944Sobrienset_ui_file_isatty (struct ui_file *file, ui_file_isatty_ftype *isatty)
22398944Sobrien{
22498944Sobrien  file->to_isatty = isatty;
22598944Sobrien}
22698944Sobrien
22798944Sobrienvoid
22898944Sobrienset_ui_file_rewind (struct ui_file *file, ui_file_rewind_ftype *rewind)
22998944Sobrien{
23098944Sobrien  file->to_rewind = rewind;
23198944Sobrien}
23298944Sobrien
23398944Sobrienvoid
23498944Sobrienset_ui_file_put (struct ui_file *file, ui_file_put_ftype *put)
23598944Sobrien{
23698944Sobrien  file->to_put = put;
23798944Sobrien}
23898944Sobrien
23998944Sobrienvoid
24098944Sobrienset_ui_file_write (struct ui_file *file,
24198944Sobrien		    ui_file_write_ftype *write)
24298944Sobrien{
24398944Sobrien  file->to_write = write;
24498944Sobrien}
24598944Sobrien
24698944Sobrienvoid
247130803Smarcelset_ui_file_read (struct ui_file *file, ui_file_read_ftype *read)
248130803Smarcel{
249130803Smarcel  file->to_read = read;
250130803Smarcel}
251130803Smarcel
252130803Smarcelvoid
25398944Sobrienset_ui_file_fputs (struct ui_file *file, ui_file_fputs_ftype *fputs)
25498944Sobrien{
25598944Sobrien  file->to_fputs = fputs;
25698944Sobrien}
25798944Sobrien
25898944Sobrienvoid
25998944Sobrienset_ui_file_data (struct ui_file *file, void *data,
26098944Sobrien		  ui_file_delete_ftype *delete)
26198944Sobrien{
26298944Sobrien  file->to_data = data;
26398944Sobrien  file->to_delete = delete;
26498944Sobrien}
26598944Sobrien
26698944Sobrien/* ui_file utility function for converting a ``struct ui_file'' into
26798944Sobrien   a memory buffer''. */
26898944Sobrien
26998944Sobrienstruct accumulated_ui_file
27098944Sobrien{
27198944Sobrien  char *buffer;
27298944Sobrien  long length;
27398944Sobrien};
27498944Sobrien
27598944Sobrienstatic void
27698944Sobriendo_ui_file_xstrdup (void *context, const char *buffer, long length)
27798944Sobrien{
27898944Sobrien  struct accumulated_ui_file *acc = context;
27998944Sobrien  if (acc->buffer == NULL)
28098944Sobrien    acc->buffer = xmalloc (length + 1);
28198944Sobrien  else
28298944Sobrien    acc->buffer = xrealloc (acc->buffer, acc->length + length + 1);
28398944Sobrien  memcpy (acc->buffer + acc->length, buffer, length);
28498944Sobrien  acc->length += length;
28598944Sobrien  acc->buffer[acc->length] = '\0';
28698944Sobrien}
28798944Sobrien
28898944Sobrienchar *
28998944Sobrienui_file_xstrdup (struct ui_file *file,
29098944Sobrien		  long *length)
29198944Sobrien{
29298944Sobrien  struct accumulated_ui_file acc;
29398944Sobrien  acc.buffer = NULL;
29498944Sobrien  acc.length = 0;
29598944Sobrien  ui_file_put (file, do_ui_file_xstrdup, &acc);
29698944Sobrien  if (acc.buffer == NULL)
29798944Sobrien    acc.buffer = xstrdup ("");
29898944Sobrien  *length = acc.length;
29998944Sobrien  return acc.buffer;
30098944Sobrien}
30198944Sobrien
30298944Sobrien/* A pure memory based ``struct ui_file'' that can be used an output
30398944Sobrien   buffer. The buffers accumulated contents are available via
30498944Sobrien   ui_file_put(). */
30598944Sobrien
30698944Sobrienstruct mem_file
30798944Sobrien  {
30898944Sobrien    int *magic;
30998944Sobrien    char *buffer;
31098944Sobrien    int sizeof_buffer;
31198944Sobrien    int length_buffer;
31298944Sobrien  };
31398944Sobrien
31498944Sobrienstatic ui_file_rewind_ftype mem_file_rewind;
31598944Sobrienstatic ui_file_put_ftype mem_file_put;
31698944Sobrienstatic ui_file_write_ftype mem_file_write;
31798944Sobrienstatic ui_file_delete_ftype mem_file_delete;
31898944Sobrienstatic struct ui_file *mem_file_new (void);
31998944Sobrienstatic int mem_file_magic;
32098944Sobrien
32198944Sobrienstatic struct ui_file *
32298944Sobrienmem_file_new (void)
32398944Sobrien{
32498944Sobrien  struct mem_file *stream = XMALLOC (struct mem_file);
32598944Sobrien  struct ui_file *file = ui_file_new ();
32698944Sobrien  set_ui_file_data (file, stream, mem_file_delete);
32798944Sobrien  set_ui_file_rewind (file, mem_file_rewind);
32898944Sobrien  set_ui_file_put (file, mem_file_put);
32998944Sobrien  set_ui_file_write (file, mem_file_write);
33098944Sobrien  stream->magic = &mem_file_magic;
33198944Sobrien  stream->buffer = NULL;
33298944Sobrien  stream->sizeof_buffer = 0;
33398944Sobrien  stream->length_buffer = 0;
33498944Sobrien  return file;
33598944Sobrien}
33698944Sobrien
33798944Sobrienstatic void
33898944Sobrienmem_file_delete (struct ui_file *file)
33998944Sobrien{
34098944Sobrien  struct mem_file *stream = ui_file_data (file);
34198944Sobrien  if (stream->magic != &mem_file_magic)
34298944Sobrien    internal_error (__FILE__, __LINE__,
34398944Sobrien		    "mem_file_delete: bad magic number");
34498944Sobrien  if (stream->buffer != NULL)
34598944Sobrien    xfree (stream->buffer);
34698944Sobrien  xfree (stream);
34798944Sobrien}
34898944Sobrien
34998944Sobrienstruct ui_file *
35098944Sobrienmem_fileopen (void)
35198944Sobrien{
35298944Sobrien  return mem_file_new ();
35398944Sobrien}
35498944Sobrien
35598944Sobrienstatic void
35698944Sobrienmem_file_rewind (struct ui_file *file)
35798944Sobrien{
35898944Sobrien  struct mem_file *stream = ui_file_data (file);
35998944Sobrien  if (stream->magic != &mem_file_magic)
36098944Sobrien    internal_error (__FILE__, __LINE__,
36198944Sobrien		    "mem_file_rewind: bad magic number");
36298944Sobrien  stream->length_buffer = 0;
36398944Sobrien}
36498944Sobrien
36598944Sobrienstatic void
36698944Sobrienmem_file_put (struct ui_file *file,
36798944Sobrien	      ui_file_put_method_ftype *write,
36898944Sobrien	      void *dest)
36998944Sobrien{
37098944Sobrien  struct mem_file *stream = ui_file_data (file);
37198944Sobrien  if (stream->magic != &mem_file_magic)
37298944Sobrien    internal_error (__FILE__, __LINE__,
37398944Sobrien		    "mem_file_put: bad magic number");
37498944Sobrien  if (stream->length_buffer > 0)
37598944Sobrien    write (dest, stream->buffer, stream->length_buffer);
37698944Sobrien}
37798944Sobrien
37898944Sobrienvoid
37998944Sobrienmem_file_write (struct ui_file *file,
38098944Sobrien		const char *buffer,
38198944Sobrien		long length_buffer)
38298944Sobrien{
38398944Sobrien  struct mem_file *stream = ui_file_data (file);
38498944Sobrien  if (stream->magic != &mem_file_magic)
38598944Sobrien    internal_error (__FILE__, __LINE__,
38698944Sobrien		    "mem_file_write: bad magic number");
38798944Sobrien  if (stream->buffer == NULL)
38898944Sobrien    {
38998944Sobrien      stream->length_buffer = length_buffer;
39098944Sobrien      stream->sizeof_buffer = length_buffer;
39198944Sobrien      stream->buffer = xmalloc (stream->sizeof_buffer);
39298944Sobrien      memcpy (stream->buffer, buffer, length_buffer);
39398944Sobrien    }
39498944Sobrien  else
39598944Sobrien    {
39698944Sobrien      int new_length = stream->length_buffer + length_buffer;
39798944Sobrien      if (new_length >= stream->sizeof_buffer)
39898944Sobrien	{
39998944Sobrien	  stream->sizeof_buffer = new_length;
40098944Sobrien	  stream->buffer = xrealloc (stream->buffer, stream->sizeof_buffer);
40198944Sobrien	}
40298944Sobrien      memcpy (stream->buffer + stream->length_buffer, buffer, length_buffer);
40398944Sobrien      stream->length_buffer = new_length;
40498944Sobrien    }
40598944Sobrien}
40698944Sobrien
40798944Sobrien/* ``struct ui_file'' implementation that maps directly onto
40898944Sobrien   <stdio.h>'s FILE. */
40998944Sobrien
41098944Sobrienstatic ui_file_write_ftype stdio_file_write;
41198944Sobrienstatic ui_file_fputs_ftype stdio_file_fputs;
412130803Smarcelstatic ui_file_read_ftype stdio_file_read;
41398944Sobrienstatic ui_file_isatty_ftype stdio_file_isatty;
41498944Sobrienstatic ui_file_delete_ftype stdio_file_delete;
41598944Sobrienstatic struct ui_file *stdio_file_new (FILE * file, int close_p);
41698944Sobrienstatic ui_file_flush_ftype stdio_file_flush;
41798944Sobrien
41898944Sobrienstatic int stdio_file_magic;
41998944Sobrien
42098944Sobrienstruct stdio_file
42198944Sobrien  {
42298944Sobrien    int *magic;
42398944Sobrien    FILE *file;
42498944Sobrien    int close_p;
42598944Sobrien  };
42698944Sobrien
42798944Sobrienstatic struct ui_file *
42898944Sobrienstdio_file_new (FILE *file, int close_p)
42998944Sobrien{
43098944Sobrien  struct ui_file *ui_file = ui_file_new ();
43198944Sobrien  struct stdio_file *stdio = xmalloc (sizeof (struct stdio_file));
43298944Sobrien  stdio->magic = &stdio_file_magic;
43398944Sobrien  stdio->file = file;
43498944Sobrien  stdio->close_p = close_p;
43598944Sobrien  set_ui_file_data (ui_file, stdio, stdio_file_delete);
43698944Sobrien  set_ui_file_flush (ui_file, stdio_file_flush);
43798944Sobrien  set_ui_file_write (ui_file, stdio_file_write);
43898944Sobrien  set_ui_file_fputs (ui_file, stdio_file_fputs);
439130803Smarcel  set_ui_file_read (ui_file, stdio_file_read);
44098944Sobrien  set_ui_file_isatty (ui_file, stdio_file_isatty);
44198944Sobrien  return ui_file;
44298944Sobrien}
44398944Sobrien
44498944Sobrienstatic void
44598944Sobrienstdio_file_delete (struct ui_file *file)
44698944Sobrien{
44798944Sobrien  struct stdio_file *stdio = ui_file_data (file);
44898944Sobrien  if (stdio->magic != &stdio_file_magic)
44998944Sobrien    internal_error (__FILE__, __LINE__,
45098944Sobrien		    "stdio_file_delete: bad magic number");
45198944Sobrien  if (stdio->close_p)
45298944Sobrien    {
45398944Sobrien      fclose (stdio->file);
45498944Sobrien    }
45598944Sobrien  xfree (stdio);
45698944Sobrien}
45798944Sobrien
45898944Sobrienstatic void
45998944Sobrienstdio_file_flush (struct ui_file *file)
46098944Sobrien{
46198944Sobrien  struct stdio_file *stdio = ui_file_data (file);
46298944Sobrien  if (stdio->magic != &stdio_file_magic)
46398944Sobrien    internal_error (__FILE__, __LINE__,
46498944Sobrien		    "stdio_file_flush: bad magic number");
46598944Sobrien  fflush (stdio->file);
46698944Sobrien}
46798944Sobrien
468130803Smarcelstatic long
469130803Smarcelstdio_file_read (struct ui_file *file, char *buf, long length_buf)
470130803Smarcel{
471130803Smarcel  struct stdio_file *stdio = ui_file_data (file);
472130803Smarcel  if (stdio->magic != &stdio_file_magic)
473130803Smarcel    internal_error (__FILE__, __LINE__,
474130803Smarcel		    "stdio_file_read: bad magic number");
475130803Smarcel  return read (fileno (stdio->file), buf, length_buf);
476130803Smarcel}
477130803Smarcel
47898944Sobrienstatic void
47998944Sobrienstdio_file_write (struct ui_file *file, const char *buf, long length_buf)
48098944Sobrien{
48198944Sobrien  struct stdio_file *stdio = ui_file_data (file);
48298944Sobrien  if (stdio->magic != &stdio_file_magic)
48398944Sobrien    internal_error (__FILE__, __LINE__,
48498944Sobrien		    "stdio_file_write: bad magic number");
48598944Sobrien  fwrite (buf, length_buf, 1, stdio->file);
48698944Sobrien}
48798944Sobrien
48898944Sobrienstatic void
48998944Sobrienstdio_file_fputs (const char *linebuffer, struct ui_file *file)
49098944Sobrien{
49198944Sobrien  struct stdio_file *stdio = ui_file_data (file);
49298944Sobrien  if (stdio->magic != &stdio_file_magic)
49398944Sobrien    internal_error (__FILE__, __LINE__,
49498944Sobrien		    "stdio_file_fputs: bad magic number");
49598944Sobrien  fputs (linebuffer, stdio->file);
49698944Sobrien}
49798944Sobrien
49898944Sobrienstatic int
49998944Sobrienstdio_file_isatty (struct ui_file *file)
50098944Sobrien{
50198944Sobrien  struct stdio_file *stdio = ui_file_data (file);
50298944Sobrien  if (stdio->magic != &stdio_file_magic)
50398944Sobrien    internal_error (__FILE__, __LINE__,
50498944Sobrien		    "stdio_file_isatty: bad magic number");
50598944Sobrien  return (isatty (fileno (stdio->file)));
50698944Sobrien}
50798944Sobrien
50898944Sobrien/* Like fdopen().  Create a ui_file from a previously opened FILE. */
50998944Sobrien
51098944Sobrienstruct ui_file *
51198944Sobrienstdio_fileopen (FILE *file)
51298944Sobrien{
51398944Sobrien  return stdio_file_new (file, 0);
51498944Sobrien}
51598944Sobrien
51698944Sobrienstruct ui_file *
51798944Sobriengdb_fopen (char *name, char *mode)
51898944Sobrien{
51998944Sobrien  FILE *f = fopen (name, mode);
52098944Sobrien  if (f == NULL)
52198944Sobrien    return NULL;
52298944Sobrien  return stdio_file_new (f, 1);
52398944Sobrien}
524130803Smarcel
525130803Smarcel/* ``struct ui_file'' implementation that maps onto two ui-file objects.  */
526130803Smarcel
527130803Smarcelstatic ui_file_write_ftype tee_file_write;
528130803Smarcelstatic ui_file_fputs_ftype tee_file_fputs;
529130803Smarcelstatic ui_file_isatty_ftype tee_file_isatty;
530130803Smarcelstatic ui_file_delete_ftype tee_file_delete;
531130803Smarcelstatic ui_file_flush_ftype tee_file_flush;
532130803Smarcel
533130803Smarcelstatic int tee_file_magic;
534130803Smarcel
535130803Smarcelstruct tee_file
536130803Smarcel  {
537130803Smarcel    int *magic;
538130803Smarcel    struct ui_file *one, *two;
539130803Smarcel    int close_one, close_two;
540130803Smarcel  };
541130803Smarcel
542130803Smarcelstruct ui_file *
543130803Smarceltee_file_new (struct ui_file *one, int close_one,
544130803Smarcel	      struct ui_file *two, int close_two)
545130803Smarcel{
546130803Smarcel  struct ui_file *ui_file = ui_file_new ();
547130803Smarcel  struct tee_file *tee = xmalloc (sizeof (struct tee_file));
548130803Smarcel  tee->magic = &tee_file_magic;
549130803Smarcel  tee->one = one;
550130803Smarcel  tee->two = two;
551130803Smarcel  tee->close_one = close_one;
552130803Smarcel  tee->close_two = close_two;
553130803Smarcel  set_ui_file_data (ui_file, tee, tee_file_delete);
554130803Smarcel  set_ui_file_flush (ui_file, tee_file_flush);
555130803Smarcel  set_ui_file_write (ui_file, tee_file_write);
556130803Smarcel  set_ui_file_fputs (ui_file, tee_file_fputs);
557130803Smarcel  set_ui_file_isatty (ui_file, tee_file_isatty);
558130803Smarcel  return ui_file;
559130803Smarcel}
560130803Smarcel
561130803Smarcelstatic void
562130803Smarceltee_file_delete (struct ui_file *file)
563130803Smarcel{
564130803Smarcel  struct tee_file *tee = ui_file_data (file);
565130803Smarcel  if (tee->magic != &tee_file_magic)
566130803Smarcel    internal_error (__FILE__, __LINE__,
567130803Smarcel		    "tee_file_delete: bad magic number");
568130803Smarcel  if (tee->close_one)
569130803Smarcel    ui_file_delete (tee->one);
570130803Smarcel  if (tee->close_two)
571130803Smarcel    ui_file_delete (tee->two);
572130803Smarcel
573130803Smarcel  xfree (tee);
574130803Smarcel}
575130803Smarcel
576130803Smarcelstatic void
577130803Smarceltee_file_flush (struct ui_file *file)
578130803Smarcel{
579130803Smarcel  struct tee_file *tee = ui_file_data (file);
580130803Smarcel  if (tee->magic != &tee_file_magic)
581130803Smarcel    internal_error (__FILE__, __LINE__,
582130803Smarcel		    "tee_file_flush: bad magic number");
583130803Smarcel  tee->one->to_flush (tee->one);
584130803Smarcel  tee->two->to_flush (tee->two);
585130803Smarcel}
586130803Smarcel
587130803Smarcelstatic void
588130803Smarceltee_file_write (struct ui_file *file, const char *buf, long length_buf)
589130803Smarcel{
590130803Smarcel  struct tee_file *tee = ui_file_data (file);
591130803Smarcel  if (tee->magic != &tee_file_magic)
592130803Smarcel    internal_error (__FILE__, __LINE__,
593130803Smarcel		    "tee_file_write: bad magic number");
594130803Smarcel  ui_file_write (tee->one, buf, length_buf);
595130803Smarcel  ui_file_write (tee->two, buf, length_buf);
596130803Smarcel}
597130803Smarcel
598130803Smarcelstatic void
599130803Smarceltee_file_fputs (const char *linebuffer, struct ui_file *file)
600130803Smarcel{
601130803Smarcel  struct tee_file *tee = ui_file_data (file);
602130803Smarcel  if (tee->magic != &tee_file_magic)
603130803Smarcel    internal_error (__FILE__, __LINE__,
604130803Smarcel		    "tee_file_fputs: bad magic number");
605130803Smarcel  tee->one->to_fputs (linebuffer, tee->one);
606130803Smarcel  tee->two->to_fputs (linebuffer, tee->two);
607130803Smarcel}
608130803Smarcel
609130803Smarcelstatic int
610130803Smarceltee_file_isatty (struct ui_file *file)
611130803Smarcel{
612130803Smarcel  struct tee_file *tee = ui_file_data (file);
613130803Smarcel  if (tee->magic != &tee_file_magic)
614130803Smarcel    internal_error (__FILE__, __LINE__,
615130803Smarcel		    "tee_file_isatty: bad magic number");
616130803Smarcel  return (0);
617130803Smarcel}
618