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