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