From: Liu Yuan <tailai.ly at taobao.com> Those are needed by sheepfs. Signed-off-by: Liu Yuan <tailai.ly at taobao.com> --- include/Makefile.am | 3 +- include/strbuf.h | 95 +++++++++++++++++++++++++ include/util.h | 1 + lib/Makefile.am | 3 +- lib/strbuf.c | 192 +++++++++++++++++++++++++++++++++++++++++++++++++++ lib/util.c | 50 ++++++++++++++ sheep/Makefile.am | 4 +- sheep/sheep_priv.h | 2 - sheep/store.c | 45 ------------ sheep/strbuf.c | 192 --------------------------------------------------- sheep/strbuf.h | 95 ------------------------- 11 files changed, 344 insertions(+), 338 deletions(-) create mode 100644 include/strbuf.h create mode 100644 lib/strbuf.c delete mode 100644 sheep/strbuf.c delete mode 100644 sheep/strbuf.h diff --git a/include/Makefile.am b/include/Makefile.am index bf254e1..5e64344 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -1,3 +1,4 @@ MAINTAINERCLEANFILES = Makefile.in config.h.in -noinst_HEADERS = bitops.h event.h logger.h sheepdog_proto.h util.h list.h net.h sheep.h exits.h +noinst_HEADERS = bitops.h event.h logger.h sheepdog_proto.h util.h \ + list.h net.h sheep.h exits.h strbuf.h diff --git a/include/strbuf.h b/include/strbuf.h new file mode 100644 index 0000000..573784b --- /dev/null +++ b/include/strbuf.h @@ -0,0 +1,95 @@ +#ifndef STRBUF_H +#define STRBUF_H + +#include <assert.h> +#include <ctype.h> +#include <stdarg.h> +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> + +#include "util.h" + +struct strbuf { + size_t alloc; + size_t len; + int eof; + char *buf; +}; + +#define alloc_nr(x) (((x)+16)*3/2) + +/* + * Realloc the buffer pointed at by variable 'x' so that it can hold + * at least 'nr' entries; the number of entries currently allocated + * is 'alloc', using the standard growing factor alloc_nr() macro. + * + * DO NOT USE any expression with side-effect for 'x' or 'alloc'. + */ +#define ALLOC_GROW(x, nr, alloc) \ + do { \ + if ((nr) > alloc) { \ + if (alloc_nr(alloc) < (nr)) \ + alloc = (nr); \ + else \ + alloc = alloc_nr(alloc); \ + x = xrealloc((x), alloc * sizeof(*(x))); \ + } \ + } while(0) + +#define STRBUF_INIT { 0, 0, 0, NULL } + +/*----- strbuf life cycle -----*/ +extern void strbuf_init(struct strbuf *, size_t); +extern void strbuf_release(struct strbuf *); +extern void strbuf_reset(struct strbuf *); +extern char *strbuf_detach(struct strbuf *); +extern void strbuf_attach(struct strbuf *, void *, size_t, size_t); + +/*----- strbuf size related -----*/ +static inline size_t strbuf_avail(struct strbuf *sb) { + return sb->alloc ? sb->alloc - sb->len - 1 : 0; +} +static inline void strbuf_setlen(struct strbuf *sb, size_t len) { + assert (len < sb->alloc); + sb->len = len; + sb->buf[len] = '\0'; +} + +extern void strbuf_grow(struct strbuf *, size_t); + +/*----- content related -----*/ +extern void strbuf_rtrim(struct strbuf *); + +/*----- add data in your buffer -----*/ +static inline void strbuf_addch(struct strbuf *sb, int c) { + strbuf_grow(sb, 1); + sb->buf[sb->len++] = c; + sb->buf[sb->len] = '\0'; +} + +/* inserts after pos, or appends if pos >= sb->len */ +extern void strbuf_insert(struct strbuf *, size_t pos, const void *, size_t); +extern void strbuf_remove(struct strbuf *, size_t pos, size_t len); + +/* splice pos..pos+len with given data */ +extern void strbuf_splice(struct strbuf *, size_t pos, size_t len, + const void *, size_t); + +extern void strbuf_add(struct strbuf *, const void *, size_t); +static inline void strbuf_addstr(struct strbuf *sb, const char *s) { + strbuf_add(sb, s, strlen(s)); +} +static inline void strbuf_addbuf(struct strbuf *sb, struct strbuf *sb2) { + strbuf_add(sb, sb2->buf, sb2->len); +} + +__attribute__((format(printf,2,3))) +extern void strbuf_addf(struct strbuf *sb, const char *fmt, ...); + +extern size_t strbuf_fread(struct strbuf *, size_t, FILE *); +/* XXX: if read fails, any partial read is undone */ +extern ssize_t strbuf_read(struct strbuf *, int fd, size_t hint); +int strbuf_getline(struct strbuf *sb, FILE *fp, int term); + +#endif diff --git a/include/util.h b/include/util.h index 10b30d7..0747ba4 100644 --- a/include/util.h +++ b/include/util.h @@ -82,6 +82,7 @@ extern ssize_t xread(int fd, void *buf, size_t len); extern ssize_t xwrite(int fd, const void *buf, size_t len); extern ssize_t xpread(int fd, void *buf, size_t count, off_t offset); extern ssize_t xpwrite(int fd, const void *buf, size_t count, off_t offset); +extern int rmdir_r(char *dir_path); /* ring_buffer.c */ struct rbuffer { diff --git a/lib/Makefile.am b/lib/Makefile.am index eda3c9a..f6ac984 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -4,4 +4,5 @@ INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include noinst_LIBRARIES = libsheepdog.a -libsheepdog_a_SOURCES = event.c logger.c net.c util.c rbtree.c ring_buffer.c +libsheepdog_a_SOURCES = event.c logger.c net.c util.c rbtree.c ring_buffer.c \ + strbuf.c diff --git a/lib/strbuf.c b/lib/strbuf.c new file mode 100644 index 0000000..1a5f855 --- /dev/null +++ b/lib/strbuf.c @@ -0,0 +1,192 @@ +/* Taken from git by Liu Yuan <namei.unix at gmail.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "strbuf.h" +#include "logger.h" + +void strbuf_init(struct strbuf *sb, size_t hint) +{ + memset(sb, 0, sizeof(*sb)); + if (hint) + strbuf_grow(sb, hint); +} + +void strbuf_release(struct strbuf *sb) +{ + free(sb->buf); + memset(sb, 0, sizeof(*sb)); +} + +void strbuf_reset(struct strbuf *sb) +{ + if (sb->len) + strbuf_setlen(sb, 0); + sb->eof = 0; +} + +char *strbuf_detach(struct strbuf *sb) +{ + char *res = sb->buf; + strbuf_init(sb, 0); + return res; +} + +void strbuf_attach(struct strbuf *sb, void *buf, size_t len, size_t alloc) +{ + strbuf_release(sb); + sb->buf = buf; + sb->len = len; + sb->alloc = alloc; + strbuf_grow(sb, 0); + sb->buf[sb->len] = '\0'; +} + +void strbuf_grow(struct strbuf *sb, size_t extra) +{ + if (sb->len + extra + 1 <= sb->len) + panic("you want to use way too much memory"); + ALLOC_GROW(sb->buf, sb->len + extra + 1, sb->alloc); +} + +void strbuf_rtrim(struct strbuf *sb) +{ + while (sb->len > 0 && isspace((unsigned char)sb->buf[sb->len - 1])) + sb->len--; + sb->buf[sb->len] = '\0'; +} + +void strbuf_insert(struct strbuf *sb, size_t pos, const void *data, size_t len) +{ + strbuf_grow(sb, len); + if (pos > sb->len) + panic("`pos' is too far after the end of the buffer"); + memmove(sb->buf + pos + len, sb->buf + pos, sb->len - pos); + memcpy(sb->buf + pos, data, len); + strbuf_setlen(sb, sb->len + len); +} + +void strbuf_splice(struct strbuf *sb, size_t pos, size_t len, + const void *data, size_t dlen) +{ + if (pos + len < pos) + panic("you want to use way too much memory"); + if (pos > sb->len) + panic("`pos' is too far after the end of the buffer"); + if (pos + len > sb->len) + panic("`pos + len' is too far after the end of the buffer"); + + if (dlen >= len) + strbuf_grow(sb, dlen - len); + memmove(sb->buf + pos + dlen, + sb->buf + pos + len, + sb->len - pos - len); + memcpy(sb->buf + pos, data, dlen); + strbuf_setlen(sb, sb->len + dlen - len); +} + +void strbuf_remove(struct strbuf *sb, size_t pos, size_t len) +{ + strbuf_splice(sb, pos, len, NULL, 0); +} + +void strbuf_add(struct strbuf *sb, const void *data, size_t len) +{ + strbuf_grow(sb, len); + memcpy(sb->buf + sb->len, data, len); + strbuf_setlen(sb, sb->len + len); +} + +void strbuf_addf(struct strbuf *sb, const char *fmt, ...) +{ + int len; + va_list ap; + + va_start(ap, fmt); + len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap); + va_end(ap); + if (len < 0) { + len = 0; + } + if (len > strbuf_avail(sb)) { + strbuf_grow(sb, len); + va_start(ap, fmt); + len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap); + va_end(ap); + if (len > strbuf_avail(sb)) { + panic("this should not happen, your snprintf is broken"); + } + } + strbuf_setlen(sb, sb->len + len); +} + +size_t strbuf_fread(struct strbuf *sb, size_t size, FILE *f) +{ + size_t res; + + strbuf_grow(sb, size); + res = fread(sb->buf + sb->len, 1, size, f); + if (res > 0) { + strbuf_setlen(sb, sb->len + res); + } + return res; +} + +ssize_t strbuf_read(struct strbuf *sb, int fd, size_t hint) +{ + size_t oldlen = sb->len; + + strbuf_grow(sb, hint ? hint : 8192); + for (;;) { + ssize_t cnt; + + cnt = xread(fd, sb->buf + sb->len, sb->alloc - sb->len - 1); + if (cnt < 0) { + strbuf_setlen(sb, oldlen); + return -1; + } + if (!cnt) + break; + sb->len += cnt; + strbuf_grow(sb, 8192); + } + + sb->buf[sb->len] = '\0'; + return sb->len - oldlen; +} + +static int strbuf_getwholeline(struct strbuf *sb, FILE *fp, int term) +{ + int ch; + + if (feof(fp)) + return EOF; + + strbuf_reset(sb); + while ((ch = fgetc(fp)) != EOF) { + strbuf_grow(sb, 1); + sb->buf[sb->len++] = ch; + if (ch == term) + break; + } + if (ch == EOF && sb->len == 0) + return EOF; + + sb->buf[sb->len] = '\0'; + return 0; +} + +int strbuf_getline(struct strbuf *sb, FILE *fp, int term) +{ + if (strbuf_getwholeline(sb, fp, term)) + return EOF; + if (sb->buf[sb->len-1] == term) + strbuf_setlen(sb, sb->len-1); + return 0; +} diff --git a/lib/util.c b/lib/util.c index 5a314ba..ea8f1b8 100644 --- a/lib/util.c +++ b/lib/util.c @@ -12,6 +12,11 @@ #include <unistd.h> #include <errno.h> #include <stdlib.h> +#include <sys/types.h> +#include <dirent.h> +#include <sys/stat.h> +#include <unistd.h> +#include <stdio.h> #include "util.h" #include "logger.h" @@ -212,3 +217,48 @@ ssize_t xpwrite(int fd, const void *buf, size_t count, off_t offset) return total; } + +/* remove directory recursively */ +int rmdir_r(char *dir_path) +{ + int ret; + struct stat s; + DIR *dir; + struct dirent *d; + char path[PATH_MAX]; + + dir = opendir(dir_path); + if (!dir) { + if (errno != ENOENT) + eprintf("failed to open %s: %m\n", dir_path); + return -errno; + } + + while ((d = readdir(dir))) { + if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")) + continue; + + snprintf(path, sizeof(path), "%s/%s", dir_path, d->d_name); + ret = stat(path, &s); + if (ret) { + eprintf("failed to stat %s: %m\n", path); + goto out; + } + if (S_ISDIR(s.st_mode)) + ret = rmdir_r(path); + else + ret = unlink(path); + + if (ret != 0) { + eprintf("failed to remove %s %s: %m\n", + S_ISDIR(s.st_mode) ? "directory" : "file", + path); + goto out; + } + } + + ret = rmdir(dir_path); +out: + closedir(dir); + return ret; +} diff --git a/sheep/Makefile.am b/sheep/Makefile.am index d296d61..149a5c4 100644 --- a/sheep/Makefile.am +++ b/sheep/Makefile.am @@ -25,7 +25,7 @@ INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include \ sbin_PROGRAMS = sheep sheep_SOURCES = sheep.c group.c sdnet.c store.c vdi.c work.c \ - journal.c ops.c recovery.c cluster/local.c strbuf.c \ + journal.c ops.c recovery.c cluster/local.c \ object_cache.c object_list_cache.c if BUILD_COROSYNC @@ -51,7 +51,7 @@ sheep_LDADD = ../lib/libsheepdog.a -lpthread \ sheep_DEPENDENCIES = ../lib/libsheepdog.a -noinst_HEADERS = work.h sheep_priv.h cluster.h strbuf.h farm/farm.h trace/trace.h +noinst_HEADERS = work.h sheep_priv.h cluster.h farm/farm.h trace/trace.h EXTRA_DIST = diff --git a/sheep/sheep_priv.h b/sheep/sheep_priv.h index 21ee282..a86d98e 100644 --- a/sheep/sheep_priv.h +++ b/sheep/sheep_priv.h @@ -313,8 +313,6 @@ int merge_objlist(uint64_t *list1, int nr_list1, uint64_t *list2, int nr_list2); void del_sheep_fd(int fd); int get_sheep_fd(uint8_t *addr, uint16_t port, int node_idx, uint32_t epoch); -int rmdir_r(char *dir_path); - int prealloc(int fd, uint32_t size); int init_objlist_cache(void); diff --git a/sheep/store.c b/sheep/store.c index 80cfb72..0ed7157 100644 --- a/sheep/store.c +++ b/sheep/store.c @@ -546,51 +546,6 @@ uint32_t get_latest_epoch(void) return epoch; } -/* remove directory recursively */ -int rmdir_r(char *dir_path) -{ - int ret; - struct stat s; - DIR *dir; - struct dirent *d; - char path[PATH_MAX]; - - dir = opendir(dir_path); - if (!dir) { - if (errno != ENOENT) - eprintf("failed to open %s: %m\n", dir_path); - return -errno; - } - - while ((d = readdir(dir))) { - if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")) - continue; - - snprintf(path, sizeof(path), "%s/%s", dir_path, d->d_name); - ret = stat(path, &s); - if (ret) { - eprintf("failed to stat %s: %m\n", path); - goto out; - } - if (S_ISDIR(s.st_mode)) - ret = rmdir_r(path); - else - ret = unlink(path); - - if (ret != 0) { - eprintf("failed to remove %s %s: %m\n", - S_ISDIR(s.st_mode) ? "directory" : "file", - path); - goto out; - } - } - - ret = rmdir(dir_path); -out: - closedir(dir); - return ret; -} - int set_cluster_ctime(uint64_t ct) { int fd, ret; diff --git a/sheep/strbuf.c b/sheep/strbuf.c deleted file mode 100644 index 1a5f855..0000000 --- a/sheep/strbuf.c +++ /dev/null @@ -1,192 +0,0 @@ -/* Taken from git by Liu Yuan <namei.unix at gmail.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#include "strbuf.h" -#include "logger.h" - -void strbuf_init(struct strbuf *sb, size_t hint) -{ - memset(sb, 0, sizeof(*sb)); - if (hint) - strbuf_grow(sb, hint); -} - -void strbuf_release(struct strbuf *sb) -{ - free(sb->buf); - memset(sb, 0, sizeof(*sb)); -} - -void strbuf_reset(struct strbuf *sb) -{ - if (sb->len) - strbuf_setlen(sb, 0); - sb->eof = 0; -} - -char *strbuf_detach(struct strbuf *sb) -{ - char *res = sb->buf; - strbuf_init(sb, 0); - return res; -} - -void strbuf_attach(struct strbuf *sb, void *buf, size_t len, size_t alloc) -{ - strbuf_release(sb); - sb->buf = buf; - sb->len = len; - sb->alloc = alloc; - strbuf_grow(sb, 0); - sb->buf[sb->len] = '\0'; -} - -void strbuf_grow(struct strbuf *sb, size_t extra) -{ - if (sb->len + extra + 1 <= sb->len) - panic("you want to use way too much memory"); - ALLOC_GROW(sb->buf, sb->len + extra + 1, sb->alloc); -} - -void strbuf_rtrim(struct strbuf *sb) -{ - while (sb->len > 0 && isspace((unsigned char)sb->buf[sb->len - 1])) - sb->len--; - sb->buf[sb->len] = '\0'; -} - -void strbuf_insert(struct strbuf *sb, size_t pos, const void *data, size_t len) -{ - strbuf_grow(sb, len); - if (pos > sb->len) - panic("`pos' is too far after the end of the buffer"); - memmove(sb->buf + pos + len, sb->buf + pos, sb->len - pos); - memcpy(sb->buf + pos, data, len); - strbuf_setlen(sb, sb->len + len); -} - -void strbuf_splice(struct strbuf *sb, size_t pos, size_t len, - const void *data, size_t dlen) -{ - if (pos + len < pos) - panic("you want to use way too much memory"); - if (pos > sb->len) - panic("`pos' is too far after the end of the buffer"); - if (pos + len > sb->len) - panic("`pos + len' is too far after the end of the buffer"); - - if (dlen >= len) - strbuf_grow(sb, dlen - len); - memmove(sb->buf + pos + dlen, - sb->buf + pos + len, - sb->len - pos - len); - memcpy(sb->buf + pos, data, dlen); - strbuf_setlen(sb, sb->len + dlen - len); -} - -void strbuf_remove(struct strbuf *sb, size_t pos, size_t len) -{ - strbuf_splice(sb, pos, len, NULL, 0); -} - -void strbuf_add(struct strbuf *sb, const void *data, size_t len) -{ - strbuf_grow(sb, len); - memcpy(sb->buf + sb->len, data, len); - strbuf_setlen(sb, sb->len + len); -} - -void strbuf_addf(struct strbuf *sb, const char *fmt, ...) -{ - int len; - va_list ap; - - va_start(ap, fmt); - len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap); - va_end(ap); - if (len < 0) { - len = 0; - } - if (len > strbuf_avail(sb)) { - strbuf_grow(sb, len); - va_start(ap, fmt); - len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap); - va_end(ap); - if (len > strbuf_avail(sb)) { - panic("this should not happen, your snprintf is broken"); - } - } - strbuf_setlen(sb, sb->len + len); -} - -size_t strbuf_fread(struct strbuf *sb, size_t size, FILE *f) -{ - size_t res; - - strbuf_grow(sb, size); - res = fread(sb->buf + sb->len, 1, size, f); - if (res > 0) { - strbuf_setlen(sb, sb->len + res); - } - return res; -} - -ssize_t strbuf_read(struct strbuf *sb, int fd, size_t hint) -{ - size_t oldlen = sb->len; - - strbuf_grow(sb, hint ? hint : 8192); - for (;;) { - ssize_t cnt; - - cnt = xread(fd, sb->buf + sb->len, sb->alloc - sb->len - 1); - if (cnt < 0) { - strbuf_setlen(sb, oldlen); - return -1; - } - if (!cnt) - break; - sb->len += cnt; - strbuf_grow(sb, 8192); - } - - sb->buf[sb->len] = '\0'; - return sb->len - oldlen; -} - -static int strbuf_getwholeline(struct strbuf *sb, FILE *fp, int term) -{ - int ch; - - if (feof(fp)) - return EOF; - - strbuf_reset(sb); - while ((ch = fgetc(fp)) != EOF) { - strbuf_grow(sb, 1); - sb->buf[sb->len++] = ch; - if (ch == term) - break; - } - if (ch == EOF && sb->len == 0) - return EOF; - - sb->buf[sb->len] = '\0'; - return 0; -} - -int strbuf_getline(struct strbuf *sb, FILE *fp, int term) -{ - if (strbuf_getwholeline(sb, fp, term)) - return EOF; - if (sb->buf[sb->len-1] == term) - strbuf_setlen(sb, sb->len-1); - return 0; -} diff --git a/sheep/strbuf.h b/sheep/strbuf.h deleted file mode 100644 index 573784b..0000000 --- a/sheep/strbuf.h +++ /dev/null @@ -1,95 +0,0 @@ -#ifndef STRBUF_H -#define STRBUF_H - -#include <assert.h> -#include <ctype.h> -#include <stdarg.h> -#include <unistd.h> -#include <stdio.h> -#include <stdlib.h> - -#include "util.h" - -struct strbuf { - size_t alloc; - size_t len; - int eof; - char *buf; -}; - -#define alloc_nr(x) (((x)+16)*3/2) - -/* - * Realloc the buffer pointed at by variable 'x' so that it can hold - * at least 'nr' entries; the number of entries currently allocated - * is 'alloc', using the standard growing factor alloc_nr() macro. - * - * DO NOT USE any expression with side-effect for 'x' or 'alloc'. - */ -#define ALLOC_GROW(x, nr, alloc) \ - do { \ - if ((nr) > alloc) { \ - if (alloc_nr(alloc) < (nr)) \ - alloc = (nr); \ - else \ - alloc = alloc_nr(alloc); \ - x = xrealloc((x), alloc * sizeof(*(x))); \ - } \ - } while(0) - -#define STRBUF_INIT { 0, 0, 0, NULL } - -/*----- strbuf life cycle -----*/ -extern void strbuf_init(struct strbuf *, size_t); -extern void strbuf_release(struct strbuf *); -extern void strbuf_reset(struct strbuf *); -extern char *strbuf_detach(struct strbuf *); -extern void strbuf_attach(struct strbuf *, void *, size_t, size_t); - -/*----- strbuf size related -----*/ -static inline size_t strbuf_avail(struct strbuf *sb) { - return sb->alloc ? sb->alloc - sb->len - 1 : 0; -} -static inline void strbuf_setlen(struct strbuf *sb, size_t len) { - assert (len < sb->alloc); - sb->len = len; - sb->buf[len] = '\0'; -} - -extern void strbuf_grow(struct strbuf *, size_t); - -/*----- content related -----*/ -extern void strbuf_rtrim(struct strbuf *); - -/*----- add data in your buffer -----*/ -static inline void strbuf_addch(struct strbuf *sb, int c) { - strbuf_grow(sb, 1); - sb->buf[sb->len++] = c; - sb->buf[sb->len] = '\0'; -} - -/* inserts after pos, or appends if pos >= sb->len */ -extern void strbuf_insert(struct strbuf *, size_t pos, const void *, size_t); -extern void strbuf_remove(struct strbuf *, size_t pos, size_t len); - -/* splice pos..pos+len with given data */ -extern void strbuf_splice(struct strbuf *, size_t pos, size_t len, - const void *, size_t); - -extern void strbuf_add(struct strbuf *, const void *, size_t); -static inline void strbuf_addstr(struct strbuf *sb, const char *s) { - strbuf_add(sb, s, strlen(s)); -} -static inline void strbuf_addbuf(struct strbuf *sb, struct strbuf *sb2) { - strbuf_add(sb, sb2->buf, sb2->len); -} - -__attribute__((format(printf,2,3))) -extern void strbuf_addf(struct strbuf *sb, const char *fmt, ...); - -extern size_t strbuf_fread(struct strbuf *, size_t, FILE *); -/* XXX: if read fails, any partial read is undone */ -extern ssize_t strbuf_read(struct strbuf *, int fd, size_t hint); -int strbuf_getline(struct strbuf *sb, FILE *fp, int term); - -#endif -- 1.7.10.2 |