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