more function attribute updates

This commit is contained in:
leitner
2024-11-22 19:40:24 +00:00
parent 626c55b122
commit 4b84fba68b
4 changed files with 136 additions and 48 deletions

View File

@@ -15,17 +15,6 @@
extern "C" {
#endif
/* dietlibc defines these in sys/cdefs.h, which is included from stddef.h */
#ifndef __writememsz__
#define __writememsz__(a,b)
#endif
#ifndef __readmemsz__
#define __readmemsz__(a,b)
#endif
#ifndef __readmem__
#define __readmem__(a)
#endif
typedef struct buffer {
char *x; /* actual buffer space */
size_t p; /* current position */
@@ -45,22 +34,22 @@ 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) */
att_writen(4,5)
__bufout(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) */
att_writen(4,5)
__bufout(4,5)
void buffer_init_free(buffer* b,ssize_t (*op)(),int fd,char* y,size_t ylen);
/* Call buffer_init with op=read(), return 0.
* If fd==-1, return -1 instead, leaving b untouched. */
att_writen(3,4)
__bufout(3,4)
int buffer_init_read(buffer* b, int fd, char* y, size_t ylen);
/* Call buffer_init with op=write(), return 0.
* If fd==-1, return -1 instead, leaving b untouched. */
att_writen(3,4)
__bufout(3,4)
int buffer_init_write(buffer* b, int fd, char* y, size_t ylen);
/* Will allocate a buffer of size ylen and then call
@@ -83,12 +72,12 @@ int buffer_init_write_allocbuf(buffer* b, int fd, 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)
__bufin(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)
__bufin(2,3)
void buffer_init_staticcontents_free(buffer* b,char* y,size_t ylen);
@@ -102,7 +91,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)
__strin(2)
int buffer_mmapread(buffer* b,const char* filename);
/* Indicate you are done with a buffer.
@@ -115,22 +104,22 @@ void buffer_close(buffer* b);
* the data in the buffer. */
int buffer_flush(buffer* b);
att_readn(2,3)
__bufin(2,3)
int buffer_put(buffer* b,const char* x,size_t len);
att_readn(2,3)
__bufin(2,3)
int buffer_putalign(buffer* b,const char* x,size_t len);
att_readn(2,3)
__bufin(2,3)
int buffer_putflush(buffer* b,const char* x,size_t len);
att_read(2)
__strin(2)
int buffer_puts(buffer* b,const char* x);
att_read(2)
__strin(2)
int buffer_putsalign(buffer* b,const char* x);
att_read(2)
__strin(2)
int buffer_putsflush(buffer* b,const char* x);
#if defined(__GNUC__) && !defined(__LIBOWFAT_INTERNAL)
@@ -155,22 +144,24 @@ int buffer_putnlflush(buffer* b); /* put \n and flush */
: buffer_put((s),&(c),1) \
)
att_writen(2,3)
__bufout(2,3)
ssize_t buffer_get(buffer* b,char* x,size_t len);
ssize_t buffer_feed(buffer* b);
att_write(2) att_nonnull(2)
ssize_t buffer_getc(buffer* b,char* x);
att_write(2) att_nonnull(2)
ssize_t buffer_peekc(buffer* b,char* x);
att_writen(2,3)
__bufout(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 */
att_writen(2,3)
att_readn(4,5)
__bufout(2,3)
__bufin(4,5)
ssize_t buffer_get_token(buffer* b,char* x,size_t len,const char* charset,size_t setlen);
att_writen(2,3)
__bufout(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
@@ -178,7 +169,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 */
att_writen(2,3)
__bufout(2,3)
ssize_t buffer_get_token_pred(buffer* b,char* x,size_t len,string_predicate p);
char *buffer_peek(buffer* b);
@@ -228,13 +219,13 @@ int buffer_putsaflush(buffer* b,const stralloc* sa);
* data is available. */
/* read token from buffer to stralloc */
att_readn(3,4)
__bufin(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 */
att_readn(3,4)
__bufin(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);
@@ -252,7 +243,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
att_readn(2,3)
__bufin(2,3)
void buffer_frombuf(buffer* b,const char* x,size_t l); /* buffer reads from static buffer */
#ifdef ARRAY_H

View File

@@ -1,9 +1,16 @@
#include <errno.h>
#include "array.h"
#include "buffer.h"
static ssize_t fail() {
errno=EINVAL;
return -1;
}
void buffer_fromarray(buffer* b,array* a) {
if (array_failed(a))
buffer_frombuf(b,NULL,0);
else
if (array_failed(a)) {
memset(b,0,sizeof *b);
b->op=fail;
} else
buffer_frombuf(b,array_start(a),a->initialized);
}

16
case.h
View File

@@ -10,29 +10,23 @@ extern "C" {
#endif
/* turn upper case letters to lower case letters, ASCIIZ */
att_mangle(1)
__strinout(1)
void case_lowers(char *s);
/* turn upper case letters to lower case letters, binary */
att_manglen(1,2)
__strninout(1,2)
void case_lowerb(void *buf,size_t len);
/* like str_diff, ignoring case */
att_pure
att_read(1)
att_read(2)
att_pure __strin(1) __strin(2)
int case_diffs(const char *,const char *);
/* like byte_diff, ignoring case */
att_pure
att_readn(1,2)
att_readn(3,2)
att_pure __strnin(1,2) __strnin(3,2)
int case_diffb(const void *,size_t ,const void *);
/* like str_start, ignoring case */
att_pure
att_read(1)
att_read(2)
att_pure __strin(1) __strin(2)
int case_starts(const char *,const char *);
#define case_equals(s,t) (!case_diffs((s),(t)))

View File

@@ -1,7 +1,7 @@
#ifndef LIBOWFAT_ATTRIBUTES_H
#define LIBOWFAT_ATTRIBUTES_H
// This is here so you can use inline with older gcc versions
#if __GNUC__ && (__STDC_VERSION__ < 199901L)
#define inline __inline__
#endif
@@ -12,6 +12,7 @@
#define __extension__
#endif
// This is here so we can put noexcept on function declarations in headers
#ifndef __cplusplus
#define noexcept
#endif
@@ -24,6 +25,9 @@
#define restrict
#endif
// Use this to tell the compiler something is likely to be true or false
// The compiler can use that to give hints to the CPU and group error
// handling code to "cold" pages that never get paged in by the OS
#if GCC_VERSION_ATLEAST(3,0)
#define likely(a) __builtin_expect((a), 1)
#define unlikely(a) __builtin_expect((a), 0)
@@ -32,30 +36,49 @@
#define unlikely(a) (a)
#endif
// Function attribute for functions like abs() that depend only on the
// arguments and does not access any other memory in the program. The
// compiler can then optimize multiple calls on the same value into just
// one call.
#if GCC_VERSION_ATLEAST(2, 5)
#define att_const __attribute__((__const__))
#else
#define att_const
#endif
// Function attribute. Tells the compiler the function has no effect on
// the state of the program except for the return value, but unlike
// att_const the function can read other global state in the program,
// like the memory pointer arguments point to.
#if GCC_VERSION_ATLEAST(2, 96)
#define att_pure __attribute__((__pure__))
#else
#define att_pure
#endif
// Function attribute for functions that return freshly allocated
// memory. The compiler then knows the pointer does not alias with other
// pointers, which enables several optimizations.
#if GCC_VERSION_ATLEAST(3, 0)
#define att_malloc __attribute__((__malloc__))
#else
#define att_malloc
#endif
// Function attribute for functions that return an important value, like
// an error code, where it would be a security issue not to check the
// return value, for example link or rename. The compiler will then warn
// if the caller ignores the return value.
#if GCC_VERSION_ATLEAST(3, 4)
#define att_warn_unused_result __attribute__((__warn_unused_result__))
#else
#define att_warn_unused_result
#endif
// Function attributes. The compiler will put hot and cold functions
// adjacent in memory. If you mark error handling functions as
// cold, the compiler can arrange the binary so the operating system
// never reads those pages into main memory from disk.
#if GCC_VERSION_ATLEAST(4, 3)
#define att_hot __attribute__((__hot__))
#define att_cold __attribute__((__cold__))
@@ -64,6 +87,13 @@
#define att_cold
#endif
// Function attributes. att_alloc tells the compiler that the compiler
// returns a buffer of the size given in the function argument x
// (as an index, counted left to right, starting at 1). att_calloc says
// the buffer size is a*b (both again as an function argument index,
// counted from left to right, starting at 1)
// If we tell the compiler the buffer size, it can detect if we access
// values outside the buffer area.
#if GCC_VERSION_ATLEAST(4, 3)
#define att_alloc(x) __attribute__((alloc_size(x)))
#define att_calloc(x,y) __attribute__((alloc_size(x,y)))
@@ -72,6 +102,13 @@
#define att_calloc
#endif
// Function attributes.
// att_read(1) says the function reads from the first function argument.
// att_readn(1,2) is like att_read but the buffer size is given as the second argument.
// att_write(1) says the function writes to the first function argument.
// att_writen(1) is like att_write but the buffer size is given as the second argument.
// att_mangle(1) says the function read/writes to the first function argument.
// att_manglen(1) is like att_mangle but the buffer size is given as the second argument.
#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)))
@@ -88,18 +125,24 @@
#define att_manglen(argno_ptr, argno_size)
#endif
// Function attribute. The compiler will warn if you call this function.
#if GCC_VERSION_ATLEAST(3, 2)
#define att_dontuse __attribute__((__deprecated__))
#else
#define att_dontuse
#endif
// Function attribute. Tells the compiler that the param's function
// argument can not be NULL (given as index of function arguments,
// counted left to right from 1)
#if GCC_VERSION_ATLEAST(3, 3)
#define att_nonnull(params) __attribute__((__nonnull__(params)))
#else
#define att_nonnull(params)
#endif
// Function attribute. Makes the compiler emit a warning or an error,
// abort compilation on error.
#if GCC_VERSION_ATLEAST(4, 3)
#define att_warn(message) __attribute__((__warning__(message)))
#define att_error(message) __attribute__((__warning__(message)))
@@ -108,8 +151,61 @@
#define att_error(message)
#endif
// __builtin_constant_p is a GCC extension used in macros to handle
// cases differently where a macro argument is a constant
#ifndef __GNUC__
#define __builtin_constant_p(x) 0
#endif
#if defined(__GNUC__)
#if __has_attribute(null_terminated_string_arg)
// Function arguments.
// __strin: Argument idx (counted left to right from 1) is a non-NULL string the function reads
#define __strin(idx) __attribute__((nonnull(idx),access(read_only,idx),null_terminated_string_arg(idx)))
// __strnin: Argument idx (counted left to right from 1) is a non-NULL string the function reads, length limit in array elements given in the szidx'th argument
#define __strnin(idx,szidx) __attribute__((nonnull(idx),access(read_only,idx,szidx),null_terminated_string_arg(idx)))
// __bufin: Argument idx (counted left to right from 1) is a non-NULL buffer the function reads from, length limit in array elements given in the szidx'th argument
#define __bufin(bufidx,szidx) __attribute__((nonnull(bufidx),access(read_only,bufidx,szidx)))
// __strout: Argument idx (counted left to right from 1) is a non-NULL string the function writes
// Currently we can't tell the compiler that the output will be 0-terminated.
#define __strout(idx) __attribute__((nonnull(idx),access(write_only,idx)))
// __strnout: Argument idx (counted left to right from 1) is a non-NULL string the function writes, buffer size given in szidx'th function argument (in array elements, not necessarily bytes)
// Currently we can't tell the compiler that the output will be 0-terminated.
#define __strnout(idx,szidx) __attribute__((nonnull(idx),access(write_only,idx,szidx)))
// __bufout: Argument idx (counted left to right from 1) is a non-NULL buffer the function writes, buffer size given in szidx'th function argument (in array elements, not necessarily bytes)
#define __bufout(bufidx,szidx) __attribute__((nonnull(bufidx),access(write_only,bufidx,szidx)))
// __strinout: Argument idx (counted left to right from 1) is a non-NULL string the function reads and writes
// Currently we can't tell the compiler that the output will be 0-terminated.
#define __strinout(idx) __attribute__((nonnull(idx),access(read_write,idx),null_terminated_string_arg(idx)))
// __strninout: Argument idx (counted left to right from 1) is a non-NULL string the function reads and writes, buffer size in szidx'th function argument (in array elements, not necessarily bytes)
// Currently we can't tell the compiler that the output will be 0-terminated.
#define __strninout(idx,szidx) __attribute__((nonnull(idx),access(read_write,idx,szidx),null_terminated_string_arg(idx)))
// __bufinout: Argument idx (counted left to right from 1) is a non-NULL buffer the function reads and writes, buffer size in szidx'th function argument (in array elements, not necessarily bytes)
#define __bufinout(bufidx,szidx) __attribute__((nonnull(bufidx),access(read_write,bufidx,szidx)))
#elif GCC_VERSION_ATLEAST(10, 0)
#define __strin(idx) __attribute__((nonnull(idx),access(read_only,idx)))
#define __strnin(idx,szidx) __attribute__((nonnull(idx),access(read_only,idx,szidx)))
#define __bufin(bufidx,szidx) __attribute__((nonnull(bufidx),access(read_only,bufidx,szidx)))
#define __strout(idx) __attribute__((nonnull(idx),access(write_only,idx)))
#define __strnout(idx,szidx) __attribute__((nonnull(idx),access(write_only,idx,szidx)))
#define __bufout(bufidx,szidx) __attribute__((nonnull(bufidx),access(write_only,bufidx,szidx)))
#define __strinout(idx) __attribute__((nonnull(idx),access(read_write,idx)))
#define __strninout(idx,szidx) __attribute__((nonnull(idx),access(read_write,idx,szidx)))
#define __bufinout(bufidx,szidx) __attribute__((nonnull(bufidx),access(read_write,bufidx,szidx)))
#elif GCC_VERSION_ATLEAST(3, 3)
#define __strin(idx) __attribute__((nonnull(idx)))
#define __strnin(idx,szidx) __attribute__((nonnull(idx)))
#define __bufin(bufidx,szidx) __attribute__((nonnull(bufidx)))
#define __strout(idx) __attribute__((nonnull(idx)))
#define __strnout(idx,szidx) __attribute__((nonnull(idx)))
#define __bufout(bufidx,szidx) __attribute__((nonnull(bufidx)))
#define __strinout(idx) __attribute__((nonnull(idx)))
#define __strninout(idx,szidx) __attribute__((nonnull(idx)))
#define __bufinout(bufidx,szidx) __attribute__((nonnull(bufidx)))
#endif
#endif // !defined(__GNUC__)
#endif