This commit was generated by cvs2svn to track changes on a CVS vendor
[external/binutils.git] / gdb / ui-file.c
1 /* UI_FILE - a generic STDIO like output stream.
2    Copyright (C) 1999, 2000 Free Software Foundation, Inc.
3
4    This file is part of GDB.
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 59 Temple Place - Suite 330,
19    Boston, MA 02111-1307, USA.  */
20
21 /* Implement the ``struct ui_file'' object. */
22
23 #include "defs.h"
24 #include "ui-file.h"
25 #include "gdb_string.h"
26
27 #undef XMALLOC
28 #define XMALLOC(TYPE) ((TYPE*) xmalloc (sizeof (TYPE)))
29
30 static ui_file_isatty_ftype null_file_isatty;
31 static ui_file_write_ftype null_file_write;
32 static ui_file_fputs_ftype null_file_fputs;
33 static ui_file_flush_ftype null_file_flush;
34 static ui_file_delete_ftype null_file_delete;
35 static ui_file_rewind_ftype null_file_rewind;
36 static ui_file_put_ftype null_file_put;
37
38 struct ui_file
39   {
40     int *magic;
41     ui_file_flush_ftype *to_flush;
42     ui_file_write_ftype *to_write;
43     ui_file_fputs_ftype *to_fputs;
44     ui_file_delete_ftype *to_delete;
45     ui_file_isatty_ftype *to_isatty;
46     ui_file_rewind_ftype *to_rewind;
47     ui_file_put_ftype *to_put;
48     void *to_data;
49   };
50 int ui_file_magic;
51
52 struct ui_file *
53 ui_file_new ()
54 {
55   struct ui_file *file = xmalloc (sizeof (struct ui_file));
56   file->magic = &ui_file_magic;
57   set_ui_file_data (file, NULL, null_file_delete);
58   set_ui_file_flush (file, null_file_flush);
59   set_ui_file_write (file, null_file_write);
60   set_ui_file_fputs (file, null_file_fputs);
61   set_ui_file_isatty (file, null_file_isatty);
62   set_ui_file_rewind (file, null_file_rewind);
63   set_ui_file_put (file, null_file_put);
64   return file;
65 }
66
67 void
68 ui_file_delete (file)
69      struct ui_file *file;
70 {
71   file->to_delete (file);
72   free (file);
73 }
74
75 static int
76 null_file_isatty (file)
77      struct ui_file *file;
78 {
79   return 0;
80 }
81
82 static void
83 null_file_rewind (file)
84      struct ui_file *file;
85 {
86   return;
87 }
88
89 static void
90 null_file_put (struct ui_file *file,
91                ui_file_put_method_ftype *write,
92                void *dest)
93 {
94   return;
95 }
96
97 static void
98 null_file_flush (file)
99      struct ui_file *file;
100 {
101   return;
102 }
103
104 static void
105 null_file_write (struct ui_file *file,
106                  const char *buf,
107                  long sizeof_buf)
108 {
109   if (file->to_fputs == null_file_fputs)
110     /* Both the write and fputs methods are null. Discard the
111        request. */
112     return;
113   else
114     {
115       /* The fputs method isn't null, slowly pass the write request
116          onto that.  FYI, this isn't as bad as it may look - the
117          current (as of 1999-11-07) printf_* function calls fputc and
118          fputc does exactly the below.  By having a write function it
119          is possible to clean up that code.  */
120       int i;
121       char b[2];
122       b[1] = '\0';
123       for (i = 0; i < sizeof_buf; i++)
124         {
125           b[0] = buf[i];
126           file->to_fputs (b, file);
127         }
128       return;
129     }
130 }
131
132 static void
133 null_file_fputs (buf, file)
134      const char *buf;
135      struct ui_file *file;
136 {
137   if (file->to_write == null_file_write)
138     /* Both the write and fputs methods are null. Discard the
139        request. */
140     return;
141   else
142     {
143       /* The write method was implemented, use that. */
144       file->to_write (file, buf, strlen (buf));
145     }
146 }
147
148 static void
149 null_file_delete (file)
150      struct ui_file *file;
151 {
152   return;
153 }
154
155 void *
156 ui_file_data (file)
157      struct ui_file *file;
158 {
159   if (file->magic != &ui_file_magic)
160     internal_error ("ui_file_data: bad magic number");
161   return file->to_data;
162 }
163
164 void
165 gdb_flush (file)
166      struct ui_file *file;
167 {
168   file->to_flush (file);
169 }
170
171 int
172 ui_file_isatty (file)
173      struct ui_file *file;
174 {
175   return file->to_isatty (file);
176 }
177
178 void
179 ui_file_rewind (file)
180      struct ui_file *file;
181 {
182   file->to_rewind (file);
183 }
184
185 void
186 ui_file_put (struct ui_file *file,
187               ui_file_put_method_ftype *write,
188               void *dest)
189 {
190   file->to_put (file, write, dest);
191 }
192
193 void
194 ui_file_write (struct ui_file *file,
195                 const char *buf,
196                 long length_buf)
197 {
198   file->to_write (file, buf, length_buf);
199 }
200
201 void
202 fputs_unfiltered (buf, file)
203      const char *buf;
204      struct ui_file *file;
205 {
206   file->to_fputs (buf, file);
207 }
208
209 void
210 set_ui_file_flush (file, flush)
211      struct ui_file *file;
212      ui_file_flush_ftype *flush;
213 {
214   file->to_flush = flush;
215 }
216
217 void
218 set_ui_file_isatty (file, isatty)
219      struct ui_file *file;
220      ui_file_isatty_ftype *isatty;
221 {
222   file->to_isatty = isatty;
223 }
224
225 void
226 set_ui_file_rewind (file, rewind)
227      struct ui_file *file;
228      ui_file_rewind_ftype *rewind;
229 {
230   file->to_rewind = rewind;
231 }
232
233 void
234 set_ui_file_put (file, put)
235      struct ui_file *file;
236      ui_file_put_ftype *put;
237 {
238   file->to_put = put;
239 }
240
241 void
242 set_ui_file_write (struct ui_file *file,
243                     ui_file_write_ftype *write)
244 {
245   file->to_write = write;
246 }
247
248 void
249 set_ui_file_fputs (file, fputs)
250      struct ui_file *file;
251      ui_file_fputs_ftype *fputs;
252 {
253   file->to_fputs = fputs;
254 }
255
256 void
257 set_ui_file_data (file, data, delete)
258      struct ui_file *file;
259      void *data;
260      ui_file_delete_ftype *delete;
261 {
262   file->to_data = data;
263   file->to_delete = delete;
264 }
265
266 /* ui_file utility function for converting a ``struct ui_file'' into
267    a memory buffer''. */
268
269 struct accumulated_ui_file
270 {
271   char *buffer;
272   long length;
273 };
274
275 static void
276 do_ui_file_xstrdup (void *context, const char *buffer, long length)
277 {
278   struct accumulated_ui_file *acc = context;
279   if (acc->buffer == NULL)
280     acc->buffer = xmalloc (length + 1);
281   else
282     acc->buffer = xrealloc (acc->buffer, acc->length + length + 1);
283   memcpy (acc->buffer + acc->length, buffer, length);
284   acc->length += length;
285   acc->buffer[acc->length] = '\0';
286 }
287
288 char *
289 ui_file_xstrdup (struct ui_file *file,
290                   long *length)
291 {
292   struct accumulated_ui_file acc;
293   acc.buffer = NULL;
294   acc.length = 0;
295   ui_file_put (file, do_ui_file_xstrdup, &acc);
296   if (acc.buffer == NULL)
297     acc.buffer = xstrdup ("");
298   *length = acc.length;
299   return acc.buffer;
300 }
301 \f
302 /* A pure memory based ``struct ui_file'' that can be used an output
303    buffer. The buffers accumulated contents are available via
304    ui_file_put(). */
305
306 struct mem_file
307   {
308     int *magic;
309     char *buffer;
310     int sizeof_buffer;
311     int length_buffer;
312   };
313
314 static ui_file_rewind_ftype mem_file_rewind;
315 static ui_file_put_ftype mem_file_put;
316 static ui_file_write_ftype mem_file_write;
317 static ui_file_delete_ftype mem_file_delete;
318 static struct ui_file *mem_file_new (void);
319 static int mem_file_magic;
320
321 static struct ui_file *
322 mem_file_new (void)
323 {
324   struct mem_file *stream = XMALLOC (struct mem_file);
325   struct ui_file *file = ui_file_new ();
326   set_ui_file_data (file, stream, mem_file_delete);
327   set_ui_file_rewind (file, mem_file_rewind);
328   set_ui_file_put (file, mem_file_put);
329   set_ui_file_write (file, mem_file_write);
330   stream->magic = &mem_file_magic;
331   stream->buffer = NULL;
332   stream->sizeof_buffer = 0;
333   stream->length_buffer = 0;
334   return file;
335 }
336
337 static void
338 mem_file_delete (struct ui_file *file)
339 {
340   struct mem_file *stream = ui_file_data (file);
341   if (stream->magic != &mem_file_magic)
342     internal_error ("mem_file_delete: bad magic number");
343   if (stream->buffer != NULL)
344     free (stream->buffer);
345   free (stream);
346 }
347
348 struct ui_file *
349 mem_fileopen (void)
350 {
351   return mem_file_new ();
352 }
353
354 static void
355 mem_file_rewind (struct ui_file *file)
356 {
357   struct mem_file *stream = ui_file_data (file);
358   if (stream->magic != &mem_file_magic)
359     internal_error ("mem_file_rewind: bad magic number");
360   stream->length_buffer = 0;
361 }
362
363 static void
364 mem_file_put (struct ui_file *file,
365               ui_file_put_method_ftype *write,
366               void *dest)
367 {
368   struct mem_file *stream = ui_file_data (file);
369   if (stream->magic != &mem_file_magic)
370     internal_error ("mem_file_put: bad magic number");
371   if (stream->length_buffer > 0)
372     write (dest, stream->buffer, stream->length_buffer);
373 }
374
375 void
376 mem_file_write (struct ui_file *file,
377                 const char *buffer,
378                 long length_buffer)
379 {
380   struct mem_file *stream = ui_file_data (file);
381   if (stream->magic != &mem_file_magic)
382     internal_error ("mem_file_write: bad magic number");
383   if (stream->buffer == NULL)
384     {
385       stream->length_buffer = length_buffer;
386       stream->sizeof_buffer = length_buffer;
387       stream->buffer = xmalloc (stream->sizeof_buffer);
388       memcpy (stream->buffer, buffer, length_buffer);
389     }
390   else
391     {
392       int new_length = stream->length_buffer + length_buffer;
393       if (new_length >= stream->sizeof_buffer)
394         {
395           stream->sizeof_buffer = new_length;
396           stream->buffer = xrealloc (stream->buffer, stream->sizeof_buffer);
397         }
398       memcpy (stream->buffer + stream->length_buffer, buffer, length_buffer);
399       stream->length_buffer = new_length;
400     }
401 }
402 \f
403 /* ``struct ui_file'' implementation that maps directly onto
404    <stdio.h>'s FILE. */
405
406 static ui_file_write_ftype stdio_file_write;
407 static ui_file_fputs_ftype stdio_file_fputs;
408 static ui_file_isatty_ftype stdio_file_isatty;
409 static ui_file_delete_ftype stdio_file_delete;
410 static struct ui_file *stdio_file_new (FILE * file, int close_p);
411 static ui_file_flush_ftype stdio_file_flush;
412
413 static int stdio_file_magic;
414
415 struct stdio_file
416   {
417     int *magic;
418     FILE *file;
419     int close_p;
420   };
421
422 static struct ui_file *
423 stdio_file_new (file, close_p)
424      FILE *file;
425      int close_p;
426 {
427   struct ui_file *ui_file = ui_file_new ();
428   struct stdio_file *stdio = xmalloc (sizeof (struct stdio_file));
429   stdio->magic = &stdio_file_magic;
430   stdio->file = file;
431   stdio->close_p = close_p;
432   set_ui_file_data (ui_file, stdio, stdio_file_delete);
433   set_ui_file_flush (ui_file, stdio_file_flush);
434   set_ui_file_write (ui_file, stdio_file_write);
435   set_ui_file_fputs (ui_file, stdio_file_fputs);
436   set_ui_file_isatty (ui_file, stdio_file_isatty);
437   return ui_file;
438 }
439
440 static void
441 stdio_file_delete (file)
442      struct ui_file *file;
443 {
444   struct stdio_file *stdio = ui_file_data (file);
445   if (stdio->magic != &stdio_file_magic)
446     internal_error ("stdio_file_delete: bad magic number");
447   if (stdio->close_p)
448     {
449       fclose (stdio->file);
450     }
451   free (stdio);
452 }
453
454 static void
455 stdio_file_flush (file)
456      struct ui_file *file;
457 {
458   struct stdio_file *stdio = ui_file_data (file);
459   if (stdio->magic != &stdio_file_magic)
460     internal_error ("stdio_file_flush: bad magic number");
461   fflush (stdio->file);
462 }
463
464 static void
465 stdio_file_write (struct ui_file *file, const char *buf, long length_buf)
466 {
467   struct stdio_file *stdio = ui_file_data (file);
468   if (stdio->magic != &stdio_file_magic)
469     internal_error ("stdio_file_write: bad magic number");
470   fwrite (buf, length_buf, 1, stdio->file);
471 }
472
473 static void
474 stdio_file_fputs (linebuffer, file)
475      const char *linebuffer;
476      struct ui_file *file;
477 {
478   struct stdio_file *stdio = ui_file_data (file);
479   if (stdio->magic != &stdio_file_magic)
480     internal_error ("stdio_file_fputs: bad magic number");
481   fputs (linebuffer, stdio->file);
482 }
483
484 static int
485 stdio_file_isatty (file)
486      struct ui_file *file;
487 {
488   struct stdio_file *stdio = ui_file_data (file);
489   if (stdio->magic != &stdio_file_magic)
490     internal_error ("stdio_file_isatty: bad magic number");
491   return (isatty (fileno (stdio->file)));
492 }
493
494 /* Like fdopen().  Create a ui_file from a previously opened FILE. */
495
496 struct ui_file *
497 stdio_fileopen (file)
498      FILE *file;
499 {
500   return stdio_file_new (file, 0);
501 }
502
503 struct ui_file *
504 gdb_fopen (name, mode)
505      char *name;
506      char *mode;
507 {
508   FILE *f = fopen (name, mode);
509   if (f == NULL)
510     return NULL;
511   return stdio_file_new (f, 1);
512 }