1f458c59obrien/* UI_FILE - a generic STDIO like output stream.
2ddb504emarcel
3ddb504emarcel   Copyright 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
4f458c59obrien
5f458c59obrien   This file is part of GDB.
6f458c59obrien
7f458c59obrien   This program is free software; you can redistribute it and/or modify
8f458c59obrien   it under the terms of the GNU General Public License as published by
9f458c59obrien   the Free Software Foundation; either version 2 of the License, or
10f458c59obrien   (at your option) any later version.
11f458c59obrien
12f458c59obrien   This program is distributed in the hope that it will be useful,
13f458c59obrien   but WITHOUT ANY WARRANTY; without even the implied warranty of
14f458c59obrien   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15f458c59obrien   GNU General Public License for more details.
16f458c59obrien
17f458c59obrien   You should have received a copy of the GNU General Public License
18f458c59obrien   along with this program; if not, write to the Free Software
19f458c59obrien   Foundation, Inc., 59 Temple Place - Suite 330,
20f458c59obrien   Boston, MA 02111-1307, USA.  */
21f458c59obrien
22f458c59obrien/* Implement the ``struct ui_file'' object. */
23f458c59obrien
24f458c59obrien#include "defs.h"
25f458c59obrien#include "ui-file.h"
26f458c59obrien#include "gdb_string.h"
27f458c59obrien
28ddb504emarcel#include <errno.h>
29f458c59obrien
30f458c59obrienstatic ui_file_isatty_ftype null_file_isatty;
31f458c59obrienstatic ui_file_write_ftype null_file_write;
32f458c59obrienstatic ui_file_fputs_ftype null_file_fputs;
33ddb504emarcelstatic ui_file_read_ftype null_file_read;
34f458c59obrienstatic ui_file_flush_ftype null_file_flush;
35f458c59obrienstatic ui_file_delete_ftype null_file_delete;
36f458c59obrienstatic ui_file_rewind_ftype null_file_rewind;
37f458c59obrienstatic ui_file_put_ftype null_file_put;
38f458c59obrien
39f458c59obrienstruct ui_file
40f458c59obrien  {
41f458c59obrien    int *magic;
42f458c59obrien    ui_file_flush_ftype *to_flush;
43f458c59obrien    ui_file_write_ftype *to_write;
44f458c59obrien    ui_file_fputs_ftype *to_fputs;
45ddb504emarcel    ui_file_read_ftype *to_read;
46f458c59obrien    ui_file_delete_ftype *to_delete;
47f458c59obrien    ui_file_isatty_ftype *to_isatty;
48f458c59obrien    ui_file_rewind_ftype *to_rewind;
49f458c59obrien    ui_file_put_ftype *to_put;
50f458c59obrien    void *to_data;
51f458c59obrien  };
52f458c59obrienint ui_file_magic;
53f458c59obrien
54f458c59obrienstruct ui_file *
55f458c59obrienui_file_new (void)
56f458c59obrien{
57f458c59obrien  struct ui_file *file = xmalloc (sizeof (struct ui_file));
58f458c59obrien  file->magic = &ui_file_magic;
59f458c59obrien  set_ui_file_data (file, NULL, null_file_delete);
60f458c59obrien  set_ui_file_flush (file, null_file_flush);
61f458c59obrien  set_ui_file_write (file, null_file_write);
62f458c59obrien  set_ui_file_fputs (file, null_file_fputs);
63ddb504emarcel  set_ui_file_read (file, null_file_read);
64f458c59obrien  set_ui_file_isatty (file, null_file_isatty);
65f458c59obrien  set_ui_file_rewind (file, null_file_rewind);
66f458c59obrien  set_ui_file_put (file, null_file_put);
67f458c59obrien  return file;
68f458c59obrien}
69f458c59obrien
70f458c59obrienvoid
71f458c59obrienui_file_delete (struct ui_file *file)
72f458c59obrien{
73f458c59obrien  file->to_delete (file);
74f458c59obrien  xfree (file);
75f458c59obrien}
76f458c59obrien
77f458c59obrienstatic int
78f458c59obriennull_file_isatty (struct ui_file *file)
79f458c59obrien{
80f458c59obrien  return 0;
81f458c59obrien}
82f458c59obrien
83f458c59obrienstatic void
84f458c59obriennull_file_rewind (struct ui_file *file)
85f458c59obrien{
86f458c59obrien  return;
87f458c59obrien}
88f458c59obrien
89f458c59obrienstatic void
90f458c59obriennull_file_put (struct ui_file *file,
91f458c59obrien	       ui_file_put_method_ftype *write,
92f458c59obrien	       void *dest)
93f458c59obrien{
94f458c59obrien  return;
95f458c59obrien}
96f458c59obrien
97f458c59obrienstatic void
98f458c59obriennull_file_flush (struct ui_file *file)
99f458c59obrien{
100f458c59obrien  return;
101f458c59obrien}
102f458c59obrien
103f458c59obrienstatic void
104f458c59obriennull_file_write (struct ui_file *file,
105f458c59obrien		 const char *buf,
106f458c59obrien		 long sizeof_buf)
107f458c59obrien{
108f458c59obrien  if (file->to_fputs == null_file_fputs)
109f458c59obrien    /* Both the write and fputs methods are null. Discard the
110f458c59obrien       request. */
111f458c59obrien    return;
112f458c59obrien  else
113f458c59obrien    {
114f458c59obrien      /* The fputs method isn't null, slowly pass the write request
115f458c59obrien         onto that.  FYI, this isn't as bad as it may look - the
116f458c59obrien         current (as of 1999-11-07) printf_* function calls fputc and
117f458c59obrien         fputc does exactly the below.  By having a write function it
118f458c59obrien         is possible to clean up that code.  */
119f458c59obrien      int i;
120f458c59obrien      char b[2];
121f458c59obrien      b[1] = '\0';
122f458c59obrien      for (i = 0; i < sizeof_buf; i++)
123f458c59obrien	{
124f458c59obrien	  b[0] = buf[i];
125f458c59obrien	  file->to_fputs (b, file);
126f458c59obrien	}
127f458c59obrien      return;
128f458c59obrien    }
129f458c59obrien}
130f458c59obrien
131ddb504emarcelstatic long
132ddb504emarcelnull_file_read (struct ui_file *file,
133ddb504emarcel		char *buf,
134ddb504emarcel		long sizeof_buf)
135ddb504emarcel{
136ddb504emarcel  errno = EBADF;
137ddb504emarcel  return 0;
138ddb504emarcel}
139ddb504emarcel
140f458c59obrienstatic void
141f458c59obriennull_file_fputs (const char *buf, struct ui_file *file)
142f458c59obrien{
143f458c59obrien  if (file->to_write == null_file_write)
144f458c59obrien    /* Both the write and fputs methods are null. Discard the
145f458c59obrien       request. */
146f458c59obrien    return;
147f458c59obrien  else
148f458c59obrien    {
149f458c59obrien      /* The write method was implemented, use that. */
150f458c59obrien      file->to_write (file, buf, strlen (buf));
151f458c59obrien    }
152f458c59obrien}
153f458c59obrien
154f458c59obrienstatic void
155f458c59obriennull_file_delete (struct ui_file *file)
156f458c59obrien{
157f458c59obrien  return;
158f458c59obrien}
159f458c59obrien
160f458c59obrienvoid *
161f458c59obrienui_file_data (struct ui_file *file)
162f458c59obrien{
163f458c59obrien  if (file->magic != &ui_file_magic)
164f458c59obrien    internal_error (__FILE__, __LINE__,
165f458c59obrien		    "ui_file_data: bad magic number");
166f458c59obrien  return file->to_data;
167f458c59obrien}
168f458c59obrien
169f458c59obrienvoid
170f458c59obriengdb_flush (struct ui_file *file)
171f458c59obrien{
172f458c59obrien  file->to_flush (file);
173f458c59obrien}
174f458c59obrien
175f458c59obrienint
176f458c59obrienui_file_isatty (struct ui_file *file)
177f458c59obrien{
178f458c59obrien  return file->to_isatty (file);
179f458c59obrien}
180f458c59obrien
181f458c59obrienvoid
182f458c59obrienui_file_rewind (struct ui_file *file)
183f458c59obrien{
184f458c59obrien  file->to_rewind (file);
185f458c59obrien}
186f458c59obrien
187f458c59obrienvoid
188f458c59obrienui_file_put (struct ui_file *file,
189f458c59obrien	      ui_file_put_method_ftype *write,
190f458c59obrien	      void *dest)
191f458c59obrien{
192f458c59obrien  file->to_put (file, write, dest);
193f458c59obrien}
194f458c59obrien
195f458c59obrienvoid
196f458c59obrienui_file_write (struct ui_file *file,
197f458c59obrien		const char *buf,
198f458c59obrien		long length_buf)
199f458c59obrien{
200f458c59obrien  file->to_write (file, buf, length_buf);
201f458c59obrien}
202f458c59obrien
203ddb504emarcellong
204ddb504emarcelui_file_read (struct ui_file *file, char *buf, long length_buf)
205ddb504emarcel{
206ddb504emarcel  return file->to_read (file, buf, length_buf);
207ddb504emarcel}
208ddb504emarcel
209f458c59obrienvoid
210f458c59obrienfputs_unfiltered (const char *buf, struct ui_file *file)
211f458c59obrien{
212f458c59obrien  file->to_fputs (buf, file);
213f458c59obrien}
214f458c59obrien
215f458c59obrienvoid
216f458c59obrienset_ui_file_flush (struct ui_file *file, ui_file_flush_ftype *flush)
217f458c59obrien{
218f458c59obrien  file->to_flush = flush;
219f458c59obrien}
220f458c59obrien
221f458c59obrienvoid
222f458c59obrienset_ui_file_isatty (struct ui_file *file, ui_file_isatty_ftype *isatty)
223f458c59obrien{
224f458c59obrien  file->to_isatty = isatty;
225f458c59obrien}
226f458c59obrien
227f458c59obrienvoid
228f458c59obrienset_ui_file_rewind (struct ui_file *file, ui_file_rewind_ftype *rewind)
229f458c59obrien{
230f458c59obrien  file->to_rewind = rewind;
231f458c59obrien}
232f458c59obrien
233f458c59obrienvoid
234f458c59obrienset_ui_file_put (struct ui_file *file, ui_file_put_ftype *put)
235f458c59obrien{
236f458c59obrien  file->to_put = put;
237f458c59obrien}
238f458c59obrien
239f458c59obrienvoid
240f458c59obrienset_ui_file_write (struct ui_file *file,
241f458c59obrien		    ui_file_write_ftype *write)
242f458c59obrien{
243f458c59obrien  file->to_write = write;
244f458c59obrien}
245f458c59obrien
246f458c59obrienvoid
247ddb504emarcelset_ui_file_read (struct ui_file *file, ui_file_read_ftype *read)
248ddb504emarcel{
249ddb504emarcel  file->to_read = read;
250ddb504emarcel}
251ddb504emarcel
252ddb504emarcelvoid
253f458c59obrienset_ui_file_fputs (struct ui_file *file, ui_file_fputs_ftype *fputs)
254f458c59obrien{
255f458c59obrien  file->to_fputs = fputs;
256f458c59obrien}
257f458c59obrien
258f458c59obrienvoid
259f458c59obrienset_ui_file_data (struct ui_file *file, void *data,
260f458c59obrien		  ui_file_delete_ftype *delete)
261f458c59obrien{
262f458c59obrien  file->to_data = data;
263f458c59obrien  file->to_delete = delete;
264f458c59obrien}
265f458c59obrien
266f458c59obrien/* ui_file utility function for converting a ``struct ui_file'' into
267f458c59obrien   a memory buffer''. */
268f458c59obrien
269f458c59obrienstruct accumulated_ui_file
270f458c59obrien{
271f458c59obrien  char *buffer;
272f458c59obrien  long length;
273f458c59obrien};
274f458c59obrien
275f458c59obrienstatic void
276f458c59obriendo_ui_file_xstrdup (void *context, const char *buffer, long length)
277f458c59obrien{
278f458c59obrien  struct accumulated_ui_file *acc = context;
279f458c59obrien  if (acc->buffer == NULL)
280f458c59obrien    acc->buffer = xmalloc (length + 1);
281f458c59obrien  else
282f458c59obrien    acc->buffer = xrealloc (acc->buffer, acc->length + length + 1);
283f458c59obrien  memcpy (acc->buffer + acc->length, buffer, length);
284f458c59obrien  acc->length += length;
285f458c59obrien  acc->buffer[acc->length] = '\0';
286f458c59obrien}
287f458c59obrien
288f458c59obrienchar *
289f458c59obrienui_file_xstrdup (struct ui_file *file,
290f458c59obrien		  long *length)
291f458c59obrien{
292f458c59obrien  struct accumulated_ui_file acc;
293f458c59obrien  acc.buffer = NULL;
294f458c59obrien  acc.length = 0;
295f458c59obrien  ui_file_put (file, do_ui_file_xstrdup, &acc);
296f458c59obrien  if (acc.buffer == NULL)
297f458c59obrien    acc.buffer = xstrdup ("");
298f458c59obrien  *length = acc.length;
299f458c59obrien  return acc.buffer;
300f458c59obrien}
301f458c59obrien
302f458c59obrien/* A pure memory based ``struct ui_file'' that can be used an output
303f458c59obrien   buffer. The buffers accumulated contents are available via
304f458c59obrien   ui_file_put(). */
305f458c59obrien
306f458c59obrienstruct mem_file
307f458c59obrien  {
308f458c59obrien    int *magic;
309f458c59obrien    char *buffer;
310f458c59obrien    int sizeof_buffer;
311f458c59obrien    int length_buffer;
312f458c59obrien  };
313f458c59obrien
314f458c59obrienstatic ui_file_rewind_ftype mem_file_rewind;
315f458c59obrienstatic ui_file_put_ftype mem_file_put;
316f458c59obrienstatic ui_file_write_ftype mem_file_write;
317f458c59obrienstatic ui_file_delete_ftype mem_file_delete;
318f458c59obrienstatic struct ui_file *mem_file_new (void);
319f458c59obrienstatic int mem_file_magic;
320f458c59obrien
321f458c59obrienstatic struct ui_file *
322f458c59obrienmem_file_new (void)
323f458c59obrien{
324f458c59obrien  struct mem_file *stream = XMALLOC (struct mem_file);
325f458c59obrien  struct ui_file *file = ui_file_new ();
326f458c59obrien  set_ui_file_data (file, stream, mem_file_delete);
327f458c59obrien  set_ui_file_rewind (file, mem_file_rewind);
328f458c59obrien  set_ui_file_put (file, mem_file_put);
329f458c59obrien  set_ui_file_write (file, mem_file_write);
330f458c59obrien  stream->magic = &mem_file_magic;
331f458c59obrien  stream->buffer = NULL;
332f458c59obrien  stream->sizeof_buffer = 0;
333f458c59obrien  stream->length_buffer = 0;
334f458c59obrien  return file;
335f458c59obrien}
336f458c59obrien
337f458c59obrienstatic void
338f458c59obrienmem_file_delete (struct ui_file *file)
339f458c59obrien{
340f458c59obrien  struct mem_file *stream = ui_file_data (file);
341f458c59obrien  if (stream->magic != &mem_file_magic)
342f458c59obrien    internal_error (__FILE__, __LINE__,
343f458c59obrien		    "mem_file_delete: bad magic number");
344f458c59obrien  if (stream->buffer != NULL)
345f458c59obrien    xfree (stream->buffer);
346f458c59obrien  xfree (stream);
347f458c59obrien}
348f458c59obrien
349f458c59obrienstruct ui_file *
350f458c59obrienmem_fileopen (void)
351f458c59obrien{
352f458c59obrien  return mem_file_new ();
353f458c59obrien}
354f458c59obrien
355f458c59obrienstatic void
356f458c59obrienmem_file_rewind (struct ui_file *file)
357f458c59obrien{
358f458c59obrien  struct mem_file *stream = ui_file_data (file);
359f458c59obrien  if (stream->magic != &mem_file_magic)
360f458c59obrien    internal_error (__FILE__, __LINE__,
361f458c59obrien		    "mem_file_rewind: bad magic number");
362f458c59obrien  stream->length_buffer = 0;
363f458c59obrien}
364f458c59obrien
365f458c59obrienstatic void
366f458c59obrienmem_file_put (struct ui_file *file,
367f458c59obrien	      ui_file_put_method_ftype *write,
368f458c59obrien	      void *dest)
369f458c59obrien{
370f458c59obrien  struct mem_file *stream = ui_file_data (file);
371f458c59obrien  if (stream->magic != &mem_file_magic)
372f458c59obrien    internal_error (__FILE__, __LINE__,
373f458c59obrien		    "mem_file_put: bad magic number");
374f458c59obrien  if (stream->length_buffer > 0)
375f458c59obrien    write (dest, stream->buffer, stream->length_buffer);
376f458c59obrien}
377f458c59obrien
378f458c59obrienvoid
379f458c59obrienmem_file_write (struct ui_file *file,
380f458c59obrien		const char *buffer,
381f458c59obrien		long length_buffer)
382f458c59obrien{
383f458c59obrien  struct mem_file *stream = ui_file_data (file);
384f458c59obrien  if (stream->magic != &mem_file_magic)
385f458c59obrien    internal_error (__FILE__, __LINE__,
386f458c59obrien		    "mem_file_write: bad magic number");
387f458c59obrien  if (stream->buffer == NULL)
388f458c59obrien    {
389f458c59obrien      stream->length_buffer = length_buffer;
390f458c59obrien      stream->sizeof_buffer = length_buffer;
391f458c59obrien      stream->buffer = xmalloc (stream->sizeof_buffer);
392f458c59obrien      memcpy (stream->buffer, buffer, length_buffer);
393f458c59obrien    }
394f458c59obrien  else
395f458c59obrien    {
396f458c59obrien      int new_length = stream->length_buffer + length_buffer;
397f458c59obrien      if (new_length >= stream->sizeof_buffer)
398f458c59obrien	{
399f458c59obrien	  stream->sizeof_buffer = new_length;
400f458c59obrien	  stream->buffer = xrealloc (stream->buffer, stream->sizeof_buffer);
401f458c59obrien	}
402f458c59obrien      memcpy (stream->buffer + stream->length_buffer, buffer, length_buffer);
403f458c59obrien      stream->length_buffer = new_length;
404f458c59obrien    }
405f458c59obrien}
406f458c59obrien
407f458c59obrien/* ``struct ui_file'' implementation that maps directly onto
408f458c59obrien   <stdio.h>'s FILE. */
409f458c59obrien
410f458c59obrienstatic ui_file_write_ftype stdio_file_write;
411f458c59obrienstatic ui_file_fputs_ftype stdio_file_fputs;
412ddb504emarcelstatic ui_file_read_ftype stdio_file_read;
413f458c59obrienstatic ui_file_isatty_ftype stdio_file_isatty;
414f458c59obrienstatic ui_file_delete_ftype stdio_file_delete;
415f458c59obrienstatic struct ui_file *stdio_file_new (FILE * file, int close_p);
416f458c59obrienstatic ui_file_flush_ftype stdio_file_flush;
417f458c59obrien
418f458c59obrienstatic int stdio_file_magic;
419f458c59obrien
420f458c59obrienstruct stdio_file
421f458c59obrien  {
422f458c59obrien    int *magic;
423f458c59obrien    FILE *file;
424f458c59obrien    int close_p;
425f458c59obrien  };
426f458c59obrien
427f458c59obrienstatic struct ui_file *
428f458c59obrienstdio_file_new (FILE *file, int close_p)
429f458c59obrien{
430f458c59obrien  struct ui_file *ui_file = ui_file_new ();
431f458c59obrien  struct stdio_file *stdio = xmalloc (sizeof (struct stdio_file));
432f458c59obrien  stdio->magic = &stdio_file_magic;
433f458c59obrien  stdio->file = file;
434f458c59obrien  stdio->close_p = close_p;
435f458c59obrien  set_ui_file_data (ui_file, stdio, stdio_file_delete);
436f458c59obrien  set_ui_file_flush (ui_file, stdio_file_flush);
437f458c59obrien  set_ui_file_write (ui_file, stdio_file_write);
438f458c59obrien  set_ui_file_fputs (ui_file, stdio_file_fputs);
439ddb504emarcel  set_ui_file_read (ui_file, stdio_file_read);
440f458c59obrien  set_ui_file_isatty (ui_file, stdio_file_isatty);
441f458c59obrien  return ui_file;
442f458c59obrien}
443f458c59obrien
444f458c59obrienstatic void
445f458c59obrienstdio_file_delete (struct ui_file *file)
446f458c59obrien{
447f458c59obrien  struct stdio_file *stdio = ui_file_data (file);
448f458c59obrien  if (stdio->magic != &stdio_file_magic)
449f458c59obrien    internal_error (__FILE__, __LINE__,
450f458c59obrien		    "stdio_file_delete: bad magic number");
451f458c59obrien  if (stdio->close_p)
452f458c59obrien    {
453f458c59obrien      fclose (stdio->file);
454f458c59obrien    }
455f458c59obrien  xfree (stdio);
456f458c59obrien}
457f458c59obrien
458f458c59obrienstatic void
459f458c59obrienstdio_file_flush (struct ui_file *file)
460f458c59obrien{
461f458c59obrien  struct stdio_file *stdio = ui_file_data (file);
462f458c59obrien  if (stdio->magic != &stdio_file_magic)
463f458c59obrien    internal_error (__FILE__, __LINE__,
464f458c59obrien		    "stdio_file_flush: bad magic number");
465f458c59obrien  fflush (stdio->file);
466f458c59obrien}
467f458c59obrien
468ddb504emarcelstatic long
469ddb504emarcelstdio_file_read (struct ui_file *file, char *buf, long length_buf)
470ddb504emarcel{
471ddb504emarcel  struct stdio_file *stdio = ui_file_data (file);
472ddb504emarcel  if (stdio->magic != &stdio_file_magic)
473ddb504emarcel    internal_error (__FILE__, __LINE__,
474ddb504emarcel		    "stdio_file_read: bad magic number");
475ddb504emarcel  return read (fileno (stdio->file), buf, length_buf);
476ddb504emarcel}
477ddb504emarcel
478f458c59obrienstatic void
479f458c59obrienstdio_file_write (struct ui_file *file, const char *buf, long length_buf)
480f458c59obrien{
481f458c59obrien  struct stdio_file *stdio = ui_file_data (file);
482f458c59obrien  if (stdio->magic != &stdio_file_magic)
483f458c59obrien    internal_error (__FILE__, __LINE__,
484f458c59obrien		    "stdio_file_write: bad magic number");
485f458c59obrien  fwrite (buf, length_buf, 1, stdio->file);
486f458c59obrien}
487f458c59obrien
488f458c59obrienstatic void
489f458c59obrienstdio_file_fputs (const char *linebuffer, struct ui_file *file)
490f458c59obrien{
491f458c59obrien  struct stdio_file *stdio = ui_file_data (file);
492f458c59obrien  if (stdio->magic != &stdio_file_magic)
493f458c59obrien    internal_error (__FILE__, __LINE__,
494f458c59obrien		    "stdio_file_fputs: bad magic number");
495f458c59obrien  fputs (linebuffer, stdio->file);
496f458c59obrien}
497f458c59obrien
498f458c59obrienstatic int
499f458c59obrienstdio_file_isatty (struct ui_file *file)
500f458c59obrien{
501f458c59obrien  struct stdio_file *stdio = ui_file_data (file);
502f458c59obrien  if (stdio->magic != &stdio_file_magic)
503f458c59obrien    internal_error (__FILE__, __LINE__,
504f458c59obrien		    "stdio_file_isatty: bad magic number");
505f458c59obrien  return (isatty (fileno (stdio->file)));
506f458c59obrien}
507f458c59obrien
508f458c59obrien/* Like fdopen().  Create a ui_file from a previously opened FILE. */
509f458c59obrien
510f458c59obrienstruct ui_file *
511f458c59obrienstdio_fileopen (FILE *file)
512f458c59obrien{
513f458c59obrien  return stdio_file_new (file, 0);
514f458c59obrien}
515f458c59obrien
516f458c59obrienstruct ui_file *
517f458c59obriengdb_fopen (char *name, char *mode)
518f458c59obrien{
519f458c59obrien  FILE *f = fopen (name, mode);
520f458c59obrien  if (f == NULL)
521f458c59obrien    return NULL;
522f458c59obrien  return stdio_file_new (f, 1);
523f458c59obrien}
524ddb504emarcel
525ddb504emarcel/* ``struct ui_file'' implementation that maps onto two ui-file objects.  */
526ddb504emarcel
527ddb504emarcelstatic ui_file_write_ftype tee_file_write;
528ddb504emarcelstatic ui_file_fputs_ftype tee_file_fputs;
529ddb504emarcelstatic ui_file_isatty_ftype tee_file_isatty;
530ddb504emarcelstatic ui_file_delete_ftype tee_file_delete;
531ddb504emarcelstatic ui_file_flush_ftype tee_file_flush;
532ddb504emarcel
533ddb504emarcelstatic int tee_file_magic;
534ddb504emarcel
535ddb504emarcelstruct tee_file
536ddb504emarcel  {
537ddb504emarcel    int *magic;
538ddb504emarcel    struct ui_file *one, *two;
539ddb504emarcel    int close_one, close_two;
540ddb504emarcel  };
541ddb504emarcel
542ddb504emarcelstruct ui_file *
543ddb504emarceltee_file_new (struct ui_file *one, int close_one,
544ddb504emarcel	      struct ui_file *two, int close_two)
545ddb504emarcel{
546ddb504emarcel  struct ui_file *ui_file = ui_file_new ();
547ddb504emarcel  struct tee_file *tee = xmalloc (sizeof (struct tee_file));
548ddb504emarcel  tee->magic = &tee_file_magic;
549ddb504emarcel  tee->one = one;
550ddb504emarcel  tee->two = two;
551ddb504emarcel  tee->close_one = close_one;
552ddb504emarcel  tee->close_two = close_two;
553ddb504emarcel  set_ui_file_data (ui_file, tee, tee_file_delete);
554ddb504emarcel  set_ui_file_flush (ui_file, tee_file_flush);
555ddb504emarcel  set_ui_file_write (ui_file, tee_file_write);
556ddb504emarcel  set_ui_file_fputs (ui_file, tee_file_fputs);
557ddb504emarcel  set_ui_file_isatty (ui_file, tee_file_isatty);
558ddb504emarcel  return ui_file;
559ddb504emarcel}
560ddb504emarcel
561ddb504emarcelstatic void
562ddb504emarceltee_file_delete (struct ui_file *file)
563ddb504emarcel{
564ddb504emarcel  struct tee_file *tee = ui_file_data (file);
565ddb504emarcel  if (tee->magic != &tee_file_magic)
566ddb504emarcel    internal_error (__FILE__, __LINE__,
567ddb504emarcel		    "tee_file_delete: bad magic number");
568ddb504emarcel  if (tee->close_one)
569ddb504emarcel    ui_file_delete (tee->one);
570ddb504emarcel  if (tee->close_two)
571ddb504emarcel    ui_file_delete (tee->two);
572ddb504emarcel
573ddb504emarcel  xfree (tee);
574ddb504emarcel}
575ddb504emarcel
576ddb504emarcelstatic void
577ddb504emarceltee_file_flush (struct ui_file *file)
578ddb504emarcel{
579ddb504emarcel  struct tee_file *tee = ui_file_data (file);
580ddb504emarcel  if (tee->magic != &tee_file_magic)
581ddb504emarcel    internal_error (__FILE__, __LINE__,
582ddb504emarcel		    "tee_file_flush: bad magic number");
583ddb504emarcel  tee->one->to_flush (tee->one);
584ddb504emarcel  tee->two->to_flush (tee->two);
585ddb504emarcel}
586ddb504emarcel
587ddb504emarcelstatic void
588ddb504emarceltee_file_write (struct ui_file *file, const char *buf, long length_buf)
589ddb504emarcel{
590ddb504emarcel  struct tee_file *tee = ui_file_data (file);
591ddb504emarcel  if (tee->magic != &tee_file_magic)
592ddb504emarcel    internal_error (__FILE__, __LINE__,
593ddb504emarcel		    "tee_file_write: bad magic number");
594ddb504emarcel  ui_file_write (tee->one, buf, length_buf);
595ddb504emarcel  ui_file_write (tee->two, buf, length_buf);
596ddb504emarcel}
597ddb504emarcel
598ddb504emarcelstatic void
599ddb504emarceltee_file_fputs (const char *linebuffer, struct ui_file *file)
600ddb504emarcel{
601ddb504emarcel  struct tee_file *tee = ui_file_data (file);
602ddb504emarcel  if (tee->magic != &tee_file_magic)
603ddb504emarcel    internal_error (__FILE__, __LINE__,
604ddb504emarcel		    "tee_file_fputs: bad magic number");
605ddb504emarcel  tee->one->to_fputs (linebuffer, tee->one);
606ddb504emarcel  tee->two->to_fputs (linebuffer, tee->two);
607ddb504emarcel}
608ddb504emarcel
609ddb504emarcelstatic int
610ddb504emarceltee_file_isatty (struct ui_file *file)
611ddb504emarcel{
612ddb504emarcel  struct tee_file *tee = ui_file_data (file);
613ddb504emarcel  if (tee->magic != &tee_file_magic)
614ddb504emarcel    internal_error (__FILE__, __LINE__,
615ddb504emarcel		    "tee_file_isatty: bad magic number");
616ddb504emarcel  return (0);
617ddb504emarcel}
618