/* cStringBuffer: a file-like string buffer. Copyright (C) 2004 Mooneer Salem 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 library 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 necessary includes. */ #include #include #include #include #include #include #include "config.h" #ifdef HAVE_PTHREAD_H #include #endif #include "csb_private.h" #include "csb.h" /* csb_getc(): Retrieves a character from current position. Parameters: buf: The buffer to operate on. Returns: the next character in the input. */ int csb_getc(csb_buf *buf) /*@modifies buf->ungetc_buffer, buf->fileptr, buf->ungetc_length@*/ { /* Declare variables. */ char ch; /* Perform sanity checks to make sure we have a valid buffer. */ assert(buf != NULL && buf->string != NULL); /* Retrieve character at current position and move file pointer by 1. */ if (buf->ungetc_buffer != NULL) { ch = *buf->ungetc_buffer; memmove(buf->ungetc_buffer, buf->ungetc_buffer + 1, buf->ungetc_length--); if (buf->ungetc_length == 0) { free(buf->ungetc_buffer); buf->ungetc_buffer = NULL; } else { buf->ungetc_buffer = realloc(buf->ungetc_buffer, buf->ungetc_length); } } else { ch = *buf->fileptr++; } /* Return end-of-file if the character retrieved is ASCII 0 (null). */ return (ch != '\0' ? (int)ch : EOF); } /* csb_ungetc(): Stuffs character back into buffer at the current position without destroying other data. Parameters: buf: The buffer to operate on. ch: The character to insert. Returns: nothing. */ void csb_ungetc(csb_buf *buf, const char ch) /*@modifies buf->ungetc_buffer, buf->ungetc_length@*/ { /* Perform sanity checks to make sure we have a valid buffer. */ assert(buf != NULL && buf->string != NULL); /* Call memmove() to non-destructively shift the data to the right by one character. After doing this, then insert the character at the current file pointer position so it can be read again. */ if (buf->ungetc_buffer != NULL) { buf->ungetc_buffer = realloc(buf->ungetc_buffer, buf->ungetc_length); if (buf->ungetc_buffer == NULL) { /* eeek! return! */ return; } memmove(buf->ungetc_buffer + 1, buf->ungetc_buffer, buf->ungetc_length++); } else { buf->ungetc_buffer = malloc((size_t)1); if (buf->ungetc_buffer == NULL) { /* eeek! return! */ return; } buf->ungetc_length = (size_t)1; } buf->ungetc_buffer[0] = ch; } /* csb_read(): Read binary data from string. Parameters: buf: The buffer to operate on. data: The variable to place read data in. length: The amount to read. Returns: the amount of data read, or 0 if there is no more. */ size_t csb_read(csb_buf *buf, void *data, size_t length) /*@modifies buf->fileptr, data, buf->fileptr, buf->ungetc_buffer, buf->ungetc_length@*/ { /* Declare variables.*/ unsigned long difference; size_t offset = 0; /* Perform sanity checks to make sure we have a valid buffer. */ assert(buf != NULL && buf->string != NULL); /* If the length passed in would place the file pointer past the end of the string, modify the string so it will just read whatever's left. */ difference = (unsigned long)(buf->fileptr) - (unsigned long)(buf->string); if (length + difference > buf->stringsize + buf->ungetc_length) { length = buf->stringsize - difference; } /* If the length is 0 as a result of above, just return EOF. */ if (length == 0) { return (0); } /* Copy the data from the string to data and move the file pointer to reflect that. */ if (buf->ungetc_buffer != NULL) { memcpy(data, buf->ungetc_buffer, length <= buf->ungetc_length ? length : buf->ungetc_length); if (length < buf->ungetc_length) { memmove(buf->ungetc_buffer, buf->ungetc_buffer + length, buf->ungetc_length - length); offset = 0; length = 0; } else { free(buf->ungetc_buffer); buf->ungetc_buffer = NULL; offset = buf->ungetc_length; length -= offset; buf->ungetc_length = 0; } } if (length > 0) { memcpy(data + offset, buf->fileptr, length); } /* Restore file pointer. */ CSB_SEEK_NORESET(buf, (size_t)(buf->fileptr + length)); /* Return the number of bytes read. */ return (length + offset); }