/ external / linenoise / stringbuf.c
stringbuf.c
  1  /**
  2   * resizable string buffer
  3   *
  4   * (c) 2017-2020 Steve Bennett <steveb@workware.net.au>
  5   *
  6   * See utf8.c for licence details.
  7   */
  8  #include <stdlib.h>
  9  #include <string.h>
 10  #include <stdio.h>
 11  #include <ctype.h>
 12  #include <assert.h>
 13  
 14  #ifndef STRINGBUF_H
 15  #include "stringbuf.h"
 16  #endif
 17  #ifdef USE_UTF8
 18  #ifndef UTF8_UTIL_H
 19  #include "utf8.h"
 20  #endif
 21  #endif
 22  
 23  #define SB_INCREMENT 200
 24  
 25  stringbuf *sb_alloc(void)
 26  {
 27  	stringbuf *sb = (stringbuf *)malloc(sizeof(*sb));
 28  	sb->remaining = 0;
 29  	sb->last = 0;
 30  #ifdef USE_UTF8
 31  	sb->chars = 0;
 32  #endif
 33  	sb->data = NULL;
 34  
 35  	return(sb);
 36  }
 37  
 38  void sb_free(stringbuf *sb)
 39  {
 40  	if (sb) {
 41  		free(sb->data);
 42  	}
 43  	free(sb);
 44  }
 45  
 46  static void sb_realloc(stringbuf *sb, int newlen)
 47  {
 48  	sb->data = (char *)realloc(sb->data, newlen);
 49  	sb->remaining = newlen - sb->last;
 50  }
 51  
 52  void sb_append(stringbuf *sb, const char *str)
 53  {
 54  	sb_append_len(sb, str, strlen(str));
 55  }
 56  
 57  void sb_append_len(stringbuf *sb, const char *str, int len)
 58  {
 59  	if (sb->remaining < len + 1) {
 60  		sb_realloc(sb, sb->last + len + 1 + SB_INCREMENT);
 61  	}
 62  	memcpy(sb->data + sb->last, str, len);
 63  	sb->data[sb->last + len] = 0;
 64  
 65  	sb->last += len;
 66  	sb->remaining -= len;
 67  #ifdef USE_UTF8
 68  	sb->chars += utf8_strlen(str, len);
 69  #endif
 70  }
 71  
 72  char *sb_to_string(stringbuf *sb)
 73  {
 74  	if (sb->data == NULL) {
 75  		/* Return an allocated empty string, not null */
 76  		return strdup("");
 77  	}
 78  	else {
 79  		/* Just return the data and free the stringbuf structure */
 80  		char *pt = sb->data;
 81  		free(sb);
 82  		return pt;
 83  	}
 84  }
 85  
 86  /* Insert and delete operations */
 87  
 88  /* Moves up all the data at position 'pos' and beyond by 'len' bytes
 89   * to make room for new data
 90   *
 91   * Note: Does *not* update sb->chars
 92   */
 93  static void sb_insert_space(stringbuf *sb, int pos, int len)
 94  {
 95  	assert(pos <= sb->last);
 96  
 97  	/* Make sure there is enough space */
 98  	if (sb->remaining < len) {
 99  		sb_realloc(sb, sb->last + len + SB_INCREMENT);
100  	}
101  	/* Now move it up */
102  	memmove(sb->data + pos + len, sb->data + pos, sb->last - pos);
103  	sb->last += len;
104  	sb->remaining -= len;
105  	/* And null terminate */
106  	sb->data[sb->last] = 0;
107  }
108  
109  /**
110   * Move down all the data from pos + len, effectively
111   * deleting the data at position 'pos' of length 'len'
112   */
113  static void sb_delete_space(stringbuf *sb, int pos, int len)
114  {
115  	assert(pos < sb->last);
116  	assert(pos + len <= sb->last);
117  
118  #ifdef USE_UTF8
119  	sb->chars -= utf8_strlen(sb->data + pos, len);
120  #endif
121  
122  	/* Now move it up */
123  	memmove(sb->data + pos, sb->data + pos + len, sb->last - pos - len);
124  	sb->last -= len;
125  	sb->remaining += len;
126  	/* And null terminate */
127  	sb->data[sb->last] = 0;
128  }
129  
130  void sb_insert(stringbuf *sb, int index, const char *str)
131  {
132  	if (index >= sb->last) {
133  		/* Inserting after the end of the list appends. */
134  		sb_append(sb, str);
135  	}
136  	else {
137  		int len = strlen(str);
138  
139  		sb_insert_space(sb, index, len);
140  		memcpy(sb->data + index, str, len);
141  #ifdef USE_UTF8
142  		sb->chars += utf8_strlen(str, len);
143  #endif
144  	}
145  }
146  
147  /**
148   * Delete the bytes at index 'index' for length 'len'
149   * Has no effect if the index is past the end of the list.
150   */
151  void sb_delete(stringbuf *sb, int index, int len)
152  {
153  	if (index < sb->last) {
154  		char *pos = sb->data + index;
155  		if (len < 0) {
156  			len = sb->last;
157  		}
158  
159  		sb_delete_space(sb, pos - sb->data, len);
160  	}
161  }
162  
163  void sb_clear(stringbuf *sb)
164  {
165  	if (sb->data) {
166  		/* Null terminate */
167  		sb->data[0] = 0;
168  		sb->last = 0;
169  #ifdef USE_UTF8
170  		sb->chars = 0;
171  #endif
172  	}
173  }