From 8fa47e7b377e6bf3a1d0f87c03cd33c3f1668b98 Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Tue, 13 Oct 2015 14:56:44 -0400 Subject: [PATCH] Implement bt_getline MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Implement our own getline to remove dependency from glibc 2.10+ and to increase portability to other operating systems. Signed-off-by: Mathieu Desnoyers Signed-off-by: Jérémie Galarneau --- converter/babeltrace-log.c | 5 +- include/Makefile.am | 1 + include/babeltrace/compat/stdio.h | 124 ++++++++++++++++++++++++++++++ tests/lib/test_ctf_writer.c | 7 +- 4 files changed, 131 insertions(+), 6 deletions(-) create mode 100644 include/babeltrace/compat/stdio.h diff --git a/converter/babeltrace-log.c b/converter/babeltrace-log.c index bdb01f16..db7f60f1 100644 --- a/converter/babeltrace-log.c +++ b/converter/babeltrace-log.c @@ -24,8 +24,6 @@ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. - * - * Depends on glibc 2.10 for getline(). */ #include @@ -45,6 +43,7 @@ #include #include #include +#include #include #define NSEC_PER_USEC 1000UL @@ -329,7 +328,7 @@ void trace_text(FILE *input, int output) write_packet_header(&pos, s_uuid); write_packet_context(&pos); for (;;) { - len = getline(&line, &linesize, input); + len = bt_getline(&line, &linesize, input); if (len < 0) break; nl = strrchr(line, '\n'); diff --git a/include/Makefile.am b/include/Makefile.am index 9884ac2c..6b81b234 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -57,5 +57,6 @@ noinst_HEADERS = \ babeltrace/compat/fcntl.h \ babeltrace/compat/stdlib.h \ babeltrace/compat/dirent.h \ + babeltrace/compat/stdio.h \ babeltrace/endian.h \ babeltrace/mmap-align.h diff --git a/include/babeltrace/compat/stdio.h b/include/babeltrace/compat/stdio.h new file mode 100644 index 00000000..0301e283 --- /dev/null +++ b/include/babeltrace/compat/stdio.h @@ -0,0 +1,124 @@ +#ifndef _BABELTRACE_COMPAT_STDIO_H +#define _BABELTRACE_COMPAT_STDIO_H + +/* + * Copyright (C) 2015 Mathieu Desnoyers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include + +#define BT_GETLINE_MINBUFLEN 64 + +static inline +char * _bt_getline_bufalloc(char **lineptr, size_t *n, size_t linelen) +{ + size_t buflen = *n; + char *buf = *lineptr; + + if (buflen >= linelen && buf != NULL) { + return buf; + } + if (buf == NULL) { + buflen = BT_GETLINE_MINBUFLEN; + } else { + buflen = buflen << 1; + if (buflen < BT_GETLINE_MINBUFLEN) { + buflen = BT_GETLINE_MINBUFLEN; + } + } + /* Check below not strictly needed, extra safety. */ + if (buflen < linelen) { + buflen = linelen; + } + buf = realloc(buf, buflen); + if (!buf) { + errno = ENOMEM; + return NULL; + } + *n = buflen; + *lineptr = buf; + return buf; +} + +/* + * Returns line length (including possible final \n, excluding final + * \0). On end of file, returns -1 with nonzero feof(stream) and errno + * set to 0. On error, returns -1 with errno set. + * + * This interface is similar to the getline(3) man page part of the + * Linux man-pages project, release 3.74. One major difference from the + * Open Group POSIX specification is that this implementation does not + * necessarily set the ferror() flag on error (because it is internal to + * libc). + */ +static inline +ssize_t bt_getline(char **lineptr, size_t *n, FILE *stream) +{ + size_t linelen = 0; + char *buf; + int found_eof = 0; + + if (lineptr == NULL || n == NULL) { + errno = EINVAL; + return -1; + } + for (;;) { + char c; + + c = fgetc(stream); + if (c == EOF) { + if (ferror(stream)) { + /* ferror() is set, errno set by fgetc(). */ + return -1; + } + assert(feof(stream)); + found_eof = 1; + break; + } + if (linelen == SSIZE_MAX) { + errno = EOVERFLOW; + return -1; + } + buf = _bt_getline_bufalloc(lineptr, n, ++linelen); + if (!buf) { + return -1; + } + buf[linelen - 1] = c; + if (c == '\n') { + break; + } + } + if (!linelen && found_eof) { + /* feof() is set. */ + errno = 0; + return -1; + } + buf = _bt_getline_bufalloc(lineptr, n, ++linelen); + if (!buf) { + return -1; + } + buf[linelen - 1] = '\0'; + return linelen - 1; /* Count don't include final \0. */ +} + +#endif /* _BABELTRACE_COMPAT_STDIO_H */ diff --git a/tests/lib/test_ctf_writer.c b/tests/lib/test_ctf_writer.c index e0236a38..68bb2705 100644 --- a/tests/lib/test_ctf_writer.c +++ b/tests/lib/test_ctf_writer.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -127,12 +128,12 @@ result: rewind(metadata_fp); /* Output the metadata and parser output as diagnostic */ - while (getline(&line, &len, metadata_fp) > 0) { + while (bt_getline(&line, &len, metadata_fp) > 0) { diag("%s", line); } rewind(parser_output_fp); - while (getline(&line, &len, parser_output_fp) > 0) { + while (bt_getline(&line, &len, parser_output_fp) > 0) { diag("%s", line); } @@ -224,7 +225,7 @@ result: diag("malloc error"); } rewind(babeltrace_output_fp); - while (getline(&line, &len, babeltrace_output_fp) > 0) { + while (bt_getline(&line, &len, babeltrace_output_fp) > 0) { diag("%s", line); } -- 2.34.1