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