Home
tmem.c - iomenu - interactive terminal-based selection menu HTML git clone git://bitreich.org/iomenu git://hg6vgqziawt5s4dj.onion/iomenu DIR Log DIR Files DIR Refs DIR Tags DIR README DIR LICENSE --- tmem.c (2901B) --- 1 #include "mem.h" 2 3 #include <assert.h> 4 #include <errno.h> 5 #include <stdint.h> 6 #include <stdlib.h> 7 #include <string.h> 8 #include <unistd.h> 9 10 static struct mem_block * 11 mem_block(void **memp) 12 { 13 struct mem_block *block = (void *)((char *)memp - sizeof *block); 14 15 assert(memcmp(block->magic, MEM_BLOCK_MAGIC, 8) == 0); 16 return block; 17 } 18 19 void * 20 mem_alloc(struct mem_pool *pool, size_t len) 21 { 22 struct mem_block *block; 23 24 block = calloc(1, sizeof *block + len); 25 if (block == NULL) 26 return NULL; 27 memcpy(block->magic, MEM_BLOCK_MAGIC, 8); 28 29 block->len = len; 30 block->pool = pool; 31 block->prev = NULL; 32 block->next = pool->head; 33 if (pool->head != NULL) 34 pool->head->prev = block; 35 pool->head = block; 36 37 return block->buf; 38 } 39 40 int 41 mem_resize(void **memp, size_t len) 42 { 43 struct mem_block *block = mem_block(*memp); 44 int is_first = (block == block->pool->head); 45 int is_same; 46 void *v; 47 48 v = realloc(block, sizeof *block + len); 49 if (v == NULL) 50 return -1; 51 is_same = (block == v); 52 block = v; 53 54 block->len = len; 55 56 if (is_same) 57 return 0; 58 59 if (block->prev != NULL) 60 block->prev->next = v; 61 if (block->next != NULL) 62 block->next->prev = v; 63 if (is_first) 64 block->pool->head = v; 65 *memp = block->buf; 66 67 assert(memcmp(block->magic, MEM_BLOCK_MAGIC, 8) == 0); 68 return 0; 69 } 70 71 int 72 mem_grow(void **memp, size_t len) 73 { 74 assert(SIZE_MAX - len >= mem_block(*memp)->len); 75 76 return mem_resize(memp, mem_length(*memp) + len); 77 } 78 79 int 80 mem_shrink(void **memp, size_t len) 81 { 82 assert(mem_block(*memp)->len >= len); 83 84 return mem_resize(memp, mem_length(*memp) - len); 85 } 86 87 size_t 88 mem_length(void *mem) 89 { 90 return mem_block(mem)->len; 91 } 92 93 int 94 mem_append(void **memp, void const *buf, size_t len) 95 { 96 size_t old_len = mem_length(*memp); 97 struct mem_block *block; 98 99 if (mem_grow(memp, len) < 0) 100 return -1; 101 block = mem_block(*memp); 102 memcpy((char *)block->buf + old_len, buf, len); 103 104 assert(memcmp(block->magic, MEM_BLOCK_MAGIC, 8) == 0); 105 return 0; 106 } 107 108 int 109 mem_read(void **memp, struct mem_pool *pool) 110 { 111 struct mem_block *block; 112 ssize_t sz = 0; 113 void *mem; 114 115 mem = mem_alloc(pool, 0); 116 if (mem == NULL) 117 return -1; 118 119 for (ssize_t r = 1; r > 0; sz += r) { 120 if (mem_resize(&mem, sz + 2048) < 0) 121 return -1; 122 123 r = read(0, (char *)mem + sz, 2048); 124 if (r < 0) 125 return -1; 126 } 127 block = mem_block(mem); 128 block->len = sz; 129 130 *memp = mem; 131 assert(memcmp(block->magic, MEM_BLOCK_MAGIC, 8) == 0); 132 return 0; 133 } 134 135 void 136 mem_delete(void *mem) 137 { 138 struct mem_block *block = mem_block(mem);; 139 140 if (block == block->pool->head) 141 block->pool->head = block->next; 142 if (block->next != NULL) 143 block->next->prev = block->prev; 144 if (block->prev != NULL) 145 block->prev->next = block->next; 146 memset(block, 0, sizeof *block); 147 free(block); 148 } 149 150 void 151 mem_free(struct mem_pool *pool) 152 { 153 struct mem_block *block, *next; 154 155 for (block = pool->head; block != NULL; block = next) { 156 next = block->next; 157 memset(block, 0, sizeof *block); 158 free(block); 159 } 160 }