]>
diplodocus.org Git - nmh/blob - sbr/charstring.c
2 * charstring -- dynamically-sized char array that can report size
3 * in both characters and bytes
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.
13 #ifdef MULTIBYTE_SUPPORT
14 # define NMH_MAX_CHARWIDTH MB_CUR_MAX
16 # define NMH_MAX_CHARWIDTH 1
19 #define CHARSTRING_DEFAULT_SIZE 64
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 */
30 charstring_reserve (charstring_t s
, size_t need
) {
31 const size_t cur
= s
->cur
- s
->buffer
;
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
;
41 * max is in characters
44 charstring_create (size_t max
) {
45 charstring_t s
= mh_xmalloc (sizeof *s
);
47 s
->max
= NMH_MAX_CHARWIDTH
* (max
? max
: CHARSTRING_DEFAULT_SIZE
);
48 s
->cur
= s
->buffer
= mh_xmalloc (s
->max
);
55 charstring_copy (const charstring_t src
) {
56 const size_t num
= src
->cur
- src
->buffer
;
57 charstring_t s
= mh_xmalloc (sizeof *s
);
60 s
->buffer
= mh_xmalloc (s
->max
);
61 memcpy (s
->buffer
, src
->buffer
, num
);
62 s
->cur
= s
->buffer
+ num
;
63 s
->chars
= src
->chars
;
69 * OK to call charstring_free with a NULL argument.
72 charstring_free (charstring_t s
) {
80 charstring_push_back (charstring_t s
, const char c
) {
81 charstring_reserve (s
, s
->cur
- s
->buffer
+ 1);
87 * num is the number of bytes in c, width is the display width
88 * occupied by the character(s).
91 charstring_push_back_chars (charstring_t s
, const char c
[], size_t num
,
95 charstring_reserve (s
, s
->cur
- s
->buffer
+ num
);
96 for (i
= 0; i
< num
; ++i
) { *s
->cur
++ = *c
++; }
101 charstring_append (charstring_t dest
, const charstring_t src
) {
102 const size_t num
= src
->cur
- src
->buffer
;
105 charstring_reserve (dest
, dest
->cur
- dest
->buffer
+ num
);
106 memcpy (dest
->cur
, src
->buffer
, num
);
108 dest
->chars
+= src
->chars
;
113 charstring_append_cstring (charstring_t dest
, const char src
[]) {
114 const size_t num
= strlen (src
);
117 charstring_reserve (dest
, dest
->cur
- dest
->buffer
+ num
);
118 memcpy (dest
->cur
, src
, num
); /* Exclude src's trailing newline. */
125 charstring_clear (charstring_t s
) {
131 * Don't store return value of charstring_buffer() and use later after
132 * intervening push_back's; use charstring_buffer_copy() instead.
135 charstring_buffer (const charstring_t s
) {
136 charstring_reserve (s
, s
->cur
- s
->buffer
+ 1);
138 /* This is the only place that we null-terminate the buffer. */
140 /* Don't increment cur so that more can be appended later, and so
141 that charstring_bytes() behaves as strlen() by not counting the
148 charstring_buffer_copy (const charstring_t s
) {
149 char *copy
= mh_xmalloc (s
->cur
- s
->buffer
+ 1);
151 /* Use charstring_buffer() to null terminate the buffer. */
152 memcpy (copy
, charstring_buffer (s
), s
->cur
- s
->buffer
+ 1);
158 charstring_bytes (const charstring_t s
) {
159 return s
->cur
- s
->buffer
;
163 charstring_chars (const charstring_t s
) {
168 charstring_last_char_len (const charstring_t s
) {
170 #ifdef MULTIBYTE_SUPPORT
171 const char *sp
= charstring_buffer (s
);
172 size_t remaining
= charstring_bytes (s
);
174 if (mbtowc (NULL
, NULL
, 0)) {} /* reset shift state */
176 while (*sp
&& remaining
> 0) {
179 len
= mbtowc (&wide_char
, sp
, (size_t) MB_CUR_MAX
< remaining
180 ? (size_t) MB_CUR_MAX
182 sp
+= len
> 0 ? len
: 1;
183 remaining
-= len
> 0 ? len
: 1;
185 #else /* ! MULTIBYTE_SUPPORT */
186 if (charstring_bytes (s
) > 0) { len
= 1; }
187 #endif /* ! MULTIBYTE_SUPPORT */