]> diplodocus.org Git - nmh/blob - sbr/charstring.c
mhbuildsbr.c: Flip logic, moving goto to then-block; no need for else.
[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 const size_t cur = s->cur - s->buffer;
31
32 while (need >= s->max - cur) {
33 /* Insufficient capacity, so double it. */
34 s->buffer = mh_xrealloc (s->buffer, s->max *= 2);
35 s->cur = s->buffer + cur;
36 }
37 }
38
39 /*
40 * max is in characters
41 */
42 charstring_t
43 charstring_create (size_t max) {
44 charstring_t s;
45
46 NEW(s);
47 s->max = NMH_MAX_CHARWIDTH * (max ? max : CHARSTRING_DEFAULT_SIZE);
48 s->cur = s->buffer = mh_xmalloc (s->max);
49 s->chars = 0;
50
51 return s;
52 }
53
54 charstring_t
55 charstring_copy (const charstring_t src) {
56 const size_t num = src->cur - src->buffer;
57 charstring_t s;
58
59 NEW(s);
60 s->max = src->max;
61 s->buffer = mh_xmalloc (s->max);
62 memcpy (s->buffer, src->buffer, num);
63 s->cur = s->buffer + num;
64 s->chars = src->chars;
65
66 return s;
67 }
68
69 /*
70 * OK to call charstring_free with a NULL argument.
71 */
72 void
73 charstring_free (charstring_t s) {
74 if (s) {
75 free (s->buffer);
76 free (s);
77 }
78 }
79
80 void
81 charstring_push_back (charstring_t s, const char c) {
82 charstring_reserve (s, s->cur - s->buffer + 1);
83 *s->cur++ = c;
84 ++s->chars;
85 }
86
87 /*
88 * num is the number of bytes in c, width is the display width
89 * occupied by the character(s).
90 */
91 void
92 charstring_push_back_chars (charstring_t s, const char c[], size_t num,
93 size_t width) {
94 size_t i;
95
96 charstring_reserve (s, s->cur - s->buffer + num);
97 for (i = 0; i < num; ++i) { *s->cur++ = *c++; }
98 s->chars += width;
99 }
100
101 void
102 charstring_append (charstring_t dest, const charstring_t src) {
103 const size_t num = src->cur - src->buffer;
104
105 if (num > 0) {
106 charstring_reserve (dest, dest->cur - dest->buffer + num);
107 memcpy (dest->cur, src->buffer, num);
108 dest->cur += num;
109 dest->chars += src->chars;
110 }
111 }
112
113 void
114 charstring_append_cstring (charstring_t dest, const char src[]) {
115 const size_t num = strlen (src);
116
117 if (num > 0) {
118 charstring_reserve (dest, dest->cur - dest->buffer + num);
119 memcpy (dest->cur, src, num); /* Exclude src's trailing newline. */
120 dest->cur += num;
121 dest->chars += num;
122 }
123 }
124
125 void
126 charstring_clear (charstring_t s) {
127 s->cur = s->buffer;
128 s->chars = 0;
129 }
130
131 /*
132 * Don't store return value of charstring_buffer() and use later after
133 * intervening push_back's; use charstring_buffer_copy() instead.
134 */
135 const char *
136 charstring_buffer (const charstring_t s) {
137 charstring_reserve (s, s->cur - s->buffer + 1);
138
139 /* This is the only place that we null-terminate the buffer. */
140 *s->cur = '\0';
141 /* Don't increment cur so that more can be appended later, and so
142 that charstring_bytes() behaves as strlen() by not counting the
143 null. */
144
145 return s->buffer;
146 }
147
148 char *
149 charstring_buffer_copy (const charstring_t s) {
150 char *copy = mh_xmalloc (s->cur - s->buffer + 1);
151
152 /* Use charstring_buffer() to null terminate the buffer. */
153 memcpy (copy, charstring_buffer (s), s->cur - s->buffer + 1);
154
155 return copy;
156 }
157
158 size_t
159 charstring_bytes (const charstring_t s) {
160 return s->cur - s->buffer;
161 }
162
163 size_t
164 charstring_chars (const charstring_t s) {
165 return s->chars;
166 }
167
168 int
169 charstring_last_char_len (const charstring_t s) {
170 int len = 0;
171 #ifdef MULTIBYTE_SUPPORT
172 const char *sp = charstring_buffer (s);
173 size_t remaining = charstring_bytes (s);
174
175 if (mbtowc (NULL, NULL, 0)) {} /* reset shift state */
176
177 while (*sp && remaining > 0) {
178 wchar_t wide_char;
179
180 len = mbtowc (&wide_char, sp, (size_t) MB_CUR_MAX < remaining
181 ? (size_t) MB_CUR_MAX
182 : remaining);
183 sp += max(len, 1);
184 remaining -= max(len, 1);
185 }
186 #else /* ! MULTIBYTE_SUPPORT */
187 if (charstring_bytes (s) > 0) { len = 1; }
188 #endif /* ! MULTIBYTE_SUPPORT */
189
190 return len;
191 }