summaryrefslogtreecommitdiff
path: root/lib/libsalsa/output.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libsalsa/output.c')
-rw-r--r--lib/libsalsa/output.c411
1 files changed, 411 insertions, 0 deletions
diff --git a/lib/libsalsa/output.c b/lib/libsalsa/output.c
new file mode 100644
index 0000000..0369a81
--- /dev/null
+++ b/lib/libsalsa/output.c
@@ -0,0 +1,411 @@
+/**
+ * \file output.c
+ * \brief Generic stdio-like output interface
+ * \author Abramo Bagnara <abramo@alsa-project.org>
+ * \date 2000
+ *
+ * Generic stdio-like output interface
+ */
+/*
+ * Output object
+ * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
+ *
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "local.h"
+
+#ifndef DOC_HIDDEN
+typedef struct _snd_output_ops
+{
+ int (*close) (snd_output_t * output);
+ int (*print) (snd_output_t * output, const char *format, va_list args);
+ int (*puts) (snd_output_t * output, const char *str);
+ int (*putch) (snd_output_t * output, int c);
+ int (*flush) (snd_output_t * output);
+} snd_output_ops_t;
+
+struct _snd_output
+{
+ snd_output_type_t type;
+ snd_output_ops_t *ops;
+ void *private_data;
+};
+#endif
+
+/**
+ * \brief Closes an output handle.
+ * \param output The output handle to be closed.
+ * \return Zero if successful, otherwise a negative error code.
+ */
+int
+snd_output_close (snd_output_t * output)
+{
+ int err = output->ops->close (output);
+ free (output);
+ return err;
+}
+
+/**
+ * \brief Writes formatted output (like \c fprintf(3)) to an output handle.
+ * \param output The output handle.
+ * \param format Format string in \c fprintf format.
+ * \param ... Other \c fprintf arguments.
+ * \return The number of characters written, or a negative error code.
+ */
+int
+snd_output_printf (snd_output_t * output, const char *format, ...)
+{
+ int result;
+ va_list args;
+ va_start (args, format);
+ result = output->ops->print (output, format, args);
+ va_end (args);
+ return result;
+}
+
+/**
+ * \brief Writes formatted output (like \c fprintf(3)) to an output handle.
+ * \param output The output handle.
+ * \param format Format string in \c fprintf format.
+ * \param args Other \c fprintf arguments.
+ * \return The number of characters written, or a negative error code.
+ */
+int
+snd_output_vprintf (snd_output_t * output, const char *format, va_list args)
+{
+ return output->ops->print (output, format, args);
+}
+
+/**
+ * \brief Writes a string to an output handle (like \c fputs(3)).
+ * \param output The output handle.
+ * \param str Pointer to the string.
+ * \return Zero if successful, otherwise a negative error code or \c EOF.
+ */
+int
+snd_output_puts (snd_output_t * output, const char *str)
+{
+ return output->ops->puts (output, str);
+}
+
+/**
+ * \brief Writes a character to an output handle (like \c putc(3)).
+ * \param output The output handle.
+ * \param c The character.
+ * \return Zero if successful, otherwise a negative error code or \c EOF.
+ */
+int
+snd_output_putc (snd_output_t * output, int c)
+{
+ return output->ops->putch (output, c);
+}
+
+/**
+ * \brief Flushes an output handle (like fflush(3)).
+ * \param output The output handle.
+ * \return Zero if successful, otherwise \c EOF.
+ *
+ * If the underlying destination is a stdio stream, this function calls
+ * \c fflush. If the underlying destination is a memory buffer, the write
+ * position is reset to the beginning of the buffer. \c =:-o
+ */
+int
+snd_output_flush (snd_output_t * output)
+{
+ return output->ops->flush (output);
+}
+
+#ifndef DOC_HIDDEN
+typedef struct _snd_output_stdio
+{
+ int close;
+ FILE *fp;
+} snd_output_stdio_t;
+
+static int
+snd_output_stdio_close (snd_output_t * output ATTRIBUTE_UNUSED)
+{
+ snd_output_stdio_t *stdio = output->private_data;
+ if (stdio->close)
+ fclose (stdio->fp);
+ free (stdio);
+ return 0;
+}
+
+static int
+snd_output_stdio_print (snd_output_t * output, const char *format,
+ va_list args)
+{
+ snd_output_stdio_t *stdio = output->private_data;
+ return vfprintf (stdio->fp, format, args);
+}
+
+static int
+snd_output_stdio_puts (snd_output_t * output, const char *str)
+{
+ snd_output_stdio_t *stdio = output->private_data;
+ return fputs (str, stdio->fp);
+}
+
+static int
+snd_output_stdio_putc (snd_output_t * output, int c)
+{
+ snd_output_stdio_t *stdio = output->private_data;
+ return putc (c, stdio->fp);
+}
+
+static int
+snd_output_stdio_flush (snd_output_t * output)
+{
+ snd_output_stdio_t *stdio = output->private_data;
+ return fflush (stdio->fp);
+}
+
+static snd_output_ops_t snd_output_stdio_ops = {
+ .close = snd_output_stdio_close,
+ .print = snd_output_stdio_print,
+ .puts = snd_output_stdio_puts,
+ .putch = snd_output_stdio_putc,
+ .flush = snd_output_stdio_flush,
+};
+
+#endif
+
+/**
+ * \brief Creates a new output object using an existing stdio \c FILE pointer.
+ * \param outputp The function puts the pointer to the new output object
+ * at the address specified by \p outputp.
+ * \param fp The \c FILE pointer to write to. Characters are written
+ * to the file starting at the current file position.
+ * \param close Close flag. Set this to 1 if #snd_output_close should close
+ * \p fp by calling \c fclose.
+ * \return Zero if successful, otherwise a negative error code.
+ */
+int
+snd_output_stdio_attach (snd_output_t ** outputp, FILE * fp, int _close)
+{
+ snd_output_t *output;
+ snd_output_stdio_t *stdio;
+ assert (outputp && fp);
+ stdio = calloc (1, sizeof (*stdio));
+ if (!stdio)
+ return -ENOMEM;
+ output = calloc (1, sizeof (*output));
+ if (!output)
+ {
+ free (stdio);
+ return -ENOMEM;
+ }
+ stdio->fp = fp;
+ stdio->close = _close;
+ output->type = SND_OUTPUT_STDIO;
+ output->ops = &snd_output_stdio_ops;
+ output->private_data = stdio;
+ *outputp = output;
+ return 0;
+}
+
+/**
+ * \brief Creates a new output object writing to a file.
+ * \param outputp The function puts the pointer to the new output object
+ * at the address specified by \p outputp.
+ * \param file The name of the file to open.
+ * \param mode The open mode, like \c fopen(3).
+ * \return Zero if successful, otherwise a negative error code.
+ */
+int
+snd_output_stdio_open (snd_output_t ** outputp, const char *file,
+ const char *mode)
+{
+ int err;
+ FILE *fp = fopen (file, mode);
+ if (!fp)
+ {
+ //SYSERR("fopen");
+ return -errno;
+ }
+ err = snd_output_stdio_attach (outputp, fp, 1);
+ if (err < 0)
+ fclose (fp);
+ return err;
+}
+
+#ifndef DOC_HIDDEN
+
+typedef struct _snd_output_buffer
+{
+ unsigned char *buf;
+ size_t alloc;
+ size_t size;
+} snd_output_buffer_t;
+
+static int
+snd_output_buffer_close (snd_output_t * output ATTRIBUTE_UNUSED)
+{
+ snd_output_buffer_t *buffer = output->private_data;
+ free (buffer->buf);
+ free (buffer);
+ return 0;
+}
+
+static int
+snd_output_buffer_need (snd_output_t * output, size_t size)
+{
+ snd_output_buffer_t *buffer = output->private_data;
+ size_t _free = buffer->alloc - buffer->size;
+ size_t alloc;
+ unsigned char *buf;
+
+ if (_free >= size)
+ return _free;
+ if (buffer->alloc == 0)
+ alloc = 256;
+ else
+ alloc = buffer->alloc;
+ while (alloc < size)
+ alloc *= 2;
+ buf = realloc (buffer->buf, alloc);
+ if (!buf)
+ return -ENOMEM;
+ buffer->buf = buf;
+ buffer->alloc = alloc;
+ return buffer->alloc - buffer->size;
+}
+
+static int
+snd_output_buffer_print (snd_output_t * output, const char *format,
+ va_list args)
+{
+ snd_output_buffer_t *buffer = output->private_data;
+ size_t size = 256;
+ int result;
+ result = snd_output_buffer_need (output, size);
+ if (result < 0)
+ return result;
+ result = vsnprintf (buffer->buf + buffer->size, size, format, args);
+ assert (result >= 0);
+ if ((size_t) result <= size)
+ {
+ buffer->size += result;
+ return result;
+ }
+ size = result;
+ result = snd_output_buffer_need (output, size);
+ if (result < 0)
+ return result;
+ result = vsnprintf (buffer->buf + buffer->size, result, format, args);
+ assert (result == (int) size);
+ buffer->size += result;
+ return result;
+}
+
+static int
+snd_output_buffer_puts (snd_output_t * output, const char *str)
+{
+ snd_output_buffer_t *buffer = output->private_data;
+ size_t size = strlen (str);
+ int err;
+ err = snd_output_buffer_need (output, size);
+ if (err < 0)
+ return err;
+ memcpy (buffer->buf + buffer->size, str, size);
+ buffer->size += size;
+ return size;
+}
+
+static int
+snd_output_buffer_putc (snd_output_t * output, int c)
+{
+ snd_output_buffer_t *buffer = output->private_data;
+ int err;
+ err = snd_output_buffer_need (output, 1);
+ if (err < 0)
+ return err;
+ buffer->buf[buffer->size++] = c;
+ return 0;
+}
+
+static int
+snd_output_buffer_flush (snd_output_t * output ATTRIBUTE_UNUSED)
+{
+ snd_output_buffer_t *buffer = output->private_data;
+ buffer->size = 0;
+ return 0;
+}
+
+static snd_output_ops_t snd_output_buffer_ops = {
+ .close = snd_output_buffer_close,
+ .print = snd_output_buffer_print,
+ .puts = snd_output_buffer_puts,
+ .putch = snd_output_buffer_putc,
+ .flush = snd_output_buffer_flush,
+};
+#endif
+
+/**
+ * \brief Returns the address of the buffer of a #SND_OUTPUT_TYPE_BUFFER output handle.
+ * \param output The output handle.
+ * \param buf The functions puts the current address of the buffer at the
+ * address specified by \p buf.
+ * \return The current size of valid data in the buffer.
+ *
+ * The address of the buffer may become invalid when output functions or
+ * #snd_output_close are called.
+ */
+size_t
+snd_output_buffer_string (snd_output_t * output, char **buf)
+{
+ snd_output_buffer_t *buffer = output->private_data;
+ *buf = buffer->buf;
+ return buffer->size;
+}
+
+/**
+ * \brief Creates a new output object with an auto-extending memory buffer.
+ * \param outputp The function puts the pointer to the new output object
+ * at the address specified by \p outputp.
+ * \return Zero if successful, otherwise a negative error code.
+ */
+int
+snd_output_buffer_open (snd_output_t ** outputp)
+{
+ snd_output_t *output;
+ snd_output_buffer_t *buffer;
+ assert (outputp);
+ buffer = calloc (1, sizeof (*buffer));
+ if (!buffer)
+ return -ENOMEM;
+ output = calloc (1, sizeof (*output));
+ if (!output)
+ {
+ free (buffer);
+ return -ENOMEM;
+ }
+ buffer->buf = NULL;
+ buffer->alloc = 0;
+ buffer->size = 0;
+ output->type = SND_OUTPUT_BUFFER;
+ output->ops = &snd_output_buffer_ops;
+ output->private_data = buffer;
+ *outputp = output;
+ return 0;
+}