Home | History | Annotate | Download | only in src
      1 /**
      2  * \file output.c
      3  * \brief Generic stdio-like output interface
      4  * \author Abramo Bagnara <abramo (at) 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 (at) 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_TYPE_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 
    381