mirror of
https://github.com/attractivechaos/klib
synced 2024-11-23 14:49:50 +03:00
Add kgetline() to kstring.c/.h
Similar to BSD's getline() but omits the \n terminator and manages the memory as a kstring. Call with "(kgets_func *) fgets" to read from stdio, or implement an fgets()-style function to read from other streams, e.g., a wrapper around gzgets() that reorders its parameters as per fgets().
This commit is contained in:
parent
93531803a8
commit
cbcfcabc8f
20
kstring.c
20
kstring.c
@ -105,6 +105,26 @@ int ksplit_core(char *s, int delimiter, int *_max, int **_offsets)
|
||||
return n;
|
||||
}
|
||||
|
||||
int kgetline(kstring_t *s, kgets_func *fgets_fn, void *fp)
|
||||
{
|
||||
size_t l0 = s->l;
|
||||
|
||||
while (s->l == l0 || s->s[s->l-1] != '\n') {
|
||||
if (s->m - s->l < 200) ks_resize(s, s->m + 200);
|
||||
if (fgets_fn(s->s + s->l, s->m - s->l, fp) == NULL) break;
|
||||
s->l += strlen(s->s + s->l);
|
||||
}
|
||||
|
||||
if (s->l == l0) return EOF;
|
||||
|
||||
if (s->l > l0 && s->s[s->l-1] == '\n') {
|
||||
s->l--;
|
||||
if (s->l > l0 && s->s[s->l-1] == '\r') s->l--;
|
||||
}
|
||||
s->s[s->l] = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**********************
|
||||
* Boyer-Moore search *
|
||||
**********************/
|
||||
|
@ -82,6 +82,13 @@ extern "C" {
|
||||
* if sep is not changed. */
|
||||
char *kstrtok(const char *str, const char *sep, ks_tokaux_t *aux);
|
||||
|
||||
/* kgetline() uses the supplied fgets()-like function to read a "\n"-
|
||||
* or "\r\n"-terminated line from fp. The line read is appended to the
|
||||
* kstring without its terminator and 0 is returned; EOF is returned at
|
||||
* EOF or on error (determined by querying fp, as per fgets()). */
|
||||
typedef char *kgets_func(char *, int, void *);
|
||||
int kgetline(kstring_t *s, kgets_func *fgets, void *fp);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include <limits.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@ -37,7 +38,40 @@ void test_kputl(kstring_t *ks, long n)
|
||||
check("kputl()", ks, buf);
|
||||
}
|
||||
|
||||
int main()
|
||||
static char *mem_gets(char *buf, int buflen, void *vtextp)
|
||||
{
|
||||
const char **textp = (const char **) vtextp;
|
||||
|
||||
const char *nl = strchr(*textp, '\n');
|
||||
size_t n = nl? nl - *textp + 1 : strlen(*textp);
|
||||
|
||||
if (n == 0) return NULL;
|
||||
|
||||
if (n > buflen-1) n = buflen-1;
|
||||
memcpy(buf, *textp, n);
|
||||
buf[n] = '\0';
|
||||
*textp += n;
|
||||
return buf;
|
||||
}
|
||||
|
||||
void test_kgetline(kstring_t *ks, const char *text, ...)
|
||||
{
|
||||
const char *exp;
|
||||
va_list arg;
|
||||
|
||||
va_start(arg, text);
|
||||
while ((exp = va_arg(arg, const char *)) != NULL) {
|
||||
ks->l = 0;
|
||||
if (kgetline(ks, mem_gets, &text) != 0) kputs("EOF", ks);
|
||||
check("kgetline()", ks, exp);
|
||||
}
|
||||
va_end(arg);
|
||||
|
||||
ks->l = 0;
|
||||
if (kgetline(ks, mem_gets, &text) == 0) check("kgetline()", ks, "EOF");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
kstring_t ks;
|
||||
|
||||
@ -65,6 +99,28 @@ int main()
|
||||
test_kputl(&ks, -LONG_MAX);
|
||||
test_kputl(&ks, LONG_MIN);
|
||||
|
||||
test_kgetline(&ks, "", NULL);
|
||||
test_kgetline(&ks, "apple", "apple", NULL);
|
||||
test_kgetline(&ks, "banana\n", "banana", NULL);
|
||||
test_kgetline(&ks, "carrot\r\n", "carrot", NULL);
|
||||
test_kgetline(&ks, "\n", "", NULL);
|
||||
test_kgetline(&ks, "\n\n", "", "", NULL);
|
||||
test_kgetline(&ks, "foo\nbar", "foo", "bar", NULL);
|
||||
test_kgetline(&ks, "foo\nbar\n", "foo", "bar", NULL);
|
||||
test_kgetline(&ks,
|
||||
"abcdefghijklmnopqrstuvwxyz0123456789\nABCDEFGHIJKLMNOPQRSTUVWXYZ\n",
|
||||
"abcdefghijklmnopqrstuvwxyz0123456789",
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ", NULL);
|
||||
|
||||
if (argc > 1) {
|
||||
FILE *f = fopen(argv[1], "r");
|
||||
if (f) {
|
||||
for (ks.l = 0; kgetline(&ks, (kgets_func *)fgets, f) == 0; ks.l = 0)
|
||||
puts(ks.s);
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
|
||||
free(ks.s);
|
||||
|
||||
if (nfail > 0) {
|
||||
|
Loading…
Reference in New Issue
Block a user