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