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