1 /** 2 * \file input.c 3 * \brief Generic stdio-like input interface 4 * \author Abramo Bagnara <abramo (at) alsa-project.org> 5 * \date 2000 6 * 7 * Generic stdio-like input interface 8 */ 9 /* 10 * Input 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 38 typedef struct _snd_input_ops { 39 int (*close)(snd_input_t *input); 40 int (*scan)(snd_input_t *input, const char *format, va_list args); 41 char *(*(gets))(snd_input_t *input, char *str, size_t size); 42 int (*getch)(snd_input_t *input); 43 int (*ungetch)(snd_input_t *input, int c); 44 } snd_input_ops_t; 45 46 struct _snd_input { 47 snd_input_type_t type; 48 const snd_input_ops_t *ops; 49 void *private_data; 50 }; 51 #endif 52 53 /** 54 * \brief Closes an input handle. 55 * \param input The input handle to be closed. 56 * \return Zero if successful, otherwise a negative error code. 57 */ 58 int snd_input_close(snd_input_t *input) 59 { 60 int err = input->ops->close(input); 61 free(input); 62 return err; 63 } 64 65 /** 66 * \brief Reads formatted input (like \c fscanf(3)) from an input handle. 67 * \param input The input handle. 68 * \param format Format string in \c fscanf format. 69 * \param ... Other \c fscanf arguments. 70 * \return The number of input items assigned, or \c EOF. 71 * 72 * \bug Reading from a memory buffer doesn't work. 73 */ 74 int snd_input_scanf(snd_input_t *input, const char *format, ...) 75 { 76 int result; 77 va_list args; 78 va_start(args, format); 79 result = input->ops->scan(input, format, args); 80 va_end(args); 81 return result; 82 } 83 84 /** 85 * \brief Reads a line from an input handle (like \c fgets(3)). 86 * \param input The input handle. 87 * \param str Address of the destination buffer. 88 * \param size The size of the destination buffer. 89 * \return Pointer to the buffer if successful, otherwise \c NULL. 90 * 91 * Like \c fgets, the returned string is zero-terminated, and contains 92 * the new-line character \c '\\n' if the line fits into the buffer. 93 */ 94 char *snd_input_gets(snd_input_t *input, char *str, size_t size) 95 { 96 return (input->ops->gets)(input, str, size); 97 } 98 99 /** 100 * \brief Reads a character from an input handle (like \c fgetc(3)). 101 * \param input The input handle. 102 * \return The character read, or \c EOF on end of file or error. 103 */ 104 int snd_input_getc(snd_input_t *input) 105 { 106 return input->ops->getch(input); 107 } 108 109 /** 110 * \brief Puts the last character read back to an input handle (like \c ungetc(3)). 111 * \param input The input handle. 112 * \param c The character to push back. 113 * \return The character pushed back, or \c EOF on error. 114 */ 115 int snd_input_ungetc(snd_input_t *input, int c) 116 { 117 return input->ops->ungetch(input, c); 118 } 119 120 #ifndef DOC_HIDDEN 121 typedef struct _snd_input_stdio { 122 int close; 123 FILE *fp; 124 } snd_input_stdio_t; 125 126 static int snd_input_stdio_close(snd_input_t *input ATTRIBUTE_UNUSED) 127 { 128 snd_input_stdio_t *stdio = input->private_data; 129 if (stdio->close) 130 fclose(stdio->fp); 131 free(stdio); 132 return 0; 133 } 134 135 static int snd_input_stdio_scan(snd_input_t *input, const char *format, va_list args) 136 { 137 snd_input_stdio_t *stdio = input->private_data; 138 extern int vfscanf(FILE *, const char *, va_list); 139 return vfscanf(stdio->fp, format, args); 140 } 141 142 static char *snd_input_stdio_gets(snd_input_t *input, char *str, size_t size) 143 { 144 snd_input_stdio_t *stdio = input->private_data; 145 return fgets(str, (int) size, stdio->fp); 146 } 147 148 static int snd_input_stdio_getc(snd_input_t *input) 149 { 150 snd_input_stdio_t *stdio = input->private_data; 151 return getc(stdio->fp); 152 } 153 154 static int snd_input_stdio_ungetc(snd_input_t *input, int c) 155 { 156 snd_input_stdio_t *stdio = input->private_data; 157 return ungetc(c, stdio->fp); 158 } 159 160 static const snd_input_ops_t snd_input_stdio_ops = { 161 .close = snd_input_stdio_close, 162 .scan = snd_input_stdio_scan, 163 .gets = snd_input_stdio_gets, 164 .getch = snd_input_stdio_getc, 165 .ungetch = snd_input_stdio_ungetc, 166 }; 167 #endif 168 169 /** 170 * \brief Creates a new input object using an existing stdio \c FILE pointer. 171 * \param inputp The function puts the pointer to the new input object 172 * at the address specified by \p inputp. 173 * \param fp The \c FILE pointer to read from. 174 * Reading begins at the current file position. 175 * \param _close Close flag. Set this to 1 if #snd_input_close should close 176 * \p fp by calling \c fclose. 177 * \return Zero if successful, otherwise a negative error code. 178 */ 179 int snd_input_stdio_attach(snd_input_t **inputp, FILE *fp, int _close) 180 { 181 snd_input_t *input; 182 snd_input_stdio_t *stdio; 183 assert(inputp && fp); 184 stdio = calloc(1, sizeof(*stdio)); 185 if (!stdio) 186 return -ENOMEM; 187 input = calloc(1, sizeof(*input)); 188 if (!input) { 189 free(stdio); 190 return -ENOMEM; 191 } 192 stdio->fp = fp; 193 stdio->close = _close; 194 input->type = SND_INPUT_STDIO; 195 input->ops = &snd_input_stdio_ops; 196 input->private_data = stdio; 197 *inputp = input; 198 return 0; 199 } 200 201 /** 202 * \brief Creates a new input object reading from a file. 203 * \param inputp The functions puts the pointer to the new input object 204 * at the address specified by \p inputp. 205 * \param file The name of the file to read from. 206 * \param mode The open mode, like \c fopen(3). 207 * \return Zero if successful, otherwise a negative error code. 208 */ 209 int snd_input_stdio_open(snd_input_t **inputp, const char *file, const char *mode) 210 { 211 int err; 212 FILE *fp = fopen(file, mode); 213 if (!fp) { 214 //SYSERR("fopen"); 215 return -errno; 216 } 217 err = snd_input_stdio_attach(inputp, fp, 1); 218 if (err < 0) 219 fclose(fp); 220 return err; 221 } 222 223 #ifndef DOC_HIDDEN 224 225 typedef struct _snd_input_buffer { 226 unsigned char *buf; 227 unsigned char *ptr; 228 size_t size; 229 } snd_input_buffer_t; 230 231 static int snd_input_buffer_close(snd_input_t *input) 232 { 233 snd_input_buffer_t *buffer = input->private_data; 234 free(buffer->buf); 235 free(buffer); 236 return 0; 237 } 238 239 static int snd_input_buffer_scan(snd_input_t *input, const char *format, va_list args) 240 { 241 snd_input_buffer_t *buffer = input->private_data; 242 extern int vsscanf(const char *, const char *, va_list); 243 /* FIXME: how can I obtain consumed chars count? */ 244 assert(0); 245 return vsscanf((char *)buffer->ptr, format, args); 246 } 247 248 static char *snd_input_buffer_gets(snd_input_t *input, char *str, size_t size) 249 { 250 snd_input_buffer_t *buffer = input->private_data; 251 size_t bsize = buffer->size; 252 while (--size > 0 && bsize > 0) { 253 unsigned char c = *buffer->ptr++; 254 bsize--; 255 *str++ = c; 256 if (c == '\n') 257 break; 258 } 259 if (bsize == buffer->size) 260 return NULL; 261 buffer->size = bsize; 262 *str = '\0'; 263 return str; 264 } 265 266 static int snd_input_buffer_getc(snd_input_t *input) 267 { 268 snd_input_buffer_t *buffer = input->private_data; 269 if (buffer->size == 0) 270 return EOF; 271 buffer->size--; 272 return *buffer->ptr++; 273 } 274 275 static int snd_input_buffer_ungetc(snd_input_t *input, int c) 276 { 277 snd_input_buffer_t *buffer = input->private_data; 278 if (buffer->ptr == buffer->buf) 279 return EOF; 280 buffer->ptr--; 281 assert(*buffer->ptr == (unsigned char) c); 282 buffer->size++; 283 return c; 284 } 285 286 static const snd_input_ops_t snd_input_buffer_ops = { 287 .close = snd_input_buffer_close, 288 .scan = snd_input_buffer_scan, 289 .gets = snd_input_buffer_gets, 290 .getch = snd_input_buffer_getc, 291 .ungetch = snd_input_buffer_ungetc, 292 }; 293 #endif 294 295 /** 296 * \brief Creates a new input object from a memory buffer. 297 * \param inputp The function puts the pointer to the new input object 298 * at the address specified by \p inputp. 299 * \param buf Address of the input buffer. 300 * \param size Size of the input buffer. 301 * \return Zero if successful, otherwise a negative error code. 302 * 303 * This functions creates a copy of the input buffer, so the application is 304 * not required to preserve the buffer after this function has been called. 305 */ 306 int snd_input_buffer_open(snd_input_t **inputp, const char *buf, ssize_t size) 307 { 308 snd_input_t *input; 309 snd_input_buffer_t *buffer; 310 assert(inputp); 311 buffer = calloc(1, sizeof(*buffer)); 312 if (!buffer) 313 return -ENOMEM; 314 input = calloc(1, sizeof(*input)); 315 if (!input) { 316 free(buffer); 317 return -ENOMEM; 318 } 319 if (size < 0) 320 size = strlen(buf); 321 buffer->buf = malloc((size_t)size + 1); 322 if (!buffer->buf) { 323 free(input); 324 free(buffer); 325 return -ENOMEM; 326 } 327 memcpy(buffer->buf, buf, (size_t) size); 328 buffer->buf[size] = 0; 329 buffer->ptr = buffer->buf; 330 buffer->size = size; 331 input->type = SND_INPUT_BUFFER; 332 input->ops = &snd_input_buffer_ops; 333 input->private_data = buffer; 334 *inputp = input; 335 return 0; 336 } 337 338