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