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/ledit.git (over tor)
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 anyways */
     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, function \"%s\"\n", file, line, func);
     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 <otto@drijf.net>
    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 arithmetic */
    133 	/* since the array has size cap * elem_size, it is assumed that no overflow happens */
    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_size);
    174 		char *carray = (char*)array; /* cast to char to do pointer arithmetic */
    175 		/* we already know new_cap * elem_size does not wrap around because array
    176 		   is of that size, so all the other multiplications here should be safe
    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 index to
    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_size,
    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 buffer */
    194 			memmove(
    195 			    carray + (new_cap - (len - old_gap)) * elem_size,
    196 			    carray + (old_gap + gap_size) * elem_size,
    197 			    (len - old_gap) * elem_size
    198 			);
    199 			/* move piece between index and original gap to end */
    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 buffer */
    207 			memmove(
    208 			    carray + (new_cap - (len - old_gap)) * elem_size,
    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, len, NULL);
    219 		array = ledit_reallocarray(array, new_cap, elem_size);
    220 		move_gap(array, elem_size, index, len, new_cap, len, NULL);
    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 }