Initial Import
[profile/ivi/alsa-lib.git] / src / output.c
1 /**
2  * \file output.c
3  * \brief Generic stdio-like output interface
4  * \author Abramo Bagnara <abramo@alsa-project.org>
5  * \date 2000
6  *
7  * Generic stdio-like output interface
8  */
9 /*
10  *  Output object
11  *  Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
12  *
13  *
14  *   This library is free software; you can redistribute it and/or modify
15  *   it under the terms of the GNU Lesser General Public License as
16  *   published by the Free Software Foundation; either version 2.1 of
17  *   the License, or (at your option) any later version.
18  *
19  *   This program is distributed in the hope that it will be useful,
20  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
21  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  *   GNU Lesser General Public License for more details.
23  *
24  *   You should have received a copy of the GNU Lesser General Public
25  *   License along with this library; if not, write to the Free Software
26  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
27  *
28  */
29
30 #include <stdarg.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include "local.h"
35
36 #ifndef DOC_HIDDEN
37 typedef struct _snd_output_ops {
38         int (*close)(snd_output_t *output);
39         int (*print)(snd_output_t *output, const char *format, va_list args);
40         int (*puts)(snd_output_t *output, const char *str);
41         int (*putch)(snd_output_t *output, int c);
42         int (*flush)(snd_output_t *output);
43 } snd_output_ops_t;
44
45 struct _snd_output {
46         snd_output_type_t type;
47         const snd_output_ops_t *ops;
48         void *private_data;
49 };
50 #endif
51
52 /**
53  * \brief Closes an output handle.
54  * \param output The output handle to be closed.
55  * \return Zero if successful, otherwise a negative error code.
56  */
57 int snd_output_close(snd_output_t *output)
58 {
59         int err = output->ops->close(output);
60         free(output);
61         return err;
62 }
63
64 /**
65  * \brief Writes formatted output (like \c fprintf(3)) to an output handle.
66  * \param output The output handle.
67  * \param format Format string in \c fprintf format.
68  * \param ... Other \c fprintf arguments.
69  * \return The number of characters written, or a negative error code.
70  */
71 int snd_output_printf(snd_output_t *output, const char *format, ...)
72 {
73         int result;
74         va_list args;
75         va_start(args, format);
76         result = output->ops->print(output, format, args);
77         va_end(args);
78         return result;
79 }
80
81 /**
82  * \brief Writes formatted output (like \c fprintf(3)) to an output handle.
83  * \param output The output handle.
84  * \param format Format string in \c fprintf format.
85  * \param args Other \c fprintf arguments.
86  * \return The number of characters written, or a negative error code.
87  */
88 int snd_output_vprintf(snd_output_t *output, const char *format, va_list args)
89 {
90         return output->ops->print(output, format, args);
91 }
92
93 /**
94  * \brief Writes a string to an output handle (like \c fputs(3)).
95  * \param output The output handle.
96  * \param str Pointer to the string.
97  * \return Zero if successful, otherwise a negative error code or \c EOF.
98  */
99 int snd_output_puts(snd_output_t *output, const char *str)
100 {
101         return output->ops->puts(output, str);
102 }
103                         
104 /**
105  * \brief Writes a character to an output handle (like \c putc(3)).
106  * \param output The output handle.
107  * \param c The character.
108  * \return Zero if successful, otherwise a negative error code or \c EOF.
109  */
110 int snd_output_putc(snd_output_t *output, int c)
111 {
112         return output->ops->putch(output, c);
113 }
114
115 /**
116  * \brief Flushes an output handle (like fflush(3)).
117  * \param output The output handle.
118  * \return Zero if successful, otherwise \c EOF.
119  *
120  * If the underlying destination is a stdio stream, this function calls
121  * \c fflush. If the underlying destination is a memory buffer, the write
122  * position is reset to the beginning of the buffer. \c =:-o
123  */
124 int snd_output_flush(snd_output_t *output)
125 {
126         return output->ops->flush(output);
127 }
128
129 #ifndef DOC_HIDDEN
130 typedef struct _snd_output_stdio {
131         int close;
132         FILE *fp;
133 } snd_output_stdio_t;
134
135 static int snd_output_stdio_close(snd_output_t *output)
136 {
137         snd_output_stdio_t *stdio = output->private_data;
138         if (stdio->close)
139                 fclose(stdio->fp);
140         free(stdio);
141         return 0;
142 }
143
144 static int snd_output_stdio_print(snd_output_t *output, const char *format, va_list args)
145 {
146         snd_output_stdio_t *stdio = output->private_data;
147         return vfprintf(stdio->fp, format, args);
148 }
149
150 static int snd_output_stdio_puts(snd_output_t *output, const char *str)
151 {
152         snd_output_stdio_t *stdio = output->private_data;
153         return fputs(str, stdio->fp);
154 }
155                         
156 static int snd_output_stdio_putc(snd_output_t *output, int c)
157 {
158         snd_output_stdio_t *stdio = output->private_data;
159         return putc(c, stdio->fp);
160 }
161
162 static int snd_output_stdio_flush(snd_output_t *output)
163 {
164         snd_output_stdio_t *stdio = output->private_data;
165         return fflush(stdio->fp);
166 }
167
168 static const snd_output_ops_t snd_output_stdio_ops = {
169         .close          = snd_output_stdio_close,
170         .print          = snd_output_stdio_print,
171         .puts           = snd_output_stdio_puts,
172         .putch          = snd_output_stdio_putc,
173         .flush          = snd_output_stdio_flush,
174 };
175
176 #endif
177
178 /**
179  * \brief Creates a new output object using an existing stdio \c FILE pointer.
180  * \param outputp The function puts the pointer to the new output object
181  *                at the address specified by \p outputp.
182  * \param fp The \c FILE pointer to write to. Characters are written
183  *           to the file starting at the current file position.
184  * \param _close Close flag. Set this to 1 if #snd_output_close should close
185  *              \p fp by calling \c fclose.
186  * \return Zero if successful, otherwise a negative error code.
187  */
188 int snd_output_stdio_attach(snd_output_t **outputp, FILE *fp, int _close)
189 {
190         snd_output_t *output;
191         snd_output_stdio_t *stdio;
192         assert(outputp && fp);
193         stdio = calloc(1, sizeof(*stdio));
194         if (!stdio)
195                 return -ENOMEM;
196         output = calloc(1, sizeof(*output));
197         if (!output) {
198                 free(stdio);
199                 return -ENOMEM;
200         }
201         stdio->fp = fp;
202         stdio->close = _close;
203         output->type = SND_OUTPUT_STDIO;
204         output->ops = &snd_output_stdio_ops;
205         output->private_data = stdio;
206         *outputp = output;
207         return 0;
208 }
209         
210 /**
211  * \brief Creates a new output object writing to a file.
212  * \param outputp The function puts the pointer to the new output object
213  *                at the address specified by \p outputp.
214  * \param file The name of the file to open.
215  * \param mode The open mode, like \c fopen(3).
216  * \return Zero if successful, otherwise a negative error code.
217  */
218 int snd_output_stdio_open(snd_output_t **outputp, const char *file, const char *mode)
219 {
220         int err;
221         FILE *fp = fopen(file, mode);
222         if (!fp) {
223                 //SYSERR("fopen");
224                 return -errno;
225         }
226         err = snd_output_stdio_attach(outputp, fp, 1);
227         if (err < 0)
228                 fclose(fp);
229         return err;
230 }
231
232 #ifndef DOC_HIDDEN
233
234 typedef struct _snd_output_buffer {
235         unsigned char *buf;
236         size_t alloc;
237         size_t size;
238 } snd_output_buffer_t;
239
240 static int snd_output_buffer_close(snd_output_t *output)
241 {
242         snd_output_buffer_t *buffer = output->private_data;
243         free(buffer->buf);
244         free(buffer);
245         return 0;
246 }
247
248 static int snd_output_buffer_need(snd_output_t *output, size_t size)
249 {
250         snd_output_buffer_t *buffer = output->private_data;
251         size_t _free = buffer->alloc - buffer->size;
252         size_t alloc;
253         unsigned char *buf;
254
255         if (_free >= size)
256                 return _free;
257         if (buffer->alloc == 0)
258                 alloc = 256;
259         else
260                 alloc = buffer->alloc;
261         while (alloc < buffer->size + size)
262                 alloc *= 2;
263         buf = realloc(buffer->buf, alloc);
264         if (!buf)
265                 return -ENOMEM;
266         buffer->buf = buf;
267         buffer->alloc = alloc;
268         return buffer->alloc - buffer->size;
269 }
270
271 static int snd_output_buffer_print(snd_output_t *output, const char *format, va_list args)
272 {
273         snd_output_buffer_t *buffer = output->private_data;
274         size_t size = 256;
275         int result;
276         result = snd_output_buffer_need(output, size);
277         if (result < 0)
278                 return result;
279         result = vsnprintf((char *)buffer->buf + buffer->size, size, format, args);
280         assert(result >= 0);
281         if ((size_t)result <= size) {
282                 buffer->size += result;
283                 return result;
284         }
285         size = result;
286         result = snd_output_buffer_need(output, size);
287         if (result < 0)
288                 return result;
289         result = vsnprintf((char *)buffer->buf + buffer->size, result, format, args);
290         assert(result == (int)size);
291         buffer->size += result;
292         return result;
293 }
294
295 static int snd_output_buffer_puts(snd_output_t *output, const char *str)
296 {
297         snd_output_buffer_t *buffer = output->private_data;
298         size_t size = strlen(str);
299         int err;
300         err = snd_output_buffer_need(output, size);
301         if (err < 0)
302                 return err;
303         memcpy(buffer->buf + buffer->size, str, size);
304         buffer->size += size;
305         return size;
306 }
307                         
308 static int snd_output_buffer_putc(snd_output_t *output, int c)
309 {
310         snd_output_buffer_t *buffer = output->private_data;
311         int err;
312         err = snd_output_buffer_need(output, 1);
313         if (err < 0)
314                 return err;
315         buffer->buf[buffer->size++] = c;
316         return 0;
317 }
318
319 static int snd_output_buffer_flush(snd_output_t *output ATTRIBUTE_UNUSED)
320 {
321         snd_output_buffer_t *buffer = output->private_data;
322         buffer->size = 0;
323         return 0;
324 }
325
326 static const snd_output_ops_t snd_output_buffer_ops = {
327         .close          = snd_output_buffer_close,
328         .print          = snd_output_buffer_print,
329         .puts           = snd_output_buffer_puts,
330         .putch          = snd_output_buffer_putc,
331         .flush          = snd_output_buffer_flush,
332 };
333 #endif
334
335 /**
336  * \brief Returns the address of the buffer of a #SND_OUTPUT_BUFFER output handle.
337  * \param output The output handle.
338  * \param buf The functions puts the current address of the buffer at the
339  *            address specified by \p buf.
340  * \return The current size of valid data in the buffer.
341  *
342  * The address of the buffer may become invalid when output functions or
343  * #snd_output_close are called.
344  */
345 size_t snd_output_buffer_string(snd_output_t *output, char **buf)
346 {
347         snd_output_buffer_t *buffer = output->private_data;
348         *buf = (char *)buffer->buf;
349         return buffer->size;
350 }
351
352 /**
353  * \brief Creates a new output object with an auto-extending memory buffer.
354  * \param outputp The function puts the pointer to the new output object
355  *                at the address specified by \p outputp.
356  * \return Zero if successful, otherwise a negative error code.
357  */
358 int snd_output_buffer_open(snd_output_t **outputp)
359 {
360         snd_output_t *output;
361         snd_output_buffer_t *buffer;
362         assert(outputp);
363         buffer = calloc(1, sizeof(*buffer));
364         if (!buffer)
365                 return -ENOMEM;
366         output = calloc(1, sizeof(*output));
367         if (!output) {
368                 free(buffer);
369                 return -ENOMEM;
370         }
371         buffer->buf = NULL;
372         buffer->alloc = 0;
373         buffer->size = 0;
374         output->type = SND_OUTPUT_BUFFER;
375         output->ops = &snd_output_buffer_ops;
376         output->private_data = buffer;
377         *outputp = output;
378         return 0;
379 }
380