add compiler.h to abstract gcc attributes

master
Felix von Leitner 3 years ago
parent 78084c5bd5
commit a10f89d5f3

@ -5,6 +5,7 @@
add automated way to run unit test: make check
add parse.h
add bytestream abstraction for parsing data from a buffer or a file
add compiler.h to abstract gcc attributes
0.32:
remove OpenBSD #warning (obsd maintainer says no longer needed)

@ -209,7 +209,7 @@ INCLUDES=buffer.h byte.h fmt.h ip4.h ip6.h mmap.h scan.h socket.h str.h stralloc
uint16.h uint32.h uint64.h open.h textcode.h tai.h taia.h dns.h iopause.h case.h \
openreadclose.h readclose.h ndelay.h array.h io.h safemult.h iob.h havealloca.h \
errmsg.h cdb.h cdb_make.h rangecheck.h iarray.h va_narg.h isset.h \
compiletimeassert.h critbit.h parse.h
compiletimeassert.h critbit.h parse.h compiler.h
libowfat:
-mkdir libowfat

@ -3,7 +3,8 @@
#define ARRAY_H
#include <stddef.h>
#include "uint64.h"
#include <libowfat/compiler.h>
#include <libowfat/uint64.h>
#ifdef __cplusplus
extern "C" {
@ -21,25 +22,30 @@ typedef struct {
size_t headroom; /* the actual pointer for free() and realloc() is p-headroom */
} array;
void* array_allocate(array* x,uint64 membersize,int64 pos);
void* array_get(const array* const x,uint64 membersize,int64 pos);
void* array_start(const array* const x);
int64 array_length(const array* const x,uint64 membersize);
int64 array_bytes(const array* const x);
void array_truncate(array* x,uint64 membersize,int64 len);
void array_trunc(array* x);
void array_reset(array* x);
void array_fail(array* x);
int array_equal(const array* const x,const array* const y);
void array_cat(array* to,const array* const from);
void array_catb(array* to,const char* from,uint64 len);
void array_cats(array* to,const char* from);
void array_cats0(array* to,const char* from);
void array_cat0(array* to);
void array_cate(array* to,const array* const from,int64 pos,int64 stop);
void array_shift(array* x,uint64 membersize,uint64 members);
void array_chop(array* x,uint64 membersize,uint64 members);
void* array_allocate(array* x,uint64 membersize,int64 pos) noexcept;
void* array_get(const array* const x,uint64 membersize,int64 pos) noexcept;
void* array_start(const array* const x) noexcept;
att_pure
int64 array_length(const array* const x,uint64 membersize) noexcept;
att_pure
int64 array_bytes(const array* const x) noexcept;
void array_truncate(array* x,uint64 membersize,int64 len) noexcept;
void array_trunc(array* x) noexcept;
void array_reset(array* x) noexcept;
void array_fail(array* x) noexcept;
int array_equal(const array* const x,const array* const y) noexcept;
void array_cat(array* to,const array* const from) noexcept;
void array_catb(array* to,const char* from,uint64 len) noexcept;
void array_cats(array* to,const char* from) noexcept;
void array_cats0(array* to,const char* from) noexcept;
void array_cat0(array* to) noexcept;
void array_cate(array* to,const array* const from,int64 pos,int64 stop) noexcept;
void array_shift(array* x,uint64 membersize,uint64 members) noexcept;
void array_chop(array* x,uint64 membersize,uint64 members) noexcept;
#define array_failed(x) (array_bytes(x)==-1)
#define array_unallocated(x) (array_bytes(x)==0)

@ -9,6 +9,8 @@
/* for strlen */
#include <string.h>
#include <libowfat/compiler.h>
#ifdef __cplusplus
extern "C" {
#endif
@ -43,12 +45,12 @@ typedef struct buffer {
/* 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 */
__writememsz__(4,5)
att_writen(4,5)
void buffer_init(buffer* b,ssize_t (*op)(),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) */
__writememsz__(4,5)
att_writen(4,5)
void buffer_init_free(buffer* b,ssize_t (*op)(),int fd,char* y,size_t ylen);
/* Initialize a buffer without actual I/O.
@ -57,10 +59,12 @@ void buffer_init_free(buffer* b,ssize_t (*op)(),int fd,char* y,size_t ylen);
* that memory area. If it reaches the end, it will signal EOF and never
* actually attempt to read from any actual file.
* Does not take ownership. Useful for testing. */
att_readn(2,3)
void buffer_init_staticcontents(buffer* b,char* y,size_t ylen);
/* Same but the buffer takes ownership of the static buffer and frees it
* in buffer_close. */
att_readn(2,3)
void buffer_init_staticcontents_free(buffer* b,char* y,size_t ylen);
@ -74,6 +78,7 @@ void buffer_munmap(void* buf);
/* Initialize a buffer so it will read from this file by memory mapping
* the whole thing. */
att_read(2)
int buffer_mmapread(buffer* b,const char* filename);
/* Indicate you are done with a buffer.
@ -86,17 +91,22 @@ void buffer_close(buffer* b);
* the data in the buffer. */
int buffer_flush(buffer* b);
__readmemsz__(2,3)
att_readn(2,3)
int buffer_put(buffer* b,const char* x,size_t len);
__readmemsz__(2,3)
att_readn(2,3)
int buffer_putalign(buffer* b,const char* x,size_t len);
__readmemsz__(2,3)
att_readn(2,3)
int buffer_putflush(buffer* b,const char* x,size_t len);
__readmem__(2)
att_read(2)
int buffer_puts(buffer* b,const char* x);
__readmem__(2)
att_read(2)
int buffer_putsalign(buffer* b,const char* x);
__readmem__(2)
att_read(2)
int buffer_putsflush(buffer* b,const char* x);
#if defined(__GNUC__) && !defined(__LIBOWFAT_INTERNAL)
@ -121,22 +131,22 @@ int buffer_putnlflush(buffer* b); /* put \n and flush */
: buffer_put((s),&(c),1) \
)
__writememsz__(2,3)
att_writen(2,3)
ssize_t buffer_get(buffer* b,char* x,size_t len);
ssize_t buffer_feed(buffer* b);
ssize_t buffer_getc(buffer* b,char* x);
ssize_t buffer_peekc(buffer* b,char* x);
__writememsz__(2,3)
att_writen(2,3)
ssize_t buffer_getn(buffer* b,char* x,size_t len);
/* read bytes until the destination buffer is full (len bytes), end of
* file is reached or the read char is in charset (setlen bytes). An
* empty line when looking for \n will write '\n' to x and return 0. If
* EOF is reached, \0 is written to the buffer */
__writememsz__(2,3)
__readmemsz__(4,5)
att_writen(2,3)
att_readn(4,5)
ssize_t buffer_get_token(buffer* b,char* x,size_t len,const char* charset,size_t setlen);
__writememsz__(2,3)
att_writen(2,3)
ssize_t buffer_getline(buffer* b,char* x,size_t len);
/* this predicate is given the string as currently read from the buffer
@ -144,7 +154,7 @@ ssize_t buffer_getline(buffer* b,char* x,size_t len);
typedef int (*string_predicate)(const char* x,size_t len);
/* like buffer_get_token but the token ends when your predicate says so */
__writememsz__(2,3)
att_writen(2,3)
ssize_t buffer_get_token_pred(buffer* b,char* x,size_t len,string_predicate p);
char *buffer_peek(buffer* b);
@ -194,13 +204,13 @@ int buffer_putsaflush(buffer* b,const stralloc* sa);
* data is available. */
/* read token from buffer to stralloc */
__readmemsz__(3,4)
att_readn(3,4)
int buffer_get_token_sa(buffer* b,stralloc* sa,const char* charset,size_t setlen);
/* read line from buffer to stralloc */
int buffer_getline_sa(buffer* b,stralloc* sa);
/* same as buffer_get_token_sa but empty sa first */
__readmemsz__(3,4)
att_readn(3,4)
int buffer_get_new_token_sa(buffer* b,stralloc* sa,const char* charset,size_t setlen);
/* same as buffer_getline_sa but empty sa first */
int buffer_getnewline_sa(buffer* b,stralloc* sa);
@ -218,7 +228,7 @@ void buffer_fromsa(buffer* b,const stralloc* sa); /* read from sa */
int buffer_tosa(buffer*b,stralloc* sa); /* write to sa, auto-growing it */
#endif
__readmemsz__(2,3)
att_readn(2,3)
void buffer_frombuf(buffer* b,const char* x,size_t l); /* buffer reads from static buffer */
#ifdef ARRAY_H

@ -1,6 +1,6 @@
#include "parse.h"
size_t bs_capacityleft(struct bytestream* bs) {
size_t bs_capacityleft(const struct bytestream* bs) {
if (bs->cur>=bs->max) // if EOF or error, return 0
return 0;
return bs->max - bs->cur;

@ -1,6 +1,6 @@
#include "parse.h"
int bs_err(struct bytestream* bs) {
int bs_err(const struct bytestream* bs) {
return (bs->cur > bs->max);
}

@ -9,76 +9,69 @@
extern "C" {
#endif
/* dietlibc defines these in sys/cdefs.h, which is included from stddef.h */
#ifndef __pure__
#define __pure__
#endif
#ifndef __writememsz__
#define __writememsz__(a,b)
#define __readmemsz__(a,b)
#endif
#ifndef __readmem__
#define __readmem__(a)
#endif
#include <libowfat/compiler.h>
/* byte_chr returns the smallest integer i between 0 and len-1
* inclusive such that one[i] equals needle, or len if not found. */
__readmemsz__(1,2)
size_t byte_chr(const void* haystack, size_t len, char needle) __pure__;
att_readn(1,2)
size_t byte_chr(const void* haystack, size_t len, char needle) noexcept;
/* byte_rchr returns the largest integer i between 0 and len-1 inclusive
* such that one[i] equals needle, or len if not found. */
__readmemsz__(1,2)
size_t byte_rchr(const void* haystack,size_t len,char needle) __pure__;
att_pure
att_readn(1,2)
size_t byte_rchr(const void* haystack,size_t len,char needle) noexcept;
/* byte_copy copies in[0] to out[0], in[1] to out[1], ... and in[len-1]
* to out[len-1]. */
__writememsz__(1,2)
__readmemsz__(3,2)
void byte_copy(void* out, size_t len, const void* in);
att_writen(1,2)
att_readn(3,2)
void byte_copy(void* out, size_t len, const void* in) noexcept;
/* byte_copyr copies in[len-1] to out[len-1], in[len-2] to out[len-2],
* ... and in[0] to out[0] */
__writememsz__(1,2)
__readmemsz__(3,2)
void byte_copyr(void* out, size_t len, const void* in);
att_writen(1,2)
att_readn(3,2)
void byte_copyr(void* out, size_t len, const void* in) noexcept;
/* byte_diff returns negative, 0, or positive, depending on whether the
* string a[0], a[1], ..., a[len-1] is lexicographically smaller
* than, equal to, or greater than the string b[0], b[1], ...,
* b[len-1]. When the strings are different, byte_diff does not read
* bytes past the first difference. */
__readmemsz__(1,2)
__readmemsz__(3,2)
int byte_diff(const void* a, size_t len, const void* b) __pure__;
att_pure
att_readn(1,2)
att_readn(3,2)
int byte_diff(const void* a, size_t len, const void* b) noexcept;
/* byte_zero sets the bytes out[0], out[1], ..., out[len-1] to 0 */
__writememsz__(1,2)
void byte_zero(void* out, size_t len);
att_writen(1,2)
void byte_zero(void* out, size_t len) noexcept;
#define byte_equal(s,n,t) (!byte_diff((s),(n),(t)))
/* Return 1 iff (b,blen) is a prefix of (a,alen), 0 otherwise.
* Will abort early on mismatch */
__readmemsz__(1,2)
__readmemsz__(3,4)
int byte_start(const void* a,size_t alen,const void* b,size_t blen) __pure__;
att_pure
att_readn(1,2)
att_readn(3,4)
int byte_start(const void* a,size_t alen,const void* b,size_t blen) noexcept;
/* equivalent to byte_start(a,alen,str,strlen(str)) */
__readmemsz__(1,2)
__readmem__(3)
int byte_starts(const void* a,size_t alen,const char* str) __pure__;
att_pure
att_readn(1,2)
att_read(3)
int byte_starts(const void* a,size_t alen,const char* str) noexcept;
#if defined(__GNUC__) && !defined(__LIBOWFAT_INTERNAL)
/* If str is a string constant, strlen will be done at compile time */
#define byte_starts(a,alen,str) (__builtin_constant_p(str) ? byte_start(a,alen,str,strlen(str)) : byte_starts(a,alen,str))
#endif
__readmemsz__(1,2)
__readmemsz__(3,2)
int byte_equal_notimingattack(const void* a, size_t len,const void* b) __pure__;
att_pure
att_readn(1,2)
att_readn(3,2)
int byte_equal_notimingattack(const void* a, size_t len,const void* b) noexcept;
#if defined(__i386__) || defined(__x86_64__)
#define UNALIGNED_ACCESS_OK

@ -3,22 +3,36 @@
#define CASE_H
#include <stddef.h>
#include <libowfat/compiler.h>
#ifdef __cplusplus
extern "C" {
#endif
/* turn upper case letters to lower case letters, ASCIIZ */
att_mangle(1)
void case_lowers(char *s);
/* turn upper case letters to lower case letters, binary */
att_manglen(1,2)
void case_lowerb(void *buf,size_t len);
/* like str_diff, ignoring case */
att_pure
att_read(1)
att_read(2)
int case_diffs(const char *,const char *);
/* like byte_diff, ignoring case */
att_pure
att_readn(1,2)
att_readn(3,2)
int case_diffb(const void *,size_t ,const void *);
/* like str_start, ignoring case */
att_pure
att_read(1)
att_read(2)
int case_starts(const char *,const char *);
#define case_equals(s,t) (!case_diffs((s),(t)))

26
cdb.h

@ -2,16 +2,22 @@
#ifndef CDB_H
#define CDB_H
#include "uint32.h"
#include "uint64.h"
#include <stddef.h>
#include <libowfat/uint32.h>
#include <libowfat/uint64.h>
#include <libowfat/compiler.h>
#ifdef __cplusplus
extern "C" {
#endif
#define CDB_HASHSTART 5381
extern uint32 cdb_hashadd(uint32 h,unsigned char c);
extern uint32 cdb_hash(const unsigned char *buf,unsigned long int len);
att_const
uint32 cdb_hashadd(uint32 h, unsigned char c);
att_pure
att_read(1)
uint32 cdb_hash(const unsigned char *buf, size_t len);
struct cdb {
char *map; /* 0 if no map is available */
@ -26,19 +32,19 @@ struct cdb {
uint32 dlen; /* initialized if cdb_findnext() returns 1 */
} ;
extern void cdb_free(struct cdb *);
extern void cdb_init(struct cdb *,int64 fd);
void cdb_free(struct cdb *);
void cdb_init(struct cdb *, int64 fd);
extern int cdb_read(struct cdb *,unsigned char *,unsigned long int,uint32);
int cdb_read(struct cdb * restrict, unsigned char * restrict, size_t, uint32);
extern void cdb_findstart(struct cdb *);
extern int cdb_findnext(struct cdb *,const unsigned char *,unsigned long int);
extern int cdb_find(struct cdb *,const unsigned char *,unsigned long int);
extern int cdb_findnext(struct cdb *, const unsigned char *, size_t);
extern int cdb_find(struct cdb *, const unsigned char *, size_t);
extern int cdb_firstkey(struct cdb *c,uint32 *kpos);
extern int cdb_nextkey(struct cdb *c,uint32 *kpos);
extern int cdb_successor(struct cdb *c,const unsigned char *,unsigned long int);
extern int cdb_successor(struct cdb *c, const unsigned char *, size_t);
#define cdb_datapos(c) ((c)->dpos)
#define cdb_datalen(c) ((c)->dlen)

@ -58,7 +58,7 @@ void cdb_init(struct cdb *c,int64 fd) {
#endif
}
int cdb_read(struct cdb *c,unsigned char *buf,unsigned long len,uint32 pos) {
int cdb_read(struct cdb *c, unsigned char *buf, size_t len, uint32 pos) {
if (c->map) {
if ((pos > c->size) || (c->size - pos < len)) goto FORMAT;
byte_copy(buf,len,c->map + pos);
@ -96,7 +96,7 @@ int cdb_read(struct cdb *c,unsigned char *buf,unsigned long len,uint32 pos) {
return -1;
}
static int match(struct cdb *c,const unsigned char *key,unsigned long int len,uint32 pos) {
static int match(struct cdb * restrict c, const unsigned char * restrict key, size_t len, uint32 pos) {
unsigned char buf[32];
unsigned long n;
@ -112,7 +112,7 @@ static int match(struct cdb *c,const unsigned char *key,unsigned long int len,ui
return 1;
}
int cdb_findnext(struct cdb *c,const unsigned char *key,unsigned long int len) {
int cdb_findnext(struct cdb *c, const unsigned char *key, size_t len) {
unsigned char buf[8];
uint32 pos;
uint32 u;
@ -156,7 +156,7 @@ int cdb_findnext(struct cdb *c,const unsigned char *key,unsigned long int len) {
return 0;
}
int cdb_find(struct cdb *c,const unsigned char *key,unsigned long int len) {
int cdb_find(struct cdb *c, const unsigned char *key, size_t len) {
cdb_findstart(c);
return cdb_findnext(c,key,len);
}

@ -6,13 +6,13 @@ cdb_find \- look up a key in a constant database
.br
.B #include <libowfat/uint32.h>
int cdb_find(struct cdb *\fIc\fR,char *\fIkey\fR,unsigned long int \fIkeylen\fR);
int cdb_find(struct cdb *\fIc\fR, char *\fIkey\fR, size_t \fIkeylen\fR);
.br
int cdb_datalen(struct cdb *\fIc\fR);
.br
int cdb_datapos(struct cdb *\fIc\fR);
.br
int cdb_findnext(struct cdb *\fIc\fR,char *\fIkey\fR,unsigned long int \fIkeylen\fR);
int cdb_findnext(struct cdb *\fIc\fR, char *\fIkey\fR, size_t \fIkeylen\fR);
.SH DESCRIPTION
\fBcdb_find\fR looks for \fIkey\fR. If cdb_find returns 0, the database

@ -6,7 +6,7 @@ cdb_firstkey \- find first physical record in constant database
.br
.B #include <libowfat/uint32.h>
int cdb_firstkey(struct cdb *\fIc\fR,uint32 *\fIkpos\fR);
int cdb_firstkey(struct cdb *\fIc\fR, uint32 *\fIkpos\fR);
.SH DESCRIPTION
\fBcdb_firstkey\fR finds the physically first record in the constant

@ -6,7 +6,7 @@ uint32 cdb_hashadd(uint32 h,unsigned char c) {
return h ^ c;
}
uint32 cdb_hash(const unsigned char *buf,unsigned long int len) {
uint32 cdb_hash(const unsigned char *buf,size_t len) {
uint32 h;
h = CDB_HASHSTART;

@ -4,7 +4,7 @@ cdb_init \- open a constant database
.SH SYNTAX
.B #include <libowfat/cdb.h>
int cdb_init(struct cdb *\fIc\fR,int \fIfd\fR);
int cdb_init(struct cdb *\fIc\fR, int \fIfd\fR);
.SH DESCRIPTION
.B cdb_init

@ -55,7 +55,7 @@ int cdb_make_addend(struct cdb_make *c,unsigned long int keylen,unsigned long in
return 0;
}
int cdb_make_addbegin(struct cdb_make *c,unsigned long int keylen,unsigned long int datalen) {
int cdb_make_addbegin(struct cdb_make *c, size_t keylen, size_t datalen) {
char buf[8];
if (keylen > 0xffffffff) { errno = ENOMEM; return -1; }
@ -67,7 +67,7 @@ int cdb_make_addbegin(struct cdb_make *c,unsigned long int keylen,unsigned long
return 0;
}
int cdb_make_add(struct cdb_make *c,const unsigned char *key,unsigned long int keylen,const unsigned char *data,unsigned long int datalen)
int cdb_make_add(struct cdb_make *c, const unsigned char *key, size_t keylen, const unsigned char *data, size_t datalen)
{
if (cdb_make_addbegin(c,keylen,datalen) == -1) return -1;
if (buffer_putalign(&c->b,(char*)key,keylen) == -1) return -1;

@ -6,7 +6,7 @@ cdb_nextkey \- find next physical record in constant database
.br
.B #include <libowfat/uint32.h>
int cdb_nextkey(struct cdb *\fIc\fR,uint32 *\fIkpos\fR);
int cdb_nextkey(struct cdb *\fIc\fR, uint32 *\fIkpos\fR);
.SH DESCRIPTION
\fBcdb_nextkey\fR finds the next physical record in the constant

@ -6,7 +6,7 @@ cdb_read \- read bytes from a constant database
.br
.B #include <libowfat/uint32.h>
int cdb_read(struct cdb *\fIc\fR,char *\fIbuf\fR,unsigned long int \fIlen\fR,uint32 \fIposition\fR);
int cdb_read(struct cdb *\fIc\fR, char *\fIbuf\fR, size_t \fIlen\fR, uint32 \fIposition\fR);
.SH DESCRIPTION
\fBcdb_read\fR reads \fIlen\fR bytes starting at \fIposition\fR from

@ -4,7 +4,7 @@ cdb_successor \- find next record
.SH SYNTAX
.B #include <libowfat/cdb.h>
int cdb_successor(struct cdb *\fIc\fR,char *\fIkey\fR,unsigned long int \fIklen\fR);
int cdb_successor(struct cdb *\fIc\fR, char *\fIkey\fR, size_t \fIklen\fR);
.SH DESCRIPTION
\fBcdb_successor\fR finds the record that follows \fIkey\fR. If

@ -2,9 +2,9 @@
#ifndef CDB_MAKE_H
#define CDB_MAKE_H
#include "buffer.h"
#include "uint64.h"
#include "uint32.h"
#include <libowfat/buffer.h>
#include <libowfat/uint64.h>
#include <libowfat/uint32.h>
#ifdef __cplusplus
extern "C" {
@ -35,9 +35,9 @@ struct cdb_make {
} ;
extern int cdb_make_start(struct cdb_make *,int64);
extern int cdb_make_addbegin(struct cdb_make *,unsigned long int,unsigned long int);
extern int cdb_make_addend(struct cdb_make *,unsigned long int,unsigned long int,uint32);
extern int cdb_make_add(struct cdb_make *,const unsigned char *,unsigned long int,const unsigned char *,unsigned long int);
extern int cdb_make_addbegin(struct cdb_make *, size_t, size_t);
extern int cdb_make_addend(struct cdb_make *, size_t, size_t, uint32);
extern int cdb_make_add(struct cdb_make *, const unsigned char *, size_t, const unsigned char *, size_t);
extern int cdb_make_finish(struct cdb_make *);
#ifdef __cplusplus

@ -0,0 +1,110 @@
#ifndef LIBOWFAT_ATTRIBUTES_H
#define LIBOWFAT_ATTRIBUTES_H
#ifndef __GNUC__
// macro attribute declarations away if we don't have gcc or clang
#define __attribute__(x)
#define __extension__
#endif
#ifndef __cplusplus
#define noexcept
#endif
#define GCC_VERSION_ATLEAST(a,b) (__GNUC__ > a) || ((__GNUC__ == a) && (__GNUC_MINOR__ >= b))
#if GCC_VERSION_ATLEAST(2,95) && !defined(__STRICT_ANSI__)
#undef restrict
#else
#define restrict
#endif
#if GCC_VERSION_ATLEAST(3,0)
#define likely(a) __builtin_expect((a), 1)
#define unlikely(a) __builtin_expect((a), 0)
#else
#define likely(a) (a)
#define unlikely(a) (a)
#endif
#if GCC_VERSION_ATLEAST(2, 5)
#define att_const __attribute__((__const__))
#else
#define att_const
#endif
#if GCC_VERSION_ATLEAST(2, 96)
#define att_pure __attribute__((__pure__))
#else
#define att_pure
#endif
#if GCC_VERSION_ATLEAST(3, 0)
#define att_malloc __attribute__((__malloc__))
#else
#define att_malloc
#endif
#if GCC_VERSION_ATLEAST(3, 4)
#define att_warn_unused_result __attribute__((__warn_unused_result__))
#else
#define att_warn_unused_result
#endif
#if GCC_VERSION_ATLEAST(4, 3)
#define att_hot __attribute__((__hot__))
#define att_cold __attribute__((__cold__))
#else
#define att_hot
#define att_cold
#endif
#if GCC_VERSION_ATLEAST(4, 3)
#define att_alloc(x) __attribute__((alloc_size(x)))
#define att_calloc(x,y) __attribute__((alloc_size(x,y)))
#else
#define att_alloc
#define att_calloc
#endif
#if GCC_VERSION_ATLEAST(10, 0)
#define att_read(argno_ptr) __attribute__((access(read_only, argno_ptr)))
#define att_readn(argno_ptr, argno_size) __attribute__((access(read_only, argno_ptr, argno_size)))
#define att_write(argno_ptr) __attribute__((access(write_only, argno_ptr)))
#define att_writen(argno_ptr, argno_size) __attribute__((access(write_only, argno_ptr, argno_size)))
#define att_mangle(argno_ptr) __attribute__((access(read_write, argno_ptr)))
#define att_manglen(argno_ptr, argno_size) __attribute__((access(read_write, argno_ptr, argno_size)))
#else
#define att_read(argno_ptr)
#define att_readn(argno_ptr, argno_size)
#define att_write(argno_ptr)
#define att_writen(argno_ptr, argno_size)
#define att_mangle(argno_ptr)
#define att_manglen(argno_ptr, argno_size)
#endif
#if GCC_VERSION_ATLEAST(3, 2)
#define att_dontuse __attribute__((__deprecated__))
#else
#define att_dontuse
#endif
#if GCC_VERSION_ATLEAST(3, 3)
#define att_nonnull(params) __attribute__((__nonnull__(params)))
#else
#define att_nonnull(params)l
#endif
#if GCC_VERSION_ATLEAST(4, 3)
#define att_warn(message) __attribute__((__warning__(message)))
#define att_error(message) __attribute__((__warning__(message)))
#else
#define att_warn(message)
#define att_error(message)
#endif
#ifndef __GNUC__
#define __builtin_constant_p(x) 0
#endif
#endif

@ -1,11 +1,17 @@
#if __STDC_VERSION__ >= 201710L
#ifdef __clang__
#define compiletimeassert(cond) _Static_assert(cond)
// clang already includes the condition in the error message and emits
// an additional warning here if we use the variant without message
#define compiletimeassert(cond) _Static_assert(cond,"")
#elif __STDC_VERSION__ >= 201710L
#define compiletimeassert(cond) _Static_assert(cond,#cond)
#elif __STDC_VERSION__ >= 201112L
#define compiletimeassert(cond) _Static_assert(cond,"")
#define compiletimeassert(cond) _Static_assert(cond,#cond)
#else

@ -5,23 +5,23 @@
extern "C" {
#endif
/* for __pure__ if we are compiling under dietlibc */
#include <stddef.h>
#ifndef __pure__
#define __pure__
#endif
#include <libowfat/compiler.h>
typedef struct {
void *root;
} critbit0_tree;
int critbit0_contains(critbit0_tree *t, const char *u) __pure__;
int critbit0_insert(critbit0_tree *t, const char *u);
int critbit0_delete(critbit0_tree *t, const char *u);
void critbit0_clear(critbit0_tree *t);
att_pure
int critbit0_contains(critbit0_tree *t, const char *u) noexcept;
int critbit0_insert(critbit0_tree *t, const char *u) noexcept;
int critbit0_delete(critbit0_tree *t, const char *u) noexcept;
void critbit0_clear(critbit0_tree *t) noexcept;
int critbit0_allprefixed(critbit0_tree *t, const char *prefix,
int (*handle) (const char *, void *), void *arg);
int (*handle) (const char *, void *), void *arg) noexcept;
#ifdef __cplusplus
};

@ -2,9 +2,9 @@
#ifndef DNS_H
#define DNS_H
#include "stralloc.h"
#include "iopause.h"
#include "taia.h"
#include <libowfat/stralloc.h>
#include <libowfat/iopause.h>
#include <libowfat/taia.h>
#ifdef __cplusplus
extern "C" {

171
fmt.h

@ -13,16 +13,13 @@
#include <sys/types.h>
#endif
/* for byte_copy */
#include "byte.h"
#include <libowfat/byte.h>
#include <libowfat/compiler.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifndef __pure__
#define __pure__
#endif
#define FMT_LONG 41 /* enough space to hold -2^127 in decimal, plus \0 */
#define FMT_ULONG 40 /* enough space to hold 2^128 - 1 in decimal, plus \0 */
#define FMT_8LONG 44 /* enough space to hold 2^128 - 1 in octal, plus \0 */
@ -50,31 +47,38 @@ extern "C" {
/* convert signed src integer -23 to ASCII '-','2','3', return number of
* bytes of value in output format (3 in this example).
* If dest is not NULL, write result to dest */
size_t fmt_long(char *dest,signed long src) __pure__;
att_write(1)
size_t fmt_long(char *dest,signed long src) noexcept;
/* convert unsigned src integer 23 to ASCII '2','3', return number of
* bytes of value in output format (2 in this example).
* If dest is not NULL, write result to dest */
size_t fmt_ulong(char *dest,unsigned long src) __pure__;
att_write(1)
size_t fmt_ulong(char *dest,unsigned long src) noexcept;
/* convert unsigned src integer 0x23 to ASCII '2','3', return number of
* bytes of value in output format (2 in this example).
* If dest is not NULL, write result to dest */
size_t fmt_xlong(char *dest,unsigned long src) __pure__;
att_write(1)
size_t fmt_xlong(char *dest,unsigned long src) noexcept;
/* convert unsigned src integer 023 to ASCII '2','3', return number of
* bytes of value in output format (2 in this example).
* If dest is not NULL, write result to dest */
size_t fmt_8long(char *dest,unsigned long src) __pure__;
att_write(1)
size_t fmt_8long(char *dest,unsigned long src) noexcept;
/* like fmt_long but for long long */
size_t fmt_longlong(char *dest,signed long long src) __pure__;
att_write(1)
size_t fmt_longlong(char *dest,signed long long src) noexcept;
/* like fmt_ulong but for unsigned long long */
size_t fmt_ulonglong(char *dest,unsigned long long src) __pure__;
att_write(1)
size_t fmt_ulonglong(char *dest,unsigned long long src) noexcept;
/* like fmt_xlong but for unsigned long long */
size_t fmt_xlonglong(char *dest,unsigned long long src) __pure__;
att_write(1)
size_t fmt_xlonglong(char *dest,unsigned long long src) noexcept;
#define fmt_uint(dest,src) fmt_ulong(dest,src)
#define fmt_int(dest,src) fmt_long(dest,src)
@ -85,22 +89,26 @@ size_t fmt_xlonglong(char *dest,unsigned long long src) __pure__;
* Does not truncate! */
/* fmt_ulong0(buf,23,4) -> '0','0','2','3' return 4 */
/* fmt_ulong0(buf,234,2) -> '2','3','4', return 3 */
size_t fmt_ulong0(char *,unsigned long src,size_t padto) __pure__;
att_write(1)
size_t fmt_ulong0(char *,unsigned long src,size_t padto) noexcept;
#define fmt_uint0(buf,src,padto) fmt_ulong0(buf,src,padto)
/* convert src double 1.7 to ASCII '1','.','7', return length.
* If dest is not NULL, write result to dest */
size_t fmt_double(char *dest, double d,int max,int prec) __pure__;
att_write(1)
size_t fmt_double(char *dest, double d,int max,int prec) noexcept;
/* if src is negative, write '-' and return 1.
* if src is positive, write '+' and return 1.
* otherwise return 0 */
size_t fmt_plusminus(char *dest,int src) __pure__;
att_write(1)
size_t fmt_plusminus(char *dest,int src) noexcept;
/* if src is negative, write '-' and return 1.
* otherwise return 0. */
size_t fmt_minus(char *dest,int src) __pure__;
att_write(1)
size_t fmt_minus(char *dest,int src) noexcept;
/* copy str to dest until \0 byte, return number of copied bytes. */
/* fmt_str(NULL,str) == strlen(str) */
@ -112,13 +120,17 @@ size_t fmt_minus(char *dest,int src) __pure__;
* This is more efficient because strcat needs to scan the string to
* find the end and append.
*/
size_t fmt_str(char *dest,const char *src) __pure__;
att_write(1)
size_t fmt_str(char *dest,const char *src) noexcept;
/* copy str to dest until \0 byte or limit bytes copied.
* return number of copied bytes. */
size_t fmt_strn(char *dest,const char *src,size_t limit) __pure__;
att_writen(1,3)
att_readn(2,3)
size_t fmt_strn(char *dest,const char *src,size_t limit) noexcept;
/* copy n bytes from src to dest, return n */
att_writen(1,3)
static inline size_t fmt_copybytes(char* dest,const char* src,size_t n) {
if (dest) byte_copy(dest,n,src);
return n;
@ -135,59 +147,103 @@ static inline size_t fmt_copybytes(char* dest,const char* src,size_t n) {
* write padlen-srclen spaces, if that is >= 0. Then copy srclen
* characters from src. Truncate only if total length is larger than
* maxlen. Return number of characters written. */
size_t fmt_pad(char* dest,const char* src,size_t srclen,size_t padlen,size_t maxlen) __pure__;
att_writen(1,5)
att_readn(2,3)
size_t fmt_pad(char* dest,const char* src,size_t srclen,size_t padlen,size_t maxlen) noexcept;
/* "foo" -> "foo "
* append padlen-srclen spaces after dest, if that is >= 0. Truncate
* only if total length is larger than maxlen. Return number of
* characters written. */
size_t fmt_fill(char* dest,size_t srclen,size_t padlen,size_t maxlen) __pure__;
att_writen(1,4)
size_t fmt_fill(char* dest,size_t srclen,size_t padlen,size_t maxlen) noexcept;
/* 1 -> "1", 4900 -> "4.9k", 2300000 -> "2.3M" */
size_t fmt_human(char* dest,unsigned long long l) __pure__;
att_write(1)
size_t fmt_human(char* dest,unsigned long long l) noexcept;
/* 1 -> "1", 4900 -> "4.8k", 2300000 -> "2.2M" */
size_t fmt_humank(char* dest,unsigned long long l) __pure__;
att_write(1)
size_t fmt_humank(char* dest,unsigned long long l) noexcept;
/* "Sun, 06 Nov 1994 08:49:37 GMT" */
size_t fmt_httpdate(char* dest,time_t t); /* not marked pure because it calls gmtime */
att_write(1)
size_t fmt_httpdate(char* dest,time_t t) noexcept; /* not marked pure because it calls gmtime */
/* "2014-05-27T19:22:16.247Z" */
size_t fmt_iso8601(char* dest,time_t t) __pure__;
att_write(1)
size_t fmt_iso8601(char* dest,time_t t) noexcept;
#define FMT_UTF8 5
#define FMT_ASN1LENGTH 17 /* enough space to hold 2^128-1 */
#define FMT_ASN1TAG 19 /* enough space to hold 2^128-1 */
/* some variable length encodings for integers */
size_t fmt_utf8(char* dest,uint32_t n) __pure__; /* can store 0-0x7fffffff */
size_t fmt_utf8_scratch(char* dest,uint32_t n) __pure__; /* same, but is allowed to overwrite up to 7 additional bytes */
size_t fmt_asn1derlength(char* dest,unsigned long long l) __pure__; /* 0-0x7f: 1 byte, above that 1+bytes_needed bytes */
size_t fmt_asn1derlength_scratch(char* dest,unsigned long long l) __pure__; /* same, but is allowed to overwrite up to 7 additional bytes */
size_t fmt_asn1dertag(char* dest,unsigned long long l) __pure__; /* 1 byte for each 7 bits; upper bit = more bytes coming */
size_t fmt_asn1dertag_scratch(char* dest,unsigned long long l) __pure__;/* same, but is allowed to overwrite up to 7 additional bytes */
att_write(1)
size_t fmt_utf8(char* dest,uint32_t n) noexcept; /* can store 0-0x7fffffff */
att_write(1)
size_t fmt_utf8_scratch(char* dest,uint32_t n) noexcept; /* same, but is allowed to overwrite up to 7 additional bytes */
att_write(1)
size_t fmt_asn1derlength(char* dest,unsigned long long l) noexcept; /* 0-0x7f: 1 byte, above that 1+bytes_needed bytes */
att_write(1)
size_t fmt_asn1derlength_scratch(char* dest,unsigned long long l) noexcept; /* same, but is allowed to overwrite up to 7 additional bytes */
att_write(1)
size_t fmt_asn1dertag(char* dest,unsigned long long l) noexcept; /* 1 byte for each 7 bits; upper bit = more bytes coming */
att_write(1)
size_t fmt_asn1dertag_scratch(char* dest,unsigned long long l) noexcept;/* same, but is allowed to overwrite up to 7 additional bytes */
/* Google Protocol Buffers, https://developers.google.com/protocol-buffers/docs/encoding */
size_t fmt_varint(char* dest,unsigned long long l) __pure__; /* protocol buffers encoding; like asn1dertag but little endian */
size_t fmt_pb_tag(char* dest,size_t fieldno,unsigned char type) __pure__; /* protocol buffer tag */
size_t fmt_pb_type0_int(char* dest,unsigned long long l) __pure__; /* protocol buffers encoding: type 0 bool/enum/int32/uint32/int64/uint64 */
size_t fmt_pb_type0_sint(char* dest,signed long long l) __pure__;/* protocol buffers encoding: type 0 sint32/sint64 */
size_t fmt_pb_type1_double(char* dest,double d) __pure__; /* protocol buffers encoding: double (64-bit little endian blob) */
size_t fmt_pb_type1_fixed64(char* dest,uint64_t l) __pure__; /* protocol buffers encoding: 64-bit little endian blob */
att_write(1)
size_t fmt_varint(char* dest,unsigned long long l) noexcept; /* protocol buffers encoding; like asn1dertag but little endian */
att_write(1)
size_t fmt_pb_tag(char* dest,size_t fieldno,unsigned char type) noexcept; /* protocol buffer tag */
att_write(1)
size_t fmt_pb_type0_int(char* dest,unsigned long long l) noexcept; /* protocol buffers encoding: type 0 bool/enum/int32/uint32/int64/uint64 */
att_write(1)
size_t fmt_pb_type0_sint(char* dest,signed long long l) noexcept;/* protocol buffers encoding: type 0 sint32/sint64 */
att_write(1)
size_t fmt_pb_type1_double(char* dest,double d) noexcept; /* protocol buffers encoding: double (64-bit little endian blob) */
att_write(1)
size_t fmt_pb_type1_fixed64(char* dest,uint64_t l) noexcept; /* protocol buffers encoding: 64-bit little endian blob */
/* fmt_pb_type2_string can return 0 if (s,l) is clearly invalid */
size_t fmt_pb_type2_string(char* dest,const char* s,size_t l) __pure__; /* protocol buffers encoding: varint length + blob */
size_t fmt_pb_type5_float(char* dest,float f) __pure__; /* protocol buffers encoding: float (32-bit little endian blob) */
size_t fmt_pb_type5_fixed32(char* dest,uint32_t l) __pure__; /* protocol buffers encoding: 32-bit little endian blob */
att_write(1)
size_t fmt_pb_type2_string(char* dest,const char* s,size_t l) noexcept; /* protocol buffers encoding: varint length + blob */
att_write(1)
size_t fmt_pb_type5_float(char* dest,float f) noexcept; /* protocol buffers encoding: float (32-bit little endian blob) */
att_write(1)
size_t fmt_pb_type5_fixed32(char* dest,uint32_t l) noexcept; /* protocol buffers encoding: 32-bit little endian blob */
att_write(1)
size_t fmt_pb_int(char* dest,size_t fieldno,unsigned long long l) noexcept;
size_t fmt_pb_int(char* dest,size_t fieldno,unsigned long long l) __pure__;
size_t fmt_pb_sint(char* dest,size_t fieldno,signed long long l) __pure__;
size_t fmt_pb_double(char* dest,size_t fieldno,double d) __pure__;
size_t fmt_pb_float(char* dest,size_t fieldno,float f) __pure__;
size_t fmt_pb_string(char* dest,size_t fieldno,const char* s,size_t l) __pure__;
att_write(1)
size_t fmt_pb_sint(char* dest,size_t fieldno,signed long long l) noexcept;
att_write(1)
size_t fmt_pb_double(char* dest,size_t fieldno,double d) noexcept;
att_write(1)
size_t fmt_pb_float(char* dest,size_t fieldno,float f) noexcept;
att_writen(1,4)
size_t fmt_pb_string(char* dest,size_t fieldno,const char* s,size_t l) noexcept;
/* fmt_netstring can return 0 if (src,len) is clearly invalid */
size_t fmt_netstring(char* dest,const char* src,size_t len) __pure__;
att_writen(1,3)
size_t fmt_netstring(char* dest,const char* src,size_t len) noexcept;
/* Marshaling helper functions.
* Escape one character, no matter if it needs escaping or not.
@ -199,27 +255,36 @@ size_t fmt_netstring(char* dest,const char* src,size_t len) __pure__;
* unicode codepoint) may be limited to 0x7f, 0xff or 0x10ffff. */
/* XML escaping: '&' -> '&amp;', '<' -> '&lt;', 'ö' -> '&#xf6;' */
size_t fmt_escapecharxml(char* dest,uint32_t ch) __pure__;
att_write(1)
size_t fmt_escapecharxml(char* dest,uint32_t ch) noexcept;
/* HTML escaping is the same as XML escaping. */
size_t fmt_escapecharhtml(char* dest,uint32_t ch) __pure__;
att_write(1)
size_t fmt_escapecharhtml(char* dest,uint32_t ch) noexcept;
/* JSON escaping: '\' -> '\\', '"' -> '\"', 'ö' -> '\u00f6' */
size_t fmt_escapecharjson(char* dest,uint32_t ch) __pure__;
att_write(1)
size_t fmt_escapecharjson(char* dest,uint32_t ch) noexcept;
/* MIME quoted-printable escaping: 'ö' -> '=f6', characters > 0xff not supported */
size_t fmt_escapecharquotedprintable(char* dest,uint32_t ch) __pure__;
att_write(1)
size_t fmt_escapecharquotedprintable(char* dest,uint32_t ch) noexcept;
/* MIME quoted-printable escaping with UTF-8: 'ö' -> '=c3=b6', characters > 0x7fffffff not supported */
size_t fmt_escapecharquotedprintableutf8(char* dest,uint32_t ch) __pure__;
att_write(1)
size_t fmt_escapecharquotedprintableutf8(char* dest,uint32_t ch) noexcept;
/* C99 style escaping: '\' -> '\\', newline -> '\n', 0xc2 -> '\302' */
size_t fmt_escapecharc(char* dest,uint32_t ch) __pure__;
att_write(1)
size_t fmt_escapecharc(char* dest,uint32_t ch) noexcept;
/* internal functions, may be independently useful */
char fmt_tohex(char c) __attribute__((__const__));
att_const
char fmt_tohex(char c);
#define fmt_strm(b,...) fmt_strm_internal(b,__VA_ARGS__,(char*)0)
size_t fmt_strm_internal(char* dest,...) __pure__;
att_write(1)
size_t fmt_strm_internal(char* dest,...) noexcept;
#ifndef MAX_ALLOCA
#define MAX_ALLOCA 100000

@ -9,7 +9,7 @@
* - the compiler supports it via __sync_val_compare_and_swap
*/
#include "uint64.h"
#include <libowfat/uint64.h>
#include <stddef.h>
#ifdef _WIN32
#include <windows.h>

38
io.h

@ -4,8 +4,9 @@
/* http://cr.yp.to/lib/io.html */
#include "uint64.h"
#include "taia.h"
#include <libowfat/uint64.h>
#include <libowfat/taia.h>
#include <libowfat/compiler.h>
#ifdef __cplusplus
extern "C" {
@ -13,33 +14,52 @@ extern "C" {
/* like open(s,O_RDONLY) */
/* return 1 if ok, 0 on error */
int io_readfile(int64* d,const char* s);
att_read(2)
att_write(1)
int io_readfile(int64* d,const char* filename);
/* like open(s,O_WRONLY|O_CREAT|O_TRUNC,0600) */
/* return 1 if ok, 0 on error */
int io_createfile(int64* d,const char* s);
att_read(2)
att_write(1)
int io_createfile(int64* d,const char* filename);
/* like open(s,O_RDWR) */
/* return 1 if ok, 0 on error */
int io_readwritefile(int64* d,const char* s);
att_read(2)
att_write(1)
int io_readwritefile(int64* d,const char* filename);
/* like open(s,O_WRONLY|O_APPEND|O_CREAT,0600) */
/* return 1 if ok, 0 on error */
int io_appendfile(int64* d,const char* s);
att_read(2)
att_write(1)
int io_appendfile(int64* d,const char* filename);
/* like pipe(d) */
/* return 1 if ok, 0 on error */
att_write(1)
int io_pipe(int64* d);
/* like socketpair() */
/* return 1 if ok, 0 on error */
att_write(1)
int io_socketpair(int64* d);
/* non-blocking read(), -1 for EAGAIN and -3+errno for other errors */
att_writen(2, 3)
int64 io_tryread(int64 d,char* buf,int64 len);
/* blocking read(), with -3 instead of -1 for errors */
att_writen(2, 3)
int64 io_waitread(int64 d,char* buf,int64 len);
/* non-blocking write(), -1 for EAGAIN and -3+errno for other errors */
att_readn(2, 3)
int64 io_trywrite(int64 d,const char* buf,int64 len);
/* blocking write(), with -3 instead of -1 for errors */
att_readn(2, 3)
int64 io_waitwrite(int64 d,const char* buf,int64 len);
/* modify timeout attribute of file descriptor */
@ -47,10 +67,12 @@ void io_timeout(int64 d,tai6464 t);
/* like io_tryread but will return -2,errno=ETIMEDOUT if d has a timeout
* associated and it is passed without input being there */
att_writen(2, 3)
int64 io_tryreadtimeout(int64 d,char* buf,int64 len);
/* like io_trywrite but will return -2,errno=ETIMEDOUT if d has a timeout
* associated and it is passed without being able to write */
att_readn(2, 3)
int64 io_trywritetimeout(int64 d,const char* buf,int64 len);
void io_wantread(int64 d);
@ -95,7 +117,9 @@ int io_fd(int64 d); /* use this for sockets before you called connect() or acce
int io_fd_canwrite(int64 d); /* use this for connected sockets (assumes socket is writable) */
int io_fd_flags(int64 d,int flags); /* can be used to tell io_fd to skip one syscall */
att_write(2)
void io_setcookie(int64 d,void* cookie);
void* io_getcookie(int64 d);
/* put descriptor in non-blocking mode */
@ -128,9 +152,11 @@ int64 io_receivefd(int64 sock);
int io_starteventloopthread(unsigned int threads);
#define HAVE_IO_QUEUEFORREAD
/* Artificially queue a file descriptor as readable.
* The next call to io_canread will return this descriptor. */
int io_queueforread(int64 d);
/* Artificially queue a file descriptor as writable.
* The next call to io_canread will return this descriptor. */
int io_queueforwrite(int64 d);

@ -4,10 +4,10 @@ io_appendfile \- open a file for appending
.SH SYNTAX
.B #include <libowfat/io.h>
int \fBio_appendfile\fP(int64* d,const char* s);
int \fBio_appendfile\fP(int64* d,const char* filename);
.SH DESCRIPTION
io_appendfile sets d to the number of a new descriptor writing to the
end of the disk file named \fIs\fR, and returns 1. If the file does not
end of the disk file named \fIfilename\fR, and returns 1. If the file does not
exist, it will be created with mode 0600.
If something goes wrong, io_appendfile sets \fIerrno\fR to indicate the error, and

@ -4,10 +4,10 @@ io_createfile \- create a file
.SH SYNTAX
.B #include <libowfat/io.h>
int \fBio_createfile\fP(int64* d,const char* s);
int \fBio_createfile\fP(int64* d,const char* filename);
.SH DESCRIPTION
io_createfile sets d to the number of a new descriptor writing to the disk file
named \fIs\fR, and returns 1. If \fIs\fR already existed, it is truncated to length 0;
named \fIs\fR, and returns 1. If \fIfilename\fR already existed, it is truncated to length 0;
otherwise, it is created, with mode 0600.
If something goes wrong, io_createfile sets \fIerrno\fR to indicate the error, and

@ -4,10 +4,10 @@ io_readfile \- open a file for reading
.SH SYNTAX
.B #include <libowfat/io.h>
int \fBio_readfile\fP(int64* d,const char* s);
int \fBio_readfile\fP(int64* d,const char* filename);
.SH DESCRIPTION
io_readfile sets d to the number of a new descriptor reading from the
disk file named \fIs\fR, and returns 1.
disk file named \fIfilename\fR, and returns 1.
If something goes wrong, io_readfile sets \fIerrno\fR to indicate the error, and
returns 0; it does not create a new descriptor, and it does not touch d.

@ -4,10 +4,10 @@ io_readfile \- open a file for reading and writing
.SH SYNTAX
.B #include <libowfat/io.h>
int \fBio_readwritefile\fP(int64* d,const char* s);
int \fBio_readwritefile\fP(int64* d,const char* filename);
.SH DESCRIPTION
io_readwritefile sets d to the number of a new descriptor reading from
and writing to the disk file named \fIs\fR, and returns 1. The file
and writing to the disk file named \fIfilename\fR, and returns 1. The file
needs to exist.
If something goes wrong, io_readwritefile sets \fIerrno\fR to indicate the error, and

15
iob.h

@ -13,8 +13,9 @@
* frames as possible. On Linux it will also use the TCP_CORK socket
* option. */
#include "libowfat/io.h"
#include "libowfat/array.h"
#include <libowfat/io.h>
#include <libowfat/array.h>
#include <libowfat/compiler.h>
#ifdef __cplusplus
extern "C" {
@ -27,10 +28,20 @@ typedef struct io_batch {
} io_batch;
io_batch* iob_new(int hint_entries);
att_readn(2,3)
int iob_addbuf(io_batch* b,const void* buf,uint64 n);
att_readn(2,3)
int iob_addbuf_free(io_batch* b,const void* buf,uint64 n);
att_readn(2,3)
int iob_addbuf_munmap(io_batch* b,const void* buf,uint64 n);
att_read(2)
int iob_adds(io_batch* b,const char* s);
att_read(2)
int iob_adds_free(io_batch* b,const char* s);
int iob_addfile(io_batch* b,int64 fd,uint64 off,uint64 n);
int iob_addfile_close(io_batch* b,int64 fd,uint64 off,uint64 n);