summaryrefslogtreecommitdiff
path: root/components/libc/compilers/common/cstdio.c
diff options
context:
space:
mode:
Diffstat (limited to 'components/libc/compilers/common/cstdio.c')
-rw-r--r--components/libc/compilers/common/cstdio.c85
1 files changed, 85 insertions, 0 deletions
diff --git a/components/libc/compilers/common/cstdio.c b/components/libc/compilers/common/cstdio.c
new file mode 100644
index 0000000000..3dffe55aa7
--- /dev/null
+++ b/components/libc/compilers/common/cstdio.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2014-05-22 ivanrad implement getline
+ */
+
+#include "posix/stdio.h"
+#include <stdlib.h>
+#include <limits.h>
+#include <sys/errno.h>
+
+ssize_t getdelim(char **lineptr, size_t *n, int delim, FILE *stream)
+{
+ char *cur_pos, *new_lineptr;
+ size_t new_lineptr_len;
+ int c;
+
+ if (lineptr == NULL || n == NULL || stream == NULL)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (*lineptr == NULL)
+ {
+ *n = 128; /* init len */
+ if ((*lineptr = (char *)malloc(*n)) == NULL)
+ {
+ errno = ENOMEM;
+ return -1;
+ }
+ }
+
+ cur_pos = *lineptr;
+ for (;;)
+ {
+ c = getc(stream);
+
+ if (ferror(stream) || (c == EOF && cur_pos == *lineptr))
+ return -1;
+
+ if (c == EOF)
+ break;
+
+ if ((*lineptr + *n - cur_pos) < 2)
+ {
+ if (LONG_MAX / 2 < *n)
+ {
+#ifdef EOVERFLOW
+ errno = EOVERFLOW;
+#else
+ errno = ERANGE; /* no EOVERFLOW defined */
+#endif
+ return -1;
+ }
+ new_lineptr_len = *n * 2;
+
+ if ((new_lineptr = (char *)realloc(*lineptr, new_lineptr_len)) == NULL)
+ {
+ errno = ENOMEM;
+ return -1;
+ }
+ cur_pos = new_lineptr + (cur_pos - *lineptr);
+ *lineptr = new_lineptr;
+ *n = new_lineptr_len;
+ }
+
+ *cur_pos++ = (char)c;
+
+ if (c == delim)
+ break;
+ }
+
+ *cur_pos = '\0';
+ return (ssize_t)(cur_pos - *lineptr);
+}
+
+ssize_t getline(char **lineptr, size_t *n, FILE *stream)
+{
+ return getdelim(lineptr, n, '\n', stream);
+}