1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2011, 2012 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19 #include "libpspp/u8-line.h"
22 #include "libpspp/cast.h"
23 #include "libpspp/str.h"
26 u8_line_init (struct u8_line *line)
28 ds_init_empty (&line->s);
33 u8_line_clear (struct u8_line *line)
40 u8_line_destroy (struct u8_line *line)
42 ds_destroy (&line->s);
46 u8_mb_to_display (int *wp, const uint8_t *s, size_t n)
52 ofs = u8_mbtouc (&uc, s, n);
53 if (ofs < n && s[ofs] == '\b')
56 ofs += u8_mbtouc (&uc, s + ofs, n - ofs);
59 w = uc_width (uc, "UTF-8");
68 int mblen = u8_mbtouc (&uc, s + ofs, n - ofs);
69 if (uc_width (uc, "UTF-8") > 0)
87 u8_line_find_pos (struct u8_line *line, int target_x, struct u8_pos *c)
89 const uint8_t *s = CHAR_CAST (const uint8_t *, ds_cstr (&line->s));
90 size_t length = ds_length (&line->s);
96 for (ofs = 0; ; ofs += mblen)
100 mblen = u8_mb_to_display (&w, s + ofs, length - ofs);
101 if (x + w > target_x)
106 c->ofs1 = ofs + mblen;
114 u8_line_reserve (struct u8_line *line, int x0, int x1, int n)
116 if (x0 >= line->width)
118 /* The common case: adding new characters at the end of a line. */
119 ds_put_byte_multiple (&line->s, ' ', x0 - line->width);
121 return ds_put_uninit (&line->s, n);
127 /* An unusual case: overwriting characters in the middle of a line. We
128 don't keep any kind of mapping from bytes to display positions, so we
129 have to iterate over the whole line starting from the beginning. */
130 struct u8_pos p0, p1;
133 /* Find the positions of the first and last character. We must find both
134 characters' positions before changing the line, because that would
135 prevent finding the other character's position. */
136 u8_line_find_pos (line, x0, &p0);
137 if (x1 < line->width)
138 u8_line_find_pos (line, x1, &p1);
140 /* If a double-width character occupies both x0 - 1 and x0, then replace
141 its first character width by '?'. */
142 s = ds_data (&line->s);
149 if (x1 >= line->width)
151 ds_truncate (&line->s, p0.ofs0);
153 return ds_put_uninit (&line->s, n);
156 /* If a double-width character occupies both x1 - 1 and x1, then replace
157 its second character width by '?'. */
166 return ds_splice_uninit (&line->s, p0.ofs0, p1.ofs1 - p0.ofs0, n);
169 return ds_splice_uninit (&line->s, p0.ofs0, p1.ofs0 - p0.ofs0, n);