]> diplodocus.org Git - nmh/blob - sbr/charstring.c
forwsbr.c: Move interface declaration to own forwsbr.h.
[nmh] / sbr / charstring.c
1 /* charstring.c -- dynamically-sized char array that can report size
2 * in both characters and bytes
3 *
4 * This code is Copyright (c) 2014, by the authors of nmh. See the
5 * COPYRIGHT file in the root directory of the nmh distribution for
6 * complete copyright information.
7 */
8
9 #include <h/mh.h>
10 #include <h/utils.h>
11
12 #ifdef MULTIBYTE_SUPPORT
13 # define NMH_MAX_CHARWIDTH MB_CUR_MAX
14 #else
15 # define NMH_MAX_CHARWIDTH 1
16 #endif
17
18 #define CHARSTRING_DEFAULT_SIZE 64
19
20 struct charstring {
21 char *buffer; /* the char array, not always null-terminated */
22 size_t max; /* current size of the char array, in bytes */
23 char *cur; /* size in bytes = cur - buffer, without trailing null */
24 size_t chars; /* size in characters */
25 };
26
27
28 static void
29 charstring_reserve (charstring_t s, size_t need)
30 {
31 const size_t cur = s->cur - s->buffer;
32
33 while (need >= s->max - cur) {
34 /* Insufficient capacity, so double it. */
35 s->buffer = mh_xrealloc (s->buffer, s->max *= 2);
36 s->cur = s->buffer + cur;
37 }
38 }
39
40 /*
41 * max is in characters
42 */
43 charstring_t
44 charstring_create (size_t max)
45 {
46 charstring_t s;
47
48 NEW(s);
49 s->max = NMH_MAX_CHARWIDTH * (max ? max : CHARSTRING_DEFAULT_SIZE);
50 s->cur = s->buffer = mh_xmalloc (s->max);
51 s->chars = 0;
52
53 return s;
54 }
55
56 charstring_t
57 charstring_copy (const charstring_t src)
58 {
59 const size_t num = src->cur - src->buffer;
60 charstring_t s;
61
62 NEW(s);
63 s->max = src->max;
64 s->buffer = mh_xmalloc (s->max);
65 memcpy (s->buffer, src->buffer, num);
66 s->cur = s->buffer + num;
67 s->chars = src->chars;
68
69 return s;
70 }
71
72 /*
73 * OK to call charstring_free with a NULL argument.
74 */
75 void
76 charstring_free (charstring_t s)
77 {
78 if (s) {
79 free (s->buffer);
80 free (s);
81 }
82 }
83
84 void
85 charstring_push_back (charstring_t s, const char c)
86 {
87 charstring_reserve (s, s->cur - s->buffer + 1);
88 *s->cur++ = c;
89 ++s->chars;
90 }
91
92 /*
93 * num is the number of bytes in c, width is the display width
94 * occupied by the character(s).
95 */
96 void
97 charstring_push_back_chars (charstring_t s, const char c[], size_t num,
98 size_t width)
99 {
100 size_t i;
101
102 charstring_reserve (s, s->cur - s->buffer + num);
103 for (i = 0; i < num; ++i) { *s->cur++ = *c++; }
104 s->chars += width;
105 }
106
107 void
108 charstring_append (charstring_t dest, const charstring_t src)
109 {
110 const size_t num = src->cur - src->buffer;
111
112 if (num > 0) {
113 charstring_reserve (dest, dest->cur - dest->buffer + num);
114 memcpy (dest->cur, src->buffer, num);
115 dest->cur += num;
116 dest->chars += src->chars;
117 }
118 }
119
120 void
121 charstring_append_cstring (charstring_t dest, const char src[])
122 {
123 const size_t num = strlen (src);
124
125 if (num > 0) {
126 charstring_reserve (dest, dest->cur - dest->buffer + num);
127 memcpy (dest->cur, src, num); /* Exclude src's trailing newline. */
128 dest->cur += num;
129 dest->chars += num;
130 }
131 }
132
133 void
134 charstring_clear (charstring_t s)
135 {
136 s->cur = s->buffer;
137 s->chars = 0;
138 }
139
140 /*
141 * Don't store return value of charstring_buffer() and use later after
142 * intervening push_back's; use charstring_buffer_copy() instead.
143 */
144 const char *
145 charstring_buffer (const charstring_t s)
146 {
147 charstring_reserve (s, s->cur - s->buffer + 1);
148
149 /* This is the only place that we null-terminate the buffer. */
150 *s->cur = '\0';
151 /* Don't increment cur so that more can be appended later, and so
152 that charstring_bytes() behaves as strlen() by not counting the
153 null. */
154
155 return s->buffer;
156 }
157
158 char *
159 charstring_buffer_copy (const charstring_t s)
160 {
161 char *copy = mh_xmalloc (s->cur - s->buffer + 1);
162
163 /* Use charstring_buffer() to null terminate the buffer. */
164 memcpy (copy, charstring_buffer (s), s->cur - s->buffer + 1);
165
166 return copy;
167 }
168
169 size_t
170 charstring_bytes (const charstring_t s)
171 {
172 return s->cur - s->buffer;
173 }
174
175 size_t
176 charstring_chars (const charstring_t s)
177 {
178 return s->chars;
179 }
180
181 int
182 charstring_last_char_len (const charstring_t s)
183 {
184 int len = 0;
185 #ifdef MULTIBYTE_SUPPORT
186 const char *sp = charstring_buffer (s);
187 size_t remaining = charstring_bytes (s);
188
189 if (mbtowc (NULL, NULL, 0)) {} /* reset shift state */
190
191 while (*sp && remaining > 0) {
192 wchar_t wide_char;
193
194 len = mbtowc (&wide_char, sp, (size_t) MB_CUR_MAX < remaining
195 ? (size_t) MB_CUR_MAX
196 : remaining);
197 sp += max(len, 1);
198 remaining -= max(len, 1);
199 }
200 #else /* ! MULTIBYTE_SUPPORT */
201 if (charstring_bytes (s) > 0) { len = 1; }
202 #endif /* ! MULTIBYTE_SUPPORT */
203
204 return len;
205 }