72 lines
1.8 KiB
C
72 lines
1.8 KiB
C
/** @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 <assert.h>
|
|
#include <errno.h>
|
|
|
|
#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);
|
|
}
|