Move to kernel style SPDX license identifiers
[babeltrace.git] / src / compat / stdio.h
1 /*
2 * SPDX-License-Identifier: MIT
3 *
4 * Copyright (C) 2015 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
5 */
6
7 #ifndef _BABELTRACE_COMPAT_STDIO_H
8 #define _BABELTRACE_COMPAT_STDIO_H
9
10 #include <stdio.h>
11 #include <errno.h>
12 #include <stdlib.h>
13 #include <limits.h>
14 #include "common/assert.h"
15
16 #define BT_GETLINE_MINBUFLEN 64
17
18 static inline
19 char * _bt_getline_bufalloc(char **lineptr, size_t *n, size_t linelen)
20 {
21 size_t buflen = *n;
22 char *buf = *lineptr;
23
24 if (buflen >= linelen && buf) {
25 return buf;
26 }
27 if (!buf) {
28 buflen = BT_GETLINE_MINBUFLEN;
29 } else {
30 buflen = buflen << 1;
31 if (buflen < BT_GETLINE_MINBUFLEN) {
32 buflen = BT_GETLINE_MINBUFLEN;
33 }
34 }
35 /* Check below not strictly needed, extra safety. */
36 if (buflen < linelen) {
37 buflen = linelen;
38 }
39 buf = realloc(buf, buflen);
40 if (!buf) {
41 errno = ENOMEM;
42 return NULL;
43 }
44 *n = buflen;
45 *lineptr = buf;
46 return buf;
47 }
48
49 /*
50 * Returns line length (including possible final \n, excluding final
51 * \0). On end of file, returns -1 with nonzero feof(stream) and errno
52 * set to 0. On error, returns -1 with errno set.
53 *
54 * This interface is similar to the getline(3) man page part of the
55 * Linux man-pages project, release 3.74. One major difference from the
56 * Open Group POSIX specification is that this implementation does not
57 * necessarily set the ferror() flag on error (because it is internal to
58 * libc).
59 */
60 static inline
61 ssize_t bt_getline(char **lineptr, size_t *n, FILE *stream)
62 {
63 size_t linelen = 0;
64 char *buf;
65 int found_eof = 0;
66
67 if (!lineptr || !n) {
68 errno = EINVAL;
69 return -1;
70 }
71 for (;;) {
72 char c;
73 int ret;
74
75 ret = fgetc(stream);
76 if (ret == EOF) {
77 if (ferror(stream)) {
78 /* ferror() is set, errno set by fgetc(). */
79 return -1;
80 }
81 BT_ASSERT_DBG(feof(stream));
82 found_eof = 1;
83 break;
84 }
85 c = (char) ret;
86 if (linelen == SSIZE_MAX) {
87 errno = EOVERFLOW;
88 return -1;
89 }
90 buf = _bt_getline_bufalloc(lineptr, n, ++linelen);
91 if (!buf) {
92 return -1;
93 }
94 buf[linelen - 1] = c;
95 if (c == '\n') {
96 break;
97 }
98 }
99 if (!linelen && found_eof) {
100 /* feof() is set. */
101 errno = 0;
102 return -1;
103 }
104 buf = _bt_getline_bufalloc(lineptr, n, ++linelen);
105 if (!buf) {
106 return -1;
107 }
108 buf[linelen - 1] = '\0';
109 return linelen - 1; /* Count don't include final \0. */
110 }
111
112 #endif /* _BABELTRACE_COMPAT_STDIO_H */
This page took 0.031791 seconds and 4 git commands to generate.