memory.c - ledit - Text editor (WIP) | |
git clone git://lumidify.org/ledit.git (fast, but not encrypted) | |
git clone https://lumidify.org/ledit.git (encrypted, but very slow) | |
git clone git://4kcetb7mo7hj6grozzybxtotsub5bempzo4lirzc3437amof2c2impyd.onion/… | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
memory.c (6618B) | |
--- | |
1 #include <stdio.h> | |
2 #include <stdint.h> | |
3 #include <stdlib.h> | |
4 #include <string.h> | |
5 | |
6 #include "assert.h" | |
7 #include "memory.h" | |
8 #include "cleanup.h" | |
9 | |
10 static void | |
11 fatal_err(const char *msg) { | |
12 fprintf(stderr, "%s", msg); | |
13 /* FIXME: maybe don't cleanup here - it will probably fail anywa… | |
14 ledit_cleanup(); | |
15 exit(1); | |
16 } | |
17 | |
18 void | |
19 err_overflow_impl(const char *file, int line, const char *func) { | |
20 (void)fprintf(stderr, "Integer overflow: file \"%s\", line %d, f… | |
21 ledit_emergencydump(file, line, func, "Integer overflow"); | |
22 abort(); | |
23 } | |
24 | |
25 /* FIXME: should these perform emergencydump instead of just | |
26 fatal_err? It probably isn't of much use when there isn't | |
27 even any memory left. */ | |
28 char * | |
29 ledit_strdup(const char *s) { | |
30 char *str = strdup(s); | |
31 ledit_assert(str && "Out of memory."); | |
32 if (!str) | |
33 fatal_err("Out of memory.\n"); | |
34 return str; | |
35 } | |
36 | |
37 char * | |
38 ledit_strndup(const char *s, size_t n) { | |
39 char *str = strndup(s, n); | |
40 if (!str) | |
41 fatal_err("Out of memory.\n"); | |
42 return str; | |
43 } | |
44 | |
45 void * | |
46 ledit_malloc(size_t size) { | |
47 void *ptr = malloc(size); | |
48 if (!ptr) | |
49 fatal_err("Out of memory.\n"); | |
50 return ptr; | |
51 } | |
52 | |
53 void * | |
54 ledit_calloc(size_t nmemb, size_t size) { | |
55 void *ptr = calloc(nmemb, size); | |
56 if (!ptr) | |
57 fatal_err("Out of memory.\n"); | |
58 return ptr; | |
59 } | |
60 | |
61 void * | |
62 ledit_realloc(void *ptr, size_t size) { | |
63 void *new_ptr = realloc(ptr, size); | |
64 if (!new_ptr) | |
65 fatal_err("Out of memory.\n"); | |
66 return new_ptr; | |
67 } | |
68 | |
69 /* Concatenate the two given strings and return the result. | |
70 This allocates new memory for the result string, unlike | |
71 the actual strcat. Aborts program on error */ | |
72 char * | |
73 ledit_strcat(const char *str1, const char *str2) { | |
74 size_t len1, len2; | |
75 char *ret; | |
76 | |
77 len1 = strlen(str1); | |
78 len2 = strlen(str2); | |
79 ret = ledit_malloc(len1 + len2 + 1); | |
80 strcpy(ret, str1); | |
81 strcpy(ret + len1, str2); | |
82 | |
83 return ret; | |
84 } | |
85 | |
86 char * | |
87 print_fmt(char *fmt, ...) { | |
88 va_list args; | |
89 va_start(args, fmt); | |
90 int len = vsnprintf(NULL, 0, fmt, args); | |
91 /* FIXME: what should be done on error? */ | |
92 if (len < 0) | |
93 fatal_err("Error in vsnprintf called from print_fmt"); | |
94 /* FIXME: overflow */ | |
95 char *str = ledit_malloc(len + 1); | |
96 va_end(args); | |
97 va_start(args, fmt); | |
98 vsnprintf(str, len + 1, fmt, args); | |
99 va_end(args); | |
100 return str; | |
101 } | |
102 | |
103 /* | |
104 * This (reallocarray) is from OpenBSD (adapted to exit on error): | |
105 * Copyright (c) 2008 Otto Moerbeek <[email protected]> | |
106 */ | |
107 | |
108 /* | |
109 * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX | |
110 * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW | |
111 */ | |
112 #define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4)) | |
113 | |
114 void * | |
115 ledit_reallocarray(void *optr, size_t nmemb, size_t size) | |
116 { | |
117 if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && | |
118 nmemb > 0 && SIZE_MAX / nmemb < size) { | |
119 err_overflow(); | |
120 } | |
121 return ledit_realloc(optr, size * nmemb); | |
122 } | |
123 | |
124 void | |
125 move_gap( | |
126 void *array, size_t elem_size, size_t index, | |
127 size_t gap, size_t cap, size_t len, | |
128 size_t *new_gap_ret) { | |
129 ledit_assert(array != NULL); | |
130 ledit_assert(index <= len); | |
131 ledit_assert(len <= cap); | |
132 char *carray = (char *)array; /* cast to char * for pointer arit… | |
133 /* since the array has size cap * elem_size, it is assumed that … | |
134 if (index > gap) { | |
135 /* move piece between end of original gap and | |
136 index to beginning of original gap */ | |
137 memmove( | |
138 carray + gap * elem_size, | |
139 carray + (gap + cap - len) * elem_size, | |
140 (index - gap) * elem_size | |
141 ); | |
142 } else if (index < gap) { | |
143 /* move piece between index and original gap to | |
144 end of original gap */ | |
145 memmove( | |
146 carray + (index + cap - len) * elem_size, | |
147 carray + index * elem_size, | |
148 (gap - index) * elem_size | |
149 ); | |
150 } | |
151 if (new_gap_ret) | |
152 *new_gap_ret = index; | |
153 } | |
154 | |
155 /* FIXME: replace with macro version that takes type parameter in order | |
156 to avoid errors with elem_size */ | |
157 /* This is almost certainly premature optimization and maybe | |
158 not optimization at all. */ | |
159 void * | |
160 resize_and_move_gap( | |
161 void *array, size_t elem_size, | |
162 size_t old_gap, size_t old_cap, size_t len, | |
163 size_t min_size, size_t index, | |
164 size_t *new_gap_ret, size_t *new_cap_ret) { | |
165 ledit_assert(array != NULL || (len == 0 && old_cap == 0)); | |
166 ledit_assert(index <= len); | |
167 ledit_assert(len <= old_cap); | |
168 ledit_assert(old_gap <= len); | |
169 size_t gap_size = old_cap - len; | |
170 size_t new_cap = ideal_array_size(old_cap, min_size);; | |
171 if (new_cap >= old_cap) { | |
172 if (new_cap > old_cap) | |
173 array = ledit_reallocarray(array, new_cap, elem_… | |
174 char *carray = (char*)array; /* cast to char to do point… | |
175 /* we already know new_cap * elem_size does not wrap aro… | |
176 is of that size, so all the other multiplications her… | |
177 (at least that's what I think, but I may be wrong) */ | |
178 if (index > old_gap) { | |
179 /* move piece between end of original gap and in… | |
180 beginning of original gap */ | |
181 memmove( | |
182 carray + old_gap * elem_size, | |
183 carray + (old_gap + gap_size) * elem_size, | |
184 (index - old_gap) * elem_size | |
185 ); | |
186 /* move piece after index to end of buffer */ | |
187 memmove( | |
188 carray + (new_cap - (len - index)) * elem_si… | |
189 carray + (index + gap_size) * elem_size, | |
190 (len - index) * elem_size | |
191 ); | |
192 } else if (index < old_gap) { | |
193 /* move piece after original gap to end of buffe… | |
194 memmove( | |
195 carray + (new_cap - (len - old_gap)) * elem_… | |
196 carray + (old_gap + gap_size) * elem_size, | |
197 (len - old_gap) * elem_size | |
198 ); | |
199 /* move piece between index and original gap to … | |
200 memmove( | |
201 carray + (new_cap - len + index) * elem_size, | |
202 carray + index * elem_size, | |
203 (old_gap - index) * elem_size | |
204 ); | |
205 } else { | |
206 /* move piece after original gap to end of buffe… | |
207 memmove( | |
208 carray + (new_cap - (len - old_gap)) * elem_… | |
209 carray + (old_gap + gap_size) * elem_size, | |
210 (len - old_gap) * elem_size | |
211 ); | |
212 } | |
213 } else { | |
214 /* otherwise, parts may be cut off */ | |
215 ledit_assert(min_size >= len); | |
216 /* FIXME: optimize this */ | |
217 if (array) | |
218 move_gap(array, elem_size, len, old_gap, old_cap… | |
219 array = ledit_reallocarray(array, new_cap, elem_size); | |
220 move_gap(array, elem_size, index, len, new_cap, len, NUL… | |
221 } | |
222 if (new_gap_ret) | |
223 *new_gap_ret = index; | |
224 if (new_cap_ret) | |
225 *new_cap_ret = new_cap; | |
226 return array; | |
227 } | |
228 | |
229 /* FIXME: maybe don't double when already very large? */ | |
230 /* FIXME: better start size when old == 0? */ | |
231 size_t | |
232 ideal_array_size(size_t old, size_t needed) { | |
233 size_t ret = old; | |
234 if (old < needed) | |
235 ret = old * 2 > needed ? old * 2 : needed; | |
236 else if (needed * 4 < old) | |
237 ret = old / 2; | |
238 if (ret == 0) | |
239 ret = 1; /* not sure if this is necessary */ | |
240 return ret; | |
241 } |