Mon, 27 Dec 2021 16:51:10 +0100
add ported UCX buffer implementation
Notes:
* ucx_buffer_extend has been removed
in favor of cxBufferMinimumCapacity
* the buffer struct now has a union for
char* and unsigned char* buffers
src/CMakeLists.txt | file | annotate | diff | comparison | revisions | |
src/buffer.c | file | annotate | diff | comparison | revisions | |
src/cx/buffer.h | file | annotate | diff | comparison | revisions | |
src/cx/common.h | file | annotate | diff | comparison | revisions | |
src/cx/utils.h | file | annotate | diff | comparison | revisions | |
src/utils.c | file | annotate | diff | comparison | revisions |
1.1 --- a/src/CMakeLists.txt Mon Dec 27 14:44:08 2021 +0100 1.2 +++ b/src/CMakeLists.txt Mon Dec 27 16:51:10 2021 +0100 1.3 @@ -1,13 +1,17 @@ 1.4 set(sources 1.5 + utils.c 1.6 allocator.c 1.7 linked_list.c 1.8 tree.c 1.9 + buffer.c 1.10 ) 1.11 set(headers 1.12 + cx/utils.h 1.13 cx/allocator.h 1.14 cx/list.h 1.15 cx/linked_list.h 1.16 cx/tree.h 1.17 + cx/buffer.h 1.18 ) 1.19 1.20 add_library(ucx SHARED ${sources})
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/src/buffer.c Mon Dec 27 16:51:10 2021 +0100 2.3 @@ -0,0 +1,328 @@ 2.4 +/* 2.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 2.6 + * 2.7 + * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved. 2.8 + * 2.9 + * Redistribution and use in source and binary forms, with or without 2.10 + * modification, are permitted provided that the following conditions are met: 2.11 + * 2.12 + * 1. Redistributions of source code must retain the above copyright 2.13 + * notice, this list of conditions and the following disclaimer. 2.14 + * 2.15 + * 2. Redistributions in binary form must reproduce the above copyright 2.16 + * notice, this list of conditions and the following disclaimer in the 2.17 + * documentation and/or other materials provided with the distribution. 2.18 + * 2.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 2.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 2.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 2.29 + * POSSIBILITY OF SUCH DAMAGE. 2.30 + */ 2.31 + 2.32 +#include "cx/buffer.h" 2.33 +#include "cx/utils.h" 2.34 + 2.35 +#include <stdlib.h> 2.36 +#include <string.h> 2.37 + 2.38 +CxBuffer cxBufferCreate( 2.39 + void *space, 2.40 + size_t capacity, 2.41 + int flags 2.42 +) { 2.43 + CxBuffer buffer = (CxBuffer) malloc(sizeof(cx_buffer_s)); 2.44 + if (buffer) { 2.45 + buffer->flags = flags; 2.46 + if (!space) { 2.47 + buffer->bytes = malloc(capacity); 2.48 + if (!buffer->bytes) { 2.49 + free(buffer); 2.50 + return NULL; 2.51 + } 2.52 + memset(buffer->bytes, 0, capacity); 2.53 + buffer->flags |= CX_BUFFER_FREE_CONTENTS; 2.54 + } else { 2.55 + buffer->bytes = space; 2.56 + } 2.57 + buffer->capacity = capacity; 2.58 + buffer->size = 0; 2.59 + 2.60 + buffer->pos = 0; 2.61 + } 2.62 + 2.63 + return buffer; 2.64 +} 2.65 + 2.66 +void cxBufferDestroy(CxBuffer buffer) { 2.67 + if ((buffer->flags & CX_BUFFER_FREE_CONTENTS) == CX_BUFFER_FREE_CONTENTS) { 2.68 + free(buffer->bytes); 2.69 + } 2.70 + free(buffer); 2.71 +} 2.72 + 2.73 +CxBuffer cxBufferExtract( 2.74 + CxBuffer src, 2.75 + size_t start, 2.76 + size_t length, 2.77 + int flags 2.78 +) { 2.79 + if (src->size == 0 || length == 0 || 2.80 + ((size_t) -1) - start < length || start + length > src->capacity) { 2.81 + return NULL; 2.82 + } 2.83 + 2.84 + CxBuffer dst = (CxBuffer) malloc(sizeof(cx_buffer_s)); 2.85 + if (dst) { 2.86 + dst->bytes = malloc(length); 2.87 + if (!dst->bytes) { 2.88 + free(dst); 2.89 + return NULL; 2.90 + } 2.91 + dst->capacity = length; 2.92 + dst->size = length; 2.93 + dst->flags = flags | CX_BUFFER_FREE_CONTENTS; 2.94 + dst->pos = 0; 2.95 + memcpy(dst->bytes, src->bytes + start, length); 2.96 + } 2.97 + return dst; 2.98 +} 2.99 + 2.100 +int cxBufferSeek( 2.101 + CxBuffer buffer, 2.102 + off_t offset, 2.103 + int whence 2.104 +) { 2.105 + size_t npos; 2.106 + switch (whence) { 2.107 + case SEEK_CUR: 2.108 + npos = buffer->pos; 2.109 + break; 2.110 + case SEEK_END: 2.111 + npos = buffer->size; 2.112 + break; 2.113 + case SEEK_SET: 2.114 + npos = 0; 2.115 + break; 2.116 + default: 2.117 + return -1; 2.118 + } 2.119 + 2.120 + size_t opos = npos; 2.121 + npos += offset; 2.122 + 2.123 + if ((offset > 0 && npos < opos) || (offset < 0 && npos > opos)) { 2.124 + return -1; 2.125 + } 2.126 + 2.127 + if (npos >= buffer->size) { 2.128 + return -1; 2.129 + } else { 2.130 + buffer->pos = npos; 2.131 + return 0; 2.132 + } 2.133 + 2.134 +} 2.135 + 2.136 +int cxBufferEof(CxBuffer buffer) { 2.137 + return buffer->pos >= buffer->size; 2.138 +} 2.139 + 2.140 +int cxBufferMinimumCapacity( 2.141 + CxBuffer buffer, 2.142 + size_t additional_bytes 2.143 +) { 2.144 + size_t newcap = buffer->capacity + additional_bytes; 2.145 + 2.146 + // overflow protection 2.147 + if (newcap < buffer->capacity) { 2.148 + return -1; 2.149 + } 2.150 + 2.151 + unsigned char *newspace = realloc(buffer->bytes, newcap); 2.152 + if (newspace) { 2.153 + memset(newspace + buffer->size, 0, newcap - buffer->size); 2.154 + buffer->bytes = newspace; 2.155 + buffer->capacity = newcap; 2.156 + } else { 2.157 + return -1; 2.158 + } 2.159 + 2.160 + return 0; 2.161 +} 2.162 + 2.163 +size_t cxBufferWrite( 2.164 + const void *ptr, 2.165 + size_t size, 2.166 + size_t nitems, 2.167 + CxBuffer buffer 2.168 +) { 2.169 + size_t len; 2.170 + if (cx_szmul(size, nitems, &len)) { 2.171 + return 0; 2.172 + } 2.173 + size_t required = buffer->pos + len; 2.174 + if (buffer->pos > required) { 2.175 + return 0; 2.176 + } 2.177 + 2.178 + if (required > buffer->capacity) { 2.179 + if ((buffer->flags & CX_BUFFER_AUTO_EXTEND) == CX_BUFFER_AUTO_EXTEND) { 2.180 + if (cxBufferMinimumCapacity(buffer, required)) { 2.181 + return 0; 2.182 + } 2.183 + } else { 2.184 + len = buffer->capacity - buffer->pos; 2.185 + if (size > 1) { 2.186 + len -= len % size; 2.187 + } 2.188 + } 2.189 + } 2.190 + 2.191 + if (len == 0) { 2.192 + return len; 2.193 + } 2.194 + 2.195 + memcpy(buffer->bytes + buffer->pos, ptr, len); 2.196 + buffer->pos += len; 2.197 + if (buffer->pos > buffer->size) { 2.198 + buffer->size = buffer->pos; 2.199 + } 2.200 + 2.201 + return len / size; 2.202 +} 2.203 + 2.204 +size_t cxBufferRead( 2.205 + void *ptr, 2.206 + size_t size, 2.207 + size_t nitems, 2.208 + CxBuffer buffer 2.209 +) { 2.210 + size_t len; 2.211 + if (cx_szmul(size, nitems, &len)) { 2.212 + return 0; 2.213 + } 2.214 + if (buffer->pos + len > buffer->size) { 2.215 + len = buffer->size - buffer->pos; 2.216 + if (size > 1) len -= len % size; 2.217 + } 2.218 + 2.219 + if (len <= 0) { 2.220 + return len; 2.221 + } 2.222 + 2.223 + memcpy(ptr, buffer->bytes + buffer->pos, len); 2.224 + buffer->pos += len; 2.225 + 2.226 + return len / size; 2.227 +} 2.228 + 2.229 +int cxBufferPut( 2.230 + CxBuffer buffer, 2.231 + int c 2.232 +) { 2.233 + if (buffer->pos >= buffer->capacity) { 2.234 + if ((buffer->flags & CX_BUFFER_AUTO_EXTEND) == CX_BUFFER_AUTO_EXTEND) { 2.235 + if (cxBufferMinimumCapacity(buffer, buffer->capacity + 1)) { 2.236 + return EOF; 2.237 + } 2.238 + } else { 2.239 + return EOF; 2.240 + } 2.241 + } 2.242 + 2.243 + c &= 0xFF; 2.244 + buffer->bytes[buffer->pos] = (unsigned char) c; 2.245 + buffer->pos++; 2.246 + if (buffer->pos > buffer->size) { 2.247 + buffer->size = buffer->pos; 2.248 + } 2.249 + return c; 2.250 +} 2.251 + 2.252 +int cxBufferGet(CxBuffer buffer) { 2.253 + if (cxBufferEof(buffer)) { 2.254 + return EOF; 2.255 + } else { 2.256 + int c = buffer->bytes[buffer->pos]; 2.257 + buffer->pos++; 2.258 + return c; 2.259 + } 2.260 +} 2.261 + 2.262 +size_t cxBufferPutString( 2.263 + CxBuffer buffer, 2.264 + const char *str 2.265 +) { 2.266 + return cxBufferWrite(str, 1, strlen(str), buffer); 2.267 +} 2.268 + 2.269 +int cxBufferShiftLeft( 2.270 + CxBuffer buffer, 2.271 + size_t shift 2.272 +) { 2.273 + if (shift >= buffer->size) { 2.274 + buffer->pos = buffer->size = 0; 2.275 + } else { 2.276 + memmove(buffer->bytes, buffer->bytes + shift, buffer->size - shift); 2.277 + buffer->size -= shift; 2.278 + 2.279 + if (buffer->pos >= shift) { 2.280 + buffer->pos -= shift; 2.281 + } else { 2.282 + buffer->pos = 0; 2.283 + } 2.284 + } 2.285 + return 0; 2.286 +} 2.287 + 2.288 +int cxBufferShiftRight( 2.289 + CxBuffer buffer, 2.290 + size_t shift 2.291 +) { 2.292 + size_t req_capacity = buffer->size + shift; 2.293 + size_t movebytes; 2.294 + 2.295 + // auto extend buffer, if required and enabled 2.296 + if (buffer->capacity < req_capacity) { 2.297 + if ((buffer->flags & CX_BUFFER_AUTO_EXTEND) == CX_BUFFER_AUTO_EXTEND) { 2.298 + if (cxBufferMinimumCapacity(buffer, req_capacity)) { 2.299 + return 1; 2.300 + } 2.301 + movebytes = buffer->size; 2.302 + } else { 2.303 + movebytes = buffer->capacity - shift; 2.304 + } 2.305 + } else { 2.306 + movebytes = buffer->size; 2.307 + } 2.308 + 2.309 + memmove(buffer->bytes + shift, buffer->bytes, movebytes); 2.310 + buffer->size = shift + movebytes; 2.311 + 2.312 + buffer->pos += shift; 2.313 + if (buffer->pos > buffer->size) { 2.314 + buffer->pos = buffer->size; 2.315 + } 2.316 + 2.317 + return 0; 2.318 +} 2.319 + 2.320 +int cxBufferShift( 2.321 + CxBuffer buffer, 2.322 + off_t shift 2.323 +) { 2.324 + if (shift < 0) { 2.325 + return cxBufferShiftLeft(buffer, (size_t) (-shift)); 2.326 + } else if (shift > 0) { 2.327 + return cxBufferShiftRight(buffer, (size_t) shift); 2.328 + } else { 2.329 + return 0; 2.330 + } 2.331 +}
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 3.2 +++ b/src/cx/buffer.h Mon Dec 27 16:51:10 2021 +0100 3.3 @@ -0,0 +1,377 @@ 3.4 +/* 3.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 3.6 + * 3.7 + * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved. 3.8 + * 3.9 + * Redistribution and use in source and binary forms, with or without 3.10 + * modification, are permitted provided that the following conditions are met: 3.11 + * 3.12 + * 1. Redistributions of source code must retain the above copyright 3.13 + * notice, this list of conditions and the following disclaimer. 3.14 + * 3.15 + * 2. Redistributions in binary form must reproduce the above copyright 3.16 + * notice, this list of conditions and the following disclaimer in the 3.17 + * documentation and/or other materials provided with the distribution. 3.18 + * 3.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 3.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 3.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 3.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 3.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 3.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 3.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 3.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 3.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 3.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 3.29 + * POSSIBILITY OF SUCH DAMAGE. 3.30 + */ 3.31 + 3.32 +/** 3.33 + * \file buffer.h 3.34 + * 3.35 + * \brief Advanced buffer implementation. 3.36 + * 3.37 + * Instances of CxBuffer can be used to read from or to write to like one 3.38 + * would do with a stream. 3.39 + * 3.40 + * Some features for convenient use of the buffer 3.41 + * can be enabled. See the documentation of the macro constants for more 3.42 + * information. 3.43 + * 3.44 + * \author Mike Becker 3.45 + * \author Olaf Wintermann 3.46 + * \version 3.0 3.47 + * \copyright 2-Clause BSD License 3.48 + */ 3.49 + 3.50 +#ifndef UCX_BUFFER_H 3.51 +#define UCX_BUFFER_H 3.52 + 3.53 +#include <sys/types.h> 3.54 +#include <stdio.h> 3.55 + 3.56 +#ifdef __cplusplus 3.57 +extern "C" { 3.58 +#endif 3.59 + 3.60 +/** 3.61 + * No buffer features enabled (all flags cleared). 3.62 + */ 3.63 +#define CX_BUFFER_DEFAULT 0x00 3.64 + 3.65 +/** 3.66 + * If this flag is enabled, the buffer will automatically free its contents when destroyed. 3.67 + */ 3.68 +#define CX_BUFFER_FREE_CONTENTS 0x01 3.69 + 3.70 +/** 3.71 + * If this flag is enabled, the buffer will automatically extends its capacity. 3.72 + */ 3.73 +#define CX_BUFFER_AUTO_EXTEND 0x02 3.74 + 3.75 +/** Structure for the UCX buffer data. */ 3.76 +typedef struct { 3.77 + /** A pointer to the buffer contents. */ 3.78 + union { 3.79 + /** 3.80 + * Data is interpreted as text. 3.81 + */ 3.82 + char *space; 3.83 + /** 3.84 + * Data is interpreted as binary. 3.85 + */ 3.86 + unsigned char *bytes; 3.87 + }; 3.88 + /** Current position of the buffer. */ 3.89 + size_t pos; 3.90 + /** Current capacity (i.e. maximum size) of the buffer. */ 3.91 + size_t capacity; 3.92 + /** Current size of the buffer content. */ 3.93 + size_t size; 3.94 + /** 3.95 + * Flag register for buffer features. 3.96 + * \see #CX_BUFFER_DEFAULT 3.97 + * \see #CX_BUFFER_FREE_CONTENTS 3.98 + * \see #CX_BUFFER_AUTO_EXTEND 3.99 + */ 3.100 + int flags; 3.101 +} cx_buffer_s; 3.102 + 3.103 +/** 3.104 + * UCX buffer. 3.105 + */ 3.106 +typedef cx_buffer_s *CxBuffer; 3.107 + 3.108 +/** 3.109 + * Creates a new buffer. 3.110 + * 3.111 + * \note You may provide \c NULL as argument for \p space. 3.112 + * Then this function will allocate the space and enforce 3.113 + * the #CX_BUFFER_FREE_CONTENTS flag. 3.114 + * 3.115 + * \param space pointer to the memory area, or <code>NULL</code> to allocate 3.116 + * new memory 3.117 + * \param capacity the capacity of the buffer 3.118 + * \param flags buffer features (see cx_buffer_s.flags) 3.119 + * \return the new buffer 3.120 + */ 3.121 +CxBuffer cxBufferCreate( 3.122 + void *space, 3.123 + size_t capacity, 3.124 + int flags 3.125 +); 3.126 + 3.127 +/** 3.128 + * Destroys a buffer. 3.129 + * 3.130 + * If the #CX_BUFFER_FREE_CONTENTS feature is enabled, the contents of the buffer 3.131 + * are also freed. 3.132 + * 3.133 + * \param buffer the buffer to destroy 3.134 + */ 3.135 +void cxBufferDestroy(CxBuffer buffer); 3.136 + 3.137 +/** 3.138 + * Creates a new buffer and fills it with content copied from another buffer. 3.139 + * 3.140 + * \note The #CX_BUFFER_FREE_CONTENTS feature is enforced for the new buffer. 3.141 + * 3.142 + * \param src the source buffer 3.143 + * \param start the start position of extraction 3.144 + * \param length the count of bytes to extract (must not be zero) 3.145 + * \param flags features for the new buffer (#CX_BUFFER_FREE_CONTENTS will always be enabled) 3.146 + * \return a new buffer containing the extraction 3.147 + */ 3.148 +CxBuffer cxBufferExtract( 3.149 + CxBuffer src, 3.150 + size_t start, 3.151 + size_t length, 3.152 + int flags 3.153 +); 3.154 + 3.155 +/** 3.156 + * A shorthand macro for copying an entire buffer. 3.157 + * 3.158 + * \param src the source buffer 3.159 + * \param flags features for the new buffer (#CX_BUFFER_FREE_CONTENTS will always be enabled) 3.160 + * \return a new buffer with the copied content 3.161 + */ 3.162 +#define cxBufferClone(src, flags) cxBufferExtract(src, 0, (src)->capacity, flags) 3.163 + 3.164 + 3.165 +/** 3.166 + * Shifts the contents of the buffer by the given offset. 3.167 + * 3.168 + * If the offset is positive, the contents are shifted to the right. 3.169 + * If auto extension is enabled, the buffer grows, if necessary. 3.170 + * In case the auto extension fails, this function returns a non-zero value and 3.171 + * no contents are changed. 3.172 + * If auto extension is disabled, the contents that do not fit into the buffer 3.173 + * are discarded. 3.174 + * 3.175 + * If the offset is negative, the contents are shifted to the left where the 3.176 + * first \p shift bytes are discarded. 3.177 + * The new size of the buffer is the old size minus the absolute shift value. 3.178 + * If this value is larger than the buffer size, the buffer is emptied (but 3.179 + * not cleared, see the security note below). 3.180 + * 3.181 + * The buffer position gets shifted alongside with the content but is kept 3.182 + * within the boundaries of the buffer. 3.183 + * 3.184 + * \note For situations where \c off_t is not large enough, there are specialized cxBufferShiftLeft() and 3.185 + * cxBufferShiftRight() functions using a \c size_t as parameter type. 3.186 + * 3.187 + * \par Security Note 3.188 + * The shifting operation does \em not erase the previously occupied memory cells. 3.189 + * You can easily do that manually, e.g. by calling 3.190 + * <code>memset(buffer->bytes, 0, shift)</code> for a right shift or 3.191 + * <code>memset(buffer->size, 0, buffer->capacity - buffer->size)</code> 3.192 + * for a left shift. 3.193 + * 3.194 + * \param buffer the buffer 3.195 + * \param shift the shift offset (negative means left shift) 3.196 + * \return 0 on success, non-zero if a required auto-extension fails 3.197 + */ 3.198 +int cxBufferShift( 3.199 + CxBuffer buffer, 3.200 + off_t shift 3.201 +); 3.202 + 3.203 +/** 3.204 + * Shifts the buffer to the right. 3.205 + * See cxBufferShift() for details. 3.206 + * 3.207 + * \param buffer the buffer 3.208 + * \param shift the shift offset 3.209 + * \return 0 on success, non-zero if a required auto-extension fails 3.210 + * \see cxBufferShift() 3.211 + */ 3.212 +int cxBufferShiftRight( 3.213 + CxBuffer buffer, 3.214 + size_t shift 3.215 +); 3.216 + 3.217 +/** 3.218 + * Shifts the buffer to the left. 3.219 + * See cxBufferShift() for details. 3.220 + * 3.221 + * \note Since a left shift cannot fail due to memory allocation problems, this 3.222 + * function always returns zero. 3.223 + * 3.224 + * \param buffer the buffer 3.225 + * \param shift the positive shift offset 3.226 + * \return always zero 3.227 + * \see cxBufferShift() 3.228 + */ 3.229 +int cxBufferShiftLeft( 3.230 + CxBuffer buffer, 3.231 + size_t shift 3.232 +); 3.233 + 3.234 + 3.235 +/** 3.236 + * Moves the position of the buffer. 3.237 + * 3.238 + * The new position is relative to the \p whence argument. 3.239 + * 3.240 + * \li \c SEEK_SET marks the start of the buffer. 3.241 + * \li \c SEEK_CUR marks the current position. 3.242 + * \li \c SEEK_END marks the end of the buffer. 3.243 + * 3.244 + * With an offset of zero, this function sets the buffer position to zero 3.245 + * (\c SEEK_SET), the buffer size (\c SEEK_END) or leaves the buffer position 3.246 + * unchanged (\c SEEK_CUR). 3.247 + * 3.248 + * \param buffer the buffer 3.249 + * \param offset position offset relative to \p whence 3.250 + * \param whence one of \c SEEK_SET, \c SEEK_CUR or \c SEEK_END 3.251 + * \return 0 on success, non-zero if the position is invalid 3.252 + * 3.253 + */ 3.254 +int cxBufferSeek( 3.255 + CxBuffer buffer, 3.256 + off_t offset, 3.257 + int whence 3.258 +); 3.259 + 3.260 +/** 3.261 + * Clears the buffer by resetting the position and deleting the data. 3.262 + * 3.263 + * The data is deleted by zeroing it with a call to memset(). 3.264 + * 3.265 + * \param buffer the buffer to be cleared 3.266 + */ 3.267 +#define cxBufferClear(buffer) memset((buffer)->bytes, 0, (buffer)->size); \ 3.268 + (buffer)->size = 0; (buffer)->pos = 0; 3.269 + 3.270 +/** 3.271 + * Tests, if the buffer position has exceeded the buffer capacity. 3.272 + * 3.273 + * \param buffer the buffer to test 3.274 + * \return non-zero, if the current buffer position has exceeded the last 3.275 + * available byte of the buffer. 3.276 + */ 3.277 +int cxBufferEof(CxBuffer buffer); 3.278 + 3.279 + 3.280 +/** 3.281 + * Ensures that the buffer has a minimum capacity. 3.282 + * 3.283 + * If the current capacity is not sufficient, the buffer will be extended. 3.284 + * 3.285 + * \param buffer the buffer 3.286 + * \param capacity the minimum required capacity for this buffer 3.287 + * \return 0 on success or a non-zero value on failure 3.288 + */ 3.289 +int cxBufferMinimumCapacity( 3.290 + CxBuffer buffer, 3.291 + size_t capacity 3.292 +); 3.293 + 3.294 +/** 3.295 + * Writes data to a CxBuffer. 3.296 + * 3.297 + * The position of the buffer is increased by the number of bytes written. 3.298 + * 3.299 + * \note The signature is compatible with the fwrite() family of functions. 3.300 + * 3.301 + * \param ptr a pointer to the memory area containing the bytes to be written 3.302 + * \param size the length of one element 3.303 + * \param nitems the element count 3.304 + * \param buffer the CxBuffer to write to 3.305 + * \return the total count of bytes written 3.306 + */ 3.307 +size_t cxBufferWrite( 3.308 + const void *ptr, 3.309 + size_t size, 3.310 + size_t nitems, 3.311 + CxBuffer buffer 3.312 +); 3.313 + 3.314 +/** 3.315 + * Reads data from a CxBuffer. 3.316 + * 3.317 + * The position of the buffer is increased by the number of bytes read. 3.318 + * 3.319 + * \note The signature is compatible with the fread() family of functions. 3.320 + * 3.321 + * \param ptr a pointer to the memory area where to store the read data 3.322 + * \param size the length of one element 3.323 + * \param nitems the element count 3.324 + * \param buffer the CxBuffer to read from 3.325 + * \return the total number of elements read 3.326 + */ 3.327 +size_t cxBufferRead( 3.328 + void *ptr, 3.329 + size_t size, 3.330 + size_t nitems, 3.331 + CxBuffer buffer 3.332 +); 3.333 + 3.334 +/** 3.335 + * Writes a character to a buffer. 3.336 + * 3.337 + * The least significant byte of the argument is written to the buffer. If the 3.338 + * end of the buffer is reached and #CX_BUFFER_AUTO_EXTEND feature is enabled, 3.339 + * the buffer capacity is extended by cxBufferMinimumCapacity(). If the feature is 3.340 + * disabled or buffer extension fails, \c EOF is returned. 3.341 + * 3.342 + * On successful write, the position of the buffer is increased. 3.343 + * 3.344 + * \param buffer the buffer to write to 3.345 + * \param c the character to write 3.346 + * \return the byte that has bean written or \c EOF when the end of the stream is 3.347 + * reached and automatic extension is not enabled or not possible 3.348 + */ 3.349 +int cxBufferPut( 3.350 + CxBuffer buffer, 3.351 + int c 3.352 +); 3.353 + 3.354 +/** 3.355 + * Gets a character from a buffer. 3.356 + * 3.357 + * The current position of the buffer is increased after a successful read. 3.358 + * 3.359 + * \param buffer the buffer to read from 3.360 + * \return the character or \c EOF, if the end of the buffer is reached 3.361 + */ 3.362 +int cxBufferGet(CxBuffer buffer); 3.363 + 3.364 +/** 3.365 + * Writes a string to a buffer. 3.366 + * 3.367 + * \param buffer the buffer 3.368 + * \param str the zero-terminated string 3.369 + * \return the number of bytes written 3.370 + */ 3.371 +size_t cxBufferPutString( 3.372 + CxBuffer buffer, 3.373 + const char *str 3.374 +); 3.375 + 3.376 +#ifdef __cplusplus 3.377 +} 3.378 +#endif 3.379 + 3.380 +#endif /* UCX_BUFFER_H */
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 4.2 +++ b/src/cx/common.h Mon Dec 27 16:51:10 2021 +0100 4.3 @@ -0,0 +1,73 @@ 4.4 +/* 4.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 4.6 + * 4.7 + * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved. 4.8 + * 4.9 + * Redistribution and use in source and binary forms, with or without 4.10 + * modification, are permitted provided that the following conditions are met: 4.11 + * 4.12 + * 1. Redistributions of source code must retain the above copyright 4.13 + * notice, this list of conditions and the following disclaimer. 4.14 + * 4.15 + * 2. Redistributions in binary form must reproduce the above copyright 4.16 + * notice, this list of conditions and the following disclaimer in the 4.17 + * documentation and/or other materials provided with the distribution. 4.18 + * 4.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 4.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 4.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 4.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 4.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 4.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 4.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 4.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 4.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 4.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 4.29 + * POSSIBILITY OF SUCH DAMAGE. 4.30 + */ 4.31 + 4.32 +/** 4.33 + * \file common.h 4.34 + * 4.35 + * \brief Common definitions and feature checks. 4.36 + * 4.37 + * \author Mike Becker 4.38 + * \author Olaf Wintermann 4.39 + * \version 3.0 4.40 + * \copyright 2-Clause BSD License 4.41 + */ 4.42 + 4.43 +#ifndef UCX_COMMON_H 4.44 +#define UCX_COMMON_H 4.45 + 4.46 +/** Major UCX version as integer constant. */ 4.47 +#define UCX_VERSION_MAJOR 3 4.48 + 4.49 +/** Minor UCX version as integer constant. */ 4.50 +#define UCX_VERSION_MINOR 0 4.51 + 4.52 +/** Version constant which ensures to increase monotonically. */ 4.53 +#define UCX_VERSION (((UCX_VERSION_MAJOR)<<16)|UCX_VERSION_MINOR) 4.54 + 4.55 + 4.56 +#ifdef _WIN32 4.57 +#if !(defined __ssize_t_defined || defined _SSIZE_T_) 4.58 +#include <BaseTsd.h> 4.59 +typedef SSIZE_T ssize_t; 4.60 +#define __ssize_t_defined 4.61 +#define _SSIZE_T_ 4.62 +#endif /* __ssize_t_defined and _SSIZE_T */ 4.63 +#ifndef __WORDSIZE 4.64 +#ifdef _WIN64 4.65 +#define __WORDSIZE 64 4.66 +#else 4.67 +#define __WORDSIZE 32 4.68 +#endif 4.69 +#endif /* __WORDSIZE */ 4.70 +#else /* !_WIN32 */ 4.71 + 4.72 +#include <sys/types.h> 4.73 + 4.74 +#endif /* _WIN32 */ 4.75 + 4.76 +#endif /* UCX_COMMON_H */
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 5.2 +++ b/src/cx/utils.h Mon Dec 27 16:51:10 2021 +0100 5.3 @@ -0,0 +1,120 @@ 5.4 +/* 5.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 5.6 + * 5.7 + * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved. 5.8 + * 5.9 + * Redistribution and use in source and binary forms, with or without 5.10 + * modification, are permitted provided that the following conditions are met: 5.11 + * 5.12 + * 1. Redistributions of source code must retain the above copyright 5.13 + * notice, this list of conditions and the following disclaimer. 5.14 + * 5.15 + * 2. Redistributions in binary form must reproduce the above copyright 5.16 + * notice, this list of conditions and the following disclaimer in the 5.17 + * documentation and/or other materials provided with the distribution. 5.18 + * 5.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 5.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 5.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 5.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 5.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 5.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 5.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 5.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 5.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 5.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 5.29 + * POSSIBILITY OF SUCH DAMAGE. 5.30 + */ 5.31 + 5.32 +/** 5.33 + * \file utils.h 5.34 + * 5.35 + * \brief General purpose utility functions. 5.36 + * 5.37 + * \author Mike Becker 5.38 + * \author Olaf Wintermann 5.39 + * \version 3.0 5.40 + * \copyright 2-Clause BSD License 5.41 + */ 5.42 + 5.43 +#ifndef UCX_UTILS_H 5.44 +#define UCX_UTILS_H 5.45 + 5.46 +#include "common.h" 5.47 + 5.48 +#ifdef __cplusplus 5.49 +extern "C" { 5.50 +#endif 5.51 + 5.52 +/* ---------------------- 5.53 + * cx_szmul() definition. 5.54 + * ---------------------- */ 5.55 + 5.56 +#if (__GNUC__ >= 5 || defined(__clang__)) && !defined(CX_NO_SZMUL_BUILTIN) 5.57 +#define CX_SZMUL_BUILTIN 5.58 + 5.59 +#if __WORDSIZE == 32 5.60 +/** 5.61 + * Alias for \c __builtin_umul_overflow. 5.62 + * 5.63 + * Performs a multiplication of size_t values and checks for overflow. 5.64 + * 5.65 + * @param a first operand 5.66 + * @param b second operand 5.67 + * @param result a pointer to a size_t, where the result should 5.68 + * be stored 5.69 + * @return zero, if no overflow occurred and the result is correct, non-zero 5.70 + * otherwise 5.71 + */ 5.72 +#define cx_szmul(a, b, result) __builtin_umul_overflow(a, b, result) 5.73 +#else /* __WORDSIZE != 32 */ 5.74 +/** 5.75 + * Alias for \c __builtin_umull_overflow. 5.76 + * 5.77 + * Performs a multiplication of size_t values and checks for overflow. 5.78 + * 5.79 + * @param a first operand 5.80 + * @param b second operand 5.81 + * @param result a pointer to a size_t, where the result should 5.82 + * be stored 5.83 + * @return zero, if no overflow occurred and the result is correct, non-zero 5.84 + * otherwise 5.85 + */ 5.86 +#define cx_szmul(a, b, result) __builtin_umull_overflow(a, b, result) 5.87 +#endif /* __WORDSIZE */ 5.88 + 5.89 +#else /* no GNUC or clang bultin */ 5.90 + 5.91 +/** 5.92 + * Performs a multiplication of size_t values and checks for overflow. 5.93 + * 5.94 + * @param a first operand 5.95 + * @param b second operand 5.96 + * @param result a pointer to a size_t, where the result should 5.97 + * be stored 5.98 + * @return zero, if no overflow occurred and the result is correct, non-zero 5.99 + * otherwise 5.100 + */ 5.101 +#define cx_szmul(a, b, result) cx_szmul_impl(a, b, result) 5.102 + 5.103 +/** 5.104 + * Performs a multiplication of size_t values and checks for overflow. 5.105 + * 5.106 + * This is a custom implementation in case there is no compiler builtin 5.107 + * available. 5.108 + * 5.109 + * @param a first operand 5.110 + * @param b second operand 5.111 + * @param result a pointer to a size_t where the result should be stored 5.112 + * @return zero, if no overflow occurred and the result is correct, non-zero 5.113 + * otherwise 5.114 + */ 5.115 +int cx_szmul_impl(size_t a, size_t b, size_t *result); 5.116 + 5.117 +#endif 5.118 + 5.119 +#ifdef __cplusplus 5.120 +} 5.121 +#endif 5.122 + 5.123 +#endif /* UCX_UTILS_H */
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 6.2 +++ b/src/utils.c Mon Dec 27 16:51:10 2021 +0100 6.3 @@ -0,0 +1,46 @@ 6.4 +/* 6.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 6.6 + * 6.7 + * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved. 6.8 + * 6.9 + * Redistribution and use in source and binary forms, with or without 6.10 + * modification, are permitted provided that the following conditions are met: 6.11 + * 6.12 + * 1. Redistributions of source code must retain the above copyright 6.13 + * notice, this list of conditions and the following disclaimer. 6.14 + * 6.15 + * 2. Redistributions in binary form must reproduce the above copyright 6.16 + * notice, this list of conditions and the following disclaimer in the 6.17 + * documentation and/or other materials provided with the distribution. 6.18 + * 6.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 6.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 6.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 6.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 6.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 6.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 6.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 6.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 6.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 6.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 6.29 + * POSSIBILITY OF SUCH DAMAGE. 6.30 + */ 6.31 + 6.32 +#include "cx/utils.h" 6.33 + 6.34 +#ifndef CX_SZMUL_BUILTIN 6.35 +int cx_szmul_impl(size_t a, size_t b, size_t *result) { 6.36 + if(a == 0 || b == 0) { 6.37 + *result = 0; 6.38 + return 0; 6.39 + } 6.40 + size_t r = a * b; 6.41 + if(r / b == a) { 6.42 + *result = r; 6.43 + return 0; 6.44 + } else { 6.45 + *result = 0; 6.46 + return 1; 6.47 + } 6.48 +} 6.49 +#endif