diff --git a/CHANGES b/CHANGES index a456a3a..201f078 100644 --- a/CHANGES +++ b/CHANGES @@ -4,6 +4,9 @@ some arm fixes (char is unsigned on arm) str_diff* included byte.h instead of str.h (Mathias Gumz) ownership warnings for clang (can diagnose double free if you free after iob_addbuf_free) + gcc 15 and C23 force some union trickery on buffer.h :-( + add a few buffer_init*_forread variants to pretend we have type safety + make sure buffer_init_staticcontents handles flushing attempts 0.34: be more C99 compliant (Florian Weimer) diff --git a/buffer.h b/buffer.h index 7d99b47..8854e10 100644 --- a/buffer.h +++ b/buffer.h @@ -15,33 +15,48 @@ extern "C" { #endif +/* NOTE: unlike stdio a buffer can always only be for reading OR for + * writing, not both at the same time! Also, there is no linked flushing + * logic (reading from buffer_0 won't implicitly flush buffer_1 first */ typedef struct buffer { char *x; /* actual buffer space */ size_t p; /* current position */ size_t n; /* current size of string in buffer */ size_t a; /* allocated buffer size */ - ssize_t (*op)(); /* use read(2) or write(2) */ + union { + ssize_t (*wop)(int fd,const void* buf,size_t len); // for write(2) + ssize_t (*rop)(int fd,void* buf,size_t len); // for read(2) + ssize_t (*wopc)(int fd,const char* buf,size_t len, void* cookie); // write(2) w/ cookie + ssize_t (*ropc)(int fd,char* buf,size_t len, void* cookie); // read(2) w/ cookie + } op; void* cookie; /* used internally by the to-stralloc buffers, and for buffer chaining */ void (*deinit)(void*); /* called to munmap/free cleanup, with a pointer to the buffer as argument */ int fd; /* passed as first argument to op */ } buffer; -#define BUFFER_INIT(op,fd,buf,len) { (char*)(buf), 0, 0, (len), (op), NULL, NULL, (fd) } -#define BUFFER_INIT_FREE(op,fd,buf,len) { (buf), 0, 0, (len), (op), NULL, buffer_free, (fd) } -#define BUFFER_INIT_READ(op,fd,buf,len) BUFFER_INIT(op,fd,buf,len) /*obsolete*/ +#define BUFFER_INIT(func,filedes,buf,len) { .x=(buf), .p=0, .n=0, .a=(len), .op.wop=(func), .cookie=NULL, .deinit=NULL, .fd=(filedes) } +#define BUFFER_INIT_FREE(func,filedes,buf,len) { .x=(buf), .p=0, .n=0, .a=(len), .op.wop=(func), .cookie=NULL, .deinit=buffer_free, .fd=(filedes) } +#define BUFFER_INIT_READ(func,filedes,buf,len) { .x=(buf), .p=0, .n=0, .a=(len), .op.rop=(func), .cookie=NULL, .deinit=NULL, .fd=(filedes) } #define BUFFER_INSIZE 8192 #define BUFFER_OUTSIZE 8192 /* Initialize a buffer with an existing memory area, which the buffer * will NOT take ownership of (i.e. won't free the memory when it's done) */ __bufout(4,5) -void buffer_init(buffer* b, ssize_t (*op)(), int fd, char* y, size_t ylen); +void buffer_init(buffer* b, ssize_t (*op)(int fd,const void* buf,size_t l), int fd, char* y, size_t ylen); + +__bufout(4,5) +void buffer_init_forread(buffer* b, ssize_t (*op)(int fd,void* buf,size_t l), int fd, char* y, size_t ylen); /* Initialize a buffer with an existing memory area, which the buffer * WILL take ownership of (it will call free() on it when it's done) */ __bufout(4,5) att_free(malloc,4) -void buffer_init_free(buffer* b,ssize_t (*op)(),int fd,char* y,size_t ylen); +void buffer_init_free(buffer* b,ssize_t (*op)(int fd,const void* buf,size_t l),int fd,char* y,size_t ylen); + +__bufout(4,5) +att_free(malloc,4) +void buffer_init_free_forread(buffer* b,ssize_t (*op)(int fd,void* buf,size_t l),int fd,char* y,size_t ylen); /* Call buffer_init with op=read(), return 0. * If fd==-1, return -1 instead, leaving b untouched. */ @@ -57,7 +72,9 @@ int buffer_init_write(buffer* b, int fd, char* y, size_t ylen); * buffer_init_free(b, op, fd, thebuffer, ylen) on it. * Returns 0 on success, -1 on error (setting errno). * Passing fd==-1 is treated as error (so you can pass open*() for fd). */ -int buffer_init_allocbuf(buffer* b, ssize_t (*op)(), int fd, size_t ylen); +int buffer_init_allocbuf(buffer* b, ssize_t (*op)(int fd,const void* buf,size_t l), int fd, size_t ylen); + +int buffer_init_allocbuf_forread(buffer* b, ssize_t (*op)(int fd,void* buf,size_t l), int fd, size_t ylen); /* Call buffer_init_allocbuf with op=read */ int buffer_init_read_allocbuf(buffer* b, int fd, size_t ylen); @@ -74,9 +91,11 @@ int buffer_init_write_allocbuf(buffer* b, int fd, size_t ylen); * actually attempt to read from any actual file. * Does not take ownership. Useful for testing. */ __bufin(2,3) -att_holds(malloc,2) void buffer_init_staticcontents(buffer* b,char* y,size_t ylen); +__bufin(2,3) +void buffer_init_staticcontents_forread(buffer* b,const char* y,size_t ylen); + /* Same but the buffer takes ownership of the static buffer and frees it * in buffer_close. */ __bufin(2,3) diff --git a/buffer/bs_get.c b/buffer/bs_get.c index ef29e98..0d35163 100644 --- a/buffer/bs_get.c +++ b/buffer/bs_get.c @@ -71,7 +71,7 @@ int main() { /* second test: iobuf with no limit. Otherwise the same. */ struct buffer b; - buffer_init_staticcontents(&b, "fnord\nx", 6); // this will let us read 6 bytes + buffer_init_staticcontents_forread(&b, "fnord\nx", 6); // this will let us read 6 bytes bs_init_iobuf(&bs, &b); for (i=0; i<6; ++i) { buf[i] = bs_get(&bs); @@ -85,7 +85,7 @@ int main() { assert(bs_err(&bs)); /* third test: iobuf with limit. Otherwise the same. */ - buffer_init_staticcontents(&b, "fnord\nx", 7); // this will let us read 7 bytes + buffer_init_staticcontents_forread(&b, "fnord\nx", 7); // this will let us read 7 bytes bs_init_iobuf_size(&bs, &b, 6); // but we tell bytestream the limit is 6 for (i=0; i<6; ++i) { @@ -100,7 +100,7 @@ int main() { assert(bs_err(&bs)); /* fourth test: iobuf with EOF */ - buffer_init_staticcontents(&b, "fnord\nx", 6); + buffer_init_staticcontents_forread(&b, "fnord\nx", 6); bs_init_iobuf(&bs, &b); // bytestream has no limit but will hit EOF in backing buffer for (i=0; i<6; ++i) { buf[i] = bs_get(&bs); diff --git a/buffer/bs_peek.c b/buffer/bs_peek.c index 3fc633a..18118a5 100644 --- a/buffer/bs_peek.c +++ b/buffer/bs_peek.c @@ -66,7 +66,7 @@ int main() { /* second test: iobuf with no limit. Otherwise the same. */ struct buffer b; - buffer_init_staticcontents(&b, "fx", 1); + buffer_init_staticcontents_forread(&b, "fx", 1); bs_init_iobuf(&bs, &b); assert(bs_peek(&bs) == 'f'); @@ -78,7 +78,7 @@ int main() { assert(bs_err(&bs)); /* third test: iobuf with limit. Otherwise the same. */ - buffer_init_staticcontents(&b, "fx", 2); + buffer_init_staticcontents_forread(&b, "fx", 2); bs_init_iobuf_size(&bs, &b, 1); assert(bs_peek(&bs) == 'f'); @@ -90,7 +90,7 @@ int main() { assert(bs_err(&bs)); /* fourth test: iobuf with EOF */ - buffer_init_staticcontents(&b, "fx", 1); + buffer_init_staticcontents_forread(&b, "fx", 1); bs_init_iobuf(&bs, &b); // bytestream has no limit but will hit EOF in backing buffer assert(bs_peek(&bs) == 'f'); diff --git a/buffer/bs_skip.c b/buffer/bs_skip.c index b75801e..3a040b1 100644 --- a/buffer/bs_skip.c +++ b/buffer/bs_skip.c @@ -50,6 +50,7 @@ size_t bs_skip(struct bytestream* bs, size_t len) { #include "buffer/bs_capacityassert.c" #include "byte/byte_copy.c" #include "buffer/buffer_init.c" +#include "buffer/buffer_init_read.c" int main() { struct bytestream bs; @@ -71,7 +72,7 @@ int main() { int fd = open_read("GNUmakefile"); assert(fd != -1); unsigned char iobuf[42]; - buffer b = BUFFER_INIT(read, fd, iobuf+32, 10); + buffer b = BUFFER_INIT_READ(read, fd, iobuf+32, 10); bs_init_iobuf(&bs, &b); assert(bs_skip(&bs, 100) == 100); assert(prs_readblob(&bs, iobuf, 10) == 10); @@ -91,7 +92,7 @@ int main() { write(pipes[1], iobuf, 32); } } - buffer_init(&b, read, pipes[0], iobuf+32, 10); + buffer_init_read(&b, pipes[0], iobuf+32, 10); bs_init_iobuf(&bs, &b); assert(bs_skip(&bs, 20) == 20); diff --git a/buffer/buffer_0.c b/buffer/buffer_0.c index 8f5f94f..8997c54 100644 --- a/buffer/buffer_0.c +++ b/buffer/buffer_0.c @@ -1,7 +1,7 @@ #include #include "buffer.h" -static ssize_t b0read(int fd,char* buf, size_t len) { +static ssize_t b0read(int fd,void* buf, size_t len) { if (buffer_flush(buffer_1)<0) return -1; return read(fd,buf,len); } diff --git a/buffer/buffer_0small.c b/buffer/buffer_0small.c index c0cfbf3..f8f8204 100644 --- a/buffer/buffer_0small.c +++ b/buffer/buffer_0small.c @@ -1,7 +1,7 @@ #include #include "buffer.h" -static ssize_t b0read(int fd,char* buf, size_t len) { +static ssize_t b0read(int fd,void* buf, size_t len) { if (buffer_flush(buffer_1small)<0) return -1; return read(fd,buf,len); } diff --git a/buffer/buffer_feed.c b/buffer/buffer_feed.c index 9d97eda..c25ac8a 100644 --- a/buffer/buffer_feed.c +++ b/buffer/buffer_feed.c @@ -1,11 +1,11 @@ #include "buffer.h" -extern ssize_t buffer_stubborn_read(ssize_t (*op)(),int fd,const char* buf, size_t len,void* cookie); +extern ssize_t buffer_stubborn_read(ssize_t (*op)(int fd,char* buf,size_t l,void* c),int fd,char* buf, size_t len,void* cookie); ssize_t buffer_feed(buffer* b) { if (b->p==b->n) { ssize_t w; - if ((w=buffer_stubborn_read(b->op,b->fd,b->x,b->a,b))<0) + if ((w=buffer_stubborn_read(b->op.ropc,b->fd,b->x,b->a,b))<0) return -1; b->n=(size_t)w; b->p=0; diff --git a/buffer/buffer_flush.c b/buffer/buffer_flush.c index 786cb16..3ab59d8 100644 --- a/buffer/buffer_flush.c +++ b/buffer/buffer_flush.c @@ -1,13 +1,15 @@ #include "buffer.h" -extern ssize_t buffer_stubborn(ssize_t (*op)(),int fd,const char* buf, size_t len,void* cookie); +extern ssize_t buffer_stubborn(ssize_t (*op)(int fd,const char* buf,size_t len,void* cookie),int fd,const char* buf, size_t len,void* cookie); extern int buffer_flush(buffer* b) { register size_t p; register ssize_t r; if (!(p=b->p)) return 0; /* buffer already empty */ - b->p=0; - r=buffer_stubborn(b->op,b->fd,b->x,p,b); - if (r>0) r=0; + r=buffer_stubborn(b->op.wopc,b->fd,b->x,p,b); + if (r>0) { + r=0; + b->p=0; + } return (int)r; } diff --git a/buffer/buffer_fromarray.c b/buffer/buffer_fromarray.c index 77d8483..0926c1e 100644 --- a/buffer/buffer_fromarray.c +++ b/buffer/buffer_fromarray.c @@ -2,7 +2,10 @@ #include "array.h" #include "buffer.h" -static ssize_t fail() { +static ssize_t fail(int fd,void* buf,size_t l) { + (void)fd; + (void)buf; + (void)l; errno=EINVAL; return -1; } @@ -10,7 +13,7 @@ static ssize_t fail() { void buffer_fromarray(buffer* b,array* a) { if (array_failed(a)) { memset(b,0,sizeof *b); - b->op=fail; + b->op.rop=fail; } else buffer_frombuf(b,array_start(a),a->initialized); } diff --git a/buffer/buffer_frombuf.c b/buffer/buffer_frombuf.c index 0c9d931..4c85c6f 100644 --- a/buffer/buffer_frombuf.c +++ b/buffer/buffer_frombuf.c @@ -1,7 +1,7 @@ #include "stralloc.h" #include "buffer.h" -static ssize_t dummyreadwrite(int fd,char* buf,size_t len) { +static ssize_t dummyreadwrite(int fd,void* buf,size_t len) { (void)fd; (void)buf; (void)len; @@ -14,6 +14,6 @@ void buffer_frombuf(buffer* b,const char* x,size_t l) { b->n=l; b->a=l; b->fd=0; - b->op=dummyreadwrite; + b->op.rop=dummyreadwrite; b->deinit=0; } diff --git a/buffer/buffer_get_token.c b/buffer/buffer_get_token.c index b5c91e3..779c555 100644 --- a/buffer/buffer_get_token.c +++ b/buffer/buffer_get_token.c @@ -1,3 +1,6 @@ +// goddamn glibc! +#define _XOPEN_SOURCE + #include #include diff --git a/buffer/buffer_get_token_sa_pred.c b/buffer/buffer_get_token_sa_pred.c index 44ba216..e55ba80 100644 --- a/buffer/buffer_get_token_sa_pred.c +++ b/buffer/buffer_get_token_sa_pred.c @@ -1,7 +1,5 @@ -#include "byte.h" #include "stralloc.h" #include "buffer.h" -#include int buffer_get_token_sa_pred(buffer* b,stralloc* sa,sa_predicate p) { for (;;) { diff --git a/buffer/buffer_getc.c b/buffer/buffer_getc.c index de979ae..dfeaa21 100644 --- a/buffer/buffer_getc.c +++ b/buffer/buffer_getc.c @@ -1,4 +1,3 @@ -#include "byte.h" #include "buffer.h" ssize_t buffer_getc(buffer* b,char* x) { diff --git a/buffer/buffer_getn.c b/buffer/buffer_getn.c index 0981e7a..3f1d77a 100644 --- a/buffer/buffer_getn.c +++ b/buffer/buffer_getn.c @@ -1,4 +1,3 @@ -#include "byte.h" #include "buffer.h" ssize_t buffer_getn(buffer* b,char* x,size_t len) { diff --git a/buffer/buffer_init.3 b/buffer/buffer_init.3 index 3138544..5bfd73b 100644 --- a/buffer/buffer_init.3 +++ b/buffer/buffer_init.3 @@ -5,7 +5,11 @@ buffer_init \- initialize buffer structure .B #include void \fBbuffer_init\fR(buffer &\fIb\fR, - ssize_t (*\fIop\fR)(int,char*,size_t), + ssize_t (*\fIop\fR)(int,const void*,size_t), + int \fIfd\fR, char* \fIy\fR, size_t \fIylen\fR); + +void \fBbuffer_init_forread\fR(buffer &\fIb\fR, + ssize_t (*\fIop\fR)(int,void*,size_t), int \fIfd\fR, char* \fIy\fR, size_t \fIylen\fR); .SH DESCRIPTION buffer_init prepares \fIb\fR to store a string in \fIy\fR[0], \fIy\fR[1], ..., @@ -18,11 +22,25 @@ You can use buffer \fIb\fR = BUFFER_INIT(\fIop\fR,\fIfd\fR,\fIy\fR,\fIylen\fR); +or + + buffer \fIb\fR = BUFFER_INIT_READ(\fIop\fR,\fIfd\fR,\fIy\fR,\fIylen\fR); + to initialize \fIb\fR statically if \fIop\fR, \fIfd\fR, \fIy\fR, and \fIylen\fR are compile-time constants. You can call buffer_init again at any time. Note that this discards the currently buffered string. + +The prototypes for \fIop\fR match write(2) and read(2). + +If you want to actually pass write(2), use buffer_init_write() instead, +and for read(2) use buffer_init_read(). + +If you want to hand over ownership of \fIy\fR, so that buffer_close +also calls free() on the associated memory buffer, use +buffer_init_free(3) or buffer_init_free_forread(3). + .SH EXAMPLE #include #include @@ -42,4 +60,5 @@ currently buffered string. } .SH "SEE ALSO" -buffer_flush(3), buffer(3) +buffer_flush(3), buffer(3), buffer_init_read(3), buffer_init_write(3), +buffer_init_free(3) diff --git a/buffer/buffer_init.c b/buffer/buffer_init.c index 2d2070c..2dbaaf3 100644 --- a/buffer/buffer_init.c +++ b/buffer/buffer_init.c @@ -1,8 +1,8 @@ #include -void buffer_init(buffer* b,ssize_t (*op)(),int fd, +void buffer_init(buffer* b,ssize_t (*op)(int fd,const void* buf,size_t l),int fd, char* y,size_t ylen) { - b->op=op; + b->op.wop=op; b->fd=fd; b->x=y; b->a=ylen; @@ -11,3 +11,8 @@ void buffer_init(buffer* b,ssize_t (*op)(),int fd, b->cookie=0; b->deinit=0; } + +void buffer_init_forread(buffer* b,ssize_t (*op)(int fd,void* buf,size_t l),int fd, + char* y,size_t ylen) { + buffer_init(b,(void*)op,fd,y,ylen); +} diff --git a/buffer/buffer_init_allocbuf.c b/buffer/buffer_init_allocbuf.c index 3bfde5d..6ff8c34 100644 --- a/buffer/buffer_init_allocbuf.c +++ b/buffer/buffer_init_allocbuf.c @@ -2,7 +2,7 @@ #include #include -int buffer_init_allocbuf(buffer* b, ssize_t (*op)(), int fd, size_t ylen) { +int buffer_init_allocbuf(buffer* b, ssize_t (*op)(int fd,const void* buf,size_t l), int fd, size_t ylen) { if (fd==-1) return -1; char* thebuffer; if (!(thebuffer=malloc(ylen))) @@ -11,3 +11,6 @@ int buffer_init_allocbuf(buffer* b, ssize_t (*op)(), int fd, size_t ylen) { return 0; } +int buffer_init_allocbuf_forread(buffer* b, ssize_t (*op)(int fd,void* buf,size_t l), int fd, size_t ylen) { + return buffer_init_allocbuf(b,(void*)op,fd,ylen); +} diff --git a/buffer/buffer_init_forread.3 b/buffer/buffer_init_forread.3 new file mode 100644 index 0000000..2e682e4 --- /dev/null +++ b/buffer/buffer_init_forread.3 @@ -0,0 +1,55 @@ +.TH buffer_init_forread 3 +.SH NAME +buffer_init_forread \- initialize buffer structure +.SH SYNTAX +.B #include + +void \fBbuffer_init_forread\fR(buffer &\fIb\fR, + ssize_t (*\fIop\fR)(int,void*,size_t), + int \fIfd\fR, char* \fIy\fR, size_t \fIylen\fR); +.SH DESCRIPTION +buffer_init prepares \fIb\fR to store a string in \fIy\fR[0], \fIy\fR[1], ..., +\fIy\fR[\fIylen\fR-1]. Initially the string is empty. + +buffer_init_forread also prepares \fIb\fR to use the read operation specified by +\fIop\fR and \fIfd\fR. + +You can use + + buffer \fIb\fR = BUFFER_INIT_READ(\fIop\fR,\fIfd\fR,\fIy\fR,\fIylen\fR); + +to initialize \fIb\fR statically if \fIop\fR, \fIfd\fR, \fIy\fR, and \fIylen\fR +are compile-time constants. + +You can call buffer_init again at any time. Note that this discards the +currently buffered string. + +The prototype for \fIop\fR matches read(2). + +If you want to actually pass read(2) as op, use buffer_init_read() instead. + +If you want to hand over ownership of \fIy\fR, so that buffer_close +also calls free() on the associated memory buffer, use +buffer_init_free_forread(3). + +.SH EXAMPLE + #include + #include + + char buf[4096]; + int fd=open_read("/etc/services"); + buffer input; + + if (fd>=0) { + char x; + buffer_init_forread(&input,read,fd,buf,sizeof buf); + while (buffer_get(&input,&x,1)==1) { + buffer_put(buffer_1,&x,1); + if (x=='\\n') break; + } + buffer_flush(buffer_1); + } + +.SH "SEE ALSO" +buffer_flush(3), buffer(3), buffer_init_read(3), buffer_init_write(3), +buffer_init_free(3) diff --git a/buffer/buffer_init_free.3 b/buffer/buffer_init_free.3 index d8ef383..16e507e 100644 --- a/buffer/buffer_init_free.3 +++ b/buffer/buffer_init_free.3 @@ -7,8 +7,15 @@ buffer_init_free \- initialize buffer structure void \fBbuffer_init_free\fR(buffer &\fIb\fR, ssize_t (*\fIop\fR)(int,char*,size_t), int \fIfd\fR, char* \fIy\fR, size_t \fIylen\fR); + +void \fBbuffer_init_free_forread\fR(buffer &\fIb\fR, + ssize_t (*\fIop\fR)(int,char*,size_t), + int \fIfd\fR, char* \fIy\fR, size_t \fIylen\fR); .SH DESCRIPTION buffer_init_free is like buffer_init except that the memory (\fIy\fR is -marked to be freed by buffer_close(). +marked to be freed by buffer_close). + +buffer_init_free_forread is like buffer_init_forread except that the memory (\fIy\fR is +marked to be freed by buffer_close). .SH "SEE ALSO" buffer_init(3), buffer_mmap_read(3), buffer(3) diff --git a/buffer/buffer_init_free.c b/buffer/buffer_init_free.c index a8571a8..545bf2e 100644 --- a/buffer/buffer_init_free.c +++ b/buffer/buffer_init_free.c @@ -1,7 +1,13 @@ #include -void buffer_init_free(buffer* b,ssize_t (*op)(),int fd, +void buffer_init_free(buffer* b,ssize_t (*op)(int fd,const void* buf,size_t l),int fd, char* y,size_t ylen) { buffer_init(b,op,fd,y,ylen); b->deinit=buffer_free; } + +void buffer_init_free_forread(buffer* b,ssize_t (*op)(int fd,void* buf,size_t l),int fd, + char* y,size_t ylen) { + buffer_init_forread(b,op,fd,y,ylen); + b->deinit=buffer_free; +} diff --git a/buffer/buffer_init_read.3 b/buffer/buffer_init_read.3 new file mode 100644 index 0000000..2f6a5f0 --- /dev/null +++ b/buffer/buffer_init_read.3 @@ -0,0 +1,32 @@ +.TH buffer_init_read 3 +.SH NAME +buffer_init_read \- initialize buffer structure +.SH SYNTAX +.B #include + +void \fBbuffer_init_read\fR(buffer &\fIb\fR, + int \fIfd\fR, char* \fIy\fR, size_t \fIylen\fR); + +.SH DESCRIPTION +buffer_init_read is equivalent to calling buffer_init_forread with read(2) as op. + +.SH EXAMPLE + #include + #include + + char buf[4096]; + int fd=open_read("/etc/services"); + buffer input; + + if (fd>=0) { + char x; + buffer_init_read(&input,fd,buf,sizeof buf); + while (buffer_get(&input,&x,1)==1) { + buffer_put(buffer_1,&x,1); + if (x=='\\n') break; + } + buffer_flush(buffer_1); + } + +.SH "SEE ALSO" +buffer_init(3), buffer(3), buffer_init_write(3) diff --git a/buffer/buffer_init_read.c b/buffer/buffer_init_read.c index 491d141..b2ad050 100644 --- a/buffer/buffer_init_read.c +++ b/buffer/buffer_init_read.c @@ -3,7 +3,7 @@ int buffer_init_read(buffer* b, int fd, char* y,size_t ylen) { if (fd==-1) return -1; - buffer_init(b, read, fd, y, ylen); + buffer_init_forread(b, read, fd, y, ylen); return 0; } diff --git a/buffer/buffer_init_read_allocbuf.c b/buffer/buffer_init_read_allocbuf.c index f078478..a3b8731 100644 --- a/buffer/buffer_init_read_allocbuf.c +++ b/buffer/buffer_init_read_allocbuf.c @@ -2,6 +2,6 @@ #include int buffer_init_read_allocbuf(buffer* b, int fd, size_t ylen) { - return buffer_init_allocbuf(b, read, fd, ylen); + return buffer_init_allocbuf_forread(b, read, fd, ylen); } diff --git a/buffer/buffer_init_staticcontents.3 b/buffer/buffer_init_staticcontents.3 new file mode 100644 index 0000000..ae2fe62 --- /dev/null +++ b/buffer/buffer_init_staticcontents.3 @@ -0,0 +1,37 @@ +.TH buffer_init_staticcontents 3 +.SH NAME +buffer_init_staticcontents \- initialize buffer structure +.SH SYNTAX +.B #include + +void \fBbuffer_init_staticcontents\fR(buffer &\fIb\fR, + char* \fIy\fR, size_t \fIylen\fR); + +void \fBbuffer_init_staticcontents_forread\fR(buffer &\fIb\fR, + const char* \fIy\fR, size_t \fIylen\fR); + +.SH DESCRIPTION +buffer_init_staticcontents sets up a buffer pointing to a fixed buffer. +No file is associated with the buffer. No resizing is done on the +buffer. Writing past capacity will return an error. + +buffer_init_staticcontents_forread sets up a buffer for reading, +pointing to a pre-filled fixed buffer. + +This is useful for writing unit tests. + +.SH EXAMPLE + #include + #include + #include + + char buf[4096]; + buffer output; + + char x; + buffer_init_staticcontents(&output,buf,sizeof buf); + buffer_putsflush(&output,"foo\\nbar\\n"); + assert(output.p==8 && byte_equal(buf,8,"foo\\nbar\\n")); + +.SH "SEE ALSO" +buffer_init(3), buffer(3), buffer_init_write(3) diff --git a/buffer/buffer_init_staticcontents.c b/buffer/buffer_init_staticcontents.c index 814b6cc..51472e0 100644 --- a/buffer/buffer_init_staticcontents.c +++ b/buffer/buffer_init_staticcontents.c @@ -1,14 +1,28 @@ #include +#include -static ssize_t op() { +static ssize_t op(int fd,const void* buf,size_t l) { + (void)fd; + (void)buf; + (void)l; + errno=ENOENT; return 0; } void buffer_init_staticcontents(buffer* b, char* y, size_t len) { b->x=y; - b->p=0; b->a=b->n=len; + b->p=0; b->a=len; b->n=0; b->fd=-1; - b->op=op; + b->op.wop=op; + b->deinit=0; +} + +void buffer_init_staticcontents_forread(buffer* b, const char* y, size_t len) { + b->x=(char*)y; + b->p=0; + b->a=b->n=len; + b->fd=-1; + b->op.wop=op; b->deinit=0; } @@ -26,7 +40,7 @@ void buffer_init_staticcontents(buffer* b, char* y, size_t len) { int main() { buffer b; - buffer_init_staticcontents(&b, "fnord", 5); + buffer_init_staticcontents_forread(&b, "fnord", 5); char tmp[6]; assert(buffer_get(&b, tmp, 6) == 5); assert(!memcmp(tmp,"fnord",5)); diff --git a/buffer/buffer_init_staticcontents_forread.3 b/buffer/buffer_init_staticcontents_forread.3 new file mode 100644 index 0000000..6f00e69 --- /dev/null +++ b/buffer/buffer_init_staticcontents_forread.3 @@ -0,0 +1,32 @@ +.TH buffer_init_staticcontents_forread 3 +.SH NAME +buffer_init_staticcontents_forread \- initialize buffer structure +.SH SYNTAX +.B #include + +void \fBbuffer_init_staticcontents_forread\fR(buffer &\fIb\fR, + const char* \fIy\fR, size_t \fIylen\fR); + +.SH DESCRIPTION +buffer_init_staticcontents_forread sets up a buffer for reading, +pointing to a pre-filled fixed buffer. + +This is useful for writing unit tests. + +.SH EXAMPLE + #include + #include + + char buf[]="foo\\nbar\\n"; + buffer input; + + char x; + buffer_init_staticcontents_forread(&input,buf,sizeof buf); + while (buffer_get(&input,&x,1)==1) { + buffer_put(buffer_1,&x,1); + if (x=='\\n') break; + } + buffer_flush(buffer_1); + +.SH "SEE ALSO" +buffer_init(3), buffer(3), buffer_init_staticcontents(3) diff --git a/buffer/buffer_init_write.3 b/buffer/buffer_init_write.3 new file mode 100644 index 0000000..cff3024 --- /dev/null +++ b/buffer/buffer_init_write.3 @@ -0,0 +1,14 @@ +.TH buffer_init_write 3 +.SH NAME +buffer_init_write \- initialize buffer structure +.SH SYNTAX +.B #include + +void \fBbuffer_init_write\fR(buffer &\fIb\fR, + int \fIfd\fR, char* \fIy\fR, size_t \fIylen\fR); + +.SH DESCRIPTION +buffer_init_read is equivalent to calling buffer_init with write(2) as op. + +.SH "SEE ALSO" +buffer_init(3), buffer(3), buffer_init_read(3) diff --git a/buffer/buffer_mmapread.c b/buffer/buffer_mmapread.c index 1f5977e..2517d4d 100644 --- a/buffer/buffer_mmapread.c +++ b/buffer/buffer_mmapread.c @@ -1,7 +1,10 @@ #include #include -static ssize_t op() { +static ssize_t op(int fd,void* buf,size_t l) { + (void)fd; + (void)buf; + (void)l; return 0; } @@ -9,7 +12,7 @@ int buffer_mmapread(buffer* b,const char* filename) { if (!(b->x=(char*)mmap_read(filename,&b->n))) return -1; b->p=0; b->a=b->n; b->fd=-1; - b->op=op; + b->op.rop=op; b->deinit=buffer_munmap; return 0; } diff --git a/buffer/buffer_peekc.c b/buffer/buffer_peekc.c index 9935bcd..24e7546 100644 --- a/buffer/buffer_peekc.c +++ b/buffer/buffer_peekc.c @@ -1,4 +1,3 @@ -#include "byte.h" #include "buffer.h" ssize_t buffer_peekc(buffer* b,char* x) { diff --git a/buffer/buffer_put.c b/buffer/buffer_put.c index 3a36a88..82ade78 100644 --- a/buffer/buffer_put.c +++ b/buffer/buffer_put.c @@ -5,7 +5,7 @@ #endif #include "buffer.h" -extern ssize_t buffer_stubborn(ssize_t (*op)(),int fd,const char* buf, size_t len,void* cookie); +extern ssize_t buffer_stubborn(ssize_t (*op)(int fd,const char* buf,size_t len,void* cookie),int fd,const char* buf, size_t len,void* cookie); #ifndef __unlikely #ifdef __GNUC__ @@ -18,7 +18,7 @@ extern ssize_t buffer_stubborn(ssize_t (*op)(),int fd,const char* buf, size_t le int buffer_put(buffer* b,const char* buf,size_t len) { if (__unlikely(len>b->a-b->p)) { /* doesn't fit */ #ifndef __MINGW32__ - if (b->op==write) { + if (b->op.wop==write) { /* if it's write, we can substitute writev */ struct iovec v[2]; ssize_t r; @@ -38,7 +38,7 @@ int buffer_put(buffer* b,const char* buf,size_t len) { #endif if (buffer_flush(b)==-1) return -1; if (len>b->a) { - if (buffer_stubborn(b->op,b->fd,buf,len,b)<0) return -1; + if (buffer_stubborn(b->op.wopc,b->fd,buf,len,b)<0) return -1; return 0; } } diff --git a/buffer/buffer_putflush.c b/buffer/buffer_putflush.c index c78af7a..ff9e7a3 100644 --- a/buffer/buffer_putflush.c +++ b/buffer/buffer_putflush.c @@ -14,15 +14,25 @@ #endif #endif -extern ssize_t buffer_stubborn(ssize_t (*op)(),int fd,const char* buf, size_t len,void* cookie); +extern ssize_t buffer_stubborn(ssize_t (*op)(int fd,const char* buf,size_t len,void* cookie),int fd,const char* buf, size_t len,void* cookie); int buffer_putflush(buffer* b,const char* x,size_t len) { /* Since we know we are going to flush anyway, let's see if we can * optimize a bit */ - if (!b->p) /* if the buffer is empty, just call buffer_stubborn directly */ - return buffer_stubborn(b->op,b->fd,x,len,b); + if (!b->p) { /* if the buffer is empty, just call buffer_stubborn directly */ + ssize_t r = buffer_stubborn(b->op.wopc,b->fd,x,len,b); + if (r == -1 && errno==ENOENT) { + // tried to flush on buffer_init_staticcontents, ignore + } else { + if (r <= 0 || (size_t)r == len) return r; // common case + // partial write + x+=r; + len-=r; + // fall through + } + } #ifndef __MINGW32__ - if (b->op==write && len>sizeof(struct iovec)*2) { + if (b->op.wop==write && len>sizeof(struct iovec)*2) { struct iovec v[2]; ssize_t w; size_t cl=b->p+len; @@ -37,11 +47,11 @@ int buffer_putflush(buffer* b,const char* x,size_t len) { if (__unlikely((size_t)w!=cl)) { /* partial write. ugh. */ if ((size_t)wop,b->fd,v[0].iov_base+w,v[0].iov_len-w,b) || - buffer_stubborn(b->op,b->fd,v[1].iov_base,v[0].iov_len,b)) return -1; + if (buffer_stubborn(b->op.wopc,b->fd,v[0].iov_base+w,v[0].iov_len-w,b) || + buffer_stubborn(b->op.wopc,b->fd,v[1].iov_base,v[0].iov_len,b)) return -1; } else { w-=v[0].iov_len; - return buffer_stubborn(b->op,b->fd,v[1].iov_base+w,v[1].iov_len-w,b); + return buffer_stubborn(b->op.wopc,b->fd,v[1].iov_base+w,v[1].iov_len-w,b); } } b->p=0; diff --git a/buffer/buffer_putnlflush.c b/buffer/buffer_putnlflush.c index aa6ab97..de49a5b 100644 --- a/buffer/buffer_putnlflush.c +++ b/buffer/buffer_putnlflush.c @@ -1,4 +1,3 @@ -#include "str.h" #include "buffer.h" int buffer_putnlflush(buffer* b) { diff --git a/buffer/buffer_putspace.c b/buffer/buffer_putspace.c index 48fea2a..f1f4b1b 100644 --- a/buffer/buffer_putspace.c +++ b/buffer/buffer_putspace.c @@ -1,4 +1,3 @@ -#include "str.h" #include "buffer.h" int buffer_putspace(buffer* b) { diff --git a/buffer/buffer_stubborn2.c b/buffer/buffer_stubborn2.c index 1979497..709ddd3 100644 --- a/buffer/buffer_stubborn2.c +++ b/buffer/buffer_stubborn2.c @@ -1,7 +1,7 @@ #include #include "buffer.h" -ssize_t buffer_stubborn_read(ssize_t (*op)(int fd,const char* buf,size_t len,void* cookie),int fd,const char* buf, size_t len,void* cookie) { +ssize_t buffer_stubborn_read(ssize_t (*op)(int fd,char* buf,size_t len,void* cookie),int fd,char* buf, size_t len,void* cookie) { ssize_t w; for (;;) { if ((w=op(fd,buf,len,cookie))<0) diff --git a/buffer/buffer_tosa.c b/buffer/buffer_tosa.c index a10be4f..bb2b5ac 100644 --- a/buffer/buffer_tosa.c +++ b/buffer/buffer_tosa.c @@ -1,7 +1,7 @@ #include "stralloc.h" #include "buffer.h" -static ssize_t strallocwrite(int fd,char* buf,size_t len,void* myself) { +static ssize_t strallocwrite(int fd,const char* buf,size_t len,void* myself) { buffer* b=myself; stralloc* sa=b->cookie; sa->len+=len; @@ -21,7 +21,7 @@ int buffer_tosa(buffer* b,stralloc* sa) { b->n=0; b->a=1024; b->fd=0; - b->op=strallocwrite; + b->op.wopc=strallocwrite; b->cookie=sa; b->deinit=0; return 0; diff --git a/buffer/prs_readblob.c b/buffer/prs_readblob.c index 28017df..c2e8851 100644 --- a/buffer/prs_readblob.c +++ b/buffer/prs_readblob.c @@ -81,7 +81,7 @@ int main() { int fd = open_read("Makefile"); assert(fd!=-1); - buffer b = BUFFER_INIT(read, fd, buf+32, 10); + buffer b = BUFFER_INIT_READ(read, fd, buf+32, 10); bs_init_iobuf_size(&bs, &b, 100); assert(prs_readblob(&bs, buf, 20) == 20); // make sure we can read a 20 byte blob at once even if the iobuf buffer size is smaller // strace will show two read calls here