add compiler.h to abstract gcc attributes

master
leitner 4 years ago
parent 51869a80f8
commit ddfdd4d077

@ -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 @@ 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;

@ -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_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);

@ -2,8 +2,8 @@
#ifndef IP6_H
#define IP6_H
#include "byte.h"
#include "uint32.h"
#include <libowfat/byte.h>
#include <libowfat/uint32.h>
#ifdef __cplusplus
extern "C" {

@ -6,11 +6,15 @@
extern "C" {
#endif
#include <libowfat/compiler.h>
/* open filename for reading and return the file handle or -1 on error */
att_read(1)
int open_read(const char* filename);
/* create filename for exclusive write only use (mode 0600) and return
* the file handle or -1 on error */
att_read(1)
int open_excl(const char* filename);
/* open filename for appending write only use (mode 0600)
@ -18,19 +22,23 @@ int open_excl(const char* filename);
* All write operation will append after the last byte, regardless of
* seeking or other processes also appending to the file. The file will
* be created if it does not exist. */
att_read(1)
int open_append(const char* filename);
/* open filename for writing (mode 0644). Create the file if it does
* not exist, truncate it to zero length otherwise. Return the file
* handle or -1 on error. */
att_read(1)
int open_trunc(const char* filename);
/* open filename for writing. Create the file if it does not exist.
* Return the file handle or -1 on error. */
att_read(1)
int open_write(const char* filename);
/* open filename for reading and writing. Create file if not there.
* Return file handle or -1 on error. */
att_read(1)
int open_rw(const char* filename);
#ifdef __cplusplus

@ -2,12 +2,14 @@
#ifndef OPENREADCLOSE_H
#define OPENREADCLOSE_H
#include "stralloc.h"
#include <libowfat/compiler.h>
#include <libowfat/stralloc.h>
#ifdef __cplusplus
extern "C" {
#endif
att_read(1)
int openreadclose(const char *filename,stralloc *buf,size_t initiallength);
#ifdef __cplusplus

@ -7,6 +7,8 @@
/* for uint32_t: */
#include <stdint.h>
#include <libowfat/compiler.h>
#include <libowfat/buffer.h>
#include <libowfat/uint16.h>
@ -63,11 +65,20 @@ struct bytestream {
} u;
};
att_write(1)
att_read(2)
void bs_init_membuf(struct bytestream* bs,const unsigned char* membuf,size_t len);
att_write(1)
att_mangle(2)
void bs_init_iobuf(struct bytestream* bs,struct buffer* b);
att_write(1)
att_mangle(2)
void bs_init_iobuf_size(struct bytestream* bs,struct buffer* b,size_t maxlen);
att_write(1)
att_mangle(2)
void bs_init_bstream_size(struct bytestream* bs,struct bytestream* parent,size_t maxlen);
#define BS_FROM_MEMBUF(buf,len) { .type=MEMBUF, .max=(len), .u.base=(const unsigned char*)(buf) }
@ -75,51 +86,80 @@ void bs_init_bstream_size(struct bytestream* bs,struct bytestream* parent,size_t
#define BS_FROM_BUFFER_SIZE(buffer,len) { .type=IOBUF, .max=(len), u.b=(buffer) }
/* return next byte from stream or 0 if EOF or read error. */
att_mangle(1)
unsigned char bs_get(struct bytestream* bs);
/* like bs_get but do not advance position in stream. */
// This is NOT read-only because it sets bs to error state if it hits EOF
att_mangle(1)
unsigned char bs_peek(struct bytestream* bs);
/* was there a read error or did we attempt to read more than maxlen bytes? */
int bs_err(struct bytestream* bs);
att_pure
att_read(1)
int bs_err(const struct bytestream* bs);
/* mark bytestream as erroneous */
att_mangle(1)
void bs_seterrorstate(struct bytestream* b);
/* Can we read this much more bytes from the bytestream? */
/* returns 1 for yes, 0 for no */
att_pure
att_read(1)
int bs_capacitycheck(struct bytestream* bs,size_t capacity);
/* Like bs_capacitycheck but will set stream to error state on fail */
att_pure
att_mangle(1)
int bs_capacityassert(struct bytestream* bs,size_t capacity);
/* Return number of bytes left before limit, or 0 on error. */
/* If the backend is an iobuf without limit, return max size_t value. */
size_t bs_capacityleft(struct bytestream* bs);
att_pure
att_read(1)
size_t bs_capacityleft(const struct bytestream* bs);
/* Assert there are no more bytes left in a bytestream. */
/* Useful to make sure that you parsed the whole packet
* and there were no slack bytes in the end.
* Return 1 if there really were no more bytes in the stream.
* If there ARE bytes left, will set error flag in stream and return 0 */
att_mangle(1)
int bs_nomoredataassert(struct bytestream* bs);
/* Consume all bytes left before limit */
/* Useful for nested structs or when the backing store is an iobuf */
/* Return number of bytes consumed */
att_mangle(1)
size_t bs_consumeleftovers(struct bytestream* bs);
/* Skip n bytes, return number skipped (or 0 if error) */
att_mangle(1)
size_t bs_skip(struct bytestream* bs, size_t n);
/* Read n bytes from stream. Return n.
* Set stream to error state if not enough space or I/O error. */
att_mangle(1)
att_writen(2,3)
ssize_t prs_readblob(struct bytestream* bs,unsigned char* dest,size_t destlen);
att_mangle(1)
uint16_t prs_u16(struct bytestream* bs);
att_mangle(1)
uint16_t prs_u16_big(struct bytestream* bs);
att_mangle(1)
uint32_t prs_u32(struct bytestream* bs);
att_mangle(1)
uint32_t prs_u32_big(struct bytestream* bs);
att_mangle(1)
uint64_t prs_u64(struct bytestream* bs);
att_mangle(1)
uint64_t prs_u64_big(struct bytestream* bs);
/* Read an asciiz string from the byte stream, up to len bytes (including the 0 terminator). */
@ -127,6 +167,8 @@ uint64_t prs_u64_big(struct bytestream* bs);
/* If there is no 0 byte in these len bytes, set error flag in stream and return -1. */
/* Calling this function with destsize==0 is an error. */
/* destsize will be clamped to the maximum number representable in ssize_t */
att_mangle(1)
att_writen(2, 3)
ssize_t prs_asciiz(struct bytestream* bs, char* dest, size_t destsize);
/* Some protocols have a fixed field length for a string,
@ -137,6 +179,8 @@ ssize_t prs_asciiz(struct bytestream* bs, char* dest, size_t destsize);
* For a field of length 8, you need to pass destsize as 9 so we can add
* a 0 terminator. This function will consume the 8 bytes and add a 0 byte.
* The return value is strlen(dest). */
att_mangle(1)
att_writen(2, 3)
ssize_t prs_asciiz_fixedlen(struct bytestream* bs, char* dest, size_t destsize);
#ifdef __cplusplus

@ -5,6 +5,8 @@
#include <inttypes.h>
#include <stddef.h>
#include <libowfat/compiler.h>
#ifdef __cplusplus
extern "C" {
#endif
@ -105,16 +107,20 @@ __static inline __gnuinline int range_bufinbuf(const void* buf1,size_t len1,cons
/* does an array of "elements" members of size "membersize" starting at
* "arraystart" lie inside buf1[0..len-1]? */
att_const
int range_arrayinbuf(const void* buf,size_t len,
const void* arraystart,size_t elements,size_t membersize);
/* does an ASCIIZ string starting at "ptr" lie in buf[0..len-1]? */
att_const
int range_strinbuf(const void* buf,size_t len,const void* stringstart);
/* does an UTF-16 string starting at "ptr" lie in buf[0..len-1]? */
att_const
int range_str2inbuf(const void* buf,size_t len,const void* stringstart);
/* does an UTF-32 string starting at "ptr" lie in buf[0..len-1]? */
att_const
int range_str4inbuf(const void* buf,size_t len,const void* stringstart);

@ -2,9 +2,9 @@
#ifndef SAFEMULT_H
#define SAFEMULT_H
#include "uint16.h"
#include "uint32.h"
#include "uint64.h"
#include <libowfat/uint16.h>
#include <libowfat/uint32.h>
#include <libowfat/uint64.h>
#ifdef __cplusplus
extern "C" {

154
scan.h

@ -11,20 +11,12 @@
/* for struct timespec: */
#include <time.h>
#include <libowfat/compiler.h>
#ifdef __cplusplus
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
/* This file declares functions used to decode / scan / unmarshal
* integer or string values from a buffer.
* The first argument is always the source buffer, the second argument
@ -44,72 +36,90 @@ extern "C" {
* NB: will detect integer overflow and abort on excessively large
* values, i.e. on a 32-bit system:
* scan_ulong("4294967296",&i" -> i=429496729, return 9 */
size_t scan_ulong(const char *src,unsigned long *dest);
__readmemsz__(1,2)
size_t scan_ulongn(const char* src,size_t n,unsigned long* dest);
att_read(1) att_write(2)
size_t scan_ulong(const char *src,unsigned long *dest) noexcept;
att_readn(1,2) att_write(3)
size_t scan_ulongn(const char* src,size_t n,unsigned long* dest) noexcept;
/* Interpret src as ASCII hexadecimal number, write number to dest and
* return the number of bytes that were parsed.
* Note: leading '+' or '-' not accepted! */
size_t scan_xlong(const char *src,unsigned long *dest);
__readmemsz__(1,2)
size_t scan_xlongn(const char *src,size_t n,unsigned long *dest);
att_read(1) att_write(2)
size_t scan_xlong(const char *src,unsigned long *dest) noexcept;
att_readn(1,2) att_write(3)
size_t scan_xlongn(const char *src,size_t n,unsigned long *dest) noexcept;
/* interpret src as ASCII octal number, write number to dest and
* return the number of bytes that were parsed.
* Note: leading '+' or '-' not accepted! */
size_t scan_8long(const char *src,unsigned long *dest);
__readmemsz__(1,2)
size_t scan_8longn(const char *src,size_t n,unsigned long *dest);
att_read(1) att_write(2)
size_t scan_8long(const char *src,unsigned long *dest) noexcept;
att_readn(1,2) att_write(3)
size_t scan_8longn(const char *src,size_t n,unsigned long *dest) noexcept;
/* interpret src as signed ASCII decimal number, write number to dest
* and return the number of bytes that were parsed.
* Note: leading spaces not accepted! */
size_t scan_long(const char *src,signed long *dest);
__readmemsz__(1,2)
size_t scan_longn(const char *src,size_t n,signed long *dest);
size_t scan_longlong(const char *src,signed long long *dest);
size_t scan_ulonglong(const char *src,unsigned long long *dest);
size_t scan_xlonglong(const char *src,unsigned long long *dest);
size_t scan_8longlong(const char *src,unsigned long long *dest);
size_t scan_uint(const char *src,unsigned int *dest);
size_t scan_xint(const char *src,unsigned int *dest);
size_t scan_8int(const char *src,unsigned int *dest);
size_t scan_int(const char *src,signed int *dest);
size_t scan_ushort(const char *src,unsigned short *dest);
size_t scan_xshort(const char *src,unsigned short *dest);
size_t scan_8short(const char *src,unsigned short *dest);
size_t scan_short(const char *src,signed short *dest);
att_read(1) att_write(2)
size_t scan_long(const char *src,signed long *dest) noexcept;
att_readn(1,2) att_write(3)
size_t scan_longn(const char *src,size_t n,signed long *dest) noexcept;
att_read(1) att_write(2)
size_t scan_longlong(const char *src,signed long long *dest) noexcept;
att_read(1) att_write(2)
size_t scan_ulonglong(const char *src,unsigned long long *dest) noexcept;
att_read(1) att_write(2)
size_t scan_xlonglong(const char *src,unsigned long long *dest) noexcept;
att_read(1) att_write(2)
size_t scan_8longlong(const char *src,unsigned long long *dest) noexcept;
att_read(1) att_write(2)
size_t scan_uint(const char *src,unsigned int *dest) noexcept;
att_read(1) att_write(2)
size_t scan_xint(const char *src,unsigned int *dest) noexcept;
att_read(1) att_write(2)
size_t scan_8int(const char *src,unsigned int *dest) noexcept;
att_read(1) att_write(2)
size_t scan_int(const char *src,signed int *dest) noexcept;
att_read(1) att_write(2)
size_t scan_ushort(const char *src,unsigned short *dest) noexcept;
att_read(1) att_write(2)
size_t scan_xshort(const char *src,unsigned short *dest) noexcept;
att_read(1) att_write(2)
size_t scan_8short(const char *src,unsigned short *dest) noexcept;
att_read(1) att_write(2)
size_t scan_short(const char *src,signed short *dest) noexcept;
/* interpret src as double precision floating point number,
* write number to dest and return the number of bytes that were parsed */
size_t scan_double(const char *in, double *dest);
att_read(1) att_write(2)
size_t scan_double(const char *in, double *dest) noexcept;
/* if *src=='-', set *dest to -1 and return 1.
* if *src=='+', set *dest to 1 and return 1.
* otherwise set *dest to 1 return 0. */
size_t scan_plusminus(const char *src,signed int *dest);
att_read(1) att_write(2)
size_t scan_plusminus(const char *src,signed int *dest) noexcept;
/* return the highest integer n<=limit so that isspace(in[i]) for all 0<=i<=n */
__readmemsz__(1,2)
size_t scan_whitenskip(const char *in,size_t limit) __pure__;
att_pure att_readn(1,2)
size_t scan_whitenskip(const char *in,size_t limit) noexcept;
/* return the highest integer n<=limit so that !isspace(in[i]) for all 0<=i<=n */
__readmemsz__(1,2)
size_t scan_nonwhitenskip(const char *in,size_t limit) __pure__;
att_pure att_readn(1,2)
size_t scan_nonwhitenskip(const char *in,size_t limit) noexcept;
/* return the highest integer n<=limit so that in[i] is element of
* charset (ASCIIZ string) for all 0<=i<=n */
__readmemsz__(1,3)
size_t scan_charsetnskip(const char *in,const char *charset,size_t limit) __pure__;
att_pure att_readn(1,3) att_read(2)
size_t scan_charsetnskip(const char *in,const char *charset,size_t limit) noexcept;
/* return the highest integer n<=limit so that in[i] is not element of
* charset (ASCIIZ string) for all 0<=i<=n */
__readmemsz__(1,3)
size_t scan_noncharsetnskip(const char *in,const char *charset,size_t limit) __pure__;
att_pure att_readn(1,3) att_read(2)
size_t scan_noncharsetnskip(const char *in,const char *charset,size_t limit) noexcept;
/* try to parse ASCII GMT date; does not understand time zones. */
/* example dates:
@ -117,17 +127,23 @@ size_t scan_noncharsetnskip(const char *in,const char *charset,size_t limit) __p
* "Sunday, 06-Nov-94 08:49:37 GMT"
* "Sun Nov 6 08:49:37 1994"
*/
size_t scan_httpdate(const char *in,time_t *t) __pure__;
att_read(1) att_write(2)
size_t scan_httpdate(const char *in,time_t *t) noexcept;
/* try to parse ASCII ISO-8601 date; does not understand time zones. */
/* example date: "2014-05-27T19:22:16Z" */
size_t scan_iso8601(const char* in,struct timespec* t) __pure__;
att_pure att_read(1) att_write(2)
size_t scan_iso8601(const char* in,struct timespec* t) noexcept;
/* some variable length encodings for integers */
size_t scan_utf8(const char* in,size_t len,uint32_t* n) __pure__;
size_t scan_utf8_sem(const char* in,size_t len,uint32_t* n) __pure__;
size_t scan_asn1derlength(const char* in,size_t len,unsigned long long* n) __pure__;
size_t scan_asn1dertag(const char* in,size_t len,unsigned long long* n) __pure__;
att_pure att_readn(1, 2) att_write(3)
size_t scan_utf8(const char* in,size_t len,uint32_t* n) noexcept;
att_pure att_readn(1, 2) att_write(3)
size_t scan_utf8_sem(const char* in,size_t len,uint32_t* n) noexcept;
att_pure att_readn(1, 2) att_write(3)
size_t scan_asn1derlength(const char* in,size_t len,unsigned long long* n) noexcept;
att_pure att_readn(1, 2) att_write(3)
size_t scan_asn1dertag(const char* in,size_t len,unsigned long long* n) noexcept;
/* Google protocol buffers */
/* A protocol buffer is a sequence of (tag,value).
@ -136,15 +152,21 @@ size_t scan_asn1dertag(const char* in,size_t len,unsigned long long* n) __pure__
* 0, double type 1, strings type 2 and floats type 5. However, you
* have to check this yourself.
*/
size_t scan_varint(const char* in,size_t len, unsigned long long* n) __pure__; /* internal */
size_t scan_pb_tag(const char* in,size_t len, size_t* fieldno,unsigned char* type) __pure__;
att_readn(1, 2) att_write(3)
size_t scan_varint(const char* in, size_t len, unsigned long long* n); /* internal */
att_readn(1, 2) att_write(3) att_write(4)
size_t scan_pb_tag(const char* in, size_t len, size_t* fieldno,unsigned char* type);
/* Then, depending on the field number, validate the type and call the
* corresponding of these functions to parse the value */
size_t scan_pb_type0_int(const char* in,size_t len,unsigned long long* l) __pure__;
size_t scan_pb_type0_sint(const char* in,size_t len,signed long long* l) __pure__;
size_t scan_pb_type1_double(const char* in,size_t len,double* d) __pure__;
size_t scan_pb_type1_fixed64(const char* in,size_t len,uint64_t* b) __pure__;
att_readn(1, 2) att_write(3)
size_t scan_pb_type0_int(const char* in,size_t len,unsigned long long* l);
att_readn(1, 2) att_write(3)
size_t scan_pb_type0_sint(const char* in,size_t len,signed long long* l);
att_readn(1, 2) att_write(3)
size_t scan_pb_type1_double(const char* in,size_t len,double* d);
att_readn(1, 2) att_write(3)
size_t scan_pb_type1_fixed64(const char* in,size_t len,uint64_t* b);
/* NOTE: scan_pb_type2_stringlen only parses the length of the string,
* not the string itself. It will return the number of bytes parsed in
* the length, then set slen to the value of the length integer it just
@ -155,9 +177,12 @@ size_t scan_pb_type1_fixed64(const char* in,size_t len,uint64_t* b) __pure__;
* parsing early without having to read and allocate memory for the rest
* (potentially gigabytes) of the data announced by one unreasonable
* string length value. */
size_t scan_pb_type2_stringlen(const char* in,size_t len,const char** string, size_t* slen) __pure__;
size_t scan_pb_type5_float(const char* in,size_t len,float* f) __pure__;
size_t scan_pb_type5_fixed32(const char* in,size_t len,uint32_t* b) __pure__;
att_readn(1, 2) att_write(3) att_write(4)
size_t scan_pb_type2_stringlen(const char* in,size_t len,const char** string, size_t* slen);
att_readn(1, 2) att_write(3)
size_t scan_pb_type5_float(const char* in,size_t len,float* f);
att_readn(1, 2) att_write(3)
size_t scan_pb_type5_fixed32(const char* in,size_t len,uint32_t* b);
/* parse a netstring, input buffer is in (len bytes).
* if parsing is successful:
@ -167,11 +192,12 @@ size_t scan_pb_type5_fixed32(const char* in,size_t len,uint32_t* b) __pure__;
* return 0
* Note: *dest will point inside the input buffer!
*/
__readmemsz__(1,2)
size_t scan_netstring(const char* in,size_t len,char** dest,size_t* slen) __pure__;
att_readn(1, 2) att_write(3) att_write(4)
size_t scan_netstring(const char* in,size_t len,char** dest,size_t* slen);
/* internal function that might be useful independently */
/* convert from hex ASCII, return 0 to 15 for success or -1 for failure */
att_const
int scan_fromhex(unsigned char c);
#ifdef __cplusplus

@ -4,8 +4,9 @@
#include <sys/types.h>
#include "uint16.h"
#include "uint32.h"
#include <libowfat/compiler.h>
#include <libowfat/uint16.h>
#include <libowfat/uint32.h>
#ifdef __cplusplus
extern "C" {
@ -38,12 +39,21 @@ int socket_bind6_reuse(int s,const char* ip,uint16 port,uint32 scope_id);
int socket_listen(int s,unsigned int backlog);
int socket_accept4(int s,char* ip,uint16* port);
int socket_accept6(int s,char* ip,uint16* port,uint32* scope_id);
att_writen(2,3) att_nonnull(2)
ssize_t socket_recv4(int s,char* buf,size_t len,char* ip,uint16* port);
att_writen(2,3) att_nonnull(2)
ssize_t socket_recv6(int s,char* buf,size_t len,char* ip,uint16* port,uint32* scope_id);
att_readn(2,3) att_nonnull(2)
ssize_t socket_send4(int s,const char* buf,size_t len,const char* ip,uint16 port);
att_readn(2,3) att_nonnull(2)
ssize_t socket_send4_flag(int s,const char* buf,size_t len,const char* ip,uint16 port,int flags);
att_readn(2,3) att_nonnull(2)
ssize_t socket_send6(int s,const char* buf,size_t len,const char* ip,uint16 port,uint32 scope_id);
att_readn(2,3) att_nonnull(2)
ssize_t socket_send6_flag(int s,const char* buf,size_t len,const char* ip,uint16 port,uint32 scope_id,int flags);
int socket_local4(int s,char* ip,uint16* port);
int socket_local6(int s,char* ip,uint16* port,uint32* scope_id);
int socket_remote4(int s,char* ip,uint16* port);

27
str.h

@ -4,24 +4,24 @@
#include <stddef.h>
#include <libowfat/compiler.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifndef __pure__
#define __pure__
#endif
/* str_copy copies leading bytes from in to out until \0.
* return number of copied bytes. */
size_t str_copy(char *out,const char *in);
att_write(1) att_read(2)
size_t str_copy(char *out,const char *in) noexcept;
/* str_diff returns negative, 0, or positive, depending on whether the
* string a[0], a[1], ..., a[n]=='\0' is lexicographically smaller than,
* equal to, or greater than the string b[0], b[1], ..., b[m-1]=='\0'.
* If the strings are different, str_diff does not read bytes past the
* first difference. */
int str_diff(const char *a,const char *b) __pure__;
att_pure att_read(1) att_read(2)
int str_diff(const char *a,const char *b) noexcept;
/* str_diffn returns negative, 0, or positive, depending on whether the
* string a[0], a[1], ..., a[n]=='\0' is lexicographically smaller than,
@ -29,24 +29,29 @@ int str_diff(const char *a,const char *b) __pure__;
* If the strings are different, str_diffn does not read bytes past the
* first difference. The strings will be considered equal if the first
* limit characters match. */
int str_diffn(const char *a,const char *b,size_t limit) __pure__;
att_pure att_read(1) att_read(2)
int str_diffn(const char *a,const char *b,size_t limit) noexcept;
#ifdef __dietlibc__
#include <string.h>
#define str_len(foo) strlen(foo)
#else
/* str_len returns the index of \0 in s */
size_t str_len(const char *s) __pure__;
att_pure att_read(1)
size_t str_len(const char *s) noexcept;
#endif
/* str_chr returns the index of the first occurance of needle or \0 in haystack */
size_t str_chr(const char *haystack,char needle) __pure__;
att_pure att_read(1)
size_t str_chr(const char *haystack,char needle) noexcept;
/* str_rchr returns the index of the last occurance of needle or \0 in haystack */
size_t str_rchr(const char *haystack,char needle) __pure__;
att_pure att_read(1)
size_t str_rchr(const char *haystack,char needle) noexcept;
/* str_start returns 1 if the b is a prefix of a, 0 otherwise */
int str_start(const char *a,const char *b) __pure__;
att_pure att_read(1) att_read(2)
int str_start(const char *a,const char *b) noexcept;
/* convenience shortcut to test for string equality */
#define str_equal(s,t) (!str_diff((s),(t)))

@ -4,20 +4,12 @@
#include <stddef.h>
#include <libowfat/compiler.h>
#ifdef __cplusplus
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
/* stralloc is the internal data structure all functions are working on.
* s is the string.
* len is the used length of the string.
@ -33,7 +25,7 @@ typedef struct stralloc {
/* stralloc_init will initialize a stralloc.
* Previously allocated memory will not be freed; use stralloc_free for
* that. To assign an empty string, use stralloc_copys(sa,""). */
void stralloc_init(stralloc* sa);
void stralloc_init(stralloc* sa) noexcept;
/* stralloc_ready makes sure that sa has enough space allocated to hold
* len bytes: If sa is not allocated, stralloc_ready allocates at least
@ -42,53 +34,56 @@ void stralloc_init(stralloc* sa);
* bytes of space, copies the old string into the new space, frees the
* old space, and returns 1. Note that this changes sa.s. If the
* allocation fails, stralloc_ready leaves sa alone and returns 0. */
int stralloc_ready(stralloc* sa,size_t len);
int stralloc_ready(stralloc* sa,size_t len) noexcept;
/* stralloc_readyplus is like stralloc_ready except that, if sa is
* already allocated, stralloc_readyplus adds the current length of sa
* to len. */
int stralloc_readyplus(stralloc* sa,size_t len);
int stralloc_readyplus(stralloc* sa,size_t len) noexcept;
/* stralloc_copyb copies the string buf[0], buf[1], ..., buf[len-1] into
* sa, allocating space if necessary, and returns 1. If it runs out of
* memory, stralloc_copyb leaves sa alone and returns 0. */
__readmemsz__(2,3)
int stralloc_copyb(stralloc* sa,const char* buf,size_t len);
att_readn(2, 3)
int stralloc_copyb(stralloc* sa,const char* buf,size_t len) noexcept;
/* stralloc_copys copies a \0-terminated string from buf into sa,
* without the \0. It is the same as
* stralloc_copyb(&sa,buf,str_len(buf)). */
int stralloc_copys(stralloc* sa,const char* buf);
att_read(2)
int stralloc_copys(stralloc* sa,const char* buf) noexcept;
/* stralloc_copy copies the string stored in sa2 into sa. It is the same
* as stralloc_copyb(&sa,sa2.s,sa2.len). sa2 must already be allocated. */
int stralloc_copy(stralloc* sa,const stralloc* sa2);
int stralloc_copy(stralloc* sa,const stralloc* sa2) noexcept;
/* stralloc_catb adds the string buf[0], buf[1], ... buf[len-1] to the
* end of the string stored in sa, allocating space if necessary, and
* returns 1. If sa is unallocated, stralloc_catb is the same as
* stralloc_copyb. If it runs out of memory, stralloc_catb leaves sa
* alone and returns 0. */
__readmemsz__(2,3)
int stralloc_catb(stralloc* sa,const char* in,size_t len);
att_readn(2, 3)
int stralloc_catb(stralloc* sa,const char* in,size_t len) noexcept;
/* stralloc_cats is analogous to stralloc_copys */
int stralloc_cats(stralloc* sa,const char* in);
att_read(2)
int stralloc_cats(stralloc* sa,const char* in) noexcept;
void stralloc_zero(stralloc* sa);
void stralloc_zero(stralloc* sa) noexcept;
/* like stralloc_cats but can cat more than one string at once */
int stralloc_catm_internal(stralloc* sa,...);
int stralloc_catm_internal(stralloc* sa,...) noexcept;
#define stralloc_catm(sa,...) stralloc_catm_internal(sa,__VA_ARGS__,(char*)0)
#define stralloc_copym(sa,...) (stralloc_zero(sa), stralloc_catm_internal(sa,__VA_ARGS__,(char*)0))
/* stralloc_cat is analogous to stralloc_copy */
int stralloc_cat(stralloc* sa,const stralloc* in);
int stralloc_cat(stralloc* sa,const stralloc* in) noexcept;
/* stralloc_append adds one byte in[0] to the end of the string stored
* in sa. It is the same as stralloc_catb(&sa,in,1). */
int stralloc_append(stralloc* sa,const char* in); /* beware: this takes a pointer to 1 char */
att_read(2)
int stralloc_append(stralloc* sa,const char* in) noexcept; /* beware: this takes a pointer to 1 char */
#if 0
#define stralloc_APPEND(sa,in) \
@ -109,17 +104,20 @@ static inline int stralloc_APPEND(stralloc* sa,const char* in) {
/* stralloc_starts returns 1 if the \0-terminated string in "in", without
* the terminating \0, is a prefix of the string stored in sa. Otherwise
* it returns 0. sa must already be allocated. */
int stralloc_starts(stralloc* sa,const char* in) __pure__;
att_pure att_read(2)
int stralloc_starts(stralloc* sa,const char* in) noexcept;
/* stralloc_diff returns negative, 0, or positive, depending on whether
* a is lexicographically smaller than, equal to, or greater than the
* string b. */
int stralloc_diff(const stralloc* a,const stralloc* b) __pure__;
att_pure
int stralloc_diff(const stralloc* a,const stralloc* b) noexcept;
/* stralloc_diffs returns negative, 0, or positive, depending on whether
* a is lexicographically smaller than, equal to, or greater than the
* string b[0], b[1], ..., b[n]=='\0'. */
int stralloc_diffs(const stralloc* a,const char* b) __pure__;
att_pure att_read(2)
int stralloc_diffs(const stralloc* a,const char* b) noexcept;
#define stralloc_equal(a,b) (!stralloc_diff((a),(b)))
#define stralloc_equals(a,b) (!stralloc_diffs((a),(b)))
@ -128,15 +126,15 @@ int stralloc_diffs(const stralloc* a,const char* b) __pure__;
#define stralloc_0(sa) stralloc_append(sa,"")
/* stralloc_catulong0 appends a '0' padded ASCII representation of in */
int stralloc_catulong0(stralloc* sa,unsigned long int in,size_t n);
int stralloc_catulong0(stralloc* sa,unsigned long int in,size_t n) noexcept;
/* stralloc_catlong0 appends a '0' padded ASCII representation of in */
/* note that the n does not include the sign:
* stralloc_catlong0(&sa,-10,4) -> "-0010" */
int stralloc_catlong0(stralloc* sa,signed long int in,size_t n);
int stralloc_catlong0(stralloc* sa,signed long int in,size_t n) noexcept;
/* stralloc_free frees the storage associated with sa */
void stralloc_free(stralloc* sa);
void stralloc_free(stralloc* sa) noexcept;
#define stralloc_catlong(sa,l) (stralloc_catlong0((sa),(l),0))
#define stralloc_catulong(sa,l) (stralloc_catulong0((sa),(l),0))
@ -146,10 +144,10 @@ void stralloc_free(stralloc* sa);
#define stralloc_catuint(sa,i) (stralloc_catulong0((sa),(i),0))
/* remove last char. Return removed byte as unsigned char (or -1 if stralloc was empty). */
int stralloc_chop(stralloc* sa);
int stralloc_chop(stralloc* sa) noexcept;
/* remove trailing "\r\n", "\n" or "\r". Return number of removed chars (0,1 or 2) */
int stralloc_chomp(stralloc* sa);
int stralloc_chomp(stralloc* sa) noexcept;
#ifdef BUFFER_H
/* write stralloc to buffer */
@ -169,13 +167,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);

2
t.c

@ -37,6 +37,8 @@
// #define atomic_add(mem,val) asm volatile ("lock; add%z0 %1, %0": "+m" (mem): "ir" (val))
// compiletimeassert(sizeof(long) == 2);
int64 writecb(int64 fd,const void* buf,uint64 n) {
(void)fd;
(void)buf;

@ -4,7 +4,7 @@
/* Times with 1 second precision */
#include "uint64.h"
#include <libowfat/uint64.h>
#ifdef __cplusplus
extern "C" {

@ -4,8 +4,8 @@
/* Times with 1 attosecond precision */
#include "tai.h"
#include "uint32.h"
#include <libowfat/tai.h>
#include <libowfat/uint32.h>
#ifdef __cplusplus
extern "C" {

@ -12,71 +12,91 @@ extern "C" {
* dest (if dest != NULL), returning the number of bytes written. */
/* dietlibc defines these in sys/cdefs.h, which is included from stddef.h */
#ifndef __writememsz__
#ifndef __readmemsz__
#define __readmemsz__(a,b)
#endif
#ifndef __writemem__
#define __writemem__(a)
#endif
/* Needs len/3*4 bytes */
__readmemsz__(2,3)
__writemem__(1) __readmemsz__(2,3)
size_t fmt_uuencoded(char* dest,const char* src,size_t len);
/* Needs len/3*4 bytes */
__readmemsz__(2,3)
__writemem__(1) __readmemsz__(2,3)
size_t fmt_base64(char* dest,const char* src,size_t len);
__readmemsz__(2,3)
__writemem__(1) __readmemsz__(2,3)
size_t fmt_base64url(char* dest,const char* src,size_t len);
/* Worst case: len*3 */
__readmemsz__(2,3)
__writemem__(1) __readmemsz__(2,3)
size_t fmt_quotedprintable(char* dest,const char* src,size_t len);
/* Worst case: len*3 */
__readmemsz__(2,3)
__writemem__(1) __readmemsz__(2,3)
size_t fmt_quotedprintable2(char* dest,const char* src,size_t len,const char* escapeme);
/* Worst case: len*3 */
__readmemsz__(2,3)
__writemem__(1) __readmemsz__(2,3)
size_t fmt_urlencoded(char* dest,const char* src,size_t len);
/* Worst case: len*3 */
__readmemsz__(2,3)
__writemem__(1) __readmemsz__(2,3)
size_t fmt_urlencoded2(char* dest,const char* src,size_t len,const char* escapeme);
/* Worst case: len*2 */
__readmemsz__(2,3)
__writemem__(1) __readmemsz__(2,3)
size_t fmt_yenc(char* dest,const char* src,size_t len);
/* Needs len*2 bytes */
__readmemsz__(2,3)
__writemem__(1) __readmemsz__(2,3)
size_t fmt_hexdump(char* dest,const char* src,size_t len);
/* Change '<' to '&lt;' and '&' to '&amp;' and '\n' to '<br>'; worst case: len*5 */
/* This is meant for outputting text that goes between tags */
__readmemsz__(2,3)
__writemem__(1) __readmemsz__(2,3)
size_t fmt_html(char* dest,const char* src,size_t len);
/* Change '<' to '&lt;' and '&' to '&amp;' and '"' to '&quot;'; worst case: len*6 */
/* This is meant for outputting text that goes in a tag argument between double quotes*/
__readmemsz__(2,3)
__writemem__(1) __readmemsz__(2,3)
size_t fmt_html_tagarg(char* dest,const char* src,size_t len);
/* Change '<' to '&lt;' and '&' to '&amp;'; worst case: len*5 */
__readmemsz__(2,3)
__writemem__(1) __readmemsz__(2,3)
size_t fmt_xml(char* dest,const char* src,size_t len);
/* Change '\' to "\\", '\n' to "\n", ^A to "\x01" etc; worst case: len*4 */
__readmemsz__(2,3)
__writemem__(1) __readmemsz__(2,3)
size_t fmt_cescape(char* dest,const char* src,size_t len);
/* Worst case: len*4 */
__readmemsz__(2,3)
__writemem__(1) __readmemsz__(2,3)
size_t fmt_cescape2(char* dest,const char* src,size_t len,const char* escapeme);
/* Fold whitespace to '_'; this is great for writing fields with
* white spaces to a log file and still allow awk to do log analysis */
/* Worst case: same size */
__readmemsz__(2,3)
__writemem__(1) __readmemsz__(2,3)
size_t fmt_foldwhitespace(char* dest,const char* src,size_t len);
/* Worst case: len*3 */
__readmemsz__(2,3)
__writemem__(1) __readmemsz__(2,3)
size_t fmt_ldapescape(char* dest,const char* src,size_t len);
__readmemsz__(2,3)
__writemem__(1) __readmemsz__(2,3)
size_t fmt_ldapescape2(char* dest,const char* src,size_t len,const char* escapeme);
/* Encode JSON string from UTF-8; will backslash-escape the bare minimum.
* Invalid UTF-8 in input will output as valid UTF-8 for each byte
* Worst case: len*6 */
__readmemsz__(2,3)
__writemem__(1) __readmemsz__(2,3)
size_t fmt_jsonescape(char* dest,const char* src,size_t len);
__readmemsz__(2,3)
__writemem__(1) __readmemsz__(2,3)
size_t fmt_base85(char* dest,const char* src,size_t len);
/* These read one line from src, decode it, and write the result to

Loading…
Cancel
Save