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
This commit is contained in:
3
CHANGES
3
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)
|
||||
|
||||
35
buffer.h
35
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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include <unistd.h>
|
||||
#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);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include <unistd.h>
|
||||
#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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// goddamn glibc!
|
||||
#define _XOPEN_SOURCE
|
||||
|
||||
#include <libowfat/byte.h>
|
||||
#include <libowfat/buffer.h>
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#include "byte.h"
|
||||
#include "stralloc.h"
|
||||
#include "buffer.h"
|
||||
#include <errno.h>
|
||||
|
||||
int buffer_get_token_sa_pred(buffer* b,stralloc* sa,sa_predicate p) {
|
||||
for (;;) {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#include "byte.h"
|
||||
#include "buffer.h"
|
||||
|
||||
ssize_t buffer_getc(buffer* b,char* x) {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#include "byte.h"
|
||||
#include "buffer.h"
|
||||
|
||||
ssize_t buffer_getn(buffer* b,char* x,size_t len) {
|
||||
|
||||
@@ -5,7 +5,11 @@ buffer_init \- initialize buffer structure
|
||||
.B #include <libowfat/buffer.h>
|
||||
|
||||
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 <libowfat/buffer.h>
|
||||
#include <libowfat/open.h>
|
||||
@@ -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)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#include <libowfat/buffer.h>
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#include <unistd.h>
|
||||
#include <libowfat/buffer.h>
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
55
buffer/buffer_init_forread.3
Normal file
55
buffer/buffer_init_forread.3
Normal file
@@ -0,0 +1,55 @@
|
||||
.TH buffer_init_forread 3
|
||||
.SH NAME
|
||||
buffer_init_forread \- initialize buffer structure
|
||||
.SH SYNTAX
|
||||
.B #include <libowfat/buffer.h>
|
||||
|
||||
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 <libowfat/buffer.h>
|
||||
#include <libowfat/open.h>
|
||||
|
||||
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)
|
||||
@@ -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)
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
#include <libowfat/buffer.h>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
32
buffer/buffer_init_read.3
Normal file
32
buffer/buffer_init_read.3
Normal file
@@ -0,0 +1,32 @@
|
||||
.TH buffer_init_read 3
|
||||
.SH NAME
|
||||
buffer_init_read \- initialize buffer structure
|
||||
.SH SYNTAX
|
||||
.B #include <libowfat/buffer.h>
|
||||
|
||||
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 <libowfat/buffer.h>
|
||||
#include <libowfat/open.h>
|
||||
|
||||
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)
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
#include <libowfat/buffer.h>
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
37
buffer/buffer_init_staticcontents.3
Normal file
37
buffer/buffer_init_staticcontents.3
Normal file
@@ -0,0 +1,37 @@
|
||||
.TH buffer_init_staticcontents 3
|
||||
.SH NAME
|
||||
buffer_init_staticcontents \- initialize buffer structure
|
||||
.SH SYNTAX
|
||||
.B #include <libowfat/buffer.h>
|
||||
|
||||
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 <libowfat/buffer.h>
|
||||
#include <libowfat/byte.h>
|
||||
#include <assert.h>
|
||||
|
||||
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)
|
||||
@@ -1,14 +1,28 @@
|
||||
#include <libowfat/buffer.h>
|
||||
#include <errno.h>
|
||||
|
||||
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));
|
||||
|
||||
32
buffer/buffer_init_staticcontents_forread.3
Normal file
32
buffer/buffer_init_staticcontents_forread.3
Normal file
@@ -0,0 +1,32 @@
|
||||
.TH buffer_init_staticcontents_forread 3
|
||||
.SH NAME
|
||||
buffer_init_staticcontents_forread \- initialize buffer structure
|
||||
.SH SYNTAX
|
||||
.B #include <libowfat/buffer.h>
|
||||
|
||||
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 <libowfat/buffer.h>
|
||||
#include <libowfat/open.h>
|
||||
|
||||
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)
|
||||
14
buffer/buffer_init_write.3
Normal file
14
buffer/buffer_init_write.3
Normal file
@@ -0,0 +1,14 @@
|
||||
.TH buffer_init_write 3
|
||||
.SH NAME
|
||||
buffer_init_write \- initialize buffer structure
|
||||
.SH SYNTAX
|
||||
.B #include <libowfat/buffer.h>
|
||||
|
||||
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)
|
||||
@@ -1,7 +1,10 @@
|
||||
#include <libowfat/buffer.h>
|
||||
#include <libowfat/mmap.h>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#include "byte.h"
|
||||
#include "buffer.h"
|
||||
|
||||
ssize_t buffer_peekc(buffer* b,char* x) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)w<v[0].iov_len) {
|
||||
if (buffer_stubborn(b->op,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;
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#include "str.h"
|
||||
#include "buffer.h"
|
||||
|
||||
int buffer_putnlflush(buffer* b) {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#include "str.h"
|
||||
#include "buffer.h"
|
||||
|
||||
int buffer_putspace(buffer* b) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include <errno.h>
|
||||
#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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user