/** @license 2023 Neil Edelman, distributed under the terms of the [MIT License](https://opensource.org/licenses/MIT). Global stable pool of temporary strings duplicated from substrings. Doesn't support deletion, only growing. @std C89 */ #include "lorem.h" #include #include #define ARRAY_NAME block #define ARRAY_TYPE char * #include "array.h" static struct { size_t capacity, size; /* Lead block. */ struct block_array blocks; } buffer; struct lorem lorem(const char *const a, const char *const b) { struct lorem l; assert(a && a <= b); l.sub = a; l.size = (size_t)(b - a); return l; } const char *lorem_dup(const struct lorem sub) { char *string; size_t size; if(!sub.sub) { errno = EDOM; return 0; } /* Null substring. */ if(sub.size == ~(size_t)0) { errno = ERANGE; return 0; } /* Unlikely. */ if((size = sub.size + 1) > buffer.capacity - buffer.size) { size_t c0 = buffer.capacity < 8 ? 8 : buffer.capacity; char *block = 0, **record = 0; while(c0 < size) { /* Grow. */ size_t c1 = c0 + (c0 >> 1) + (c0 >> 3); if(c0 >= c1) { c0 = ~(size_t)0; break; } /* Unlikely. */ c0 = c1; } if(!(block = malloc(c0)) || !(record = block_array_new(&buffer.blocks))) { /* Error. */ free(block); if(!errno) errno = ERANGE; return 0; } *record = block; buffer.capacity = c0; buffer.size = 0; /*printf("%s size %zu\n", orcify(block), c0);*/ } assert(buffer.blocks.size); string = buffer.blocks.data[buffer.blocks.size - 1] + buffer.size; memcpy(string, sub.sub, sub.size); string[sub.size] = '\0'; buffer.size += size; return string; } void lorem_(void) { size_t i; for(i = 0; i < buffer.blocks.size; i++) { char *block = buffer.blocks.data[i]; /*printf("free %s\n", orcify(block));*/ free(block); } buffer.capacity = buffer.size = 0; block_array_(&buffer.blocks); }