aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/arg.h2
-rw-r--r--src/coopgammad.c89
-rw-r--r--src/filter.c10
-rw-r--r--src/filter.h19
-rw-r--r--src/message.c50
-rw-r--r--src/message.h31
-rw-r--r--src/output.c20
-rw-r--r--src/output.h48
-rw-r--r--src/ramps.c9
-rw-r--r--src/ramps.h20
-rw-r--r--src/ring.c16
-rw-r--r--src/ring.h36
-rw-r--r--src/server.c89
-rw-r--r--src/server.h20
-rw-r--r--src/util.c11
-rw-r--r--src/util.h29
16 files changed, 311 insertions, 188 deletions
diff --git a/src/arg.h b/src/arg.h
index 0b23c53..97e5980 100644
--- a/src/arg.h
+++ b/src/arg.h
@@ -6,7 +6,7 @@
#ifndef ARG_H__
#define ARG_H__
-extern char *argv0;
+extern char *restrict argv0;
/* use main(int argc, char *argv[]) */
#define ARGBEGIN for (argv0 = *argv, argv++, argc--;\
diff --git a/src/coopgammad.c b/src/coopgammad.c
index 9374dc9..7e6422e 100644
--- a/src/coopgammad.c
+++ b/src/coopgammad.c
@@ -45,18 +45,28 @@
-extern char* argv0_real;
-extern struct output* outputs;
+#ifndef GCC_ONLY
+# if defined(__GNUC__) && !defined(__clang__)
+# define GCC_ONLY(...) __VA_ARGS__
+# else
+# define GCC_ONLY(...) /* nothing */
+# endif
+#endif
+
+
+
+extern char* restrict argv0_real;
+extern struct output* restrict outputs;
extern size_t outputs_n;
extern int socketfd;
-extern char* pidpath;
-extern char* socketpath;
+extern char* restrict pidpath;
+extern char* restrict socketpath;
extern int gerror;
extern int method;
-extern char* sitename;
+extern char* restrict sitename;
extern libgamma_site_state_t site;
-extern libgamma_partition_state_t* partitions;
-extern libgamma_crtc_state_t* crtcs;
+extern libgamma_partition_state_t* restrict partitions;
+extern libgamma_crtc_state_t* restrict crtcs;
extern volatile sig_atomic_t reexec;
extern volatile sig_atomic_t terminate;
extern volatile sig_atomic_t connection;
@@ -66,18 +76,18 @@ extern volatile sig_atomic_t connection;
/**
* The name of the process
*/
-char* argv0;
+char* restrict argv0;
/**
* The real pathname of the process's binary,
* `NULL` if `argv0` is satisfactory
*/
-char* argv0_real = NULL;
+char* restrict argv0_real = NULL;
/**
* Array of all outputs
*/
-struct output* outputs = NULL;
+struct output* restrict outputs = NULL;
/**
* The nubmer of elements in `outputs`
@@ -92,12 +102,12 @@ int socketfd = -1;
/**
* The pathname of the PID file
*/
-char* pidpath = NULL;
+char* restrict pidpath = NULL;
/**
* The pathname of the socket
*/
-char* socketpath = NULL;
+char* restrict socketpath = NULL;
/**
* Error code returned by libgamma
@@ -112,7 +122,7 @@ int method = -1;
/**
* The site's name, may be `NULL`
*/
-char* sitename = NULL;
+char* restrict sitename = NULL;
/**
* The libgamma site state
@@ -122,12 +132,12 @@ libgamma_site_state_t site;
/**
* The libgamma partition states
*/
-libgamma_partition_state_t* partitions = NULL;
+libgamma_partition_state_t* restrict partitions = NULL;
/**
* The libgamma CRTC states
*/
-libgamma_crtc_state_t* crtcs = NULL;
+libgamma_crtc_state_t* restrict crtcs = NULL;
/**
* Has the process receive a signal
@@ -196,14 +206,15 @@ static void sig_connection(int signo)
* @param suffix The suffix for the file
* @return The pathname of the file, `NULL` on error
*/
-static char* get_pathname(const char* suffix)
+GCC_ONLY(__attribute__((malloc, nonnull)))
+static char* get_pathname(const char* restrict suffix)
{
- const char* rundir = getenv("XDG_RUNTIME_DIR");
- const char* username = "";
+ const char* restrict rundir = getenv("XDG_RUNTIME_DIR");
+ const char* restrict username = "";
char* name = NULL;
char* p;
- char* rc;
- struct passwd* pw;
+ char* restrict rc;
+ struct passwd* restrict pw;
size_t n;
int saved_errno;
@@ -260,6 +271,7 @@ static char* get_pathname(const char* suffix)
*
* @return The pathname of the socket, `NULL` on error
*/
+GCC_ONLY(__attribute__((malloc)))
static inline char* get_socket_pathname(void)
{
return get_pathname(".socket");
@@ -271,6 +283,7 @@ static inline char* get_socket_pathname(void)
*
* @return The pathname of the PID file, `NULL` on error
*/
+GCC_ONLY(__attribute__((malloc)))
static inline char* get_pidfile_pathname(void)
{
return get_pathname(".pid");
@@ -282,6 +295,7 @@ static inline char* get_pidfile_pathname(void)
*
* @return The pathname of the state file, `NULL` on error
*/
+GCC_ONLY(__attribute__((malloc)))
static inline char* get_state_pathname(void)
{
return get_pathname(".state");
@@ -294,13 +308,14 @@ static inline char* get_state_pathname(void)
* @param arg The adjustment method name (or stringised number)
* @return The adjustment method, -1 (negative) on error
*/
-static int get_method(char* arg)
+GCC_ONLY(__attribute__((nonnull)))
+static int get_method(const char* restrict arg)
{
#if LIBGAMMA_METHOD_MAX > 5
# warning libgamma has added more adjustment methods
#endif
- char* p;
+ const char* restrict p;
if (!strcmp(arg, "dummy")) return LIBGAMMA_METHOD_DUMMY;
if (!strcmp(arg, "randr")) return LIBGAMMA_METHOD_X_RANDR;
@@ -331,7 +346,9 @@ static int get_method(char* arg)
* @param crtc libgamma's state for the CRTC
* @return The name of the CRTC, `NULL` on error
*/
-static char* get_crtc_name(libgamma_crtc_information_t* info, libgamma_crtc_state_t* crtc)
+GCC_ONLY(__attribute__((nonnull)))
+static char* get_crtc_name(const libgamma_crtc_information_t* restrict info,
+ const libgamma_crtc_state_t* restrict crtc)
{
if ((info->edid_error == 0) && (info->edid != NULL))
return libgamma_behex_edid(info->edid, info->edid_length);
@@ -362,7 +379,8 @@ static char* get_crtc_name(libgamma_crtc_information_t* info, libgamma_crtc_stat
* 0: The service is already running
* 1: The PID file is outdated
*/
-static int is_pidfile_reusable(const char* pidfile, const char* token)
+GCC_ONLY(__attribute__((nonnull)))
+static int is_pidfile_reusable(const char* restrict pidfile, const char* restrict token)
{
/* PORTERS: /proc/$PID/environ is Linux specific */
@@ -456,11 +474,12 @@ static int is_pidfile_reusable(const char* pidfile, const char* token)
* @return Zero on success, -1 on error,
* -2 if the service is already running
*/
+GCC_ONLY(__attribute__((nonnull)))
static int create_pidfile(char* pidfile)
{
int fd, r, saved_errno;
char* p;
- char* token;
+ char* restrict token;
/* Create token used to validate the service. */
token = malloc(sizeof("COOPGAMMAD_PIDFILE_TOKEN=") + strlen(pidfile));
@@ -543,7 +562,7 @@ static int initialise(int full, int preserve, int foreground, int keep_stderr, i
struct rlimit rlimit;
size_t i, j, n, n0;
sigset_t mask;
- char* sitename_dup = NULL;
+ char* restrict sitename_dup = NULL;
int r;
/* Zero out some memory so it can be destoried safely. */
@@ -966,10 +985,10 @@ static void destroy(int full)
* buffer needs to be
* @return The number of marshalled bytes
*/
-static size_t marshal(void* buf)
+static size_t marshal(void* restrict buf)
{
size_t off = 0, i, n;
- char* bs = buf;
+ char* restrict bs = buf;
if (bs != NULL)
*(int*)(bs + off) = MARSHAL_VERSION;
@@ -1041,10 +1060,11 @@ static size_t marshal(void* buf)
* @param buf Buffer with the marshalled data
* @return The number of marshalled bytes, 0 on error
*/
-static size_t unmarshal(void* buf)
+GCC_ONLY(__attribute__((nonnull)))
+static size_t unmarshal(void* restrict buf)
{
size_t off = 0, i, n;
- char* bs = buf;
+ char* restrict bs = buf;
if (*(int*)(bs + off) != MARSHAL_VERSION)
{
@@ -1125,10 +1145,11 @@ static size_t unmarshal(void* buf)
* @param statefile The state file
* @return Zero on success, -1 on error
*/
-static int unmarshal_and_merge_state(const char* statefile)
+GCC_ONLY(__attribute__((nonnull)))
+static int unmarshal_and_merge_state(const char* restrict statefile)
{
- struct output* new_outputs = outputs;
- struct output* old_outputs = NULL;
+ struct output* restrict new_outputs = outputs;
+ struct output* restrict old_outputs = NULL;
size_t new_outputs_n = outputs_n;
size_t old_outputs_n = 0;
size_t i, j, k;
@@ -1221,7 +1242,7 @@ static int unmarshal_and_merge_state(const char* statefile)
*/
static int print_method_and_site(int query)
{
- const char* methodname = NULL;
+ const char* restrict methodname = NULL;
char* p;
if (query == 1)
diff --git a/src/filter.c b/src/filter.c
index 943401e..c335e0b 100644
--- a/src/filter.c
+++ b/src/filter.c
@@ -29,7 +29,7 @@
*
* @param this The filter
*/
-void filter_destroy(struct filter* this)
+void filter_destroy(struct filter* restrict this)
{
free(this->class);
free(this->ramps);
@@ -52,11 +52,11 @@ void filter_destroy(struct filter* this)
* @param ramps_size The byte-size of `this->ramps`
* @return The number of marshalled byte
*/
-size_t filter_marshal(const struct filter* this, void* buf, size_t ramps_size)
+size_t filter_marshal(const struct filter* restrict this, void* restrict buf, size_t ramps_size)
{
size_t off = 0, n;
char nonnulls = 0;
- char* bs = buf;
+ char* restrict bs = buf;
if (bs != NULL)
{
@@ -101,11 +101,11 @@ size_t filter_marshal(const struct filter* this, void* buf, size_t ramps_size)
* @param ramps_size The byte-size of `this->ramps`
* @return The number of unmarshalled bytes, 0 on error
*/
-size_t filter_unmarshal(struct filter* this, const void* buf, size_t ramps_size)
+size_t filter_unmarshal(struct filter* restrict this, const void* restrict buf, size_t ramps_size)
{
size_t off = 0, n;
char nonnulls = 0;
- const char* bs = buf;
+ const char* restrict bs = buf;
nonnulls = *(bs + off);
off += 1;
diff --git a/src/filter.h b/src/filter.h
index 385ec56..5691f6c 100644
--- a/src/filter.h
+++ b/src/filter.h
@@ -20,6 +20,16 @@
+#ifndef GCC_ONLY
+# if defined(__GNUC__) && !defined(__clang__)
+# define GCC_ONLY(...) __VA_ARGS__
+# else
+# define GCC_ONLY(...) /* nothing */
+# endif
+#endif
+
+
+
/**
* The lifespan of a filter
*/
@@ -91,7 +101,8 @@ struct filter
*
* @param this The filter
*/
-void filter_destroy(struct filter* this);
+GCC_ONLY(__attribute__((nonnull)))
+void filter_destroy(struct filter* restrict this);
/**
* Marshal a filter
@@ -103,7 +114,8 @@ void filter_destroy(struct filter* this);
* @param ramps_size The byte-size of `filter->ramps`
* @return The number of marshalled byte
*/
-size_t filter_marshal(const struct filter* this, void* buf, size_t ramps_size);
+GCC_ONLY(__attribute__((nonnull(1))))
+size_t filter_marshal(const struct filter* restrict this, void* restrict buf, size_t ramps_size);
/**
* Unmarshal a filter
@@ -114,5 +126,6 @@ size_t filter_marshal(const struct filter* this, void* buf, size_t ramps_size);
* @param ramps_size The byte-size of `filter->ramps`
* @return The number of unmarshalled bytes, 0 on error
*/
-size_t filter_unmarshal(struct filter* this, const void* buf, size_t ramps_size);
+GCC_ONLY(__attribute__((nonnull)))
+size_t filter_unmarshal(struct filter* restrict this, const void* restrict buf, size_t ramps_size);
diff --git a/src/message.c b/src/message.c
index 619ae25..48bdbff 100644
--- a/src/message.c
+++ b/src/message.c
@@ -33,7 +33,7 @@
* @param this Memory slot in which to store the new message
* @return Non-zero on error, `errno` will be set accordingly
*/
-int message_initialise(struct message* this)
+int message_initialise(struct message* restrict this)
{
this->headers = NULL;
this->header_count = 0;
@@ -56,7 +56,7 @@ int message_initialise(struct message* this)
*
* @param this The message
*/
-void message_destroy(struct message* this)
+void message_destroy(struct message* restrict this)
{
size_t i;
if (this->headers != NULL)
@@ -85,7 +85,7 @@ void message_destroy(struct message* this)
* needs to be
* @return The number of marshalled byte
*/
-size_t message_marshal(const struct message* this, void* buf)
+size_t message_marshal(const struct message* restrict this, void* restrict buf)
{
size_t i, n, off = 0;
char* bs = buf;
@@ -137,7 +137,7 @@ size_t message_marshal(const struct message* this, void* buf)
* @param buf In buffer with the marshalled data
* @return The number of unmarshalled bytes, 0 on error
*/
-size_t message_unmarshal(struct message* this, const void* buf)
+size_t message_unmarshal(struct message* restrict this, const void* restrict buf)
{
size_t i, n, off = 0, header_count;
const char* bs = buf;
@@ -236,7 +236,8 @@ size_t message_unmarshal(struct message* this, const void* buf)
* @param extent The number of additional entries
* @return Zero on success, -1 on error
*/
-static int extend_headers(struct message* this, size_t extent)
+GCC_ONLY(__attribute__((nonnull)))
+static int extend_headers(struct message* restrict this, size_t extent)
{
char** new;
if (!(new = realloc(this->headers, (this->header_count + extent) * sizeof(char*))))
@@ -252,9 +253,10 @@ static int extend_headers(struct message* this, size_t extent)
* @param this The message
* @return Zero on success, -1 on error
*/
-static int extend_buffer(struct message* this)
+GCC_ONLY(__attribute__((nonnull)))
+static int extend_buffer(struct message* restrict this)
{
- char* new;
+ char* restrict new;
if (!(new = realloc(this->buffer, (this->buffer_size << 1) * sizeof(char))))
return -1;
this->buffer = new;
@@ -268,7 +270,8 @@ static int extend_buffer(struct message* this)
*
* @param this The message
*/
-static void reset_message(struct message* this)
+GCC_ONLY(__attribute__((nonnull)))
+static void reset_message(struct message* restrict this)
{
size_t i;
if (this->headers != NULL)
@@ -291,10 +294,8 @@ static void reset_message(struct message* this)
* @param this The message
* @return Zero on success, negative on error (malformated message: unrecoverable state)
*/
-#if defined(__GNUC__)
-__attribute__((pure))
-#endif
-static int get_payload_length(struct message* this)
+GCC_ONLY(__attribute__((pure, nonnull)))
+static int get_payload_length(struct message* restrict this)
{
char* header;
size_t i;
@@ -326,12 +327,10 @@ static int get_payload_length(struct message* this)
* @param length The length of the header
* @return Zero if valid, negative if invalid (malformated message: unrecoverable state)
*/
-#if defined(__GNUC__)
-__attribute__((pure))
-#endif
-static int validate_header(const char* header, size_t length)
+GCC_ONLY(__attribute__((pure, nonnull)))
+static int validate_header(const char* restrict header, size_t length)
{
- char* p = memchr(header, ':', length * sizeof(char));
+ char* restrict p = memchr(header, ':', length * sizeof(char));
if (verify_utf8(header, 0) < 0)
/* Either the string is not UTF-8, or your are under an UTF-8 attack,
@@ -353,7 +352,8 @@ static int validate_header(const char* header, size_t length)
* @param length The number of characters to remove
* @param update_ptr Whether to update the buffer pointer
*/
-static void unbuffer_beginning(struct message* this, size_t length, int update_ptr)
+GCC_ONLY(__attribute__((nonnull)))
+static void unbuffer_beginning(struct message* restrict this, size_t length, int update_ptr)
{
memmove(this->buffer, this->buffer + length, (this->buffer_ptr - length) * sizeof(char));
if (update_ptr)
@@ -368,7 +368,8 @@ static void unbuffer_beginning(struct message* this, size_t length, int update_p
* @param this The message
* @return The return value follows the rules of `message_read`
*/
-static int initialise_payload(struct message* this)
+GCC_ONLY(__attribute__((nonnull)))
+static int initialise_payload(struct message* restrict this)
{
/* Remove the \n (end of empty line) we found from the buffer. */
unbuffer_beginning(this, 1, 1);
@@ -393,9 +394,10 @@ static int initialise_payload(struct message* this)
* @param length The length of the header, including LF-termination
* @return The return value follows the rules of `message_read`
*/
-static int store_header(struct message* this, size_t length)
+GCC_ONLY(__attribute__((nonnull)))
+static int store_header(struct message* restrict this, size_t length)
{
- char* header;
+ char* restrict header;
/* Allocate the header. */
if (!(header = malloc(length))) /* Last char is a LF, which is substituted with NUL. */
@@ -430,7 +432,8 @@ static int store_header(struct message* this, size_t length)
* @param fd The file descriptor of the socket
* @return The return value follows the rules of `message_read`
*/
-static int continue_read(struct message* this, int fd)
+GCC_ONLY(__attribute__((nonnull)))
+static int continue_read(struct message* restrict this, int fd)
{
size_t n;
ssize_t got;
@@ -480,7 +483,8 @@ static int continue_read(struct message* this, int fd)
* Other: Failure
* -2: Corrupt message (unrecoverable)
*/
-int message_read(struct message* this, int fd)
+GCC_ONLY(__attribute__((nonnull)))
+int message_read(struct message* restrict this, int fd)
{
size_t header_commit_buffer = 0;
int r;
diff --git a/src/message.h b/src/message.h
index d6447f1..15a9330 100644
--- a/src/message.h
+++ b/src/message.h
@@ -20,6 +20,16 @@
+#ifndef GCC_ONLY
+# if defined(__GNUC__) && !defined(__clang__)
+# define GCC_ONLY(...) __VA_ARGS__
+# else
+# define GCC_ONLY(...) /* nothing */
+# endif
+#endif
+
+
+
/**
* Message passed between a server and a client
*/
@@ -33,7 +43,7 @@ struct message
* but `headers` itself is `NULL` if there are no headers.
* The "Length" header should be included in this list.
*/
- char** headers;
+ char** restrict headers;
/**
* The number of headers in the message
@@ -43,7 +53,7 @@ struct message
/**
* The payload of the message, `NULL` if none (of zero-length)
*/
- char* payload;
+ char* restrict payload;
/**
* The size of the payload
@@ -58,7 +68,7 @@ struct message
/**
* Internal buffer for the reading function (internal data)
*/
- char* buffer;
+ char* restrict buffer;
/**
* The size allocated to `buffer` (internal data)
@@ -90,7 +100,8 @@ struct message
* @param this Memory slot in which to store the new message
* @return Non-zero on error, `errno` will be set accordingly
*/
-int message_initialise(struct message* this);
+GCC_ONLY(__attribute__((nonnull)))
+int message_initialise(struct message* restrict this);
/**
* Release all resources in a message, should
@@ -98,7 +109,8 @@ int message_initialise(struct message* this);
*
* @param this The message
*/
-void message_destroy(struct message* this);
+GCC_ONLY(__attribute__((nonnull)))
+void message_destroy(struct message* restrict this);
/**
* Marshal a message for state serialisation
@@ -109,7 +121,8 @@ void message_destroy(struct message* this);
* needs to be
* @return The number of marshalled byte
*/
-size_t message_marshal(const struct message* this, void* buf);
+GCC_ONLY(__attribute__((nonnull(1))))
+size_t message_marshal(const struct message* restrict this, void* restrict buf);
/**
* Unmarshal a message for state deserialisation
@@ -118,7 +131,8 @@ size_t message_marshal(const struct message* this, void* buf);
* @param buf In buffer with the marshalled data
* @return The number of unmarshalled bytes, 0 on error
*/
-size_t message_unmarshal(struct message* this, const void* buf);
+GCC_ONLY(__attribute__((nonnull)))
+size_t message_unmarshal(struct message* restrict this, const void* restrict buf);
/**
* Read the next message from a file descriptor
@@ -134,5 +148,6 @@ size_t message_unmarshal(struct message* this, const void* buf);
* Other: Failure
* -2: Corrupt message (unrecoverable)
*/
-int message_read(struct message* this, int fd);
+GCC_ONLY(__attribute__((nonnull)))
+int message_read(struct message* restrict this, int fd);
diff --git a/src/output.c b/src/output.c
index 264ad9b..e8913dd 100644
--- a/src/output.c
+++ b/src/output.c
@@ -29,7 +29,7 @@
/**
* The name of the process
*/
-extern char* argv0;
+extern char* restrict argv0;
@@ -40,7 +40,7 @@ extern char* argv0;
*
* @param this The output
*/
-void output_destroy(struct output* this)
+void output_destroy(struct output* restrict this)
{
size_t i;
@@ -106,7 +106,7 @@ void output_destroy(struct output* this)
* needs to be
* @return The number of marshalled byte
*/
-size_t output_marshal(const struct output* this, void* buf)
+size_t output_marshal(const struct output* restrict this, void* restrict buf)
{
size_t off = 0, i, n;
char* bs = buf;
@@ -163,7 +163,7 @@ size_t output_marshal(const struct output* this, void* buf)
* @param buf Buffer with the marshalled output
* @return The number of unmarshalled bytes, 0 on error
*/
-size_t output_unmarshal(struct output* this, const void* buf)
+size_t output_unmarshal(struct output* restrict this, const void* restrict buf)
{
size_t off = 0, i, n;
const char* bs = buf;
@@ -240,7 +240,7 @@ size_t output_unmarshal(struct output* this, const void* buf)
* @return See description of `a` and `b`,
* 0 if returned if they are the same
*/
-int output_cmp_by_name(const void* a, const void* b)
+int output_cmp_by_name(const void* restrict a, const void* restrict b)
{
const char* an = ((const struct output*)a)->name;
const char* bn = ((const struct output*)b)->name;
@@ -256,7 +256,7 @@ int output_cmp_by_name(const void* a, const void* b)
* @param n The number of elements in `base`
* @return Output find in `base`, `NULL` if not found
*/
-struct output* output_find_by_name(const char* key, struct output* base, size_t n)
+struct output* output_find_by_name(const char* restrict key, struct output* restrict base, size_t n)
{
struct output k;
@@ -280,7 +280,7 @@ struct output* output_find_by_name(const char* key, struct output* base, size_t
* @param filter The filter
* @return The index of the filter, `out->table_size` if not found
*/
-static ssize_t remove_filter(struct output* out, struct filter* filter)
+static ssize_t remove_filter(struct output* restrict out, struct filter* restrict filter)
{
size_t i, n = out->table_size;
@@ -314,7 +314,7 @@ static ssize_t remove_filter(struct output* out, struct filter* filter)
* @param filter The filter
* @return The index given to the filter, -1 on error
*/
-ssize_t add_filter(struct output* out, struct filter* filter)
+ssize_t add_filter(struct output* restrict out, struct filter* restrict filter)
{
size_t i, n = out->table_size;
int r = -1;
@@ -389,7 +389,7 @@ ssize_t add_filter(struct output* out, struct filter* filter)
* @param first_updated The index of the first added or removed filter
* @return Zero on success, -1 on error
*/
-int flush_filters(struct output* output, size_t first_updated)
+int flush_filters(struct output* restrict output, size_t first_updated)
{
union gamma_ramps plain;
union gamma_ramps* last;
@@ -439,7 +439,7 @@ int flush_filters(struct output* output, size_t first_updated)
* @param output The output for which the ramps shall be configured
* @return Zero on success, -1 on error
*/
-int make_plain_ramps(union gamma_ramps* ramps, struct output* output)
+int make_plain_ramps(union gamma_ramps* restrict ramps, struct output* restrict output)
{
COPY_RAMP_SIZES(&(ramps->u8), output);
switch (output->depth)
diff --git a/src/output.h b/src/output.h
index ef4172b..08978b5 100644
--- a/src/output.h
+++ b/src/output.h
@@ -24,6 +24,16 @@
+#ifndef GCC_ONLY
+# if defined(__GNUC__) && !defined(__clang__)
+# define GCC_ONLY(...) __VA_ARGS__
+# else
+# define GCC_ONLY(...) /* nothing */
+# endif
+#endif
+
+
+
/**
* Copy the ramp sizes
*
@@ -91,12 +101,12 @@ struct output
* followed by a dot and the name of the
* connector
*/
- char* name;
+ char* restrict name;
/**
* The libgamma state for the output
*/
- libgamma_crtc_state_t* crtc;
+ libgamma_crtc_state_t* restrict crtc;
/**
* Saved gamma ramps
@@ -106,7 +116,7 @@ struct output
/**
* The table of all applied filters
*/
- struct filter* table_filters;
+ struct filter* restrict table_filters;
/**
* `.table_sums[i]` is the resulting
@@ -115,7 +125,7 @@ struct output
* including `.table_filters[i]` has
* been applied
*/
- union gamma_ramps* table_sums;
+ union gamma_ramps* restrict table_sums;
/**
* The number of elements allocated
@@ -140,7 +150,8 @@ struct output
*
* @param this The output
*/
-void output_destroy(struct output* this);
+GCC_ONLY(__attribute__((nonnull)))
+void output_destroy(struct output* restrict this);
/**
* Marshal an output
@@ -151,7 +162,8 @@ void output_destroy(struct output* this);
* needs to be
* @return The number of marshalled byte
*/
-size_t output_marshal(const struct output* this, void* buf);
+GCC_ONLY(__attribute__((nonnull(1))))
+size_t output_marshal(const struct output* restrict this, void* restrict buf);
/**
* Unmarshal an output
@@ -160,7 +172,8 @@ size_t output_marshal(const struct output* this, void* buf);
* @param buf Buffer with the marshalled output
* @return The number of unmarshalled bytes, 0 on error
*/
-size_t output_unmarshal(struct output* this, const void* buf);
+GCC_ONLY(__attribute__((nonnull)))
+size_t output_unmarshal(struct output* restrict this, const void* restrict buf);
/**
* Compare to outputs by the names of their respective CRTC:s
@@ -170,10 +183,8 @@ size_t output_unmarshal(struct output* this, const void* buf);
* @return See description of `a` and `b`,
* 0 if returned if they are the same
*/
-#if defined(__GNUC__)
-__attribute__((pure))
-#endif
-int output_cmp_by_name(const void* a, const void* b);
+GCC_ONLY(__attribute__((pure, nonnull)))
+int output_cmp_by_name(const void* restrict a, const void* restrict b);
/**
* Find an output by its name
@@ -183,10 +194,8 @@ int output_cmp_by_name(const void* a, const void* b);
* @param n The number of elements in `base`
* @return Output find in `base`, `NULL` if not found
*/
-#if defined(__GNUC__)
-__attribute__((pure))
-#endif
-struct output* output_find_by_name(const char* key, struct output* base, size_t n);
+GCC_ONLY(__attribute__((pure, nonnull)))
+struct output* output_find_by_name(const char* restrict key, struct output* restrict base, size_t n);
/**
* Add a filter to an output
@@ -195,7 +204,8 @@ struct output* output_find_by_name(const char* key, struct output* base, size_t
* @param filter The filter
* @return The index given to the filter, -1 on error
*/
-ssize_t add_filter(struct output* output, struct filter* filter);
+GCC_ONLY(__attribute__((nonnull)))
+ssize_t add_filter(struct output* restrict output, struct filter* restrict filter);
/**
* Recalculate the resulting gamma and
@@ -205,7 +215,8 @@ ssize_t add_filter(struct output* output, struct filter* filter);
* @param first_updated The index of the first added or removed filter
* @return Zero on success, -1 on error
*/
-int flush_filters(struct output* output, size_t first_updated);
+GCC_ONLY(__attribute__((nonnull)))
+int flush_filters(struct output* restrict output, size_t first_updated);
/**
* Make identity mapping ramps
@@ -214,5 +225,6 @@ int flush_filters(struct output* output, size_t first_updated);
* @param output The output for which the ramps shall be configured
* @return Zero on success, -1 on error
*/
-int make_plain_ramps(union gamma_ramps* ramps, struct output* output);
+GCC_ONLY(__attribute__((nonnull)))
+int make_plain_ramps(union gamma_ramps* restrict ramps, struct output* restrict output);
diff --git a/src/ramps.c b/src/ramps.c
index f17f917..2b855a4 100644
--- a/src/ramps.c
+++ b/src/ramps.c
@@ -28,7 +28,7 @@
/**
* The name of the process
*/
-extern char* argv0;
+extern char* restrict argv0;
@@ -42,7 +42,7 @@ extern char* argv0;
* @param ramps_size The byte-size of ramps
* @return The number of marshalled byte
*/
-size_t gamma_ramps_marshal(const union gamma_ramps* this, void* buf, size_t ramps_size)
+size_t gamma_ramps_marshal(const union gamma_ramps* restrict this, void* restrict buf, size_t ramps_size)
{
if (buf != NULL)
memcpy(buf, this->u8.red, ramps_size);
@@ -59,7 +59,7 @@ size_t gamma_ramps_marshal(const union gamma_ramps* this, void* buf, size_t ramp
* @param ramps_size The byte-size of ramps
* @return The number of unmarshalled bytes, 0 on error
*/
-size_t gamma_ramps_unmarshal(union gamma_ramps* this, const void* buf, size_t ramps_size)
+size_t gamma_ramps_unmarshal(union gamma_ramps* restrict this, const void* restrict buf, size_t ramps_size)
{
size_t depth = ramps_size / (this->u8.red_size + this->u8.green_size + this->u8.blue_size);
int r = 0;
@@ -109,7 +109,8 @@ size_t gamma_ramps_unmarshal(union gamma_ramps* this, const void* buf, size_t ra
* @param base The CLUT on top of which the new filter should be applied,
* this can be the same pointer as `dest`
*/
-void apply(union gamma_ramps* dest, void* application, int depth, union gamma_ramps* base)
+void apply(union gamma_ramps* restrict dest, void* restrict application,
+ int depth, union gamma_ramps* restrict base)
{
union gamma_ramps app;
size_t bytedepth;
diff --git a/src/ramps.h b/src/ramps.h
index d6c53cf..0ba8579 100644
--- a/src/ramps.h
+++ b/src/ramps.h
@@ -19,6 +19,16 @@
+#ifndef GCC_ONLY
+# if defined(__GNUC__) && !defined(__clang__)
+# define GCC_ONLY(...) __VA_ARGS__
+# else
+# define GCC_ONLY(...) /* nothing */
+# endif
+#endif
+
+
+
/**
* Gamma ramps union for all
* lbigamma gamma ramps types
@@ -69,7 +79,8 @@ union gamma_ramps
* @param ramps_size The byte-size of ramps
* @return The number of marshalled byte
*/
-size_t gamma_ramps_marshal(const union gamma_ramps* this, void* buf, size_t ramps_size);
+GCC_ONLY(__attribute__((nonnull(1))))
+size_t gamma_ramps_marshal(const union gamma_ramps* restrict this, void* restrict buf, size_t ramps_size);
/**
* Unmarshal a ramp trio
@@ -79,7 +90,8 @@ size_t gamma_ramps_marshal(const union gamma_ramps* this, void* buf, size_t ramp
* @param ramps_size The byte-size of ramps
* @return The number of unmarshalled bytes, 0 on error
*/
-size_t gamma_ramps_unmarshal(union gamma_ramps* this, const void* buf, size_t ramps_size);
+GCC_ONLY(__attribute__((nonnull)))
+size_t gamma_ramps_unmarshal(union gamma_ramps* restrict this, const void* restrict buf, size_t ramps_size);
/**
* Apply a ramp-trio on top of another ramp-trio
@@ -93,5 +105,7 @@ size_t gamma_ramps_unmarshal(union gamma_ramps* this, const void* buf, size_t ra
* @param base The CLUT on top of which the new filter should be applied,
* this can be the same pointer as `dest`
*/
-void apply(union gamma_ramps* dest, void* application, int depth, union gamma_ramps* base);
+GCC_ONLY(__attribute__((nonnull)))
+void apply(union gamma_ramps* restrict dest, void* restrict application,
+ int depth, union gamma_ramps* restrict base);
diff --git a/src/ring.c b/src/ring.c
index 5bb9cd2..13cf8c9 100644
--- a/src/ring.c
+++ b/src/ring.c
@@ -27,7 +27,7 @@
*
* @param this The ring buffer
*/
-void ring_initialise(struct ring* this)
+void ring_initialise(struct ring* restrict this)
{
this->start = 0;
this->end = 0;
@@ -41,7 +41,7 @@ void ring_initialise(struct ring* this)
*
* @param this The ring buffer
*/
-void ring_destroy(struct ring* this)
+void ring_destroy(struct ring* restrict this)
{
free(this->buffer);
}
@@ -63,7 +63,7 @@ void ring_destroy(struct ring* this)
* is needed
* @return The number of marshalled bytes
*/
-size_t ring_marshal(const struct ring* this, void* buf)
+size_t ring_marshal(const struct ring* restrict this, void* restrict buf)
{
size_t off = 0, n = this->end - this->start;
char* bs = buf;
@@ -87,7 +87,7 @@ size_t ring_marshal(const struct ring* this, void* buf)
* @param buf Buffer with the marshalled data
* @return The number of unmarshalled bytes, 0 on error
*/
-size_t ring_unmarshal(struct ring* this, const void* buf)
+size_t ring_unmarshal(struct ring* restrict this, const void* restrict buf)
{
size_t off = 0;
const char* bs = buf;
@@ -124,7 +124,7 @@ size_t ring_unmarshal(struct ring* this, const void* buf)
* @param n The number of bytes in `data`
* @return Zero on success, -1 on error
*/
-int ring_push(struct ring* this, void* data, size_t n)
+int ring_push(struct ring* restrict this, void* restrict data, size_t n)
{
size_t used = 0;
@@ -140,7 +140,7 @@ int ring_push(struct ring* this, void* data, size_t n)
if (used + n > this->size)
{
- char* new = malloc(used + n);
+ char* restrict new = malloc(used + n);
if (new == NULL)
return -1;
if (this->buffer)
@@ -189,7 +189,7 @@ int ring_push(struct ring* this, void* data, size_t n)
* @return The beginning of the queued data,
* `NULL` if there is nothing more
*/
-void* ring_peek(struct ring* this, size_t* n)
+void* ring_peek(struct ring* restrict this, size_t* restrict n)
{
if (this->buffer == NULL)
return *n = 0, NULL;
@@ -208,7 +208,7 @@ void* ring_peek(struct ring* this, size_t* n)
* @param this The ring buffer
* @param n The number of bytes to dequeue
*/
-void ring_pop(struct ring* this, size_t n)
+void ring_pop(struct ring* restrict this, size_t n)
{
this->start += n;
this->start %= this->size;
diff --git a/src/ring.h b/src/ring.h
index 7526282..5825810 100644
--- a/src/ring.h
+++ b/src/ring.h
@@ -19,6 +19,16 @@
+#ifndef GCC_ONLY
+# if defined(__GNUC__) && !defined(__clang__)
+# define GCC_ONLY(...) __VA_ARGS__
+# else
+# define GCC_ONLY(...) /* nothing */
+# endif
+#endif
+
+
+
/**
* Ring buffer
*/
@@ -27,7 +37,7 @@ struct ring
/**
* Buffer for the data
*/
- char* buffer;
+ char* restrict buffer;
/**
* The first set byte in `.buffer`
@@ -52,14 +62,16 @@ struct ring
*
* @param this The ring buffer
*/
-void ring_initialise(struct ring* this);
+GCC_ONLY(__attribute__((nonnull)))
+void ring_initialise(struct ring* restrict this);
/**
* Release resource allocated to a ring buffer
*
* @param this The ring buffer
*/
-void ring_destroy(struct ring* this);
+GCC_ONLY(__attribute__((nonnull)))
+void ring_destroy(struct ring* restrict this);
/**
* Marshal a ring buffer
@@ -70,7 +82,8 @@ void ring_destroy(struct ring* this);
* is needed
* @return The number of marshalled bytes
*/
-size_t ring_marshal(const struct ring* this, void* buf);
+GCC_ONLY(__attribute__((nonnull(1))))
+size_t ring_marshal(const struct ring* restrict this, void* restrict buf);
/**
* Unmarshal a ring buffer
@@ -79,7 +92,8 @@ size_t ring_marshal(const struct ring* this, void* buf);
* @param buf Buffer with the marshalled data
* @return The number of unmarshalled bytes, 0 on error
*/
-size_t ring_unmarshal(struct ring* this, const void* buf);
+GCC_ONLY(__attribute__((nonnull)))
+size_t ring_unmarshal(struct ring* restrict this, const void* restrict buf);
/**
* Append data to a ring buffer
@@ -89,7 +103,8 @@ size_t ring_unmarshal(struct ring* this, const void* buf);
* @param n The number of bytes in `data`
* @return Zero on success, -1 on error
*/
-int ring_push(struct ring* this, void* data, size_t n);
+GCC_ONLY(__attribute__((nonnull(1))))
+int ring_push(struct ring* restrict this, void* restrict data, size_t n);
/**
* Get queued data from a ring buffer
@@ -103,7 +118,8 @@ int ring_push(struct ring* this, void* data, size_t n);
* @return The beginning of the queued data,
* `NULL` if there is nothing more
*/
-void* ring_peek(struct ring* this, size_t* n);
+GCC_ONLY(__attribute__((nonnull)))
+void* ring_peek(struct ring* restrict this, size_t* restrict n);
/**
* Dequeue data from a ring bubber
@@ -111,7 +127,8 @@ void* ring_peek(struct ring* this, size_t* n);
* @param this The ring buffer
* @param n The number of bytes to dequeue
*/
-void ring_pop(struct ring* this, size_t n);
+GCC_ONLY(__attribute__((nonnull)))
+void ring_pop(struct ring* restrict this, size_t n);
/**
* Check whether there is more data waiting
@@ -120,7 +137,8 @@ void ring_pop(struct ring* this, size_t n);
* @param this The ring buffer
* @return 1 if there is more data, 0 otherwise
*/
-static inline int ring_have_more(struct ring* this)
+GCC_ONLY(__attribute__((nonnull)))
+static inline int ring_have_more(struct ring* restrict this)
{
return this->buffer != NULL;
}
diff --git a/src/server.c b/src/server.c
index 9544bad..2705f4e 100644
--- a/src/server.c
+++ b/src/server.c
@@ -43,7 +43,7 @@
* Unused slots, with index less than `connections_used`,
* should have the value -1 (negative)
*/
-int* connections = NULL;
+int* restrict connections = NULL;
/**
* The number of elements allocated for `connections`
@@ -63,18 +63,18 @@ size_t connections_used = 0;
/**
* The clients' connections' inbound-message buffers
*/
-struct message* inbound = NULL;
+struct message* restrict inbound = NULL;
/**
* The clients' connections' outbound-message buffers
*/
-struct ring* outbound = NULL;
+struct ring* restrict outbound = NULL;
/**
* The name of the process
*/
-extern char* argv0;
+extern char* restrict argv0;
/**
* The server socket's file descriptor
@@ -104,7 +104,7 @@ extern volatile sig_atomic_t connection;
/**
* Array of all outputs
*/
-extern struct output* outputs;
+extern struct output* restrict outputs;
/**
* The nubmer of elements in `outputs`
@@ -177,10 +177,10 @@ void server_destroy(int disconnect)
* this buffer needs
* @return The number of marshalled bytes
*/
-size_t server_marshal(void* buf)
+size_t server_marshal(void* restrict buf)
{
size_t i, off = 0;
- char* bs = buf;
+ char* restrict bs = buf;
if (bs != NULL)
*(size_t*)(bs + off) = connections_ptr;
@@ -211,10 +211,10 @@ size_t server_marshal(void* buf)
* @param buf Buffer for the marshalled data
* @return The number of unmarshalled bytes, 0 on error
*/
-size_t server_unmarshal(const void* buf)
+size_t server_unmarshal(const void* restrict buf)
{
size_t off = 0, i, n;
- const char* bs = buf;
+ const char* restrict bs = buf;
connections = NULL;
inbound = NULL;
@@ -265,7 +265,8 @@ size_t server_unmarshal(const void* buf)
* @param fds The file descritor set
* @return The highest set file descritor plus 1
*/
-static int update_fdset(fd_set* fds)
+GCC_ONLY(__attribute__((nonnull)))
+static int update_fdset(fd_set* restrict fds)
{
int fdmax = socketfd;
size_t i;
@@ -403,9 +404,9 @@ static int connection_closed(int client)
* as success (ECONNRESET cause 1 to be returned),
* and are handled appropriately.
*/
-static int send_message(size_t conn, char* buf, size_t n)
+static int send_message(size_t conn, char* restrict buf, size_t n)
{
- struct ring* ring = outbound + conn;
+ struct ring* restrict ring = outbound + conn;
int fd = connections[conn];
int saved_errno;
size_t ptr = 0;
@@ -519,9 +520,10 @@ static inline int continue_send(size_t conn)
* 0: Success (possibily delayed)
* -1: An error occurred
*/
-static int (send_error)(size_t conn, const char* message_id, const char* desc)
+GCC_ONLY(__attribute__((nonnull)))
+static int (send_error)(size_t conn, const char* restrict message_id, const char* restrict desc)
{
- char* buf;
+ char* restrict buf;
size_t n;
MAKE_MESSAGE(&buf, &n, 0,
@@ -558,9 +560,10 @@ static int (send_error)(size_t conn, const char* message_id, const char* desc)
* 0: Success (possibily delayed)
* -1: An error occurred
*/
-static int (send_errno)(size_t conn, const char* message_id, int number)
+GCC_ONLY(__attribute__((nonnull)))
+static int (send_errno)(size_t conn, const char* restrict message_id, int number)
{
- char* buf;
+ char* restrict buf;
size_t n;
MAKE_MESSAGE(&buf, &n, 0,
@@ -582,10 +585,11 @@ static int (send_errno)(size_t conn, const char* message_id, int number)
* @return Zero on success (even if ignored), -1 on error,
* 1 if connection closed
*/
-static int enumerate_crtcs(size_t conn, char* message_id)
+GCC_ONLY(__attribute__((nonnull)))
+static int enumerate_crtcs(size_t conn, const char* restrict message_id)
{
size_t i, n = 0, len;
- char* buf;
+ char* restrict buf;
for (i = 0; i < outputs_n; i++)
n += strlen(outputs[i].name) + 1;
@@ -618,10 +622,11 @@ static int enumerate_crtcs(size_t conn, char* message_id)
* @return Zero on success (even if ignored), -1 on error,
* 1 if connection closed
*/
-static int get_gamma_info(size_t conn, char* message_id, char* crtc)
+GCC_ONLY(__attribute__((nonnull(2))))
+static int get_gamma_info(size_t conn, const char* restrict message_id, const char* restrict crtc)
{
- struct output* output;
- char* buf;
+ struct output* restrict output;
+ char* restrict buf;
char depth[3];
const char* supported;
size_t n;
@@ -676,13 +681,15 @@ static int get_gamma_info(size_t conn, char* message_id, char* crtc)
* @return Zero on success (even if ignored), -1 on error,
* 1 if connection closed
*/
-static int get_gamma(size_t conn, char* message_id, char* crtc, char* coalesce,
- char* high_priority, char* low_priority)
+GCC_ONLY(__attribute__((nonnull(2))))
+static int get_gamma(size_t conn, const char* restrict message_id, const char* restrict crtc,
+ const char* restrict coalesce, const char* restrict high_priority,
+ const char* restrict low_priority)
{
- struct output* output;
+ struct output* restrict output;
int64_t high, low;
int coal;
- char* buf;
+ char* restrict buf;
size_t start, end, len, n, i;
char depth[3];
char tables[sizeof("Tables: \n") + 3 * sizeof(size_t)];
@@ -806,13 +813,15 @@ static int get_gamma(size_t conn, char* message_id, char* crtc, char* coalesce,
* @return Zero on success (even if ignored), -1 on error,
* 1 if connection closed
*/
-static int set_gamma(size_t conn, char* message_id, char* crtc, char* priority, char* class, char* lifespan)
+GCC_ONLY(__attribute__((nonnull(2))))
+static int set_gamma(size_t conn, const char* restrict message_id, const char* restrict crtc,
+ const char* restrict priority, const char* restrict class, const char* restrict lifespan)
{
- struct message* msg = inbound + conn;
- struct output* output = NULL;
+ struct message* restrict msg = inbound + conn;
+ struct output* restrict output = NULL;
struct filter filter;
- char* p;
- char* q;
+ char* restrict p;
+ char* restrict q;
int saved_errno;
ssize_t r;
@@ -898,17 +907,17 @@ static int set_gamma(size_t conn, char* message_id, char* crtc, char* priority,
*/
static int handle_connection(size_t conn)
{
- struct message* msg = inbound + conn;
+ struct message* restrict msg = inbound + conn;
int r, fd = connections[conn];
- char* command = NULL;
- char* crtc = NULL;
- char* coalesce = NULL;
- char* high_priority = NULL;
- char* low_priority = NULL;
- char* priority = NULL;
- char* class = NULL;
- char* lifespan = NULL;
- char* message_id = NULL;
+ const char* command = NULL;
+ const char* crtc = NULL;
+ const char* coalesce = NULL;
+ const char* high_priority = NULL;
+ const char* low_priority = NULL;
+ const char* priority = NULL;
+ const char* class = NULL;
+ const char* lifespan = NULL;
+ const char* message_id = NULL;
size_t i;
again:
diff --git a/src/server.h b/src/server.h
index 617b489..adf4c36 100644
--- a/src/server.h
+++ b/src/server.h
@@ -22,13 +22,23 @@
+#ifndef GCC_ONLY
+# if defined(__GNUC__) && !defined(__clang__)
+# define GCC_ONLY(...) __VA_ARGS__
+# else
+# define GCC_ONLY(...) /* nothing */
+# endif
+#endif
+
+
+
/**
* List of all client's file descriptors
*
* Unused slots, with index less than `connections_used`,
* should have the value -1 (negative)
*/
-extern int* connections;
+extern int* restrict connections;
/**
* The number of elements allocated for `connections`
@@ -48,12 +58,12 @@ extern size_t connections_used;
/**
* The clients' connections' inbound-message buffers
*/
-extern struct message* inbound;
+extern struct message* restrict inbound;
/**
* The clients' connections' outbound-message buffers
*/
-extern struct ring* outbound;
+extern struct ring* restrict outbound;
@@ -72,7 +82,7 @@ void server_destroy(int disconnect);
* this buffer needs
* @return The number of marshalled bytes
*/
-size_t server_marshal(void* buf);
+size_t server_marshal(void* restrict buf);
/**
* Unmarshal the state of the connections
@@ -80,7 +90,7 @@ size_t server_marshal(void* buf);
* @param buf Buffer for the marshalled data
* @return The number of unmarshalled bytes, 0 on error
*/
-size_t server_unmarshal(const void* buf);
+size_t server_unmarshal(const void* restrict buf);
/**
* The program's main loop
diff --git a/src/util.c b/src/util.c
index cb04154..c116998 100644
--- a/src/util.c
+++ b/src/util.c
@@ -34,7 +34,7 @@
* @return The duplicate of the memory segment,
* `NULL` on error
*/
-void* memdup(const void* src, size_t n)
+void* memdup(const void* restrict src, size_t n)
{
void* dest = malloc(n);
if (dest == NULL)
@@ -52,7 +52,7 @@ void* memdup(const void* src, size_t n)
* @return The read content, plus a NUL byte at
* the end (not counted in `*n`)
*/
-void* nread(int fd, size_t* n)
+void* nread(int fd, size_t* restrict n)
{
size_t size = 32;
ssize_t got;
@@ -113,9 +113,9 @@ void* nread(int fd, size_t* n)
* @return The number of written bytes, less than `n`
* on error, cannot exceed `n`
*/
-size_t nwrite(int fd, const void* buf, size_t n)
+size_t nwrite(int fd, const void* restrict buf, size_t n)
{
- const char* bs = buf;
+ const char* restrict bs = buf;
ssize_t wrote;
size_t ptr = 0;
@@ -189,6 +189,7 @@ void msleep(int ms)
nanosleep(&ts, NULL);
}
+
/**
* Check whether a NUL-terminated string is encoded in UTF-8
*
@@ -196,7 +197,7 @@ void msleep(int ms)
* @param allow_modified_nul Whether Modified UTF-8 is allowed, which allows a two-byte encoding for NUL
* @return Zero if good, -1 on encoding error
*/
-int verify_utf8(const char* string, int allow_modified_nul)
+int verify_utf8(const char* restrict string, int allow_modified_nul)
{
static long BYTES_TO_MIN_BITS[] = {0, 0, 8, 12, 17, 22, 37};
static long BYTES_TO_MAX_BITS[] = {0, 7, 11, 16, 21, 26, 31};
diff --git a/src/util.h b/src/util.h
index 1c7d8a6..c1f8934 100644
--- a/src/util.h
+++ b/src/util.h
@@ -19,6 +19,16 @@
+#ifndef GCC_ONLY
+# if defined(__GNUC__) && !defined(__clang__)
+# define GCC_ONLY(...) __VA_ARGS__
+# else
+# define GCC_ONLY(...) /* nothing */
+# endif
+#endif
+
+
+
/**
* Duplicate a memory segment
*
@@ -27,8 +37,8 @@
* @return The duplicate of the memory segment,
* `NULL` on error
*/
-void* memdup(const void* src, size_t n);
-
+GCC_ONLY(__attribute__((malloc, nonnull)))
+void* memdup(const void* restrict src, size_t n);
/**
* Read an entire file
@@ -40,8 +50,8 @@ void* memdup(const void* src, size_t n);
* @return The read content, plus a NUL byte at
* the end (not counted in `*n`)
*/
-void* nread(int fd, size_t* n);
-
+GCC_ONLY(__attribute__((malloc)))
+void* nread(int fd, size_t* restrict n);
/**
* Write an entire buffer to a file
@@ -54,8 +64,7 @@ void* nread(int fd, size_t* n);
* @return The number of written bytes, less than `n`
* on error, cannot exceed `n`
*/
-size_t nwrite(int fd, const void* buf, size_t n);
-
+size_t nwrite(int fd, const void* restrict buf, size_t n);
/**
* Duplicate a file descriptor an make sure
@@ -68,7 +77,6 @@ size_t nwrite(int fd, const void* buf, size_t n);
*/
int dup2atleast(int fd, int atleast);
-
/**
* Perform a timed suspention of the process.
* The process resumes when the timer expires,
@@ -79,7 +87,6 @@ int dup2atleast(int fd, int atleast);
*/
void msleep(int ms);
-
/**
* Check whether a NUL-terminated string is encoded in UTF-8
*
@@ -87,8 +94,6 @@ void msleep(int ms);
* @param allow_modified_nul Whether Modified UTF-8 is allowed, which allows a two-byte encoding for NUL
* @return Zero if good, -1 on encoding error
*/
-#if defined(__GNUC__)
-__attribute__((pure))
-#endif
-int verify_utf8(const char* string, int allow_modified_nul);
+GCC_ONLY(__attribute__((pure, nonnull)))
+int verify_utf8(const char* restrict string, int allow_modified_nul);