2020-09-05 15:42:03 +08:00
|
|
|
/* posix_getline.c
|
|
|
|
* RT-Thread POSIX
|
|
|
|
* getdelim(), getline() - read a delimited record from stream, ersatz implementation
|
2020-09-05 22:09:22 +08:00
|
|
|
* This code is unlicensed -- free and released into the public domain.
|
2020-09-05 15:42:03 +08:00
|
|
|
* https://man7.org/linux/man-pages/man3/getline.3.html
|
|
|
|
* Authors:
|
|
|
|
* https://github.com/ivanrad/getline
|
|
|
|
* https://github.com/mysterywolf/getline/
|
|
|
|
*
|
|
|
|
* Meco Man 2020-09-03 First Version
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <posix_getline.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <errno.h>
|
2020-09-05 16:14:21 +08:00
|
|
|
#include <rtlibc.h>
|
2020-09-05 15:42:03 +08:00
|
|
|
|
|
|
|
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 (SSIZE_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);
|
|
|
|
}
|
|
|
|
|