Formerly ../stdio/obstream.c.~3~
[kopensolaris-gnu/glibc.git] / stdio / obstream.c
1 /* Copyright (C) 1992 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public License as
6 published by the Free Software Foundation; either version 2 of the
7 License, or (at your option) any later version.
8
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public
15 License along with the GNU C Library; see the file COPYING.LIB.  If
16 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
17 Cambridge, MA 02139, USA.  */
18
19 #include <ansidecl.h>
20 #include <stdio.h>
21 #include <obstack.h>
22 #include <stdarg.h>
23
24 /* Output-room function for obstack streams.  */
25
26 static void
27 DEFUN(grow, (stream, c), FILE *stream AND int c)
28 {
29   struct obstack *const obstack = (struct obstack *) stream->__cookie;
30
31   /* Move the end of the object back to include only the portion
32      of the buffer which the user has already written into.  */ 
33   obstack_blank_fast (obstack, - (stream->__put_limit - stream->__bufp));
34
35   if (stream->__target > obstack_object_size (obstack))
36     {
37       /* Our target (where the buffer maps to) is always zero except when
38          the user just did a SEEK_END fseek.  If he sought within the
39          buffer, we need do nothing and will zero the target below.  If he
40          sought past the end of the object, grow and zero-fill the object
41          up to the target address.  */
42
43       obstack_blank (obstack,
44                      stream->__target - obstack_object_size (obstack));
45       /* fseek has just flushed us, so the put limit points
46          to the end of the written data.  */
47       bzero (stream->__put_limit,
48              stream->__target - stream->__bufsize);
49     }
50
51   if (c != EOF)
52     obstack_1grow (obstack, (unsigned char) c);
53
54   /* The stream buffer always maps exactly to the object on the top
55      of the obstack.  The start of the buffer is the start of the object.
56      The put limit points just past the end of the object.  On fflush, the
57      obstack is sync'd so the end of the object points just past the last
58      character written to the stream.  */
59
60   stream->__target = stream->__offset = 0;
61   stream->__buffer = obstack_base (obstack);
62   stream->__bufsize = obstack_room (obstack);
63   stream->__bufp = obstack_next_free (obstack);
64   stream->__get_limit = stream->__bufp;
65
66   if (c == EOF)
67     /* This is fflush.  Make the stream buffer, the object,
68        and the characters actually written all match.  */
69     stream->__put_limit = stream->__get_limit;
70   else
71     {
72       /* Extend the buffer (and the object) to include
73          the rest of the obstack chunk (which is unitialized).
74          Data past bufp is undefined.  */
75       stream->__put_limit = stream->__buffer + stream->__bufsize;
76       obstack_blank_fast (obstack, stream->__put_limit - stream->__bufp);
77     }
78 }
79
80 /* Seek function for obstack streams.
81    There is no external state to munge.  */
82
83 static int
84 DEFUN(seek, (cookie, pos, whence),
85       PTR cookie AND fpos_t *pos AND int whence)
86 {
87   switch (whence)
88     {
89     case SEEK_SET:
90     case SEEK_CUR:
91       return 0;
92
93     case SEEK_END:
94       /* Return the position relative to the end of the object.
95          fseek has just flushed us, so the obstack is consistent.  */
96       *pos += obstack_object_size ((struct obstack *) cookie);
97       return 0;
98
99     default:
100       __libc_fatal ("obstream::seek called with bogus WHENCE\n");
101       return -1;
102     }
103 }
104 \f
105 /* Initialize STREAM to talk to OBSTACK.  */
106
107 static void
108 DEFUN(init_obstream, (stream, obstack),
109       FILE *stream AND struct obstack *obstack)
110 {
111   stream->__mode.__write = 1;
112   stream->__mode.__read = 1;
113
114   /* Input gets EOF.  */
115   stream->__room_funcs.__input = NULL;
116
117   /* Do nothing for close.  */
118   stream->__io_funcs.__close = NULL;
119
120   /* When the buffer is full, grow the obstack.  */
121   stream->__room_funcs.__output = grow;
122
123   /* Seek within the object, and extend it.  */
124   stream->__io_funcs.__seek = seek;
125   stream->__target = stream->__offset = 0;
126
127   stream->__seen = 1;
128
129   /* Don't deallocate that buffer!  */
130   stream->__userbuf = 1;
131
132   /* We don't have to initialize the buffer.
133      The first read attempt will call grow, which will do all the work.  */
134
135   return stream;
136 }
137
138 FILE *
139 open_obstack_stream (obstack)
140      struct obstack *obstack;
141 {
142   register FILE *stream;
143
144   stream = __newstream ();
145   if (stream == NULL)
146     return NULL;
147
148   init_obstream (stream, obstack);
149   return stream;
150 }
151
152 int
153 DEFUN(obstack_vprintf, (obstack, format, args),
154       struct obstack *obstack AND const char *format AND va_list args)
155 {
156   FILE f;
157   memset (&f, 0, sizeof (f));
158   init_obstream (&f, obstack);
159   return vfprintf (&f, format, args);
160 }
161
162 int
163 DEFUN(obstack_printf, (obstack, format),
164       struct obstack *obstack AND const char *format DOTS)
165 {
166   int result;
167   va_list ap;
168   va_start (ap, format);
169   result = obstack_vprintf (obstack, format, ap);
170   va_end (ap);
171   return result;
172 }