/* getdelim.c --- Implementation of replacement getdelim function. * Copyright (C) 1994, 1996-1998, 2001, 2003, 2005-2012 Free Software * Foundation, Inc. * * This file is part of GnuTLS. * * The gnutls 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 program. If not, see */ /* Ported from glibc by Simon Josefsson. */ #include #include #include #include #ifndef SSIZE_MAX #define SSIZE_MAX ((ssize_t) (SIZE_MAX / 2)) #endif /** * xssl_get_delim: * @sb: is a #xssl_t structure. * @lineptr: a pointer. * @n: The size of @lineptr. * @delimiter: The delimiter to stop reading at. * * Read up to (and including) a @delimiter from &sb into *LINEPTR (and * NUL-terminate it). @lineptr is a pointer returned from gnutls_malloc() * (or %NULL), pointing to @n characters of space. It is realloc'ed as * necessary. * * Only fatal errors are returned by this function. * * Returns the number of characters read (not including * the null terminator), or a negative error code on error. * * Since: 3.1.7 **/ ssize_t xssl_getdelim(xssl_t sbuf, char **lineptr, size_t * n, int delimiter) { ssize_t result; size_t cur_len = 0; if (lineptr == NULL || n == NULL || sbuf == NULL) { return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); } if (*lineptr == NULL || *n == 0) { char *new_lineptr; *n = 120; new_lineptr = (char *) gnutls_realloc_fast(*lineptr, *n); if (new_lineptr == NULL) { result = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); goto fail; } *lineptr = new_lineptr; } for (;;) { char c; result = xssl_read(sbuf, &c, 1); if (result < 0) { gnutls_assert(); break; } /* Make enough space for len+1 (for final NUL) bytes. */ if (cur_len + 1 >= *n) { size_t needed_max = SSIZE_MAX < SIZE_MAX ? (size_t) SSIZE_MAX + 1 : SIZE_MAX; size_t needed = 2 * *n + 1; /* Be generous. */ char *new_lineptr; if (needed_max < needed) needed = needed_max; if (cur_len + 1 >= needed) { result = gnutls_assert_val (GNUTLS_E_LARGE_PACKET); goto fail; } new_lineptr = (char *) gnutls_realloc_fast(*lineptr, needed); if (new_lineptr == NULL) { result = gnutls_assert_val (GNUTLS_E_MEMORY_ERROR); goto fail; } *lineptr = new_lineptr; *n = needed; } (*lineptr)[cur_len] = c; cur_len++; if (c == delimiter) break; } (*lineptr)[cur_len] = '\0'; if (cur_len != 0) result = cur_len; fail: return result; }