UNIXworkcode

1 /* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 3 * 4 * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /** 30 * \file buffer.h 31 * 32 * \brief Advanced buffer implementation. 33 * 34 * Instances of CxBuffer can be used to read from or to write to like one 35 * would do with a stream. 36 * 37 * Some features for convenient use of the buffer 38 * can be enabled. See the documentation of the macro constants for more 39 * information. 40 * 41 * \author Mike Becker 42 * \author Olaf Wintermann 43 * \version 3.0 44 * \copyright 2-Clause BSD License 45 */ 46 47 #ifndef UCX_BUFFER_H 48 #define UCX_BUFFER_H 49 50 #include "common.h" 51 #include "allocator.h" 52 53 #ifdef __cplusplus 54 extern "C" { 55 #endif 56 57 /** 58 * No buffer features enabled (all flags cleared). 59 */ 60 #define CX_BUFFER_DEFAULT 0x00 61 62 /** 63 * If this flag is enabled, the buffer will automatically free its contents when destroyed. 64 */ 65 #define CX_BUFFER_FREE_CONTENTS 0x01 66 67 /** 68 * If this flag is enabled, the buffer will automatically extends its capacity. 69 */ 70 #define CX_BUFFER_AUTO_EXTEND 0x02 71 72 /** Structure for the UCX buffer data. */ 73 typedef struct { 74 /** A pointer to the buffer contents. */ 75 union { 76 /** 77 * Data is interpreted as text. 78 */ 79 char *space; 80 /** 81 * Data is interpreted as binary. 82 */ 83 unsigned char *bytes; 84 }; 85 /** The allocator to use for automatic memory management. */ 86 CxAllocator const *allocator; 87 /** Current position of the buffer. */ 88 size_t pos; 89 /** Current capacity (i.e. maximum size) of the buffer. */ 90 size_t capacity; 91 /** Current size of the buffer content. */ 92 size_t size; 93 /** 94 * The buffer may not extend beyond this threshold before starting to flush. 95 * Default is \c SIZE_MAX (flushing disabled when auto extension is enabled). 96 */ 97 size_t flush_threshold; 98 /** 99 * The block size for the elements to flush. 100 * Default is 4096 bytes. 101 */ 102 size_t flush_blksize; 103 /** 104 * The maximum number of blocks to flush in one cycle. 105 * Zero disables flushing entirely (this is the default). 106 * Set this to \c SIZE_MAX to flush the entire buffer. 107 * 108 * @attention if the maximum number of blocks multiplied with the block size 109 * is smaller than the expected contents written to this buffer within one write 110 * operation, multiple flush cycles are performed after that write. 111 * That means the total number of blocks flushed after one write to this buffer may 112 * be larger than \c flush_blkmax. 113 */ 114 size_t flush_blkmax; 115 116 /** 117 * The write function used for flushing. 118 * If NULL, the flushed content gets discarded. 119 */ 120 cx_write_func flush_func; 121 122 /** 123 * The target for \c flush_func. 124 */ 125 void *flush_target; 126 127 /** 128 * Flag register for buffer features. 129 * @see #CX_BUFFER_DEFAULT 130 * @see #CX_BUFFER_FREE_CONTENTS 131 * @see #CX_BUFFER_AUTO_EXTEND 132 */ 133 int flags; 134 } cx_buffer_s; 135 136 /** 137 * UCX buffer. 138 */ 139 typedef cx_buffer_s CxBuffer; 140 141 /** 142 * Initializes a fresh buffer. 143 * 144 * \note You may provide \c NULL as argument for \p space. 145 * Then this function will allocate the space and enforce 146 * the #CX_BUFFER_FREE_CONTENTS flag. 147 * 148 * @param buffer the buffer to initialize 149 * @param space pointer to the memory area, or \c NULL to allocate 150 * new memory 151 * @param capacity the capacity of the buffer 152 * @param allocator the allocator this buffer shall use for automatic 153 * memory management. If \c NULL, the default heap allocator will be used. 154 * @param flags buffer features (see cx_buffer_s.flags) 155 * @return zero on success, non-zero if a required allocation failed 156 */ 157 __attribute__((__nonnull__(1))) 158 int cxBufferInit( 159 CxBuffer *buffer, 160 void *space, 161 size_t capacity, 162 CxAllocator const *allocator, 163 int flags 164 ); 165 166 /** 167 * Allocates and initializes a fresh buffer. 168 * 169 * \note You may provide \c NULL as argument for \p space. 170 * Then this function will allocate the space and enforce 171 * the #CX_BUFFER_FREE_CONTENTS flag. 172 * 173 * @param space pointer to the memory area, or \c NULL to allocate 174 * new memory 175 * @param capacity the capacity of the buffer 176 * @param allocator the allocator to use for allocating the structure and the automatic 177 * memory management within the buffer. If \c NULL, the default heap allocator will be used. 178 * @param flags buffer features (see cx_buffer_s.flags) 179 * @return a pointer to the buffer on success, \c NULL if a required allocation failed 180 */ 181 CxBuffer *cxBufferCreate( 182 void *space, 183 size_t capacity, 184 CxAllocator const *allocator, 185 int flags 186 ); 187 188 /** 189 * Destroys the buffer contents. 190 * 191 * Has no effect if the #CX_BUFFER_FREE_CONTENTS feature is not enabled. 192 * If you want to free the memory of the entire buffer, use cxBufferFree(). 193 * 194 * @param buffer the buffer which contents shall be destroyed 195 * @see cxBufferInit() 196 */ 197 __attribute__((__nonnull__)) 198 void cxBufferDestroy(CxBuffer *buffer); 199 200 /** 201 * Deallocates the buffer. 202 * 203 * If the #CX_BUFFER_FREE_CONTENTS feature is enabled, this function also destroys 204 * the contents. If you \em only want to destroy the contents, use cxBufferDestroy(). 205 * 206 * @param buffer the buffer to deallocate 207 * @see cxBufferCreate() 208 */ 209 __attribute__((__nonnull__)) 210 void cxBufferFree(CxBuffer *buffer); 211 212 /** 213 * Shifts the contents of the buffer by the given offset. 214 * 215 * If the offset is positive, the contents are shifted to the right. 216 * If auto extension is enabled, the buffer grows, if necessary. 217 * In case the auto extension fails, this function returns a non-zero value and 218 * no contents are changed. 219 * If auto extension is disabled, the contents that do not fit into the buffer 220 * are discarded. 221 * 222 * If the offset is negative, the contents are shifted to the left where the 223 * first \p shift bytes are discarded. 224 * The new size of the buffer is the old size minus the absolute shift value. 225 * If this value is larger than the buffer size, the buffer is emptied (but 226 * not cleared, see the security note below). 227 * 228 * The buffer position gets shifted alongside with the content but is kept 229 * within the boundaries of the buffer. 230 * 231 * \note For situations where \c off_t is not large enough, there are specialized cxBufferShiftLeft() and 232 * cxBufferShiftRight() functions using a \c size_t as parameter type. 233 * 234 * \attention 235 * Security Note: The shifting operation does \em not erase the previously occupied memory cells. 236 * But you can easily do that manually, e.g. by calling 237 * <code>memset(buffer->bytes, 0, shift)</code> for a right shift or 238 * <code>memset(buffer->bytes + buffer->size, 0, buffer->capacity - buffer->size)</code> 239 * for a left shift. 240 * 241 * @param buffer the buffer 242 * @param shift the shift offset (negative means left shift) 243 * @return 0 on success, non-zero if a required auto-extension fails 244 */ 245 __attribute__((__nonnull__)) 246 int cxBufferShift( 247 CxBuffer *buffer, 248 off_t shift 249 ); 250 251 /** 252 * Shifts the buffer to the right. 253 * See cxBufferShift() for details. 254 * 255 * @param buffer the buffer 256 * @param shift the shift offset 257 * @return 0 on success, non-zero if a required auto-extension fails 258 * @see cxBufferShift() 259 */ 260 __attribute__((__nonnull__)) 261 int cxBufferShiftRight( 262 CxBuffer *buffer, 263 size_t shift 264 ); 265 266 /** 267 * Shifts the buffer to the left. 268 * See cxBufferShift() for details. 269 * 270 * \note Since a left shift cannot fail due to memory allocation problems, this 271 * function always returns zero. 272 * 273 * @param buffer the buffer 274 * @param shift the positive shift offset 275 * @return always zero 276 * @see cxBufferShift() 277 */ 278 __attribute__((__nonnull__)) 279 int cxBufferShiftLeft( 280 CxBuffer *buffer, 281 size_t shift 282 ); 283 284 285 /** 286 * Moves the position of the buffer. 287 * 288 * The new position is relative to the \p whence argument. 289 * 290 * \li \c SEEK_SET marks the start of the buffer. 291 * \li \c SEEK_CUR marks the current position. 292 * \li \c SEEK_END marks the end of the buffer. 293 * 294 * With an offset of zero, this function sets the buffer position to zero 295 * (\c SEEK_SET), the buffer size (\c SEEK_END) or leaves the buffer position 296 * unchanged (\c SEEK_CUR). 297 * 298 * @param buffer the buffer 299 * @param offset position offset relative to \p whence 300 * @param whence one of \c SEEK_SET, \c SEEK_CUR or \c SEEK_END 301 * @return 0 on success, non-zero if the position is invalid 302 * 303 */ 304 __attribute__((__nonnull__)) 305 int cxBufferSeek( 306 CxBuffer *buffer, 307 off_t offset, 308 int whence 309 ); 310 311 /** 312 * Clears the buffer by resetting the position and deleting the data. 313 * 314 * The data is deleted by zeroing it with a call to memset(). 315 * 316 * @param buffer the buffer to be cleared 317 */ 318 __attribute__((__nonnull__)) 319 void cxBufferClear(CxBuffer *buffer); 320 321 /** 322 * Tests, if the buffer position has exceeded the buffer capacity. 323 * 324 * @param buffer the buffer to test 325 * @return non-zero, if the current buffer position has exceeded the last 326 * available byte of the buffer. 327 */ 328 __attribute__((__nonnull__)) 329 int cxBufferEof(CxBuffer const *buffer); 330 331 332 /** 333 * Ensures that the buffer has a minimum capacity. 334 * 335 * If the current capacity is not sufficient, the buffer will be extended. 336 * 337 * @param buffer the buffer 338 * @param capacity the minimum required capacity for this buffer 339 * @return 0 on success or a non-zero value on failure 340 */ 341 __attribute__((__nonnull__)) 342 int cxBufferMinimumCapacity( 343 CxBuffer *buffer, 344 size_t capacity 345 ); 346 347 /** 348 * Writes data to a CxBuffer. 349 * 350 * If flushing is enabled and the buffer needs to flush, the data is flushed to 351 * the target until the target signals that it cannot take more data by 352 * returning zero via the respective write function. In that case, the remaining 353 * data in this buffer is shifted to the beginning of this buffer so that the 354 * newly available space can be used to append as much data as possible. This 355 * function only stops writing more elements, when the flush target and this 356 * buffer are both incapable of taking more data or all data has been written. 357 * The number returned by this function is the total number of elements that 358 * could be written during the process. It does not necessarily mean that those 359 * elements are still in this buffer, because some of them could have also be 360 * flushed already. 361 * 362 * If automatic flushing is not enabled, the position of the buffer is increased 363 * by the number of bytes written. 364 * 365 * \note The signature is compatible with the fwrite() family of functions. 366 * 367 * @param ptr a pointer to the memory area containing the bytes to be written 368 * @param size the length of one element 369 * @param nitems the element count 370 * @param buffer the CxBuffer to write to 371 * @return the total count of elements written 372 */ 373 __attribute__((__nonnull__)) 374 size_t cxBufferWrite( 375 void const *ptr, 376 size_t size, 377 size_t nitems, 378 CxBuffer *buffer 379 ); 380 381 /** 382 * Reads data from a CxBuffer. 383 * 384 * The position of the buffer is increased by the number of bytes read. 385 * 386 * \note The signature is compatible with the fread() family of functions. 387 * 388 * @param ptr a pointer to the memory area where to store the read data 389 * @param size the length of one element 390 * @param nitems the element count 391 * @param buffer the CxBuffer to read from 392 * @return the total number of elements read 393 */ 394 __attribute__((__nonnull__)) 395 size_t cxBufferRead( 396 void *ptr, 397 size_t size, 398 size_t nitems, 399 CxBuffer *buffer 400 ); 401 402 /** 403 * Writes a character to a buffer. 404 * 405 * The least significant byte of the argument is written to the buffer. If the 406 * end of the buffer is reached and #CX_BUFFER_AUTO_EXTEND feature is enabled, 407 * the buffer capacity is extended by cxBufferMinimumCapacity(). If the feature is 408 * disabled or buffer extension fails, \c EOF is returned. 409 * 410 * On successful write, the position of the buffer is increased. 411 * 412 * @param buffer the buffer to write to 413 * @param c the character to write 414 * @return the byte that has bean written or \c EOF when the end of the stream is 415 * reached and automatic extension is not enabled or not possible 416 */ 417 __attribute__((__nonnull__)) 418 int cxBufferPut( 419 CxBuffer *buffer, 420 int c 421 ); 422 423 /** 424 * Writes a string to a buffer. 425 * 426 * @param buffer the buffer 427 * @param str the zero-terminated string 428 * @return the number of bytes written 429 */ 430 __attribute__((__nonnull__)) 431 size_t cxBufferPutString( 432 CxBuffer *buffer, 433 const char *str 434 ); 435 436 /** 437 * Gets a character from a buffer. 438 * 439 * The current position of the buffer is increased after a successful read. 440 * 441 * @param buffer the buffer to read from 442 * @return the character or \c EOF, if the end of the buffer is reached 443 */ 444 __attribute__((__nonnull__)) 445 int cxBufferGet(CxBuffer *buffer); 446 447 #ifdef __cplusplus 448 } 449 #endif 450 451 #endif // UCX_BUFFER_H 452