From bf4020471356938b9181a33984f511ffdd7ff25b Mon Sep 17 00:00:00 2001 From: Mattias Andrée Date: Tue, 22 Oct 2019 18:59:27 +0200 Subject: Change license, change style, clean up, flat file hier, clean valgrind output in test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- src/libcoopgamma.c | 2620 ---------------------------------------------------- src/libcoopgamma.h | 1680 --------------------------------- src/test.c | 273 ------ 3 files changed, 4573 deletions(-) delete mode 100644 src/libcoopgamma.c delete mode 100644 src/libcoopgamma.h delete mode 100644 src/test.c (limited to 'src') diff --git a/src/libcoopgamma.c b/src/libcoopgamma.c deleted file mode 100644 index 40baf77..0000000 --- a/src/libcoopgamma.c +++ /dev/null @@ -1,2620 +0,0 @@ -/** - * libcoopgamma -- Library for interfacing with cooperative gamma servers - * Copyright (C) 2016 Mattias Andrée (maandree@kth.se) - * - * This library is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this library. If not, see . - */ -#define _DEFAULT_SOURCE -#define _BSD_SOURCE - -#include "libcoopgamma.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - - -#if !defined(COOPGAMMAD) -# define COOPGAMMAD "coopgammad" -#endif - - - -#if defined(__clang__) -# pragma GCC diagnostic ignored "-Wdocumentation" -# pragma GCC diagnostic ignored "-Wcovered-switch-default" -# pragma GCC diagnostic ignored "-Wcast-align" -#endif - - - -#if defined(__GNUC__) -# define NAME_OF_THE_PROCESS (argv0) -extern const char* argv0; -const char* argv0 __attribute__((weak)) = "libcoopgamma"; -#else -# define NAME_OF_THE_PROCESS ("libcoopgamma") -#endif - - - -#define SUBBUF \ - (buf ? buf + off : NULL) - -#define NNSUBBUF \ - (buf + off) - -#define MARSHAL_PROLOGUE \ - char* restrict buf = vbuf; \ - size_t off = 0; - -#define UNMARSHAL_PROLOGUE \ - const char* restrict buf = vbuf; \ - size_t off = 0; - -#define MARSHAL_EPILOGUE \ - return off - -#define UNMARSHAL_EPILOGUE \ - return *np = off, LIBCOOPGAMMA_SUCCESS - -#define marshal_prim(datum, type) \ - ((buf != NULL ? *(type*)(buf + off) = (datum) : 0), off += sizeof(type)) - -#define unmarshal_prim(datum, type) \ - ((datum) = *(const type*)(buf + off), off += sizeof(type)) - -#define marshal_version(version) \ - marshal_prim(version, int) - -#define unmarshal_version(version) \ - do \ - { \ - int version__; \ - unmarshal_prim(version__, int); \ - if (version__ < (version)) \ - return LIBCOOPGAMMA_INCOMPATIBLE_DOWNGRADE; \ - if (version__ > (version)) \ - return LIBCOOPGAMMA_INCOMPATIBLE_UPGRADE; \ - } \ - while (0) - -#define marshal_buffer(data, n) \ - ((buf != NULL ? (memcpy(buf + off, (data), (n)), 0) : 0), off += (n)) - -#define unmarshal_buffer(data, n) \ - do \ - { \ - (data) = malloc(n); \ - if ((data) == NULL) \ - return LIBCOOPGAMMA_ERRNO_SET; \ - memcpy((data), buf + off, (n)); \ - off += (n); \ - } \ - while (0) - -#define marshal_string(datum) \ - ((datum) == NULL ? marshal_prim(0, char) : \ - (marshal_prim(1, char), marshal_buffer((datum), strlen(datum) + 1))) - -#define unmarshal_string(datum) \ - do \ - { \ - char nonnull__; \ - unmarshal_prim(nonnull__, char); \ - if (nonnull__) \ - unmarshal_buffer((datum), strlen(buf + off) + 1); \ - else \ - (datum) = NULL; \ - } \ - while (0) - - - -#define copy_errno(ctx) \ - ((errno == 0) ? NULL : \ - ((ctx)->error.number = (uint64_t)errno, \ - (ctx)->error.custom = 0, \ - (ctx)->error.server_side = 0, \ - free((ctx)->error.description), \ - (ctx)->error.description = NULL)) - - -#define SYNC_CALL(send_call, recv_call, fail_return) \ - libcoopgamma_async_context_t async; \ - size_t _selected; \ - if (send_call < 0) \ - { \ - reflush: \ - if (errno != EINTR) \ - return fail_return; \ - if (libcoopgamma_flush(ctx) < 0) \ - goto reflush; \ - } \ -resync: \ - if (libcoopgamma_synchronise(ctx, &async, (size_t)1, &_selected) < 0) \ - { \ - if ((errno != EINTR) && (errno != 0)) \ - return fail_return; \ - goto resync; \ - } \ - return recv_call - - -#define INTEGRAL_DEPTHS \ - case LIBCOOPGAMMA_UINT8: \ - case LIBCOOPGAMMA_UINT16: \ - case LIBCOOPGAMMA_UINT32: \ - case LIBCOOPGAMMA_UINT64: - - - -/** - * Initialise a `libcoopgamma_ramps8_t`, `libcoopgamma_ramps16_t`, `libcoopgamma_ramps32_t`, - * `libcoopgamma_ramps64_t`, `libcoopgamma_rampsf_t`, or `libcoopgamma_rampsd_t` - * - * `this->red_size`, `this->green_size`, and `this->blue_size` must already be set - * - * @param this The record to initialise - * @param width The `sizeof(*(this->red))` - * @return Zero on success, -1 on error - */ -int libcoopgamma_ramps_initialise_(void* restrict this, size_t width) -{ - libcoopgamma_ramps8_t* restrict this8 = (libcoopgamma_ramps8_t* restrict)this; - this8->red = this8->green = this8->blue = NULL; - this8->red = malloc((this8->red_size + this8->green_size + this8->blue_size) * width); - if (this8->red == NULL) - return -1; - this8->green = this8->red + this8->red_size * width; - this8->blue = this8->green + this8->green_size * width; - return 0; -} - - -/** - * Release all resources allocated to a `libcoopgamma_ramps8_t`, `libcoopgamma_ramps16_t`, - * `libcoopgamma_ramps32_t`, `libcoopgamma_ramps64_t`, `libcoopgamma_rampsf_t`, - * `libcoopgamma_rampsd_t`, or `libcoopgamma_ramps_t`, the allocation of the record - * itself is not freed - * - * Always call this function after failed call to `libcoopgamma_ramps_initialise` - * or failed call to `libcoopgamma_ramps_unmarshal` - * - * @param this The record to destroy - */ -void libcoopgamma_ramps_destroy(void* restrict this) -{ - libcoopgamma_ramps8_t* restrict this8 = (libcoopgamma_ramps8_t* restrict)this; - free(this8->red); - this8->red = this8->green = this8->blue = NULL; -} - - -/** - * Marshal a `libcoopgamma_ramps8_t`, `libcoopgamma_ramps16_t`, `libcoopgamma_ramps32_t`, - * `libcoopgamma_ramps64_t`, `libcoopgamma_rampsf_t`, or `libcoopgamma_rampsd_t` into a buffer - * - * @param this The record to marshal - * @param vbuf The output buffer, `NULL` to only measure - * how large this buffer has to be - * @param width The `sizeof(*(this->red))` - * @return The number of marshalled bytes, or if `buf == NULL`, - * how many bytes would be marshalled if `buf != NULL` - */ -size_t libcoopgamma_ramps_marshal_(const void* restrict this, void* restrict vbuf, size_t width) -{ - const libcoopgamma_ramps8_t* restrict this8 = (const libcoopgamma_ramps8_t* restrict)this; - MARSHAL_PROLOGUE; - marshal_version(LIBCOOPGAMMA_RAMPS_VERSION); - marshal_prim(this8->red_size, size_t); - marshal_prim(this8->green_size, size_t); - marshal_prim(this8->blue_size, size_t); - marshal_buffer(this8->red, (this8->red_size + this8->green_size + this8->blue_size) * width); - MARSHAL_EPILOGUE; -} - - -/** - * Unmarshal a `libcoopgamma_ramps8_t`, `libcoopgamma_ramps16_t`, `libcoopgamma_ramps32_t`, - * `libcoopgamma_ramps64_t`, `libcoopgamma_rampsf_t`, or `libcoopgamma_rampsd_t` from a buffer - * - * @param this The output parameter for unmarshalled record - * @param vbuf The buffer with the marshalled record - * @param np Output parameter for the number of unmarshalled bytes, undefined on failure - * @param width The `sizeof(*(this->red))` - * @return `LIBCOOPGAMMA_SUCCESS` (0), `LIBCOOPGAMMA_INCOMPATIBLE_DOWNGRADE`, - * `LIBCOOPGAMMA_INCOMPATIBLE_UPGRADE`, or `LIBCOOPGAMMA_ERRNO_SET` - */ -int libcoopgamma_ramps_unmarshal_(void* restrict this, const void* restrict vbuf, - size_t* restrict np, size_t width) -{ - libcoopgamma_ramps8_t* restrict this8 = (libcoopgamma_ramps8_t* restrict)this; - UNMARSHAL_PROLOGUE; - unmarshal_version(LIBCOOPGAMMA_RAMPS_VERSION); - unmarshal_prim(this8->red_size, size_t); - unmarshal_prim(this8->green_size, size_t); - unmarshal_prim(this8->blue_size, size_t); - unmarshal_buffer(this8->red, (this8->red_size + this8->green_size + this8->blue_size) * width); - this8->green = this8->red + this8->red_size * width; - this8->blue = this8->green + this8->green_size * width; - UNMARSHAL_EPILOGUE; -} - - - -/** - * Initialise a `libcoopgamma_filter_t` - * - * @param this The record to initialise - * @return Zero on success, -1 on error - */ -int libcoopgamma_filter_initialise(libcoopgamma_filter_t* restrict this) -{ - memset(this, 0, sizeof(*this)); - return 0; -} - - -/** - * Release all resources allocated to a `libcoopgamma_filter_t`, - * the allocation of the record itself is not freed - * - * Always call this function after failed call to `libcoopgamma_filter_initialise` - * or failed call to `libcoopgamma_filter_unmarshal` - * - * @param this The record to destroy - */ -void libcoopgamma_filter_destroy(libcoopgamma_filter_t* restrict this) -{ - free(this->crtc); - free(this->class); - free(this->ramps.u8.red); - memset(this, 0, sizeof(*this)); -} - - -/** - * Marshal a `libcoopgamma_filter_t` into a buffer - * - * @param this The record to marshal - * @param vbuf The output buffer, `NULL` to only measure - * how large this buffer has to be - * @return The number of marshalled bytes, or if `buf == NULL`, - * how many bytes would be marshalled if `buf != NULL` - */ -size_t libcoopgamma_filter_marshal(const libcoopgamma_filter_t* restrict this, void* restrict vbuf) -{ - MARSHAL_PROLOGUE; - marshal_version(LIBCOOPGAMMA_FILTER_VERSION); - marshal_version(LIBCOOPGAMMA_DEPTH_VERSION); - marshal_version(LIBCOOPGAMMA_LIFESPAN_VERSION); - marshal_prim(this->depth, libcoopgamma_depth_t); - marshal_prim(this->priority, int64_t); - marshal_string(this->crtc); - marshal_string(this->class); - marshal_prim(this->lifespan, libcoopgamma_lifespan_t); - switch (this->depth) - { - case LIBCOOPGAMMA_UINT8: off += libcoopgamma_ramps_marshal(&(this->ramps.u8), SUBBUF); break; - case LIBCOOPGAMMA_UINT16: off += libcoopgamma_ramps_marshal(&(this->ramps.u16), SUBBUF); break; - case LIBCOOPGAMMA_UINT32: off += libcoopgamma_ramps_marshal(&(this->ramps.u32), SUBBUF); break; - case LIBCOOPGAMMA_UINT64: off += libcoopgamma_ramps_marshal(&(this->ramps.u64), SUBBUF); break; - case LIBCOOPGAMMA_FLOAT: off += libcoopgamma_ramps_marshal(&(this->ramps.f), SUBBUF); break; - case LIBCOOPGAMMA_DOUBLE: off += libcoopgamma_ramps_marshal(&(this->ramps.d), SUBBUF); break; - default: - break; - } - MARSHAL_EPILOGUE; -} - - -/** - * Unmarshal a `libcoopgamma_filter_t` from a buffer - * - * @param this The output parameter for unmarshalled record - * @param vbuf The buffer with the marshalled record - * @param np Output parameter for the number of unmarshalled bytes, undefined on failure - * @return `LIBCOOPGAMMA_SUCCESS` (0), `LIBCOOPGAMMA_INCOMPATIBLE_DOWNGRADE`, - * `LIBCOOPGAMMA_INCOMPATIBLE_UPGRADE`, or `LIBCOOPGAMMA_ERRNO_SET` - */ -int libcoopgamma_filter_unmarshal(libcoopgamma_filter_t* restrict this, - const void* restrict vbuf, size_t* restrict np) -{ - int r = LIBCOOPGAMMA_SUCCESS; - size_t n = 0; - UNMARSHAL_PROLOGUE; - memset(this, 0, sizeof(*this)); - unmarshal_version(LIBCOOPGAMMA_FILTER_VERSION); - unmarshal_version(LIBCOOPGAMMA_DEPTH_VERSION); - unmarshal_version(LIBCOOPGAMMA_LIFESPAN_VERSION); - unmarshal_prim(this->depth, libcoopgamma_depth_t); - unmarshal_prim(this->priority, int64_t); - unmarshal_string(this->crtc); - unmarshal_string(this->class); - unmarshal_prim(this->lifespan, libcoopgamma_lifespan_t); - switch (this->depth) - { - case LIBCOOPGAMMA_UINT8: r = libcoopgamma_ramps_unmarshal(&(this->ramps.u8), NNSUBBUF, &n); break; - case LIBCOOPGAMMA_UINT16: r = libcoopgamma_ramps_unmarshal(&(this->ramps.u16), NNSUBBUF, &n); break; - case LIBCOOPGAMMA_UINT32: r = libcoopgamma_ramps_unmarshal(&(this->ramps.u32), NNSUBBUF, &n); break; - case LIBCOOPGAMMA_UINT64: r = libcoopgamma_ramps_unmarshal(&(this->ramps.u64), NNSUBBUF, &n); break; - case LIBCOOPGAMMA_FLOAT: r = libcoopgamma_ramps_unmarshal(&(this->ramps.f), NNSUBBUF, &n); break; - case LIBCOOPGAMMA_DOUBLE: r = libcoopgamma_ramps_unmarshal(&(this->ramps.d), NNSUBBUF, &n); break; - default: - break; - } - if (r != LIBCOOPGAMMA_SUCCESS) - return r; - off += n; - UNMARSHAL_EPILOGUE; -} - - - -/** - * Initialise a `libcoopgamma_crtc_info_t` - * - * @param this The record to initialise - * @return Zero on success, -1 on error - */ -int libcoopgamma_crtc_info_initialise(libcoopgamma_crtc_info_t* restrict this) -{ - memset(this, 0, sizeof(*this)); - return 0; -} - - -/** - * Release all resources allocated to a `libcoopgamma_crtc_info_t`, - * the allocation of the record itself is not freed - * - * Always call this function after failed call to `libcoopgamma_crtc_info_initialise` - * or failed call to `libcoopgamma_crtc_info_unmarshal` - * - * @param this The record to destroy - */ -#if defined(__GNUC__) -__attribute__((__const__)) -#endif -void libcoopgamma_crtc_info_destroy(libcoopgamma_crtc_info_t* restrict this) -{ - (void) this; -} - - -/** - * Marshal a `libcoopgamma_crtc_info_t` into a buffer - * - * @param this The record to marshal - * @param vbuf The output buffer, `NULL` to only measure - * how large this buffer has to be - * @return The number of marshalled bytes, or if `buf == NULL`, - * how many bytes would be marshalled if `buf != NULL` - */ -size_t libcoopgamma_crtc_info_marshal(const libcoopgamma_crtc_info_t* restrict this, void* restrict vbuf) -{ - MARSHAL_PROLOGUE; - marshal_version(LIBCOOPGAMMA_CRTC_INFO_VERSION); - marshal_version(LIBCOOPGAMMA_DEPTH_VERSION); - marshal_version(LIBCOOPGAMMA_SUPPORT_VERSION); - marshal_version(LIBCOOPGAMMA_COLOURSPACE_VERSION); - marshal_prim(this->cooperative, int); - marshal_prim(this->depth, libcoopgamma_depth_t); - marshal_prim(this->red_size, size_t); - marshal_prim(this->green_size, size_t); - marshal_prim(this->blue_size, size_t); - marshal_prim(this->supported, libcoopgamma_support_t); - marshal_prim(this->colourspace, libcoopgamma_colourspace_t); - marshal_prim(this->have_gamut, int); - marshal_prim(this->red_x, unsigned); - marshal_prim(this->red_y, unsigned); - marshal_prim(this->green_x, unsigned); - marshal_prim(this->green_y, unsigned); - marshal_prim(this->blue_x, unsigned); - marshal_prim(this->blue_y, unsigned); - marshal_prim(this->white_x, unsigned); - marshal_prim(this->white_y, unsigned); - MARSHAL_EPILOGUE; -} - - -/** - * Unmarshal a `libcoopgamma_crtc_info_t` from a buffer - * - * @param this The output parameter for unmarshalled record - * @param vbuf The buffer with the marshalled record - * @param np Output parameter for the number of unmarshalled bytes, undefined on failure - * @return `LIBCOOPGAMMA_SUCCESS` (0), `LIBCOOPGAMMA_INCOMPATIBLE_DOWNGRADE`, - * `LIBCOOPGAMMA_INCOMPATIBLE_UPGRADE`, or `LIBCOOPGAMMA_ERRNO_SET` - */ -int libcoopgamma_crtc_info_unmarshal(libcoopgamma_crtc_info_t* restrict this, - const void* restrict vbuf, size_t* restrict np) -{ - UNMARSHAL_PROLOGUE; - unmarshal_version(LIBCOOPGAMMA_CRTC_INFO_VERSION); - unmarshal_version(LIBCOOPGAMMA_DEPTH_VERSION); - unmarshal_version(LIBCOOPGAMMA_SUPPORT_VERSION); - unmarshal_version(LIBCOOPGAMMA_COLOURSPACE_VERSION); - unmarshal_prim(this->cooperative, int); - unmarshal_prim(this->depth, libcoopgamma_depth_t); - unmarshal_prim(this->red_size, size_t); - unmarshal_prim(this->green_size, size_t); - unmarshal_prim(this->blue_size, size_t); - unmarshal_prim(this->supported, libcoopgamma_support_t); - unmarshal_prim(this->colourspace, libcoopgamma_colourspace_t); - unmarshal_prim(this->have_gamut, int); - unmarshal_prim(this->red_x, unsigned); - unmarshal_prim(this->red_y, unsigned); - unmarshal_prim(this->green_x, unsigned); - unmarshal_prim(this->green_y, unsigned); - unmarshal_prim(this->blue_x, unsigned); - unmarshal_prim(this->blue_y, unsigned); - unmarshal_prim(this->white_x, unsigned); - unmarshal_prim(this->white_y, unsigned); - UNMARSHAL_EPILOGUE; -} - - - -/** - * Initialise a `libcoopgamma_filter_query_t` - * - * @param this The record to initialise - * @return Zero on success, -1 on error - */ -int libcoopgamma_filter_query_initialise(libcoopgamma_filter_query_t* restrict this) -{ - this->crtc = NULL; - this->coalesce = 0; - this->high_priority = INT64_MAX; - this->low_priority = INT64_MIN; - return 0; -} - - -/** - * Release all resources allocated to a `libcoopgamma_filter_query_t`, - * the allocation of the record itself is not freed - * - * Always call this function after failed call to `libcoopgamma_filter_query_initialise` - * or failed call to `libcoopgamma_filter_query_unmarshal` - * - * @param this The record to destroy - */ -void libcoopgamma_filter_query_destroy(libcoopgamma_filter_query_t* restrict this) -{ - free(this->crtc), this->crtc = NULL; -} - - -/** - * Marshal a `libcoopgamma_filter_query_t` into a buffer - * - * @param this The record to marshal - * @param vbuf The output buffer, `NULL` to only measure - * how large this buffer has to be - * @return The number of marshalled bytes, or if `buf == NULL`, - * how many bytes would be marshalled if `buf != NULL` - */ -size_t libcoopgamma_filter_query_marshal(const libcoopgamma_filter_query_t* restrict this, void* restrict vbuf) -{ - MARSHAL_PROLOGUE; - marshal_version(LIBCOOPGAMMA_FILTER_QUERY_VERSION); - marshal_string(this->crtc); - marshal_prim(this->coalesce, int); - marshal_prim(this->high_priority, int64_t); - marshal_prim(this->low_priority, int64_t); - MARSHAL_EPILOGUE; -} - - -/** - * Unmarshal a `libcoopgamma_filter_query_t` from a buffer - * - * @param this The output parameter for unmarshalled record - * @param vbuf The buffer with the marshalled record - * @param np Output parameter for the number of unmarshalled bytes, undefined on failure - * @return `LIBCOOPGAMMA_SUCCESS` (0), `LIBCOOPGAMMA_INCOMPATIBLE_DOWNGRADE`, - * `LIBCOOPGAMMA_INCOMPATIBLE_UPGRADE`, or `LIBCOOPGAMMA_ERRNO_SET` - */ -int libcoopgamma_filter_query_unmarshal(libcoopgamma_filter_query_t* restrict this, - const void* restrict vbuf, size_t* restrict np) -{ - UNMARSHAL_PROLOGUE; - this->crtc = NULL; - unmarshal_version(LIBCOOPGAMMA_FILTER_QUERY_VERSION); - unmarshal_string(this->crtc); - unmarshal_prim(this->coalesce, int); - unmarshal_prim(this->high_priority, int64_t); - unmarshal_prim(this->low_priority, int64_t); - UNMARSHAL_EPILOGUE; -} - - - -/** - * Initialise a `libcoopgamma_queried_filter_t` - * - * @param this The record to initialise - * @return Zero on success, -1 on error - */ -int libcoopgamma_queried_filter_initialise(libcoopgamma_queried_filter_t* restrict this) -{ - memset(this, 0, sizeof(*this)); - return 0; -} - - -/** - * Release all resources allocated to a `libcoopgamma_queried_filter_t`, - * the allocation of the record itself is not freed - * - * Always call this function after failed call to `libcoopgamma_queried_filter_initialise` - * or failed call to `libcoopgamma_queried_filter_unmarshal` - * - * @param this The record to destroy - */ -void libcoopgamma_queried_filter_destroy(libcoopgamma_queried_filter_t* restrict this) -{ - free(this->class), this->class = NULL; - libcoopgamma_ramps_destroy(&(this->ramps.u8)); -} - - -/** - * Marshal a `libcoopgamma_queried_filter_t` into a buffer - * - * @param this The record to marshal - * @param vbuf The output buffer, `NULL` to only measure - * how large this buffer has to be - * @param depth The type used of ramp stops - * @return The number of marshalled bytes, or if `buf == NULL`, - * how many bytes would be marshalled if `buf != NULL` - */ -size_t libcoopgamma_queried_filter_marshal(const libcoopgamma_queried_filter_t* restrict this, - void* restrict vbuf, libcoopgamma_depth_t depth) -{ - MARSHAL_PROLOGUE; - marshal_version(LIBCOOPGAMMA_QUERIED_FILTER_VERSION); - marshal_prim(this->priority, int64_t); - marshal_string(this->class); - switch (depth) - { - case LIBCOOPGAMMA_UINT8: off += libcoopgamma_ramps_marshal(&(this->ramps.u8), SUBBUF); break; - case LIBCOOPGAMMA_UINT16: off += libcoopgamma_ramps_marshal(&(this->ramps.u16), SUBBUF); break; - case LIBCOOPGAMMA_UINT32: off += libcoopgamma_ramps_marshal(&(this->ramps.u32), SUBBUF); break; - case LIBCOOPGAMMA_UINT64: off += libcoopgamma_ramps_marshal(&(this->ramps.u64), SUBBUF); break; - case LIBCOOPGAMMA_FLOAT: off += libcoopgamma_ramps_marshal(&(this->ramps.f), SUBBUF); break; - case LIBCOOPGAMMA_DOUBLE: off += libcoopgamma_ramps_marshal(&(this->ramps.d), SUBBUF); break; - default: - break; - } - MARSHAL_EPILOGUE; -} - - -/** - * Unmarshal a `libcoopgamma_queried_filter_t` from a buffer - * - * @param this The output parameter for unmarshalled record - * @param vbuf The buffer with the marshalled record - * @param np Output parameter for the number of unmarshalled bytes, undefined on failure - * @param depth The type used of ramp stops - * @return `LIBCOOPGAMMA_SUCCESS` (0), `LIBCOOPGAMMA_INCOMPATIBLE_DOWNGRADE`, - * `LIBCOOPGAMMA_INCOMPATIBLE_UPGRADE`, or `LIBCOOPGAMMA_ERRNO_SET` - */ -int libcoopgamma_queried_filter_unmarshal(libcoopgamma_queried_filter_t* restrict this, - const void* restrict vbuf, size_t* restrict np, - libcoopgamma_depth_t depth) -{ - int r = LIBCOOPGAMMA_SUCCESS; - size_t n = 0; - UNMARSHAL_PROLOGUE; - memset(this, 0, sizeof(*this)); - unmarshal_version(LIBCOOPGAMMA_QUERIED_FILTER_VERSION); - unmarshal_prim(this->priority, int64_t); - unmarshal_string(this->class); - switch (depth) - { - case LIBCOOPGAMMA_UINT8: r = libcoopgamma_ramps_unmarshal(&(this->ramps.u8), NNSUBBUF, &n); break; - case LIBCOOPGAMMA_UINT16: r = libcoopgamma_ramps_unmarshal(&(this->ramps.u16), NNSUBBUF, &n); break; - case LIBCOOPGAMMA_UINT32: r = libcoopgamma_ramps_unmarshal(&(this->ramps.u32), NNSUBBUF, &n); break; - case LIBCOOPGAMMA_UINT64: r = libcoopgamma_ramps_unmarshal(&(this->ramps.u64), NNSUBBUF, &n); break; - case LIBCOOPGAMMA_FLOAT: r = libcoopgamma_ramps_unmarshal(&(this->ramps.f), NNSUBBUF, &n); break; - case LIBCOOPGAMMA_DOUBLE: r = libcoopgamma_ramps_unmarshal(&(this->ramps.d), NNSUBBUF, &n); break; - default: - break; - } - if (r != LIBCOOPGAMMA_SUCCESS) - return r; - off += n; - UNMARSHAL_EPILOGUE; -} - - - -/** - * Initialise a `libcoopgamma_filter_table_t` - * - * @param this The record to initialise - * @return Zero on success, -1 on error - */ -int libcoopgamma_filter_table_initialise(libcoopgamma_filter_table_t* restrict this) -{ - memset(this, 0, sizeof(*this)); - return 0; -} - - -/** - * Release all resources allocated to a `libcoopgamma_filter_table_t`, - * the allocation of the record itself is not freed - * - * Always call this function after failed call to `libcoopgamma_filter_table_initialise` - * or failed call to `libcoopgamma_filter_table_unmarshal` - * - * @param this The record to destroy - */ -void libcoopgamma_filter_table_destroy(libcoopgamma_filter_table_t* restrict this) -{ - while (this->filter_count) - libcoopgamma_queried_filter_destroy(this->filters + --(this->filter_count)); - free(this->filters), this->filters = NULL; -} - - -/** - * Marshal a `libcoopgamma_filter_table_t` into a buffer - * - * @param this The record to marshal - * @param vbuf The output buffer, `NULL` to only measure - * how large this buffer has to be - * @return The number of marshalled bytes, or if `buf == NULL`, - * how many bytes would be marshalled if `buf != NULL` - */ -size_t libcoopgamma_filter_table_marshal(const libcoopgamma_filter_table_t* restrict this, void* restrict vbuf) -{ - size_t i; - MARSHAL_PROLOGUE; - marshal_version(LIBCOOPGAMMA_FILTER_TABLE_VERSION); - marshal_version(LIBCOOPGAMMA_DEPTH_VERSION); - marshal_prim(this->depth, libcoopgamma_depth_t); - marshal_prim(this->red_size, size_t); - marshal_prim(this->green_size, size_t); - marshal_prim(this->blue_size, size_t); - marshal_prim(this->filter_count, size_t); - for (i = 0; i < this->filter_count; i++) - off += libcoopgamma_queried_filter_marshal(this->filters + i, SUBBUF, this->depth); - MARSHAL_EPILOGUE; -} - - -/** - * Unmarshal a `libcoopgamma_filter_table_t` from a buffer - * - * @param this The output parameter for unmarshalled record - * @param vbuf The buffer with the marshalled record - * @param np Output parameter for the number of unmarshalled bytes, undefined on failure - * @return `LIBCOOPGAMMA_SUCCESS` (0), `LIBCOOPGAMMA_INCOMPATIBLE_DOWNGRADE`, - * `LIBCOOPGAMMA_INCOMPATIBLE_UPGRADE`, or `LIBCOOPGAMMA_ERRNO_SET` - */ -int libcoopgamma_filter_table_unmarshal(libcoopgamma_filter_table_t* restrict this, - const void* restrict vbuf, size_t* restrict np) -{ - size_t i, n, fn; - int r; - UNMARSHAL_PROLOGUE; - this->filter_count = 0; - this->filters = NULL; - unmarshal_version(LIBCOOPGAMMA_FILTER_TABLE_VERSION); - unmarshal_version(LIBCOOPGAMMA_DEPTH_VERSION); - unmarshal_prim(this->depth, libcoopgamma_depth_t); - unmarshal_prim(this->red_size, size_t); - unmarshal_prim(this->green_size, size_t); - unmarshal_prim(this->blue_size, size_t); - unmarshal_prim(fn, size_t); - this->filters = malloc(fn * sizeof(*(this->filters))); - if (this->filters == NULL) - return LIBCOOPGAMMA_ERRNO_SET; - for (i = 0; i < fn; i++) - { - r = libcoopgamma_queried_filter_unmarshal(this->filters + i, NNSUBBUF, &n, this->depth); - if (r != LIBCOOPGAMMA_SUCCESS) - return r; - off += n; - this->filter_count += 1; - } - UNMARSHAL_EPILOGUE; -} - - - -/** - * Initialise a `libcoopgamma_error_t` - * - * @param this The record to initialise - * @return Zero on success, -1 on error - */ -int libcoopgamma_error_initialise(libcoopgamma_error_t* restrict this) -{ - this->number = 0; - this->custom = 0; - this->description = NULL; - return 0; -} - - -/** - * Release all resources allocated to a `libcoopgamma_error_t`, - * the allocation of the record itself is not freed - * - * Always call this function after failed call to `libcoopgamma_error_initialise` - * or failed call to `libcoopgamma_error_unmarshal` - * - * @param this The record to destroy - */ -void libcoopgamma_error_destroy(libcoopgamma_error_t* restrict this) -{ - free(this->description), this->description = NULL; -} - - -/** - * Marshal a `libcoopgamma_error_t` into a buffer - * - * @param this The record to marshal - * @param vbuf The output buffer, `NULL` to only measure - * how large this buffer has to be - * @return The number of marshalled bytes, or if `buf == NULL`, - * how many bytes would be marshalled if `buf != NULL` - */ -size_t libcoopgamma_error_marshal(const libcoopgamma_error_t* restrict this, void* restrict vbuf) -{ - MARSHAL_PROLOGUE; - marshal_version(LIBCOOPGAMMA_ERROR_VERSION); - marshal_prim(this->number, uint64_t); - marshal_prim(this->custom, int); - marshal_prim(this->server_side, int); - marshal_string(this->description); - MARSHAL_EPILOGUE; -} - - -/** - * Unmarshal a `libcoopgamma_error_t` from a buffer - * - * @param this The output parameter for unmarshalled record - * @param vbuf The buffer with the marshalled record - * @param np Output parameter for the number of unmarshalled bytes, undefined on failure - * @return `LIBCOOPGAMMA_SUCCESS` (0), `LIBCOOPGAMMA_INCOMPATIBLE_DOWNGRADE`, - * `LIBCOOPGAMMA_INCOMPATIBLE_UPGRADE`, or `LIBCOOPGAMMA_ERRNO_SET` - */ -int libcoopgamma_error_unmarshal(libcoopgamma_error_t* restrict this, - const void* restrict vbuf, size_t* restrict np) -{ - UNMARSHAL_PROLOGUE; - this->description = NULL; - unmarshal_version(LIBCOOPGAMMA_ERROR_VERSION); - unmarshal_prim(this->number, uint64_t); - unmarshal_prim(this->custom, int); - unmarshal_prim(this->server_side, int); - unmarshal_string(this->description); - UNMARSHAL_EPILOGUE; -} - - - -/** - * Initialise a `libcoopgamma_context_t` - * - * @param this The record to initialise - * @return Zero on success, -1 on error - */ -int libcoopgamma_context_initialise(libcoopgamma_context_t* restrict this) -{ - memset(this, 0, sizeof(*this)); - this->fd = -1; - this->blocking = 1; - return 0; -} - - -/** - * Release all resources allocated to a `libcoopgamma_context_t`, - * the allocation of the record itself is not freed - * - * Always call this function after failed call to `libcoopgamma_context_initialise` - * or failed call to `libcoopgamma_context_unmarshal` - * - * @param this The record to destroy - * @param disconnect Disconnect from the server? - */ -void libcoopgamma_context_destroy(libcoopgamma_context_t* restrict this, int disconnect) -{ - if (disconnect && (this->fd >= 0)) - { - shutdown(this->fd, SHUT_RDWR); - close(this->fd); - } - this->fd = -1; - libcoopgamma_error_destroy(&(this->error)); - free(this->outbound), this->outbound = NULL; - free(this->inbound), this->inbound = NULL; -} - - -/** - * Marshal a `libcoopgamma_context_t` into a buffer - * - * @param this The record to marshal - * @param vbuf The output buffer, `NULL` to only measure - * how large this buffer has to be - * @return The number of marshalled bytes, or if `buf == NULL`, - * how many bytes would be marshalled if `buf != NULL` - */ -size_t libcoopgamma_context_marshal(const libcoopgamma_context_t* restrict this, void* restrict vbuf) -{ - MARSHAL_PROLOGUE; - marshal_version(LIBCOOPGAMMA_CONTEXT_VERSION); - marshal_prim(this->fd, int); - off += libcoopgamma_error_marshal(&(this->error), SUBBUF); - marshal_prim(this->message_id, uint32_t); - marshal_prim(this->outbound_head - this->outbound_tail, size_t); - marshal_buffer(this->outbound + this->outbound_tail, this->outbound_head - this->outbound_tail); - marshal_prim(this->inbound_head - this->inbound_tail, size_t); - marshal_buffer(this->inbound + this->inbound_tail, this->inbound_head - this->inbound_tail); - marshal_prim(this->length, size_t); - marshal_prim(this->curline, size_t); - marshal_prim(this->in_response_to, uint32_t); - marshal_prim(this->have_all_headers, int); - marshal_prim(this->bad_message, int); - marshal_prim(this->blocking, int); - MARSHAL_EPILOGUE; -} - - -/** - * Unmarshal a `libcoopgamma_context_t` from a buffer - * - * @param this The output parameter for unmarshalled record - * @param vbuf The buffer with the marshalled record - * @param np Output parameter for the number of unmarshalled bytes, undefined on failure - * @return `LIBCOOPGAMMA_SUCCESS` (0), `LIBCOOPGAMMA_INCOMPATIBLE_DOWNGRADE`, - * `LIBCOOPGAMMA_INCOMPATIBLE_UPGRADE`, or `LIBCOOPGAMMA_ERRNO_SET` - */ -int libcoopgamma_context_unmarshal(libcoopgamma_context_t* restrict this, - const void* restrict vbuf, size_t* restrict np) -{ - size_t n; - int r; - UNMARSHAL_PROLOGUE; - memset(this, 0, sizeof(*this)); - unmarshal_version(LIBCOOPGAMMA_CONTEXT_VERSION); - unmarshal_prim(this->fd, int); - r = libcoopgamma_error_unmarshal(&(this->error), NNSUBBUF, &n); - if (r != LIBCOOPGAMMA_SUCCESS) - return r; - off += n; - unmarshal_prim(this->message_id, uint32_t); - unmarshal_prim(this->outbound_head, size_t); - this->outbound_size = this->outbound_head; - unmarshal_buffer(this->outbound, this->outbound_head); - unmarshal_prim(this->inbound_head, size_t); - this->inbound_size = this->inbound_head; - unmarshal_buffer(this->inbound, this->inbound_head); - unmarshal_prim(this->length, size_t); - unmarshal_prim(this->curline, size_t); - unmarshal_prim(this->in_response_to, uint32_t); - unmarshal_prim(this->have_all_headers, int); - unmarshal_prim(this->bad_message, int); - unmarshal_prim(this->blocking, int); - UNMARSHAL_EPILOGUE; -} - - - -/** - * Initialise a `libcoopgamma_async_context_t` - * - * @param this The record to initialise - * @return Zero on success, -1 on error - */ -int libcoopgamma_async_context_initialise(libcoopgamma_async_context_t* restrict this) -{ - this->message_id = 0; - this->coalesce = 0; - return 0; -} - - -/** - * Release all resources allocated to a `libcoopgamma_async_context_t`, - * the allocation of the record itself is not freed - * - * Always call this function after failed call to `libcoopgamma_async_context_initialise` - * or failed call to `libcoopgamma_async_context_unmarshal` - * - * @param this The record to destroy - */ -#if defined(__GNUC__) -__attribute__((__const__)) -#endif -void libcoopgamma_async_context_destroy(libcoopgamma_async_context_t* restrict this) -{ - (void) this; -} - - -/** - * Marshal a `libcoopgamma_async_context_t` into a buffer - * - * @param this The record to marshal - * @param vbuf The output buffer, `NULL` to only measure - * how large this buffer has to be - * @return The number of marshalled bytes, or if `buf == NULL`, - * how many bytes would be marshalled if `buf != NULL` - */ -size_t libcoopgamma_async_context_marshal(const libcoopgamma_async_context_t* restrict this, - void* restrict vbuf) -{ - MARSHAL_PROLOGUE; - marshal_version(LIBCOOPGAMMA_ASYNC_CONTEXT_VERSION); - marshal_prim(this->message_id, uint32_t); - marshal_prim(this->coalesce, int); - MARSHAL_EPILOGUE; -} - - -/** - * Unmarshal a `libcoopgamma_async_context_t` from a buffer - * - * @param this The output parameter for unmarshalled record - * @param vbuf The buffer with the marshalled record - * @param np Output parameter for the number of unmarshalled bytes, undefined on failure - * @return `LIBCOOPGAMMA_SUCCESS` (0), `LIBCOOPGAMMA_INCOMPATIBLE_DOWNGRADE`, - * `LIBCOOPGAMMA_INCOMPATIBLE_UPGRADE`, or `LIBCOOPGAMMA_ERRNO_SET` - */ -int libcoopgamma_async_context_unmarshal(libcoopgamma_async_context_t* restrict this, - const void* restrict vbuf, size_t* restrict np) -{ - UNMARSHAL_PROLOGUE; - unmarshal_version(LIBCOOPGAMMA_ASYNC_CONTEXT_VERSION); - unmarshal_prim(this->message_id, uint32_t); - unmarshal_prim(this->coalesce, int); - UNMARSHAL_EPILOGUE; -} - - - -/** - * List all recognised adjustment method - * - * SIGCHLD must not be ignored or blocked - * - * @return A `NULL`-terminated list of names. You should only free - * the outer pointer, inner pointers are subpointers of the - * outer pointer and cannot be freed. `NULL` on error. - */ -char** libcoopgamma_get_methods(void) -{ - char num[5]; /* The size is base on the fact that we have limited `n` in the loop below */ - char** methods = NULL; - char** rc; - char* buffer; - int n = 0, saved_errno; - size_t size = 0; - - methods = malloc(4 * sizeof(*methods)); - if (methods == NULL) - goto fail; - - for (n = 0; n < 10000 /* just to be safe */; n++) - { - char* method; - if ((n >= 4) && ((n & -n) == n)) - { - void* new = realloc(methods, (size_t)(n << 1) * sizeof(*methods)); - if (new == NULL) - goto fail; - methods = new; - } - sprintf(num, "%i", n); - if (libcoopgamma_get_method_and_site(num, NULL, &method, NULL)) - goto fail; - if (!strcmp(method, num)) - { - free(method); - break; - } - methods[n] = method; - size += strlen(method) + 1; - } - - rc = malloc((size_t)(n + 1) * sizeof(char*) + size); - if (rc == NULL) - goto fail; - buffer = ((char*)rc) + (size_t)(n + 1) * sizeof(char*); - rc[n] = NULL; - while (n--) - { - rc[n] = buffer; - buffer = stpcpy(buffer, methods[n]) + 1; - free(methods[n]); - } - free(methods); - - return rc; - - fail: - saved_errno = errno; - while (n--) - free(methods[n]); - free(methods); - errno = saved_errno; - return NULL; -} - - -/** - * Run coopgammad with -q or -qq and return the response - * - * SIGCHLD must not be ignored or blocked - * - * @param method The adjustment method, `NULL` for automatic - * @param site The site, `NULL` for automatic - * @param arg "-q" or "-qq", which shall be passed to coopgammad? - * @return The output of coopgammad, `NULL` on error. This - * will be NUL-terminated and will not contain any - * other `NUL` bytes. - */ -static char* libcoopgamma_query(const char* restrict method, const char* restrict site, const char* restrict arg) -{ - const char* (args[7]) = {COOPGAMMAD, arg}; - size_t i = 2, n = 0, size = 0; - int pipe_rw[2] = { -1, -1 }; - pid_t pid; - int saved_errno, status; - char* msg = NULL; - ssize_t got; - - if (method != NULL) args[i++] = "-m", args[i++] = method; - if (site != NULL) args[i++] = "-s", args[i++] = site; - args[i] = NULL; - - if (pipe(pipe_rw) < 0) - goto fail; - - switch ((pid = fork())) - { - case -1: - goto fail; - case 0: - /* Child */ - close(pipe_rw[0]); - if (pipe_rw[1] != STDOUT_FILENO) - { - close(STDOUT_FILENO); - if (dup2(pipe_rw[1], STDOUT_FILENO) < 0) - goto fail_child; - close(pipe_rw[1]); - } -#if defined(__GNUC__) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wcast-qual" -#endif - execvp(COOPGAMMAD, (char* const*)(args)); -#if defined(__GNUC__) -# pragma GCC diagnostic pop -#endif - fail_child: - saved_errno = errno; - perror(NAME_OF_THE_PROCESS); - if (write(STDOUT_FILENO, &saved_errno, sizeof(int)) != sizeof(int)) - perror(NAME_OF_THE_PROCESS); - exit(1); - default: - /* Parent */ - close(pipe_rw[1]), pipe_rw[1] = -1; - for (;;) - { - if (n == size) - { - void* new = realloc(msg, size = (n ? (n << 1) : 256)); - if (new == NULL) - goto fail; - msg = new; - } - got = read(pipe_rw[0], msg + n, size - n); - if (got < 0) - { - if (errno == EINTR) - continue; - goto fail; - } - else if (got == 0) - break; - n += (size_t)got; - } - close(pipe_rw[0]), pipe_rw[0] = -1; - if (waitpid(pid, &status, 0) < 0) - goto fail; - if (status) - { - errno = EINVAL; - if ((n == sizeof(int)) && (*(int*)msg != 0)) - errno = *(int*)msg; - } - break; - } - - if (n == size) - { - void* new = realloc(msg, n + 1); - if (new == NULL) - goto fail; - msg = new; - } - msg[n] = '\0'; - - if (strchr(msg, '\0') != msg + n) - { - errno = EBADMSG; - goto fail; - } - - return msg; - fail: - saved_errno = errno; - if (pipe_rw[0] >= 0) close(pipe_rw[0]); - if (pipe_rw[1] >= 0) close(pipe_rw[1]); - free(msg); - errno = saved_errno; - return NULL; -} - - -/** - * Get the adjustment method and site - * - * SIGCHLD must not be ignored or blocked - * - * @param method The adjustment method, `NULL` for automatic - * @param site The site, `NULL` for automatic - * @param methodp Output pointer for the selected adjustment method, - * which cannot be `NULL`. It is safe to call - * this function with this parameter set to `NULL`. - * @param sitep Output pointer for the selected site, which will - * be `NULL` the method only supports one site or if - * `site == NULL` and no site can be selected - * automatically. It is safe to call this function - * with this parameter set to `NULL`. - * @return Zero on success, -1 on error - */ -int libcoopgamma_get_method_and_site(const char* restrict method, const char* restrict site, - char** restrict methodp, char** restrict sitep) -{ - int saved_errno; - char* raw; - char* p; - char* q; - - raw = libcoopgamma_query(method, site, "-q"); - if (raw == NULL) - return -1; - - if (methodp != NULL) *methodp = NULL; - if (sitep != NULL) *sitep = NULL; - - p = strchr(raw, '\n'); - if (p == NULL) - { - errno = EBADMSG; - goto fail; - } - *p++ = '\0'; - - if (methodp != NULL) - { - *methodp = malloc(strlen(raw) + 1); - if (*methodp == NULL) - goto fail; - strcpy(*methodp, raw); - } - - if ((site != NULL) && *(q = strchr(p, '\0') - 1)) - { - if (*q != '\n') - { - errno = EBADMSG; - goto fail; - } - *q = '\0'; - *sitep = malloc(strlen(p) + 1); - if (*sitep == NULL) - goto fail; - strcpy(*sitep, p); - } - - free(raw); - return 0; - fail: - saved_errno = errno; - if (methodp != NULL) - free(*methodp), *methodp = NULL; - free(raw); - errno = saved_errno; - return -1; -} - - -/** - * Get the PID file of the coopgamma server - * - * SIGCHLD must not be ignored or blocked - * - * @param method The adjustment method, `NULL` for automatic - * @param site The site, `NULL` for automatic - * @return The pathname of the server's PID file, `NULL` on error - * or if there server does not use PID files. The later - * case is detected by checking that `errno` is set to 0. - */ -char* libcoopgamma_get_pid_file(const char* restrict method, const char* restrict site) -{ - char* path; - size_t n; - - path = libcoopgamma_get_socket_file(method, site); - if (path == NULL) - return NULL; - - n = strlen(path); - if (n < 7 || strcmp(path + n - 7, ".socket")) - { - free(path); - errno = EBADMSG; - return NULL; - } - - strcpy(path + n - 7, ".pid"); - return path; -} - - -/** - * Get the socket file of the coopgamma server - * - * SIGCHLD must not be ignored or blocked - * - * @param method The adjustment method, `NULL` for automatic - * @param site The site, `NULL` for automatic - * @return The pathname of the server's socket, `NULL` on error - * or if there server does have its own socket. The later - * case is detected by checking that `errno` is set to 0, - * and is the case when communicating with a server in a - * multi-server display server like mds. - */ -char* libcoopgamma_get_socket_file(const char* restrict method, const char* restrict site) -{ - int saved_errno; - char* raw; - char* p; - - raw = libcoopgamma_query(method, site, "-qq"); - if (raw == NULL) - return NULL; - - p = strchr(raw, '\0') - 1; - if ((p < raw) || (*p != '\n')) - { - errno = EBADMSG; - goto fail; - } - *p = '\0'; - if (*raw == '\0') - { - errno = EBADMSG; - goto fail; - } - - return raw; - fail: - saved_errno = errno; - free(raw); - errno = saved_errno; - return NULL; -} - - - -/** - * Connect to a coopgamma server, and start it if necessary - * - * Use `libcoopgamma_context_destroy` to disconnect - * - * SIGCHLD must not be ignored or blocked - * - * @param method The adjustment method, `NULL` for automatic - * @param site The site, `NULL` for automatic - * @param ctx The state of the library, must be initialised - * @return Zero on success, -1 on error. On error, `errno` is set - * to 0 if the server could not be initialised. - */ -int libcoopgamma_connect(const char* restrict method, const char* restrict site, - libcoopgamma_context_t* restrict ctx) -{ - const char* (args[6]) = {COOPGAMMAD}; - struct sockaddr_un address; - char* path; - int saved_errno; - int tries = 0, status; - pid_t pid; - size_t i = 1; - - ctx->blocking = 1; - - if (method != NULL) args[i++] = "-m", args[i++] = method; - if (site != NULL) args[i++] = "-s", args[i++] = site; - args[i] = NULL; - - path = libcoopgamma_get_socket_file(method, site); - if (path == NULL) - return -1; - if (strlen(path) >= sizeof(address.sun_path)) - { - free(path); - errno = ENAMETOOLONG; - return -1; - } - - address.sun_family = AF_UNIX; - strcpy(address.sun_path, path); - free(path); - if ((ctx->fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) - return -1; - - retry: - if (connect(ctx->fd, (struct sockaddr*)(&address), (socklen_t)sizeof(address)) < 0) - { - if (((errno == ECONNREFUSED) || (errno == ENOENT) || (errno == ENOTDIR)) && !tries++) - { - switch ((pid = fork())) - { - case -1: - goto fail; - case 0: - /* Child */ - close(ctx->fd); -#if defined(__GNUC__) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wcast-qual" -#endif - execvp(COOPGAMMAD, (char* const*)(args)); -#if defined(__GNUC__) -# pragma GCC diagnostic pop -#endif - perror(NAME_OF_THE_PROCESS); - exit(1); - default: - /* Parent */ - if (waitpid(pid, &status, 0) < 0) - goto fail; - if (status) - { - errno = 0; - goto fail; - } - break; - } - goto retry; - } - goto fail; - } - - return 0; - fail: - saved_errno = errno; - close(ctx->fd), ctx->fd = -1; - errno = saved_errno; - return -1; -} - - -/** - * By default communication is blocking, this function - * can be used to switch between blocking and nonblocking - * - * After setting the communication to nonblocking, - * `libcoopgamma_flush`, `libcoopgamma_synchronise` and - * and request-sending functions can fail with EAGAIN and - * EWOULDBLOCK. It is safe to continue with `libcoopgamma_flush` - * (for `libcoopgamma_flush` it selfand equest-sending functions) - * or `libcoopgamma_synchronise` just like EINTR failure. - * - * @param ctx The state of the library, must be connected - * @param nonblocking Nonblocking mode? - * @return Zero on success, -1 on error - */ -int libcoopgamma_set_nonblocking(libcoopgamma_context_t* restrict ctx, int nonblocking) -{ - int flags = fcntl(ctx->fd, F_GETFL); - if (flags == -1) - return -1; - if (nonblocking) - flags |= O_NONBLOCK; - else - flags &= ~O_NONBLOCK; - if (fcntl(ctx->fd, F_SETFL, flags) == -1) - return -1; - ctx->blocking = !nonblocking; - return 0; -} - - -/** - * Send all pending outbound data - * - * If this function or another function that sends a request - * to the server fails with EINTR, call this function to - * complete the transfer. The `async` parameter will always - * be in a properly configured state if a function fails - * with EINTR. - * - * @param ctx The state of the library, must be connected - * @return Zero on success, -1 on error - */ -int libcoopgamma_flush(libcoopgamma_context_t* restrict ctx) -{ - ssize_t sent; - size_t chunksize = ctx->outbound_head - ctx->outbound_tail; - size_t sendsize; - - while (ctx->outbound_tail < ctx->outbound_head) - { - sendsize = ctx->outbound_head - ctx->outbound_tail; - sendsize = sendsize < chunksize ? sendsize : chunksize; - sent = send(ctx->fd, ctx->outbound + ctx->outbound_tail, sendsize, MSG_NOSIGNAL); - if (sent < 0) - { - if (errno == EPIPE) - errno = ECONNRESET; - if (errno != EMSGSIZE) - return -1; - if ((chunksize >>= 1) == 0) - return -1; - continue; - } - -#ifdef DEBUG_MODE - fprintf(stderr, "\033[31m"); - fwrite(ctx->outbound + ctx->outbound_tail, (size_t)sent, 1, stderr); - fprintf(stderr, "\033[m"); - fflush(stderr); -#endif - - ctx->outbound_tail += (size_t)sent; - } - - return 0; -} - - -/** - * Wait for the next message to be received - * - * @param ctx The state of the library, must be connected - * @param pending Information for each pending request - * @param n The number of elements in `pending` - * @param selected The index of the element in `pending` which corresponds - * to the first inbound message, note that this only means - * that the message is not for any of the other request, - * if the message is corrupt any of the listed requests can - * be selected even if it is not for any of the requests. - * Functions that parse the message will detect such corruption. - * @return Zero on success, -1 on error. If the the message is ignored, - * which happens if corresponding `libcoopgamma_async_context_t` - * is not listed, -1 is returned and `errno` is set to 0. If -1 - * is returned, `errno` is set to `ENOTRECOVERABLE` you have - * received a corrupt message and the context has been tainted - * beyond recover. - */ -int libcoopgamma_synchronise(libcoopgamma_context_t* restrict ctx, - libcoopgamma_async_context_t* restrict pending, - size_t n, size_t* restrict selected) -{ - char temp[3 * sizeof(size_t) + 1]; - ssize_t got; - size_t i; - char* p; - char* line; - char* value; - struct pollfd pollfd; - - if (ctx->inbound_head == ctx->inbound_tail) - ctx->inbound_head = ctx->inbound_tail = ctx->curline = 0; - else if (ctx->inbound_tail > 0) - { - memmove(ctx->inbound, ctx->inbound + ctx->inbound_tail, ctx->inbound_head -= ctx->inbound_tail); - ctx->curline -= ctx->inbound_tail; - ctx->inbound_tail = 0; - } - - pollfd.fd = ctx->fd; - pollfd.events = POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI; - - if (ctx->inbound_head) - goto skip_recv; - for (;;) - { - if (ctx->inbound_head == ctx->inbound_size) - { - size_t new_size = ctx->inbound_size ? (ctx->inbound_size << 1) : 1024; - void* new = realloc(ctx->inbound, new_size); - if (new == NULL) - return -1; - ctx->inbound = new; - ctx->inbound_size = new_size; - } - - if (ctx->blocking) - { - pollfd.revents = 0; - if (poll(&pollfd, (nfds_t)1, -1) < 0) - return -1; - } - got = recv(ctx->fd, ctx->inbound + ctx->inbound_head, ctx->inbound_size - ctx->inbound_head, 0); - if (got <= 0) - { - if (got == 0) - errno = ECONNRESET; - return -1; - } - -#ifdef DEBUG_MODE - fprintf(stderr, "\033[32m"); - fwrite(ctx->inbound + ctx->inbound_head, (size_t)got, 1, stderr); - fprintf(stderr, "\033[m"); - fflush(stderr); -#endif - - ctx->inbound_head += (size_t)got; - - skip_recv: - while (ctx->have_all_headers == 0) - { - line = ctx->inbound + ctx->curline; - p = memchr(line, '\n', ctx->inbound_head - ctx->curline); - if (p == NULL) - break; - if (memchr(line, '\0', (size_t)(p - line)) != NULL) - ctx->bad_message = 1; - *p++ = '\0'; - ctx->curline = (size_t)(p - ctx->inbound); - if (!*line) - { - ctx->have_all_headers = 1; - } - else if (strstr(line, "In response to: ") == line) - { - value = line + (sizeof("In response to: ") - 1); - ctx->in_response_to = (uint32_t)atol(value); - } - else if (strstr(line, "Length: ") == line) - { - value = line + (sizeof("Length: ") - 1); - ctx->length = (size_t)atol(value); - sprintf(temp, "%zu", ctx->length); - if (strcmp(value, temp)) - goto fatal; - } - } - - if (ctx->have_all_headers && (ctx->inbound_head >= ctx->curline + ctx->length)) - { - ctx->curline += ctx->length; - if (ctx->bad_message) - { - ctx->bad_message = 0; - ctx->have_all_headers = 0; - ctx->length = 0; - ctx->inbound_tail = ctx->curline; - errno = EBADMSG; - return -1; - } - for (i = 0; i < n; i++) - if (pending[i].message_id == ctx->in_response_to) - { - *selected = i; - return 0; - } - *selected = 0; - ctx->bad_message = 0; - ctx->have_all_headers = 0; - ctx->length = 0; - ctx->inbound_tail = ctx->curline; - errno = 0; - return -1; - } - } - - fatal: - errno = ENOTRECOVERABLE; - return -1; -} - - -/** - * Send a message to the server and wait for response - * - * @param resp:char** Output parameter for the response, - * will be NUL-terminated - * @param ctx:libcoopgamma_context_t* The state of the library - * @param payload:void* Data to append to the end of the message - * @param payload_size:size_t Byte-size of `payload` - * @param format:string-literal Message formatting string - * @param ... Message formatting arguments - * - * On error, the macro goes to `fail`. - */ -#define SEND_MESSAGE(ctx, payload, payload_size, format, ...) \ - do \ - { \ - ssize_t n__; \ - char* msg__; \ - snprintf(NULL, (size_t)0, format "%zn", __VA_ARGS__, &n__); \ - msg__ = malloc((size_t)n__ + (payload_size) + (size_t)1); \ - if (msg__ == NULL) \ - goto fail; \ - sprintf(msg__, format, __VA_ARGS__); \ - if ((payload) != NULL) \ - memcpy(msg__ + n__, (payload), (payload_size)); \ - if (send_message((ctx), msg__, (size_t)n__ + (payload_size)) < 0) \ - goto fail; \ - } \ - while (0) - - -/** - * Send a message to the server and wait for response - * - * @param ctx The state of the library - * @param msg The message to send - * @param n The length of `msg` - * @return Zero on success, -1 on error - */ -static int send_message(libcoopgamma_context_t* restrict ctx, char* msg, size_t n) -{ - if (ctx->outbound_head == ctx->outbound_tail) - { - free(ctx->outbound); - ctx->outbound = msg; - ctx->outbound_tail = 0; - ctx->outbound_head = n; - ctx->outbound_size = n; - } - else - { - if (ctx->outbound_head + n > ctx->outbound_size) - { - memmove(ctx->outbound, ctx->outbound + ctx->outbound_tail, ctx->outbound_head -= ctx->outbound_tail); - ctx->outbound_tail = 0; - } - if (ctx->outbound_head + n > ctx->outbound_size) - { - void* new = realloc(ctx->outbound, ctx->outbound_head + n); - if (new == NULL) - { - int saved_errno = errno; - free(msg); - errno = saved_errno; - return -1; - } - ctx->outbound = new; - ctx->outbound_size = ctx->outbound_head + n; - } - memcpy(ctx->outbound + ctx->outbound_head, msg, n); - ctx->outbound_head += n; - free(msg); - } - ctx->message_id += 1; - return libcoopgamma_flush(ctx); -} - - -/** - * Get the next header of the inbound message - * - * All headers must be read before the payload is read - * - * @param ctx The state of the library, must be connected - * @return The next header line, can never be `NULL`, - * the empty string marks the end of the headers. - * This memory segment must not be freed. - */ -static char* next_header(libcoopgamma_context_t* restrict ctx) -{ - char* rc = ctx->inbound + ctx->inbound_tail; - ctx->inbound_tail += strlen(rc) + 1; - return rc; -} - - -/** - * Get the payload of the inbound message - * - * Calling this function marks that the inbound message - * has been fully ready. You must call this function - * even if you do not expect a payload - * - * @param ctx The state of the library, must be connected - * @param n Output parameter for the size of the payload - * @return The payload (not NUL-terminated), `NULL` if - * there is no payload. Failure is impossible. - * This memory segment must not be freed. - */ -static char* next_payload(libcoopgamma_context_t* restrict ctx, size_t* n) -{ - ctx->have_all_headers = 0; - if ((*n = ctx->length)) - { - char* rc = ctx->inbound + ctx->inbound_tail; - ctx->inbound_tail += *n; - ctx->length = 0; - return rc; - } - else - return NULL; -} - - -/** - * Tell the library that you will not be parsing a receive message - * - * @param ctx The state of the library, must be connected - */ -void libcoopgamma_skip_message(libcoopgamma_context_t* restrict ctx) -{ - size_t _n; - while (*next_header(ctx)); - (void) next_payload(ctx, &_n); -} - - -/** - * Check whether the server sent an error, if so copy it to `ctx` - * - * This function will also reports EBADMSG if the message ID - * that the message is a response to does not match the request - * information, or if it is missing - * - * @param ctx The state of the library, must be connected - * @param async Information about the request - * @return 1 if the server sent an error (even indicating success), - * 0 on success, -1 on failure. Information about failure - * is copied `ctx`. - */ -static int check_error(libcoopgamma_context_t* restrict ctx, libcoopgamma_async_context_t* restrict async) -{ - char temp[3 * sizeof(uint64_t) + 1]; - size_t old_tail = ctx->inbound_tail; - char* line; - char* value; - int command_ok = 0; - int have_in_response_to = 0; - int have_error = 0; - int bad = 0; - char* payload; - size_t n; - - for (;;) - { - line = next_header(ctx); - value = strchr(line, ':') + 2; - if (!*line) - break; - else if (!strcmp(line, "Command: error")) - command_ok = 1; - else if (strstr(line, "In response to: ") == line) - { - uint32_t id = (uint32_t)atol(value); - have_in_response_to = 1 + !!have_in_response_to; - if (id != async->message_id) - bad = 1; - else - { - sprintf(temp, "%" PRIu32, id); - if (strcmp(value, temp)) - bad = 1; - } - } - else if (strstr(line, "Error: ") == line) - { - have_error = 1 + !!have_error; - ctx->error.server_side = 1; - ctx->error.custom = (strstr(value, "custom") == value); - if (ctx->error.custom) - { - if (value[6] == '\0') - { - ctx->error.number = 0; - continue; - } - else if (value[6] != ' ') - { - bad = 1; - continue; - } - value += 7; - } - ctx->error.number = (uint64_t)atoll(value); - sprintf(temp, "%" PRIu64, ctx->error.number); - if (strcmp(value, temp)) - bad = 1; - } - } - - if (command_ok == 0) - { - ctx->inbound_tail = old_tail; - return 0; - } - - payload = next_payload(ctx, &n); - if (payload != NULL) - { - if (memchr(payload, '\0', n) || (payload[n - 1] != '\n')) - goto badmsg; - ctx->error.description = malloc(n); - if (ctx->error.description == NULL) - goto fail; - memcpy(ctx->error.description, payload, n - 1); - ctx->error.description[n - 1] = '\0'; - } - - if (bad || (have_in_response_to != 1) || (have_error != 1)) - goto badmsg; - - return 1; -badmsg: - errno = EBADMSG; -fail: - copy_errno(ctx); - return -1; -} - - - -#if defined(__GNUC__) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wnonnull" -#endif - - - -/** - * List all available CRTC:s, send request part - * - * Cannot be used before connecting to the server - * - * @param ctx The state of the library, must be connected - * @param async Information about the request, that is needed to - * identify and parse the response, is stored here - * @return Zero on success, -1 on error - */ -int libcoopgamma_get_crtcs_send(libcoopgamma_context_t* restrict ctx, - libcoopgamma_async_context_t* restrict async) -{ - async->message_id = ctx->message_id; - SEND_MESSAGE(ctx, NULL, (size_t)0, - "Command: enumerate-crtcs\n" - "Message ID: %" PRIu32 "\n" - "\n", - ctx->message_id); - - return 0; - fail: - copy_errno(ctx); - return -1; -} - - -/** - * List all available CRTC:s, receive response part - * - * @param ctx The state of the library, must be connected - * @param async Information about the request - * @return A `NULL`-terminated list of names. You should only free - * the outer pointer, inner pointers are subpointers of the - * outer pointer and cannot be freed. `NULL` on error, in - * which case `ctx->error` (rather than `errno`) is read - * for information about the error. - */ -char** libcoopgamma_get_crtcs_recv(libcoopgamma_context_t* restrict ctx, - libcoopgamma_async_context_t* restrict async) -{ - char* line; - char* payload; - char* end; - int command_ok = 0; - size_t i, n, lines, len, length; - char** rc; - - if (check_error(ctx, async)) - return NULL; - - for (;;) - { - line = next_header(ctx); - if (!*line) - break; - else if (!strcmp(line, "Command: crtc-enumeration")) - command_ok = 1; - } - - payload = next_payload(ctx, &n); - - if (!command_ok || ((n > 0) && (payload[n - 1] != '\n'))) - { - errno = EBADMSG; - copy_errno(ctx); - return NULL; - } - - line = payload; - end = payload + n; - lines = length = 0; - while (line != end) - { - lines += 1; - length += len = (size_t)(strchr(line, '\n') + 1 - line); - line += len; - line[-1] = '\0'; - } - - rc = malloc((lines + 1) * sizeof(char*) + length); - if (rc == NULL) - { - copy_errno(ctx); - return NULL; - } - - line = ((char*)rc) + (lines + 1) * sizeof(char*); - memcpy(line, payload, length); - rc[lines] = NULL; - for (i = 0; i < lines; i++) - { - rc[i] = line; - line = strchr(line, '\0') + 1; - } - - return rc; -} - - -/** - * List all available CRTC:s, synchronous version - * - * This is a synchronous request function, as such, - * you have to ensure that communication is blocking - * (default), and that there are not asynchronous - * requests waiting, it also means that EINTR:s are - * silently ignored and there no wait to cancel the - * operation without disconnection from the server - * - * @param ctx The state of the library, must be connected - * @return A `NULL`-terminated list of names. You should only free - * the outer pointer, inner pointers are subpointers of the - * outer pointer and cannot be freed. `NULL` on error, in - * which case `ctx->error` (rather than `errno`) is read - * for information about the error. - */ -char** libcoopgamma_get_crtcs_sync(libcoopgamma_context_t* restrict ctx) -{ - SYNC_CALL(libcoopgamma_get_crtcs_send(ctx, &async), - libcoopgamma_get_crtcs_recv(ctx, &async), (copy_errno(ctx), NULL)); -} - - - -/** - * Retrieve information about a CRTC:s gamma ramps, send request part - * - * Cannot be used before connecting to the server - * - * @param crtc The name of the CRTC - * @param ctx The state of the library, must be connected - * @param async Information about the request, that is needed to - * identify and parse the response, is stored here - * @return Zero on success, -1 on error - */ -int libcoopgamma_get_gamma_info_send(const char* restrict crtc, libcoopgamma_context_t* restrict ctx, - libcoopgamma_async_context_t* restrict async) -{ -#if defined(__GNUC__) && !defined(__clang__) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wnonnull-compare" -#endif - if ((crtc == NULL) || strchr(crtc, '\n')) - { - errno = EINVAL; - goto fail; - } -#if defined(__GNUC__) && !defined(__clang__) -# pragma GCC diagnostic pop -#endif - - async->message_id = ctx->message_id; - SEND_MESSAGE(ctx, NULL, (size_t)0, - "Command: get-gamma-info\n" - "Message ID: %" PRIu32 "\n" - "CRTC: %s\n" - "\n", - ctx->message_id, crtc); - - return 0; - fail: - copy_errno(ctx); - return 0; -} - - -/** - * Retrieve information about a CRTC:s gamma ramps, receive response part - * - * @param info Output parameter for the information, must be initialised - * @param ctx The state of the library, must be connected - * @param async Information about the request - * @return Zero on success, -1 on error, in which case `ctx->error` - * (rather than `errno`) is read for information about the error - */ -int libcoopgamma_get_gamma_info_recv(libcoopgamma_crtc_info_t* restrict info, - libcoopgamma_context_t* restrict ctx, - libcoopgamma_async_context_t* restrict async) -{ - char temp[3 * sizeof(size_t) + 1]; - char* line; - char* value; - size_t _n; - int have_cooperative = 0, have_gamma_support = 0, have_colourspace = 0; - int have_depth = 0, have_white_x = 0, have_white_y = 0; - int have_red_size = 0, have_red_x = 0, have_red_y = 0; - int have_green_size = 0, have_green_x = 0, have_green_y = 0; - int have_blue_size = 0, have_blue_x = 0, have_blue_y = 0; - int bad = 0, r = 0, g = 0, b = 0, x = 0; - - if (check_error(ctx, async)) - return -1; - - info->cooperative = 0; /* Should be in the response, but ... */ - info->colourspace = LIBCOOPGAMMA_UNKNOWN; - - for (;;) - { - line = next_header(ctx); - value = strchr(line, ':') + 2; - if (!*line) - break; - else if (strstr(line, "Cooperative: ") == line) - { - have_cooperative = 1 + !!have_cooperative; - if (!strcmp(value, "yes")) info->cooperative = 1; - else if (!strcmp(value, "no")) info->cooperative = 0; - else - bad = 1; - } - else if (strstr(line, "Depth: ") == line) - { - have_depth = 1 + !!have_depth; - if (!strcmp(value, "8")) info->depth = LIBCOOPGAMMA_UINT8; - else if (!strcmp(value, "16")) info->depth = LIBCOOPGAMMA_UINT16; - else if (!strcmp(value, "32")) info->depth = LIBCOOPGAMMA_UINT32; - else if (!strcmp(value, "64")) info->depth = LIBCOOPGAMMA_UINT64; - else if (!strcmp(value, "f")) info->depth = LIBCOOPGAMMA_FLOAT; - else if (!strcmp(value, "d")) info->depth = LIBCOOPGAMMA_DOUBLE; - else - bad = 1; - } - else if (strstr(line, "Gamma support: ") == line) - { - have_gamma_support = 1 + !!have_gamma_support; - if (!strcmp(value, "yes")) info->supported = LIBCOOPGAMMA_YES; - else if (!strcmp(value, "no")) info->supported = LIBCOOPGAMMA_NO; - else if (!strcmp(value, "maybe")) info->supported = LIBCOOPGAMMA_MAYBE; - else - bad = 1; - } - else if (((r = (strstr(line, "Red size: ") == line))) || - ((g = (strstr(line, "Green size: ") == line))) || - (strstr(line, "Blue size: ") == line)) - { - size_t* out; - if (r) have_red_size = 1 + !!have_red_size, out = &(info->red_size); - else if (g) have_green_size = 1 + !!have_green_size, out = &(info->green_size); - else have_blue_size = 1 + !!have_blue_size, out = &(info->blue_size); - *out = (size_t)atol(value); - sprintf(temp, "%zu", *out); - if (strcmp(value, temp)) - bad = 1; - } - else if ((x = r = (strstr(line, "Red x: ") == line)) || - (r = (strstr(line, "Red y: ") == line)) || - (x = g = (strstr(line, "Green x: ") == line)) || - (g = (strstr(line, "Green y: ") == line)) || - (x = b = (strstr(line, "Blue x: ") == line)) || - (b = (strstr(line, "Blue y: ") == line)) || - (x = (strstr(line, "White x: ") == line)) || - (strstr(line, "White y: ") == line)) - { - unsigned* out; - int* have; - if (r && x) have = &have_red_x, out = &(info->red_x); - else if (r) have = &have_red_y, out = &(info->red_y); - else if (g && x) have = &have_green_x, out = &(info->green_x); - else if (g) have = &have_green_y, out = &(info->green_y); - else if (b && x) have = &have_blue_x, out = &(info->blue_x); - else if (b) have = &have_blue_y, out = &(info->blue_y); - else if (x) have = &have_white_x, out = &(info->white_x); - else have = &have_white_y, out = &(info->white_y); - *have = 1 + !!*have; - *out = (unsigned)atoi(value); - sprintf(temp, "%u", *out); - if (strcmp(value, temp)) - bad = 1; - } - else if (strstr(line, "Colour space: ") == line) - { - have_colourspace = 1 + !!have_colourspace; - if (!strcmp(value, "sRGB")) info->colourspace = LIBCOOPGAMMA_SRGB; - else if (!strcmp(value, "RGB")) info->colourspace = LIBCOOPGAMMA_RGB; - else if (!strcmp(value, "non-RGB")) info->colourspace = LIBCOOPGAMMA_NON_RGB; - else if (!strcmp(value, "grey")) info->colourspace = LIBCOOPGAMMA_GREY; - else - info->colourspace = LIBCOOPGAMMA_UNKNOWN; - } - } - - (void) next_payload(ctx, &_n); - - info->have_gamut = (have_red_x && have_green_x && have_blue_x && have_white_x && - have_red_y && have_green_y && have_blue_y && have_white_y); - - if (bad || (have_gamma_support != 1) || (have_red_x > 1) || (have_red_y > 1) || - (have_green_x > 1) || (have_green_y > 1) || (have_blue_x > 1) || (have_blue_y > 1) || - (have_white_x > 1) || (have_white_y > 1) || (have_colourspace > 1)) - { - errno = EBADMSG; - copy_errno(ctx); - return -1; - } - if (info->supported != LIBCOOPGAMMA_NO) - if ((have_cooperative > 1) || (have_depth != 1) || (have_gamma_support != 1) || - (have_red_size != 1) || (have_green_size != 1) || (have_blue_size != 1)) - { - errno = EBADMSG; - copy_errno(ctx); - return -1; - } - - return 0; -} - - -/** - * Retrieve information about a CRTC:s gamma ramps, synchronous version - * - * This is a synchronous request function, as such, - * you have to ensure that communication is blocking - * (default), and that there are not asynchronous - * requests waiting, it also means that EINTR:s are - * silently ignored and there no wait to cancel the - * operation without disconnection from the server - * - * @param crtc The name of the CRTC - * @param info Output parameter for the information, must be initialised - * @param ctx The state of the library, must be connected - * @return Zero on success, -1 on error, in which case `ctx->error` - * (rather than `errno`) is read for information about the error - */ -int libcoopgamma_get_gamma_info_sync(const char* restrict ctrc, libcoopgamma_crtc_info_t* restrict info, - libcoopgamma_context_t* restrict ctx) -{ - SYNC_CALL(libcoopgamma_get_gamma_info_send(ctrc, ctx, &async), - libcoopgamma_get_gamma_info_recv(info, ctx, &async), (copy_errno(ctx), -1)); -} - - - -/** - * Retrieve the current gamma ramp adjustments, send request part - * - * Cannot be used before connecting to the server - * - * @param query The query to send - * @param ctx The state of the library, must be connected - * @param async Information about the request, that is needed to - * identify and parse the response, is stored here - * @return Zero on success, -1 on error - */ -int libcoopgamma_get_gamma_send(const libcoopgamma_filter_query_t* restrict query, - libcoopgamma_context_t* restrict ctx, - libcoopgamma_async_context_t* restrict async) -{ -#if defined(__GNUC__) && !defined(__clang__) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wnonnull-compare" -#endif - if ((query == NULL) || (query->crtc == NULL) || strchr(query->crtc, '\n')) - { - errno = EINVAL; - goto fail; - } -#if defined(__GNUC__) && !defined(__clang__) -# pragma GCC diagnostic pop -#endif - - async->message_id = ctx->message_id; - async->coalesce = query->coalesce; - SEND_MESSAGE(ctx, NULL, (size_t)0, - "Command: get-gamma\n" - "Message ID: %" PRIu32 "\n" - "CRTC: %s\n" - "Coalesce: %s\n" - "High priority: %" PRIi64 "\n" - "Low priority: %" PRIi64 "\n" - "\n", - ctx->message_id, query->crtc, query->coalesce ? "yes" : "no", - query->high_priority, query->low_priority); - - return 0; - fail: - copy_errno(ctx); - return -1; -} - - -/** - * Retrieve the current gamma ramp adjustments, receive response part - * - * @param table Output for the response, must be initialised - * @param ctx The state of the library, must be connected - * @param async Information about the request - * @return Zero on success, -1 on error, in which case `ctx->error` - * (rather than `errno`) is read for information about the error - */ -int libcoopgamma_get_gamma_recv(libcoopgamma_filter_table_t* restrict table, - libcoopgamma_context_t* restrict ctx, - libcoopgamma_async_context_t* restrict async) -{ - char temp[3 * sizeof(size_t) + 1]; - char* line; - char* value; - char* payload; - size_t i, n, width, clutsize; - int have_depth = 0; - int have_red_size = 0; - int have_green_size = 0; - int have_blue_size = 0; - int have_tables = 0; - int bad = 0, r = 0, g = 0; - - if (check_error(ctx, async)) - return -1; - - libcoopgamma_filter_table_destroy(table); - - for (;;) - { - line = next_header(ctx); - value = strchr(line, ':') + 2; - if (!*line) - break; - else if (strstr(line, "Depth: ") == line) - { - have_depth = 1 + !!have_depth; - if (!strcmp(value, "8")) table->depth = LIBCOOPGAMMA_UINT8; - else if (!strcmp(value, "16")) table->depth = LIBCOOPGAMMA_UINT16; - else if (!strcmp(value, "32")) table->depth = LIBCOOPGAMMA_UINT32; - else if (!strcmp(value, "64")) table->depth = LIBCOOPGAMMA_UINT64; - else if (!strcmp(value, "f")) table->depth = LIBCOOPGAMMA_FLOAT; - else if (!strcmp(value, "d")) table->depth = LIBCOOPGAMMA_DOUBLE; - else - bad = 1; - } - else if (((r = (strstr(line, "Red size: ") == line))) || - ((g = (strstr(line, "Green size: ") == line))) || - (strstr(line, "Blue size: ") == line)) - { - size_t* out; - if (r) have_red_size = 1 + !!have_red_size, out = &(table->red_size); - else if (g) have_green_size = 1 + !!have_green_size, out = &(table->green_size); - else have_blue_size = 1 + !!have_blue_size, out = &(table->blue_size); - *out = (size_t)atol(value); - sprintf(temp, "%zu", *out); - if (strcmp(value, temp)) - bad = 1; - } - else if (strstr(line, "Tables: ") == line) - { - have_tables = 1 + have_tables; - table->filter_count = (size_t)atol(value); - sprintf(temp, "%zu", table->filter_count); - if (strcmp(value, temp)) - bad = 1; - } - } - - payload = next_payload(ctx, &n); - - if (bad || (have_depth != 1) || (have_red_size != 1) || (have_green_size != 1) || - (have_blue_size != 1) || (async->coalesce ? (have_tables > 1) : (have_tables == 0)) || - (((payload == NULL) || (n == 0)) && (async->coalesce || (table->filter_count > 0))) || - ((n > 0) && have_tables && (table->filter_count == 0)) || - (async->coalesce && have_tables && (table->filter_count != 1))) - goto bad; - - switch (table->depth) - { - case LIBCOOPGAMMA_FLOAT: width = sizeof(float); break; - case LIBCOOPGAMMA_DOUBLE: width = sizeof(double); break; - default: INTEGRAL_DEPTHS - if ((table->depth <= 0) || ((table->depth & 7) != 0)) - goto bad; - width = (size_t)(table->depth / 8); - break; - } - - clutsize = table->red_size + table->green_size + table->blue_size; - clutsize *= width; - - if (async->coalesce) - { - if (n != clutsize) - goto bad; - table->filters = malloc(sizeof(*(table->filters))); - if (table->filters == NULL) - goto fail; - table->filters->priority = 0; - table->filters->class = NULL; - table->filters->ramps.u8.red_size = table->red_size; - table->filters->ramps.u8.green_size = table->green_size; - table->filters->ramps.u8.blue_size = table->blue_size; - if (libcoopgamma_ramps_initialise_(&(table->filters->ramps), width) < 0) - goto fail; - memcpy(table->filters->ramps.u8.red, payload, clutsize); - table->filter_count = 1; - } - else if (table->filter_count == 0) - table->filters = NULL; - else - { - size_t off = 0, len; - table->filters = calloc(table->filter_count, sizeof(*(table->filters))); - if (table->filters == NULL) - goto fail; - for (i = 0; i < table->filter_count; i++) - { - if (off + sizeof(int64_t) > n) - goto bad; - table->filters[i].priority = *(int64_t*)(payload + off); - off += sizeof(int64_t); - if (memchr(payload + off, '\0', n - off) == NULL) - goto bad; - len = strlen(payload + off) + 1; - table->filters[i].class = malloc(len); - if (table->filters[i].class == NULL) - goto fail; - memcpy(table->filters[i].class, payload + off, len); - off += len; - if (off + clutsize > n) - goto bad; - table->filters[i].ramps.u8.red_size = table->red_size; - table->filters[i].ramps.u8.green_size = table->green_size; - table->filters[i].ramps.u8.blue_size = table->blue_size; - if (libcoopgamma_ramps_initialise_(&(table->filters[i].ramps), width) < 0) - goto fail; - memcpy(table->filters->ramps.u8.red, payload + off, clutsize); - off += clutsize; - } - if (off != n) - goto bad; - } - - return 0; - bad: - errno = EBADMSG; - fail: - copy_errno(ctx); - return -1; -} - - -/** - * Retrieve the current gamma ramp adjustments, synchronous version - * - * This is a synchronous request function, as such, - * you have to ensure that communication is blocking - * (default), and that there are not asynchronous - * requests waiting, it also means that EINTR:s are - * silently ignored and there no wait to cancel the - * operation without disconnection from the server - * - * @param query The query to send - * @param table Output for the response, must be initialised - * @param ctx The state of the library, must be connected - * @return Zero on success, -1 on error, in which case `ctx->error` - * (rather than `errno`) is read for information about the error - */ -int libcoopgamma_get_gamma_sync(const libcoopgamma_filter_query_t* restrict query, - libcoopgamma_filter_table_t* restrict table, - libcoopgamma_context_t* restrict ctx) -{ - SYNC_CALL(libcoopgamma_get_gamma_send(query, ctx, &async), - libcoopgamma_get_gamma_recv(table, ctx, &async), (copy_errno(ctx), -1)); -} - - - -/** - * Apply, update, or remove a gamma ramp adjustment, send request part - * - * Cannot be used before connecting to the server - * - * @param filter The filter to apply, update, or remove, gamma ramp meta-data must match the CRTC's - * @param ctx The state of the library, must be connected - * @param async Information about the request, that is needed to - * identify and parse the response, is stored here - * @return Zero on success, -1 on error - */ -int libcoopgamma_set_gamma_send(const libcoopgamma_filter_t* restrict filter, - libcoopgamma_context_t* restrict ctx, - libcoopgamma_async_context_t* restrict async) -{ - const void* payload = NULL; - const char* lifespan; - char priority[sizeof("Priority: \n") + 3 * sizeof(int64_t)] = {'\0'}; - char length [sizeof("Length: \n") + 3 * sizeof(size_t) ] = {'\0'}; - size_t payload_size = 0, stopwidth = 0; - -#if defined(__GNUC__) && !defined(__clang__) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wnonnull-compare" -#endif - if ((filter == NULL) || (filter->crtc == NULL) || strchr(filter->crtc, '\n') || - (filter->class == NULL) || strchr(filter->class, '\n')) - { - errno = EINVAL; - goto fail; - } -#if defined(__GNUC__) && !defined(__clang__) -# pragma GCC diagnostic pop -#endif - - switch (filter->lifespan) - { - case LIBCOOPGAMMA_REMOVE: lifespan = "remove"; break; - case LIBCOOPGAMMA_UNTIL_DEATH: lifespan = "until-death"; break; - case LIBCOOPGAMMA_UNTIL_REMOVAL: lifespan = "until-removal"; break; - default: - errno = EINVAL; - goto fail; - } - - if (filter->lifespan != LIBCOOPGAMMA_REMOVE) - { - switch (filter->depth) - { - case LIBCOOPGAMMA_FLOAT: stopwidth = sizeof(float); break; - case LIBCOOPGAMMA_DOUBLE: stopwidth = sizeof(double); break; - default: INTEGRAL_DEPTHS - if ((filter->depth <= 0) || ((filter->depth & 7) != 0)) - { - errno = EINVAL; - goto fail; - } - stopwidth = (size_t)(filter->depth / 8); - break; - } - - payload_size = filter->ramps.u8.red_size; - payload_size += filter->ramps.u8.green_size; - payload_size += filter->ramps.u8.blue_size; - payload_size *= stopwidth; - payload = filter->ramps.u8.red; - sprintf(priority, "Priority: %" PRIi64 "\n", filter->priority); - sprintf(length, "Length: %zu\n", payload_size); - } - - async->message_id = ctx->message_id; - SEND_MESSAGE(ctx, payload, payload_size, - "Command: set-gamma\n" - "Message ID: %" PRIu32 "\n" - "CRTC: %s\n" - "Class: %s\n" - "Lifespan: %s\n" - "%s" - "%s" - "\n", - ctx->message_id, filter->crtc, filter->class, lifespan, - priority, length); - - return 0; - fail: - copy_errno(ctx); - return -1; -} - - -/** - * Apply, update, or remove a gamma ramp adjustment, receive response part - * - * @param ctx The state of the library, must be connected - * @param async Information about the request - * @return Zero on success, -1 on error, in which case `ctx->error` - * (rather than `errno`) is read for information about the error - */ -int libcoopgamma_set_gamma_recv(libcoopgamma_context_t* restrict ctx, - libcoopgamma_async_context_t* restrict async) -{ - size_t _n = 0; - - if (check_error(ctx, async)) - return -(ctx->error.custom || ctx->error.number); - - while (*next_header(ctx)); - (void) next_payload(ctx, &_n); - - errno = EBADMSG; - copy_errno(ctx); - return -1; -} - - -/** - * Apply, update, or remove a gamma ramp adjustment, synchronous version - * - * This is a synchronous request function, as such, - * you have to ensure that communication is blocking - * (default), and that there are not asynchronous - * requests waiting, it also means that EINTR:s are - * silently ignored and there no wait to cancel the - * operation without disconnection from the server - * - * @param filter The filter to apply, update, or remove, gamma ramp meta-data must match the CRTC's - * @param depth The datatype for the stops in the gamma ramps, must match the CRTC's - * @param ctx The state of the library, must be connected - * @return Zero on success, -1 on error, in which case `ctx->error` - * (rather than `errno`) is read for information about the error - */ -int libcoopgamma_set_gamma_sync(const libcoopgamma_filter_t* restrict filter, - libcoopgamma_context_t* restrict ctx) -{ - SYNC_CALL(libcoopgamma_set_gamma_send(filter, ctx, &async), - libcoopgamma_set_gamma_recv(ctx, &async), (copy_errno(ctx), -1)); -} - - - -#if defined(__GNUC__) -# pragma GCC diagnostic pop -#endif - diff --git a/src/libcoopgamma.h b/src/libcoopgamma.h deleted file mode 100644 index 723d5a3..0000000 --- a/src/libcoopgamma.h +++ /dev/null @@ -1,1680 +0,0 @@ -/** - * libcoopgamma -- Library for interfacing with cooperative gamma servers - * Copyright (C) 2016 Mattias Andrée (maandree@kth.se) - * - * This library is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this library. If not, see . - */ -#ifndef LIBCOOPGAMMA_H -#define LIBCOOPGAMMA_H - - - -#include -#include -#include - - - -#if defined(__clang__) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wdocumentation" -#endif - -#if defined(__GNUC__) && !defined(__clang__) -# define LIBCOOPGAMMA_GCC_ONLY(...) __VA_ARGS__ -#else -# define LIBCOOPGAMMA_GCC_ONLY(...) /* ignore */ -#endif - - - -/** - * Unmarshal was successful - * - * This value will always be zero - */ -#define LIBCOOPGAMMA_SUCCESS 0 - -/** - * Unmarshal failed: the marshalled data was created - * with a older version of libcoopgamma that does not - * marshall the data in a compatible way - * - * This value will always be positive - */ -#define LIBCOOPGAMMA_INCOMPATIBLE_DOWNGRADE 1 - -/** - * Unmarshal failed: the marshalled data was created with - * a newer version libcoopgamma that does not marshall - * the data in a compatible way - * - * This value will always be positive - */ -#define LIBCOOPGAMMA_INCOMPATIBLE_UPGRADE 2 - -/** - * Unmarshal failed because of an error, `errno` has been set - * - * This value will always be -1 and will be the - * only negative value in this category of constants - */ -#define LIBCOOPGAMMA_ERRNO_SET -1 - - - -/** - * Number used to identify implementation - * version of `libcoopgamma_support_t`, if it - * is ever modified, this number is increased - */ -#define LIBCOOPGAMMA_SUPPORT_VERSION 0 - -/** - * Number used to identify implementation - * version of `libcoopgamma_depth_t`, if it - * is ever modified, this number is increased - */ -#define LIBCOOPGAMMA_DEPTH_VERSION 0 - -/** - * Number used to identify implementation - * version of `libcoopgamma_lifespan_t`, if it - * is ever modified, this number is increased - */ -#define LIBCOOPGAMMA_LIFESPAN_VERSION 0 - -/** - * Number used to identify implementation - * version of `libcoopgamma_colourspace_t`, if it - * is ever modified, this number is increased - */ -#define LIBCOOPGAMMA_COLOURSPACE_VERSION 0 - -/** - * Number used to identify implementation - * version of `libcoopgamma_ramps*_t`, if they - * are ever modified, this number is increased - */ -#define LIBCOOPGAMMA_RAMPS_VERSION 0 - -/** - * Number used to identify implementation - * version of `libcoopgamma_filter_t`, if it - * is ever modified, this number is increased - */ -#define LIBCOOPGAMMA_FILTER_VERSION 0 - -/** - * Number used to identify implementation - * version of `libcoopgamma_ctrc_info_t`, if it - * is ever modified, this number is increased - */ -#define LIBCOOPGAMMA_CRTC_INFO_VERSION 0 - -/** - * Number used to identify implementation - * version of `libcoopgamma_filter_query_t`, if it - * is ever modified, this number is increased - */ -#define LIBCOOPGAMMA_FILTER_QUERY_VERSION 0 - -/** - * Number used to identify implementation - * version of `libcoopgamma_queried_filter_t`, if it - * is ever modified, this number is increased - */ -#define LIBCOOPGAMMA_QUERIED_FILTER_VERSION 0 - -/** - * Number used to identify implementation - * version of `libcoopgamma_filter_table_t`, if it - * is ever modified, this number is increased - */ -#define LIBCOOPGAMMA_FILTER_TABLE_VERSION 0 - -/** - * Number used to identify implementation - * version of `libcoopgamma_error_t`, if it - * is ever modified, this number is increased - */ -#define LIBCOOPGAMMA_ERROR_VERSION 0 - -/** - * Number used to identify implementation - * version of `libcoopgamma_context_t`, if it - * is ever modified, this number is increased - */ -#define LIBCOOPGAMMA_CONTEXT_VERSION 0 - -/** - * Number used to identify implementation - * version of `libcoopgamma_async_context_t`, if it - * is ever modified, this number is increased - */ -#define LIBCOOPGAMMA_ASYNC_CONTEXT_VERSION 0 - - - -/** - * Values used to indicate the support - * for gamma adjustments - */ -typedef enum libcoopgamma_support -{ - /** - * Gamma adjustments are not supported - * - * This value will always be 0 - */ - LIBCOOPGAMMA_NO = 0, - - /** - * Don't know whether gamma - * adjustments are supported - * - * This value will always be 1 - */ - LIBCOOPGAMMA_MAYBE = 1, - - /** - * Gamma adjustments are supported - * - * This value will always be 2 - */ - LIBCOOPGAMMA_YES = 2 - -} libcoopgamma_support_t; - - -/** - * Values used to tell which datatype - * is used for the gamma ramp stops - * - * The values will always be the number - * of bits for integral types, and - * negative for floating-point types - */ -typedef enum libcoopgamma_depth -{ - /** - * `uint8_t` - */ - LIBCOOPGAMMA_UINT8 = 8, - - /** - * `uint16_t` - */ - LIBCOOPGAMMA_UINT16 = 16, - - /** - * `uint32_t` - */ - LIBCOOPGAMMA_UINT32 = 32, - - /** - * `uint64_t` - */ - LIBCOOPGAMMA_UINT64 = 64, - - /** - * `float` - */ - LIBCOOPGAMMA_FLOAT = -1, - - /** - * `double` - */ - LIBCOOPGAMMA_DOUBLE = -2 - -} libcoopgamma_depth_t; - - -/** - * Values used to tell when a filter - * should be removed - */ -typedef enum libcoopgamma_lifespan -{ - /** - * Remove the filter now - * - * This value will always be 0 - */ - LIBCOOPGAMMA_REMOVE = 0, - - /** - * Remove the filter when disconnecting - * from the coopgamma server - */ - LIBCOOPGAMMA_UNTIL_DEATH = 1, - - /** - * Only remove the filter when it - * is explicitly requested - */ - LIBCOOPGAMMA_UNTIL_REMOVAL = 2 - -} libcoopgamma_lifespan_t; - - -/** - * Colourspaces - */ -typedef enum libcoopgamma_colourspace -{ - /** - * The colourspace is unknown - * - * This value will always be 0 - */ - LIBCOOPGAMMA_UNKNOWN = 0, - - /** - * sRGB (Standard RGB) - */ - LIBCOOPGAMMA_SRGB = 1, - - /** - * RGB other than sRGB - */ - LIBCOOPGAMMA_RGB = 2, - - /** - * Non-RGB multicolour - */ - LIBCOOPGAMMA_NON_RGB = 3, - - /** - * Monochrome, greyscale, or some - * other singlecolour scale - */ - LIBCOOPGAMMA_GREY = 4 - -} libcoopgamma_colourspace_t; - - -/** - * Define a gamma ramp structure - * - * @param suffix:identifier The end of the name of the `struct` - * @param type:scalar-type The datatype of the stops - */ -#define LIBCOOPGAMMA_RAMPS__(suffix, type) \ -typedef struct libcoopgamma_ramps##suffix \ -{ \ - /** - * The number of stops in the red ramp - */ \ - size_t red_size; \ - \ - /** - * The number of stops in the green ramp - */ \ - size_t green_size; \ - \ - /** - * The number of stops in the blue ramp - */ \ - size_t blue_size; \ - \ - /** - * The red ramp - */ \ - type* red; \ - \ - /** - * The green ramp - */ \ - type* green; \ - \ - /** - * The blue ramp - */ \ - type* blue; \ - \ -} libcoopgamma_ramps##suffix##_t - -/** - * `typedef struct libcoopgamma_ramps8 libcoopgamma_ramps8_t` - * - * Gamma ramp structure with `uint8_t` stops - */ -LIBCOOPGAMMA_RAMPS__(8, uint8_t); - -/** - * `typedef struct libcoopgamma_ramps16 libcoopgamma_ramps16_t` - * - * Gamma ramp structure with `uint16_t` stops - */ -LIBCOOPGAMMA_RAMPS__(16, uint16_t); - -/** - * `typedef struct libcoopgamma_ramps32 libcoopgamma_ramps32_t` - * - * Gamma ramp structure with `uint32_t` stops - */ -LIBCOOPGAMMA_RAMPS__(32, uint32_t); - -/** - * `typedef struct libcoopgamma_ramps64 libcoopgamma_ramps64_t` - * - * Gamma ramp structure with `uint64_t` stops - */ -LIBCOOPGAMMA_RAMPS__(64, uint64_t); - -/** - * `typedef struct libcoopgamma_rampsf libcoopgamma_rampsf_t` - * - * Gamma ramp structure with `float` stops - */ -LIBCOOPGAMMA_RAMPS__(f, float); - -/** - * `typedef struct libcoopgamma_rampsd libcoopgamma_rampsd_t` - * - * Gamma ramp structure with `double` stops - */ -LIBCOOPGAMMA_RAMPS__(d, double); - - -/** - * Union with all ramp types. - */ -typedef union libcoopgamma_ramps -{ - /** - * 8-bit version - */ - libcoopgamma_ramps8_t u8; - - /** - * 16-bit version - */ - libcoopgamma_ramps16_t u16; - - /** - * 32-bit version - */ - libcoopgamma_ramps32_t u32; - - /** - * 64-bit version - */ - libcoopgamma_ramps64_t u64; - - /** - * Single precision floating-point version - */ - libcoopgamma_rampsf_t f; - - /** - * Double precision floating-point version - */ - libcoopgamma_rampsd_t d; - -} libcoopgamma_ramps_t; - - -/** - * Data set to the coopgamma server to apply, - * update, or remove a filter. - */ -typedef struct libcoopgamma_filter -{ - /** - * The priority of the filter, higher priority - * is applied first. The gamma correction should - * have priority 0. - */ - int64_t priority; - - /** - * The CRTC for which this filter shall be applied - */ - char* crtc; - - /** - * Identifier for the filter - * - * The syntax must be "${PACKAGE_NAME}::${COMMAND_NAME}::${RULE}" - */ - char* class; - - /** - * When shall the filter be removed? - * - * If this member's value is `LIBCOOPGAMMA_REMOVE`, - * only `.crtc` and `.class` need also be defined - */ - libcoopgamma_lifespan_t lifespan; - - /** - * The data type and bit-depth of the ramp stops - */ - libcoopgamma_depth_t depth; - - /** - * The gamma ramp adjustments of the filter - */ - libcoopgamma_ramps_t ramps; - -} libcoopgamma_filter_t; - - -/** - * Gamma ramp meta information for a CRTC - */ -typedef struct libcoopgamma_crtc_info -{ - /** - * Is cooperative gamma server running? - */ - int cooperative; - - /** - * The data type and bit-depth of the ramp stops - */ - libcoopgamma_depth_t depth; - - /** - * Is gamma adjustments supported on the CRTC? - * If not, `.depth`, `.red_size`, `.green_size`, - * and `.blue_size` are undefined - */ - libcoopgamma_support_t supported; - -#if INT_MAX != LONG_MAX - int padding__; -#endif - - /** - * The number of stops in the red ramp - */ - size_t red_size; - - /** - * The number of stops in the green ramp - */ - size_t green_size; - - /** - * The number of stops in the blue ramp - */ - size_t blue_size; - - /** - * The monitor's colourspace - */ - libcoopgamma_colourspace_t colourspace; - - /** - * Whether `.red_x`, `.red_y`, `.green_x`, - * `.green_y`, `.blue_x`, `.blue_y`, - * `.white_x`, and `.white_y` are set. - * - * If this is true, but the colourspace - * is not RGB (or sRGB), there is something - * wrong. Please also check the colourspace. - */ - int have_gamut; - - /** - * The x-value (CIE xyY) of the monitor's - * red colour, multiplied by 1024 - */ - unsigned red_x; - - /** - * The y-value (CIE xyY) of the monitor's - * red colour, multiplied by 1024 - */ - unsigned red_y; - - /** - * The x-value (CIE xyY) of the monitor's - * green colour, multiplied by 1024 - */ - unsigned green_x; - - /** - * The y-value (CIE xyY) of the monitor's - * green colour, multiplied by 1024 - */ - unsigned green_y; - - /** - * The x-value (CIE xyY) of the monitor's - * blue colour, multiplied by 1024 - */ - unsigned blue_x; - - /** - * The y-value (CIE xyY) of the monitor's - * blue colour, multiplied by 1024 - */ - unsigned blue_y; - - /** - * The x-value (CIE xyY) of the monitor's - * default white point, multiplied by 1024 - */ - unsigned white_x; - - /** - * The y-value (CIE xyY) of the monitor's - * default white point, multiplied by 1024 - */ - unsigned white_y; - -} libcoopgamma_crtc_info_t; - - -/** - * Data sent to the coopgamma server - * when requestng the current filter - * table - */ -typedef struct libcoopgamma_filter_query -{ - /** - * Do no return filters with higher - * priority than this value - */ - int64_t high_priority; - - /** - * Do no return filters with lower - * priority than this value - */ - int64_t low_priority; - - /** - * The CRTC for which the the current - * filters shall returned - */ - char* crtc; - - /** - * Whether to coalesce all filters - * into one gamma ramp triplet - */ - int coalesce; - -#if INT_MAX != LONG_MAX - int padding__; -#endif - -} libcoopgamma_filter_query_t; - - -/** - * Stripped down version of `libcoopgamma_filter` - * which only contains the information returned - * in response to "Command: get-gamma" - */ -typedef struct libcoopgamma_queried_filter -{ - /** - * The filter's priority - */ - int64_t priority; - - /** - * The filter's class - */ - char* class; - - /** - * The gamma ramp adjustments of the filter - */ - libcoopgamma_ramps_t ramps; - -} libcoopgamma_queried_filter_t; - - -/** - * Response type for "Command: get-gamma": a - * list of applied filters and meta-information - * that was necessary for decoding the response - */ -typedef struct libcoopgamma_filter_table -{ - /** - * The number of stops in the red ramp - */ - size_t red_size; - - /** - * The number of stops in the green ramp - */ - size_t green_size; - - /** - * The number of stops in the blue ramp - */ - size_t blue_size; - - /** - * The number of filters - */ - size_t filter_count; - - /** - * The filters, should be ordered by priority - * in descending order, lest there is something - * wrong with the coopgamma server - * - * If filter coalition was requested, there will - * be exactly one filter (`.filter_count == 1`) - * and `.filters->class == NULL` and - * `.filters->priority` is undefined. - */ - libcoopgamma_queried_filter_t* filters; - - /** - * The data type and bit-depth of the ramp stops - */ - libcoopgamma_depth_t depth; - -#if INT_MAX != LONG_MAX - int padding__; -#endif - -} libcoopgamma_filter_table_t; - - -/** - * Error message from coopgamma server - */ -typedef struct libcoopgamma_error -{ - /** - * Error code - * - * If `.custom` is false, 0 indicates - * success, otherwise, 0 indicates that - * no error code has been assigned - */ - uint64_t number; - - /** - * Is this a custom error? - */ - int custom; - - /** - * Did the error occur on the server-side? - */ - int server_side; - - /** - * Error message, can be `NULL` if - * `.custom` is false - */ - char* description; - -} libcoopgamma_error_t; - - -/** - * Library state - * - * Use of this structure is not thread-safe, - * create one instance per thread that uses - * this structure - */ -typedef struct libcoopgamma_context -{ - /** - * The error of the last failed function call - * - * This member is undefined after successful function call - */ - libcoopgamma_error_t error; - - /** - * File descriptor for the socket - */ - int fd; - - /* The members below are internal. */ - - /** - * Whether `libcoopgamma_synchronise` have - * read the empty end-of-headers line - */ - int have_all_headers; - - /** - * Whether `libcoopgamma_synchronise` is reading - * a corrupt but recoverable message - */ - int bad_message; - - /** - * Is communication blocking? - */ - int blocking; - - /** - * Message ID of the next message - */ - uint32_t message_id; - - /** - * The ID of outbound message to which the inbound - * message being read by `libcoopgamma_synchronise` - * is a response - */ - uint32_t in_response_to; - - /** - * Buffer with the outbound message - */ - char* outbound; - - /** - * The write head for `outbound` - */ - size_t outbound_head; - - /** - * The read head for `outbound` - */ - size_t outbound_tail; - - /** - * The allocation size of `outbound` - */ - size_t outbound_size; - - /** - * Buffer with the inbound message - */ - char* inbound; - - /** - * The write head for `inbound` - */ - size_t inbound_head; - - /** - * The read head for `inbound` - */ - size_t inbound_tail; - - /** - * The allocation size of `inbound` - */ - size_t inbound_size; - - /** - * The value of 'Length' header in - * the inbound message - */ - size_t length; - - /** - * The beginning of the current line that - * is being read by `libcoopgamma_synchronise` - */ - size_t curline; - -} libcoopgamma_context_t; - - -/** - * Information necessary to identify and - * parse a response from the server - */ -typedef struct libcoopgamma_async_context -{ - /* All members are internal. */ - - /** - * The value of the 'In response to' header - * in the waited message - */ - uint32_t message_id; - - /** - * Whether to coalesce all filters - * into one gamma ramp triplet - */ - int coalesce; - -} libcoopgamma_async_context_t; - - - -/** - * Initialise a `libcoopgamma_ramps8_t`, `libcoopgamma_ramps16_t`, `libcoopgamma_ramps32_t`, - * `libcoopgamma_ramps64_t`, `libcoopgamma_rampsf_t`, or `libcoopgamma_rampsd_t` - * - * `this->red_size`, `this->green_size`, and `this->blue_size` must already be set - * - * @param this The record to initialise - * @return Zero on success, -1 on error - */ -#define libcoopgamma_ramps_initialise(this) \ - (libcoopgamma_ramps_initialise_((this), sizeof(*((this)->red)))) - -/** - * Marshal a `libcoopgamma_ramps8_t`, `libcoopgamma_ramps16_t`, `libcoopgamma_ramps32_t`, - * `libcoopgamma_ramps64_t`, `libcoopgamma_rampsf_t`, or `libcoopgamma_rampsd_t` into a buffer - * - * @param this The record to marshal - * @param buf The output buffer, `NULL` to only measure - * how large this buffer has to be - * @return The number of marshalled bytes, or if `buf == NULL`, - * how many bytes would be marshalled if `buf != NULL` - */ -#define libcoopgamma_ramps_marshal(this, buf) \ - (libcoopgamma_ramps_marshal_((this), (buf), sizeof(*((this)->red)))) - -/** - * Unmarshal a `libcoopgamma_ramps8_t`, `libcoopgamma_ramps16_t`, `libcoopgamma_ramps32_t`, - * `libcoopgamma_ramps64_t`, `libcoopgamma_rampsf_t`, or `libcoopgamma_rampsd_t` from a buffer - * - * @param this The output parameter for unmarshalled record - * @param buf The buffer with the marshalled record - * @param n Output parameter for the number of unmarshalled bytes, undefined on failure - * @return `LIBCOOPGAMMA_SUCCESS` (0), `LIBCOOPGAMMA_INCOMPATIBLE_DOWNGRADE`, - * `LIBCOOPGAMMA_INCOMPATIBLE_UPGRADE`, or `LIBCOOPGAMMA_ERRNO_SET` - */ -#define libcoopgamma_ramps_unmarshal(this, buf, n) \ - (libcoopgamma_ramps_unmarshal_((this), (buf), (n), sizeof(*((this)->red)))) - - -/** - * Initialise a `libcoopgamma_ramps8_t`, `libcoopgamma_ramps16_t`, `libcoopgamma_ramps32_t`, - * `libcoopgamma_ramps64_t`, `libcoopgamma_rampsf_t`, or `libcoopgamma_rampsd_t` - * - * `this->red_size`, `this->green_size`, and `this->blue_size` must already be set - * - * @param this The record to initialise - * @param width The `sizeof(*(this->red))` - * @return Zero on success, -1 on error - */ -LIBCOOPGAMMA_GCC_ONLY(__attribute__((__nonnull__, __leaf__))) -int libcoopgamma_ramps_initialise_(void* restrict, size_t); - -/** - * Release all resources allocated to a `libcoopgamma_ramps8_t`, `libcoopgamma_ramps16_t`, - * `libcoopgamma_ramps32_t`, `libcoopgamma_ramps64_t`, `libcoopgamma_rampsf_t`, - * `libcoopgamma_rampsd_t`, or `libcoopgamma_ramps_t`, the allocation of the record - * itself is not freed - * - * Always call this function after failed call to `libcoopgamma_ramps_initialise` - * or failed call to `libcoopgamma_ramps_unmarshal` - * - * @param this The record to destroy - */ -LIBCOOPGAMMA_GCC_ONLY(__attribute__((__nonnull__, __leaf__))) -void libcoopgamma_ramps_destroy(void* restrict); - -/** - * Marshal a `libcoopgamma_ramps8_t`, `libcoopgamma_ramps16_t`, `libcoopgamma_ramps32_t`, - * `libcoopgamma_ramps64_t`, `libcoopgamma_rampsf_t`, or `libcoopgamma_rampsd_t` into a buffer - * - * @param this The record to marshal - * @param buf The output buffer, `NULL` to only measure - * how large this buffer has to be - * @param width The `sizeof(*(this->red))` - * @return The number of marshalled bytes, or if `buf == NULL`, - * how many bytes would be marshalled if `buf != NULL` - */ -LIBCOOPGAMMA_GCC_ONLY(__attribute__((__nonnull__(1), __leaf__))) -size_t libcoopgamma_ramps_marshal_(const void* restrict, void* restrict, size_t); - -/** - * Unmarshal a `libcoopgamma_ramps8_t`, `libcoopgamma_ramps16_t`, `libcoopgamma_ramps32_t`, - * `libcoopgamma_ramps64_t`, `libcoopgamma_rampsf_t`, or `libcoopgamma_rampsd_t` from a buffer - * - * @param this The output parameter for unmarshalled record - * @param buf The buffer with the marshalled record - * @param n Output parameter for the number of unmarshalled bytes, undefined on failure - * @param width The `sizeof(*(this->red))` - * @return `LIBCOOPGAMMA_SUCCESS` (0), `LIBCOOPGAMMA_INCOMPATIBLE_DOWNGRADE`, - * `LIBCOOPGAMMA_INCOMPATIBLE_UPGRADE`, or `LIBCOOPGAMMA_ERRNO_SET` - */ -LIBCOOPGAMMA_GCC_ONLY(__attribute__((__nonnull__, __leaf__))) -int libcoopgamma_ramps_unmarshal_(void* restrict, const void* restrict, size_t* restrict, size_t); - - -/** - * Initialise a `libcoopgamma_filter_t` - * - * @param this The record to initialise - * @return Zero on success, -1 on error - */ -LIBCOOPGAMMA_GCC_ONLY(__attribute__((__nonnull__, __leaf__))) -int libcoopgamma_filter_initialise(libcoopgamma_filter_t* restrict); - -/** - * Release all resources allocated to a `libcoopgamma_filter_t`, - * the allocation of the record itself is not freed - * - * Always call this function after failed call to `libcoopgamma_filter_initialise` - * or failed call to `libcoopgamma_filter_unmarshal` - * - * @param this The record to destroy - */ -LIBCOOPGAMMA_GCC_ONLY(__attribute__((__nonnull__, __leaf__))) -void libcoopgamma_filter_destroy(libcoopgamma_filter_t* restrict); - -/** - * Marshal a `libcoopgamma_filter_t` into a buffer - * - * @param this The record to marshal - * @param buf The output buffer, `NULL` to only measure - * how large this buffer has to be - * @return The number of marshalled bytes, or if `buf == NULL`, - * how many bytes would be marshalled if `buf != NULL` - */ -LIBCOOPGAMMA_GCC_ONLY(__attribute__((__nonnull__(1)))) -size_t libcoopgamma_filter_marshal(const libcoopgamma_filter_t* restrict, void* restrict); - -/** - * Unmarshal a `libcoopgamma_filter_t` from a buffer - * - * @param this The output parameter for unmarshalled record - * @param buf The buffer with the marshalled record - * @param n Output parameter for the number of unmarshalled bytes, undefined on failure - * @return `LIBCOOPGAMMA_SUCCESS` (0), `LIBCOOPGAMMA_INCOMPATIBLE_DOWNGRADE`, - * `LIBCOOPGAMMA_INCOMPATIBLE_UPGRADE`, or `LIBCOOPGAMMA_ERRNO_SET` - */ -LIBCOOPGAMMA_GCC_ONLY(__attribute__((__nonnull__))) -int libcoopgamma_filter_unmarshal(libcoopgamma_filter_t* restrict, const void* restrict, size_t* restrict); - - -/** - * Initialise a `libcoopgamma_crtc_info_t` - * - * @param this The record to initialise - * @return Zero on success, -1 on error - */ -LIBCOOPGAMMA_GCC_ONLY(__attribute__((__nonnull__, __leaf__))) -int libcoopgamma_crtc_info_initialise(libcoopgamma_crtc_info_t* restrict); - -/** - * Release all resources allocated to a `libcoopgamma_crtc_info_t`, - * the allocation of the record itself is not freed - * - * Always call this function after failed call to `libcoopgamma_crtc_info_initialise` - * or failed call to `libcoopgamma_crtc_info_unmarshal` - * - * @param this The record to destroy - */ -LIBCOOPGAMMA_GCC_ONLY(__attribute__((__nonnull__, __leaf__))) -void libcoopgamma_crtc_info_destroy(libcoopgamma_crtc_info_t* restrict); - -/** - * Marshal a `libcoopgamma_crtc_info_t` into a buffer - * - * @param this The record to marshal - * @param buf The output buffer, `NULL` to only measure - * how large this buffer has to be - * @return The number of marshalled bytes, or if `buf == NULL`, - * how many bytes would be marshalled if `buf != NULL` - */ -LIBCOOPGAMMA_GCC_ONLY(__attribute__((__nonnull__(1), __leaf__))) -size_t libcoopgamma_crtc_info_marshal(const libcoopgamma_crtc_info_t* restrict, void* restrict); - -/** - * Unmarshal a `libcoopgamma_crtc_info_t` from a buffer - * - * @param this The output parameter for unmarshalled record - * @param buf The buffer with the marshalled record - * @param n Output parameter for the number of unmarshalled bytes, undefined on failure - * @return `LIBCOOPGAMMA_SUCCESS` (0), `LIBCOOPGAMMA_INCOMPATIBLE_DOWNGRADE`, - * `LIBCOOPGAMMA_INCOMPATIBLE_UPGRADE`, or `LIBCOOPGAMMA_ERRNO_SET` - */ -LIBCOOPGAMMA_GCC_ONLY(__attribute__((__nonnull__, __leaf__))) -int libcoopgamma_crtc_info_unmarshal(libcoopgamma_crtc_info_t* restrict, - const void* restrict, size_t* restrict); - - -/** - * Initialise a `libcoopgamma_filter_query_t` - * - * @param this The record to initialise - * @return Zero on success, -1 on error - */ -LIBCOOPGAMMA_GCC_ONLY(__attribute__((__nonnull__, __leaf__))) -int libcoopgamma_filter_query_initialise(libcoopgamma_filter_query_t* restrict); - -/** - * Release all resources allocated to a `libcoopgamma_filter_query_t`, - * the allocation of the record itself is not freed - * - * Always call this function after failed call to `libcoopgamma_filter_query_initialise` - * or failed call to `libcoopgamma_filter_query_unmarshal` - * - * @param this The record to destroy - */ -LIBCOOPGAMMA_GCC_ONLY(__attribute__((__nonnull__, __leaf__))) -void libcoopgamma_filter_query_destroy(libcoopgamma_filter_query_t* restrict); - -/** - * Marshal a `libcoopgamma_filter_query_t` into a buffer - * - * @param this The record to marshal - * @param buf The output buffer, `NULL` to only measure - * how large this buffer has to be - * @return The number of marshalled bytes, or if `buf == NULL`, - * how many bytes would be marshalled if `buf != NULL` - */ -LIBCOOPGAMMA_GCC_ONLY(__attribute__((__nonnull__(1), __leaf__))) -size_t libcoopgamma_filter_query_marshal(const libcoopgamma_filter_query_t* restrict, void* restrict); - -/** - * Unmarshal a `libcoopgamma_filter_query_t` from a buffer - * - * @param this The output parameter for unmarshalled record - * @param buf The buffer with the marshalled record - * @param n Output parameter for the number of unmarshalled bytes, undefined on failure - * @return `LIBCOOPGAMMA_SUCCESS` (0), `LIBCOOPGAMMA_INCOMPATIBLE_DOWNGRADE`, - * `LIBCOOPGAMMA_INCOMPATIBLE_UPGRADE`, or `LIBCOOPGAMMA_ERRNO_SET` - */ -LIBCOOPGAMMA_GCC_ONLY(__attribute__((__nonnull__, __leaf__))) -int libcoopgamma_filter_query_unmarshal(libcoopgamma_filter_query_t* restrict, - const void* restrict, size_t* restrict); - - -/** - * Initialise a `libcoopgamma_queried_filter_t` - * - * @param this The record to initialise - * @return Zero on success, -1 on error - */ -LIBCOOPGAMMA_GCC_ONLY(__attribute__((__nonnull__, __leaf__))) -int libcoopgamma_queried_filter_initialise(libcoopgamma_queried_filter_t* restrict); - -/** - * Release all resources allocated to a `libcoopgamma_queried_filter_t`, - * the allocation of the record itself is not freed - * - * Always call this function after failed call to `libcoopgamma_queried_filter_initialise` - * or failed call to `libcoopgamma_queried_filter_unmarshal` - * - * @param this The record to destroy - */ -LIBCOOPGAMMA_GCC_ONLY(__attribute__((__nonnull__))) -void libcoopgamma_queried_filter_destroy(libcoopgamma_queried_filter_t* restrict); - -/** - * Marshal a `libcoopgamma_queried_filter_t` into a buffer - * - * @param this The record to marshal - * @param buf The output buffer, `NULL` to only measure - * how large this buffer has to be - * @param depth The type used of ramp stops - * @return The number of marshalled bytes, or if `buf == NULL`, - * how many bytes would be marshalled if `buf != NULL` - */ -LIBCOOPGAMMA_GCC_ONLY(__attribute__((__nonnull__(1)))) -size_t libcoopgamma_queried_filter_marshal(const libcoopgamma_queried_filter_t* restrict, void* restrict, - libcoopgamma_depth_t); - -/** - * Unmarshal a `libcoopgamma_queried_filter_t` from a buffer - * - * @param this The output parameter for unmarshalled record - * @param buf The buffer with the marshalled record - * @param n Output parameter for the number of unmarshalled bytes, undefined on failure - * @param depth The type used of ramp stops - * @return `LIBCOOPGAMMA_SUCCESS` (0), `LIBCOOPGAMMA_INCOMPATIBLE_DOWNGRADE`, - * `LIBCOOPGAMMA_INCOMPATIBLE_UPGRADE`, or `LIBCOOPGAMMA_ERRNO_SET` - */ -LIBCOOPGAMMA_GCC_ONLY(__attribute__((__nonnull__))) -int libcoopgamma_queried_filter_unmarshal(libcoopgamma_queried_filter_t* restrict, - const void* restrict, size_t* restrict, libcoopgamma_depth_t); - - -/** - * Initialise a `libcoopgamma_filter_table_t` - * - * @param this The record to initialise - * @return Zero on success, -1 on error - */ -LIBCOOPGAMMA_GCC_ONLY(__attribute__((__nonnull__, __leaf__))) -int libcoopgamma_filter_table_initialise(libcoopgamma_filter_table_t* restrict); - -/** - * Release all resources allocated to a `libcoopgamma_filter_table_t`, - * the allocation of the record itself is not freed - * - * Always call this function after failed call to `libcoopgamma_filter_table_initialise` - * or failed call to `libcoopgamma_filter_table_unmarshal` - * - * @param this The record to destroy - */ -LIBCOOPGAMMA_GCC_ONLY(__attribute__((__nonnull__))) -void libcoopgamma_filter_table_destroy(libcoopgamma_filter_table_t* restrict); - -/** - * Marshal a `libcoopgamma_filter_table_t` into a buffer - * - * @param this The record to marshal - * @param buf The output buffer, `NULL` to only measure - * how large this buffer has to be - * @return The number of marshalled bytes, or if `buf == NULL`, - * how many bytes would be marshalled if `buf != NULL` - */ -LIBCOOPGAMMA_GCC_ONLY(__attribute__((__nonnull__(1)))) -size_t libcoopgamma_filter_table_marshal(const libcoopgamma_filter_table_t* restrict, void* restrict); - -/** - * Unmarshal a `libcoopgamma_filter_table_t` from a buffer - * - * @param this The output parameter for unmarshalled record - * @param buf The buffer with the marshalled record - * @param n Output parameter for the number of unmarshalled bytes, undefined on failure - * @return `LIBCOOPGAMMA_SUCCESS` (0), `LIBCOOPGAMMA_INCOMPATIBLE_DOWNGRADE`, - * `LIBCOOPGAMMA_INCOMPATIBLE_UPGRADE`, or `LIBCOOPGAMMA_ERRNO_SET` - */ -LIBCOOPGAMMA_GCC_ONLY(__attribute__((__nonnull__))) -int libcoopgamma_filter_table_unmarshal(libcoopgamma_filter_table_t* restrict, - const void* restrict, size_t* restrict); - - -/** - * Initialise a `libcoopgamma_error_t` - * - * @param this The record to initialise - * @return Zero on success, -1 on error - */ -LIBCOOPGAMMA_GCC_ONLY(__attribute__((__nonnull__, __leaf__))) -int libcoopgamma_error_initialise(libcoopgamma_error_t* restrict); - -/** - * Release all resources allocated to a `libcoopgamma_error_t`, - * the allocation of the record itself is not freed - * - * Always call this function after failed call to `libcoopgamma_error_initialise` - * or failed call to `libcoopgamma_error_unmarshal` - * - * @param this The record to destroy - */ -LIBCOOPGAMMA_GCC_ONLY(__attribute__((__nonnull__, __leaf__))) -void libcoopgamma_error_destroy(libcoopgamma_error_t* restrict); - -/** - * Marshal a `libcoopgamma_error_t` into a buffer - * - * @param this The record to marshal - * @param buf The output buffer, `NULL` to only measure - * how large this buffer has to be - * @return The number of marshalled bytes, or if `buf == NULL`, - * how many bytes would be marshalled if `buf != NULL` - */ -LIBCOOPGAMMA_GCC_ONLY(__attribute__((__nonnull__(1), __leaf__))) -size_t libcoopgamma_error_marshal(const libcoopgamma_error_t* restrict, void* restrict); - -/** - * Unmarshal a `libcoopgamma_error_t` from a buffer - * - * @param this The output parameter for unmarshalled record - * @param buf The buffer with the marshalled record - * @param n Output parameter for the number of unmarshalled bytes, undefined on failure - * @return `LIBCOOPGAMMA_SUCCESS` (0), `LIBCOOPGAMMA_INCOMPATIBLE_DOWNGRADE`, - * `LIBCOOPGAMMA_INCOMPATIBLE_UPGRADE`, or `LIBCOOPGAMMA_ERRNO_SET` - */ -LIBCOOPGAMMA_GCC_ONLY(__attribute__((__nonnull__, __leaf__))) -int libcoopgamma_error_unmarshal(libcoopgamma_error_t* restrict, const void* restrict, size_t* restrict); - - -/** - * Initialise a `libcoopgamma_context_t` - * - * @param this The record to initialise - * @return Zero on success, -1 on error - */ -LIBCOOPGAMMA_GCC_ONLY(__attribute__((__nonnull__, __leaf__))) -int libcoopgamma_context_initialise(libcoopgamma_context_t* restrict); - -/** - * Release all resources allocated to a `libcoopgamma_context_t`, - * the allocation of the record itself is not freed - * - * Always call this function after failed call to `libcoopgamma_context_initialise` - * or failed call to `libcoopgamma_context_unmarshal` - * - * @param this The record to destroy - * @param disconnect Disconnect from the server? - */ -LIBCOOPGAMMA_GCC_ONLY(__attribute__((__nonnull__))) -void libcoopgamma_context_destroy(libcoopgamma_context_t* restrict, int); - -/** - * Marshal a `libcoopgamma_context_t` into a buffer - * - * @param this The record to marshal - * @param buf The output buffer, `NULL` to only measure - * how large this buffer has to be - * @return The number of marshalled bytes, or if `buf == NULL`, - * how many bytes would be marshalled if `buf != NULL` - */ -LIBCOOPGAMMA_GCC_ONLY(__attribute__((__nonnull__(1)))) -size_t libcoopgamma_context_marshal(const libcoopgamma_context_t* restrict, void* restrict); - -/** - * Unmarshal a `libcoopgamma_context_t` from a buffer - * - * @param this The output parameter for unmarshalled record - * @param buf The buffer with the marshalled record - * @param n Output parameter for the number of unmarshalled bytes, undefined on failure - * @return `LIBCOOPGAMMA_SUCCESS` (0), `LIBCOOPGAMMA_INCOMPATIBLE_DOWNGRADE`, - * `LIBCOOPGAMMA_INCOMPATIBLE_UPGRADE`, or `LIBCOOPGAMMA_ERRNO_SET` - */ -LIBCOOPGAMMA_GCC_ONLY(__attribute__((__nonnull__))) -int libcoopgamma_context_unmarshal(libcoopgamma_context_t* restrict, const void* restrict, size_t* restrict); - - -/** - * Initialise a `libcoopgamma_async_context_t` - * - * @param this The record to initialise - * @return Zero on success, -1 on error - */ -LIBCOOPGAMMA_GCC_ONLY(__attribute__((__nonnull__, __leaf__))) -int libcoopgamma_async_context_initialise(libcoopgamma_async_context_t* restrict); - -/** - * Release all resources allocated to a `libcoopgamma_async_context_t`, - * the allocation of the record itself is not freed - * - * Always call this function after failed call to `libcoopgamma_async_context_initialise` - * or failed call to `libcoopgamma_async_context_unmarshal` - * - * @param this The record to destroy - */ -LIBCOOPGAMMA_GCC_ONLY(__attribute__((__nonnull__, __leaf__))) -void libcoopgamma_async_context_destroy(libcoopgamma_async_context_t* restrict); - -/** - * Marshal a `libcoopgamma_async_context_t` into a buffer - * - * @param this The record to marshal - * @param buf The output buffer, `NULL` to only measure - * how large this buffer has to be - * @return The number of marshalled bytes, or if `buf == NULL`, - * how many bytes would be marshalled if `buf != NULL` - */ -LIBCOOPGAMMA_GCC_ONLY(__attribute__((__nonnull__(1), __leaf__))) -size_t libcoopgamma_async_context_marshal(const libcoopgamma_async_context_t* restrict, void* restrict); - -/** - * Unmarshal a `libcoopgamma_async_context_t` from a buffer - * - * @param this The output parameter for unmarshalled record - * @param buf The buffer with the marshalled record - * @param n Output parameter for the number of unmarshalled bytes, undefined on failure - * @return `LIBCOOPGAMMA_SUCCESS` (0), `LIBCOOPGAMMA_INCOMPATIBLE_DOWNGRADE`, - * `LIBCOOPGAMMA_INCOMPATIBLE_UPGRADE`, or `LIBCOOPGAMMA_ERRNO_SET` - */ -LIBCOOPGAMMA_GCC_ONLY(__attribute__((__nonnull__, __leaf__))) -int libcoopgamma_async_context_unmarshal(libcoopgamma_async_context_t* restrict, const void* restrict, - size_t* restrict); - - -/** - * List all recognised adjustment method - * - * SIGCHLD must not be ignored or blocked - * - * @return A `NULL`-terminated list of names. You should only free - * the outer pointer, inner pointers are subpointers of the - * outer pointer and cannot be freed. `NULL` on error. - */ -LIBCOOPGAMMA_GCC_ONLY(__attribute__((__malloc__))) -char** libcoopgamma_get_methods(void); - -/** - * Get the adjustment method and site - * - * SIGCHLD must not be ignored or blocked - * - * @param method The adjustment method, `NULL` for automatic - * @param site The site, `NULL` for automatic - * @param methodp Output pointer for the selected adjustment method, - * which cannot be `NULL`. It is safe to call - * this function with this parameter set to `NULL`. - * @param sitep Output pointer for the selected site, which will - * be `NULL` the method only supports one site or if - * `site == NULL` and no site can be selected - * automatically. It is safe to call this function - * with this parameter set to `NULL`. - * @return Zero on success, -1 on error - */ -int libcoopgamma_get_method_and_site(const char* restrict, const char* restrict, - char** restrict, char** restrict); - -/** - * Get the PID file of the coopgamma server - * - * SIGCHLD must not be ignored or blocked - * - * @param method The adjustment method, `NULL` for automatic - * @param site The site, `NULL` for automatic - * @return The pathname of the server's PID file, `NULL` on error - * or if there server does not use PID files. The later - * case is detected by checking that `errno` is set to 0. - */ -LIBCOOPGAMMA_GCC_ONLY(__attribute__((__malloc__))) -char* libcoopgamma_get_pid_file(const char* restrict, const char* restrict); - -/** - * Get the socket file of the coopgamma server - * - * SIGCHLD must not be ignored or blocked - * - * @param method The adjustment method, `NULL` for automatic - * @param site The site, `NULL` for automatic - * @return The pathname of the server's socket, `NULL` on error - * or if there server does have its own socket. The later - * case is detected by checking that `errno` is set to 0, - * and is the case when communicating with a server in a - * multi-server display server like mds. - */ -LIBCOOPGAMMA_GCC_ONLY(__attribute__((__malloc__))) -char* libcoopgamma_get_socket_file(const char* restrict, const char* restrict); - - -/** - * Connect to a coopgamma server, and start it if necessary - * - * Use `libcoopgamma_context_destroy` to disconnect - * - * SIGCHLD must not be ignored or blocked - * - * @param method The adjustment method, `NULL` for automatic - * @param site The site, `NULL` for automatic - * @param ctx The state of the library, must be initialised - * @return Zero on success, -1 on error. On error, `errno` is set - * to 0 if the server could not be initialised. - */ -LIBCOOPGAMMA_GCC_ONLY(__attribute__((__nonnull__(3)))) -int libcoopgamma_connect(const char* restrict, const char* restrict, libcoopgamma_context_t* restrict); - -/** - * By default communication is blocking, this function - * can be used to switch between blocking and nonblocking - * - * After setting the communication to nonblocking, - * `libcoopgamma_flush`, `libcoopgamma_synchronise` and - * and request-sending functions can fail with EAGAIN and - * EWOULDBLOCK. It is safe to continue with `libcoopgamma_flush` - * (for `libcoopgamma_flush` it selfand equest-sending functions) - * or `libcoopgamma_synchronise` just like EINTR failure. - * - * @param ctx The state of the library, must be connected - * @param nonblocking Nonblocking mode? - * @return Zero on success, -1 on error - */ -LIBCOOPGAMMA_GCC_ONLY(__attribute__((__nonnull__, __leaf__))) -int libcoopgamma_set_nonblocking(libcoopgamma_context_t* restrict, int); - -/** - * Send all pending outbound data - * - * If this function or another function that sends a request - * to the server fails with EINTR, call this function to - * complete the transfer. The `async` parameter will always - * be in a properly configured state if a function fails - * with EINTR. - * - * @param ctx The state of the library, must be connected - * @return Zero on success, -1 on error - */ -LIBCOOPGAMMA_GCC_ONLY(__attribute__((__nonnull__, __leaf__))) -int libcoopgamma_flush(libcoopgamma_context_t* restrict); - -/** - * Wait for the next message to be received - * - * @param ctx The state of the library, must be connected - * @param pending Information for each pending request - * @param n The number of elements in `pending` - * @param selected The index of the element in `pending` which corresponds - * to the first inbound message, note that this only means - * that the message is not for any of the other request, - * if the message is corrupt any of the listed requests can - * be selected even if it is not for any of the requests. - * Functions that parse the message will detect such corruption. - * @return Zero on success, -1 on error. If the the message is ignored, - * which happens if corresponding `libcoopgamma_async_context_t` - * is not listed, -1 is returned and `errno` is set to 0. If -1 - * is returned, `errno` is set to `ENOTRECOVERABLE` you have - * received a corrupt message and the context has been tainted - * beyond recover. - */ -LIBCOOPGAMMA_GCC_ONLY(__attribute__((__nonnull__(1, 4), __leaf__))) -int libcoopgamma_synchronise(libcoopgamma_context_t* restrict, libcoopgamma_async_context_t* restrict, - size_t, size_t* restrict); - -/** - * Tell the library that you will not be parsing a receive message - * - * @param ctx The state of the library, must be connected - */ -LIBCOOPGAMMA_GCC_ONLY(__attribute__((__nonnull__))) -void libcoopgamma_skip_message(libcoopgamma_context_t* restrict); - - -/** - * List all available CRTC:s, send request part - * - * Cannot be used before connecting to the server - * - * @param ctx The state of the library, must be connected - * @param async Information about the request, that is needed to - * identify and parse the response, is stored here - * @return Zero on success, -1 on error - */ -LIBCOOPGAMMA_GCC_ONLY(__attribute__((__nonnull__))) -int libcoopgamma_get_crtcs_send(libcoopgamma_context_t* restrict, libcoopgamma_async_context_t* restrict); - -/** - * List all available CRTC:s, receive response part - * - * @param ctx The state of the library, must be connected - * @param async Information about the request - * @return A `NULL`-terminated list of names. You should only free - * the outer pointer, inner pointers are subpointers of the - * outer pointer and cannot be freed. `NULL` on error, in - * which case `ctx->error` (rather than `errno`) is read - * for information about the error. - */ -LIBCOOPGAMMA_GCC_ONLY(__attribute__((__malloc__, __nonnull__))) -char** libcoopgamma_get_crtcs_recv(libcoopgamma_context_t* restrict, libcoopgamma_async_context_t* restrict); - -/** - * List all available CRTC:s, synchronous version - * - * This is a synchronous request function, as such, - * you have to ensure that communication is blocking - * (default), and that there are not asynchronous - * requests waiting, it also means that EINTR:s are - * silently ignored and there no wait to cancel the - * operation without disconnection from the server - * - * @param ctx The state of the library, must be connected - * @return A `NULL`-terminated list of names. You should only free - * the outer pointer, inner pointers are subpointers of the - * outer pointer and cannot be freed. `NULL` on error, in - * which case `ctx->error` (rather than `errno`) is read - * for information about the error. - */ -LIBCOOPGAMMA_GCC_ONLY(__attribute__((__malloc__, __nonnull__))) -char** libcoopgamma_get_crtcs_sync(libcoopgamma_context_t* restrict); - - -/** - * Retrieve information about a CRTC:s gamma ramps, send request part - * - * Cannot be used before connecting to the server - * - * @param crtc The name of the CRTC - * @param ctx The state of the library, must be connected - * @param async Information about the request, that is needed to - * identify and parse the response, is stored here - * @return Zero on success, -1 on error - */ -LIBCOOPGAMMA_GCC_ONLY(__attribute__((__nonnull__))) -int libcoopgamma_get_gamma_info_send(const char* restrict, libcoopgamma_context_t* restrict, - libcoopgamma_async_context_t* restrict); - -/** - * Retrieve information about a CRTC:s gamma ramps, receive response part - * - * @param info Output parameter for the information, must be initialised - * @param ctx The state of the library, must be connected - * @param async Information about the request - * @return Zero on success, -1 on error, in which case `ctx->error` - * (rather than `errno`) is read for information about the error - */ -LIBCOOPGAMMA_GCC_ONLY(__attribute__((__nonnull__))) -int libcoopgamma_get_gamma_info_recv(libcoopgamma_crtc_info_t* restrict, libcoopgamma_context_t* restrict, - libcoopgamma_async_context_t* restrict); - -/** - * Retrieve information about a CRTC:s gamma ramps, synchronous version - * - * This is a synchronous request function, as such, - * you have to ensure that communication is blocking - * (default), and that there are not asynchronous - * requests waiting, it also means that EINTR:s are - * silently ignored and there no wait to cancel the - * operation without disconnection from the server - * - * @param crtc The name of the CRTC - * @param info Output parameter for the information, must be initialised - * @param ctx The state of the library, must be connected - * @return Zero on success, -1 on error, in which case `ctx->error` - * (rather than `errno`) is read for information about the error - */ -LIBCOOPGAMMA_GCC_ONLY(__attribute__((__nonnull__))) -int libcoopgamma_get_gamma_info_sync(const char* restrict, libcoopgamma_crtc_info_t* restrict, - libcoopgamma_context_t* restrict); - - -/** - * Retrieve the current gamma ramp adjustments, send request part - * - * Cannot be used before connecting to the server - * - * @param query The query to send - * @param ctx The state of the library, must be connected - * @param async Information about the request, that is needed to - * identify and parse the response, is stored here - * @return Zero on success, -1 on error - */ -LIBCOOPGAMMA_GCC_ONLY(__attribute__((__nonnull__))) -int libcoopgamma_get_gamma_send(const libcoopgamma_filter_query_t* restrict, libcoopgamma_context_t* restrict, - libcoopgamma_async_context_t* restrict); - -/** - * Retrieve the current gamma ramp adjustments, receive response part - * - * @param table Output for the response, must be initialised - * @param ctx The state of the library, must be connected - * @param async Information about the request - * @return Zero on success, -1 on error, in which case `ctx->error` - * (rather than `errno`) is read for information about the error - */ -LIBCOOPGAMMA_GCC_ONLY(__attribute__((__nonnull__))) -int libcoopgamma_get_gamma_recv(libcoopgamma_filter_table_t* restrict, libcoopgamma_context_t* restrict, - libcoopgamma_async_context_t* restrict); - -/** - * Retrieve the current gamma ramp adjustments, synchronous version - * - * This is a synchronous request function, as such, - * you have to ensure that communication is blocking - * (default), and that there are not asynchronous - * requests waiting, it also means that EINTR:s are - * silently ignored and there no wait to cancel the - * operation without disconnection from the server - * - * @param query The query to send - * @param table Output for the response, must be initialised - * @param ctx The state of the library, must be connected - * @return Zero on success, -1 on error, in which case `ctx->error` - * (rather than `errno`) is read for information about the error - */ -LIBCOOPGAMMA_GCC_ONLY(__attribute__((__nonnull__))) -int libcoopgamma_get_gamma_sync(const libcoopgamma_filter_query_t* restrict, - libcoopgamma_filter_table_t* restrict, - libcoopgamma_context_t* restrict); - - -/** - * Apply, update, or remove a gamma ramp adjustment, send request part - * - * Cannot be used before connecting to the server - * - * @param filter The filter to apply, update, or remove, gamma ramp meta-data must match the CRTC's - * @param ctx The state of the library, must be connected - * @param async Information about the request, that is needed to - * identify and parse the response, is stored here - * @return Zero on success, -1 on error - */ -LIBCOOPGAMMA_GCC_ONLY(__attribute__((__nonnull__))) -int libcoopgamma_set_gamma_send(const libcoopgamma_filter_t* restrict, - libcoopgamma_context_t* restrict, libcoopgamma_async_context_t* restrict); - -/** - * Apply, update, or remove a gamma ramp adjustment, receive response part - * - * @param ctx The state of the library, must be connected - * @param async Information about the request - * @return Zero on success, -1 on error, in which case `ctx->error` - * (rather than `errno`) is read for information about the error - */ -LIBCOOPGAMMA_GCC_ONLY(__attribute__((__nonnull__))) -int libcoopgamma_set_gamma_recv(libcoopgamma_context_t* restrict, libcoopgamma_async_context_t* restrict); - -/** - * Apply, update, or remove a gamma ramp adjustment, synchronous version - * - * This is a synchronous request function, as such, - * you have to ensure that communication is blocking - * (default), and that there are not asynchronous - * requests waiting, it also means that EINTR:s are - * silently ignored and there no wait to cancel the - * operation without disconnection from the server - * - * @param filter The filter to apply, update, or remove, gamma ramp meta-data must match the CRTC's - * @param ctx The state of the library, must be connected - * @return Zero on success, -1 on error, in which case `ctx->error` - * (rather than `errno`) is read for information about the error - */ -LIBCOOPGAMMA_GCC_ONLY(__attribute__((__nonnull__))) -int libcoopgamma_set_gamma_sync(const libcoopgamma_filter_t* restrict, libcoopgamma_context_t* restrict); - - - -#if defined(__clang__) -# pragma GCC diagnostic pop -#endif - -#undef LIBCOOPGAMMA_GCC_ONLY - - - -#endif - diff --git a/src/test.c b/src/test.c deleted file mode 100644 index 4a94a42..0000000 --- a/src/test.c +++ /dev/null @@ -1,273 +0,0 @@ -/** - * libcoopgamma -- Library for interfacing with cooperative gamma servers - * Copyright (C) 2016 Mattias Andrée (maandree@kth.se) - * - * This library is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this library. If not, see . - */ -#include "libcoopgamma.h" - -#include -#include -#include - - -static int streq(const char* a, const char* b) -{ - if ((a == NULL) != (b == NULL)) - return 0; - return (a == NULL) || !strcmp(a, b); -} - - -static int rampseq(const libcoopgamma_ramps_t* a, const libcoopgamma_ramps_t* b, libcoopgamma_depth_t depth) -{ - size_t nr, ng, nb, width; - - if ((a->u8.red_size != b->u8.red_size) || - (a->u8.green_size != b->u8.green_size) || - (a->u8.blue_size != b->u8.blue_size)) - return 0; - - if (depth == -2) - width = sizeof(double); - else if (depth == -1) - width = sizeof(float); - else - width = ((size_t)depth) / 8; - - nr = a->u8.red_size * width; - ng = a->u8.green_size * width; - nb = a->u8.blue_size * width; - - if (memcmp(a->u8.red, b->u8.red, nr + ng + nb)) - return 0; - if (memcmp(a->u8.green, b->u8.green, ng + nb)) - return 0; - if (memcmp(a->u8.blue, b->u8.blue, nb)) - return 0; - - return 1; -} - - -int main(void) -{ - libcoopgamma_filter_t filter1, filter2; - libcoopgamma_crtc_info_t crtc1, crtc2; - libcoopgamma_filter_query_t query1, query2; - libcoopgamma_filter_table_t table1, table2; - libcoopgamma_context_t ctx1, ctx2; - libcoopgamma_async_context_t async1, async2; - size_t n, m, i; - char* buf; - - filter1.priority = INT64_MIN; - filter1.crtc = "CRTC"; - filter1.class = "A::B::C::D"; - filter1.lifespan = LIBCOOPGAMMA_UNTIL_REMOVAL; - filter1.depth = LIBCOOPGAMMA_DOUBLE; - filter1.ramps.d.red_size = 4; - filter1.ramps.d.green_size = 5; - filter1.ramps.d.blue_size = 6; - filter1.ramps.d.red = (double[]){0.0, 0.1, 0.2, 0.5, - 0.3, 0.11, 0.22, 0.45, 0.9, - -1, -0.5, 0, 0.5, 1, 1.5}; - filter1.ramps.d.green = filter1.ramps.d.red + filter1.ramps.d.red_size; - filter1.ramps.d.blue = filter1.ramps.d.green + filter1.ramps.d.green_size; - - crtc1.cooperative = 0; - crtc1.depth = LIBCOOPGAMMA_DOUBLE; - crtc1.supported = LIBCOOPGAMMA_YES; - crtc1.red_size = 4; - crtc1.green_size = 5; - crtc1.blue_size = 6; - crtc1.colourspace = LIBCOOPGAMMA_SRGB; - crtc1.have_gamut = 1; - crtc1.red_x = 100; - crtc1.red_y = 50; - crtc1.green_x = 300; - crtc1.green_y = 350; - crtc1.blue_x = 200; - crtc1.blue_y = 260; - crtc1.white_x = 500; - crtc1.white_y = 999; - - query1.high_priority = INT64_MIN; - query1.low_priority = INT64_MIN; - query1.crtc = "crtc"; - query1.coalesce = 1; - - table1.red_size = 4; - table1.green_size = 5; - table1.blue_size = 6; - table1.filter_count = 2; - table1.filters = (libcoopgamma_queried_filter_t[]){ - { - .priority = UINT64_MAX, - .class = "a::b::c", - .ramps.d = { - .red_size = 4, - .green_size = 5, - .blue_size = 6, - .red = (double[]){0.0, 0.1, 0.2, 0.5, - 0.3, 0.11, 0.22, 0.45, 0.9, - -1, -0.5, 0, 0.5, 1, 1.5} - } - }, { - .priority = UINT64_MAX - 1, - .class = NULL, - .ramps.d = { - .red_size = 4, - .green_size = 5, - .blue_size = 6, - .red = (double[]){0.02, 0.12, 0.22, 0.52, - 0.32, 0.112, 0.222, 0.452, 0.92, - -12, -0.52, 0.2, 0.52, 12, 1.52} - } - } - }; - table1.depth = LIBCOOPGAMMA_DOUBLE; - table1.filters[0].ramps.d.green = table1.filters[0].ramps.d.red + table1.filters[0].ramps.d.red_size; - table1.filters[1].ramps.d.green = table1.filters[1].ramps.d.red + table1.filters[1].ramps.d.red_size; - table1.filters[0].ramps.d.blue = table1.filters[0].ramps.d.green + table1.filters[0].ramps.d.green_size; - table1.filters[1].ramps.d.blue = table1.filters[1].ramps.d.green + table1.filters[1].ramps.d.green_size; - - ctx1.error.number = UINT64_MAX; - ctx1.error.custom = 1; - ctx1.error.server_side = 0; - ctx1.error.description = "description"; - ctx1.fd = 3; - ctx1.have_all_headers = 1; - ctx1.bad_message = 0; - ctx1.blocking = 2; - ctx1.message_id = UINT32_MAX; - ctx1.in_response_to = UINT32_MAX - 1; - ctx1.outbound = "0123456789"; - ctx1.outbound_head = 7; - ctx1.outbound_tail = 2; - ctx1.outbound_size = 10; - ctx1.inbound = "abcdefghi"; - ctx1.inbound_head = 6; - ctx1.inbound_tail = 3; - ctx1.inbound_size = 9; - ctx1.length = 100; - ctx1.curline = 5; - - async1.message_id = UINT32_MAX; - async1.coalesce = 1; - - n = libcoopgamma_filter_marshal(&filter1, NULL); - n += libcoopgamma_crtc_info_marshal(&crtc1, NULL); - n += libcoopgamma_filter_query_marshal(&query1, NULL); - n += libcoopgamma_filter_table_marshal(&table1, NULL); - n += libcoopgamma_context_marshal(&ctx1, NULL); - n += libcoopgamma_async_context_marshal(&async1, NULL); - - buf = malloc(n); - n = libcoopgamma_filter_marshal(&filter1, buf); - n += libcoopgamma_crtc_info_marshal(&crtc1, buf + n); - n += libcoopgamma_filter_query_marshal(&query1, buf + n); - n += libcoopgamma_filter_table_marshal(&table1, buf + n); - n += libcoopgamma_context_marshal(&ctx1, buf + n); - n += libcoopgamma_async_context_marshal(&async1, buf + n); - - if (libcoopgamma_filter_unmarshal(&filter2, buf, &m)) return 1; else n = m; - if (libcoopgamma_crtc_info_unmarshal(&crtc2, buf + n, &m)) return 2; else n += m; - if (libcoopgamma_filter_query_unmarshal(&query2, buf + n, &m)) return 3; else n += m; - if (libcoopgamma_filter_table_unmarshal(&table2, buf + n, &m)) return 4; else n += m; - if (libcoopgamma_context_unmarshal(&ctx2, buf + n, &m)) return 5; else n += m; - if (libcoopgamma_async_context_unmarshal(&async2, buf + n, &m)) return 6; - free(buf); - - if ((filter1.priority != filter2.priority) || - (!streq(filter1.crtc, filter2.crtc)) || - (!streq(filter1.class, filter2.class)) || - (filter1.lifespan != filter2.lifespan) || - (filter1.depth != filter2.depth) || - (!rampseq(&(filter1.ramps), &(filter2.ramps), filter1.depth))) - return 7; - - if ((crtc1.cooperative != crtc2.cooperative) || - (crtc1.depth != crtc2.depth) || - (crtc1.supported != crtc2.supported) || - (crtc1.red_size != crtc2.red_size) || - (crtc1.green_size != crtc2.green_size) || - (crtc1.blue_size != crtc2.blue_size) || - (crtc1.colourspace != crtc2.colourspace) || - (crtc1.have_gamut != crtc2.have_gamut) || - (crtc1.red_x != crtc2.red_x) || - (crtc1.red_y != crtc2.red_y) || - (crtc1.green_x != crtc2.green_x) || - (crtc1.green_y != crtc2.green_y) || - (crtc1.blue_x != crtc2.blue_x) || - (crtc1.blue_y != crtc2.blue_y) || - (crtc1.white_x != crtc2.white_x) || - (crtc1.white_y != crtc2.white_y)) - return 8; - - if ((query1.high_priority != query2.high_priority) || - (query1.low_priority != query2.low_priority) || - !streq(query1.crtc, query2.crtc) || - (query1.coalesce != query2.coalesce)) - return 9; - - if ((table1.red_size != table2.red_size) || - (table1.green_size != table2.green_size) || - (table1.blue_size != table2.blue_size) || - (table1.filter_count != table2.filter_count) || - (table1.depth != table2.depth)) - return 10; - for (i = 0; i < table1.filter_count; i++) - if ((table1.filters[i].priority != table2.filters[i].priority) || - !streq(table1.filters[i].class, table2.filters[i].class) || - !rampseq(&(table1.filters[i].ramps), &(table2.filters[i].ramps), table1.depth)) - return 11; - - if ((ctx1.error.number != ctx2.error.number) || - (ctx1.error.custom != ctx2.error.custom) || - (ctx1.error.server_side != ctx2.error.server_side) || - !streq(ctx1.error.description, ctx2.error.description)) - return 12; - - if ((ctx1.fd != ctx2.fd) || - (ctx1.have_all_headers != ctx2.have_all_headers) || - (ctx1.bad_message != ctx2.bad_message) || - (ctx1.blocking != ctx2.blocking) || - (ctx1.message_id != ctx2.message_id) || - (ctx1.in_response_to != ctx2.in_response_to) || - (ctx1.length != ctx2.length) || - (ctx1.curline != ctx2.curline)) - return 13; - - if ((ctx2.outbound_head > ctx2.outbound_size) || - (ctx2.outbound_tail > ctx2.outbound_size) || - (ctx2.inbound_head > ctx2.inbound_size) || - (ctx2.inbound_tail > ctx2.inbound_size)) - return 14; - - if (((n = ctx1.outbound_head - ctx1.outbound_tail) != ctx2.outbound_head - ctx2.outbound_tail) || - ((m = ctx1.inbound_head - ctx1.inbound_tail) != ctx2.inbound_head - ctx2.inbound_tail)) - return 15; - - if (memcmp(ctx1.outbound + ctx1.outbound_tail, ctx2.outbound + ctx2.outbound_tail, n) || - memcmp(ctx1.inbound + ctx1.inbound_tail, ctx2.inbound + ctx2.inbound_tail, m)) - return 16; - - if ((async1.message_id != async2.message_id) || - (async1.coalesce != async2.coalesce)) - return 17; - - return 0; -} - -- cgit v1.2.3-70-g09d2