1 /*
2  * Copyright (C) 2002,2009 Red Hat, Inc.
3  *
4  * This library is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License as published
6  * by the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This library 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 Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public License
15  * along with this library.  If not, see <https://www.gnu.org/licenses/>.
16  *
17  * Red Hat Author(s): Nalin Dahyabhai, Behdad Esfahbod
18  */
19 
20 #include <config.h>
21 
22 #include "debug.h"
23 #include "vterowdata.hh"
24 
25 #include <string.h>
26 
27 #include <type_traits>
28 
29 /* This will be true now that VteCell is POD, but make sure it'll be true
30  * once that changes.
31  */
32 static_assert(std::is_trivially_copy_constructible<VteCell>::value, "VteCell is not copy constructible");
33 static_assert(std::is_trivially_move_constructible<VteCell>::value, "VteCell is not move constructible");
34 static_assert(std::is_trivially_copyable<VteCell>::value, "VteCell is not trivially copyable");
35 static_assert(std::is_trivially_copy_assignable<VteCell>::value, "VteCell is not copy assignable");
36 static_assert(std::is_trivially_move_assignable<VteCell>::value, "VteCell is not move assignable");
37 
38 /*
39  * VteCells: A row's cell array
40  */
41 
42 typedef struct _VteCells VteCells;
43 struct _VteCells {
44 	guint32 alloc_len;
45 	VteCell cells[1];
46 };
47 
48 static inline VteCells *
_vte_cells_for_cell_array(VteCell * cells)49 _vte_cells_for_cell_array (VteCell *cells)
50 {
51 	if (G_UNLIKELY (!cells))
52 		return NULL;
53 
54 	return (VteCells *) (((guchar *) cells) - G_STRUCT_OFFSET (VteCells, cells));
55 }
56 
57 static VteCells *
_vte_cells_realloc(VteCells * cells,guint32 len)58 _vte_cells_realloc (VteCells *cells, guint32 len)
59 {
60 	guint32 alloc_len = (1 << g_bit_storage (MAX (len, 80))) - 1;
61 
62 	_vte_debug_print(VTE_DEBUG_RING, "Enlarging cell array of %d cells to %d cells\n", cells ? cells->alloc_len : 0, alloc_len);
63 	cells = (VteCells *)g_realloc (cells, G_STRUCT_OFFSET (VteCells, cells) + alloc_len * sizeof (cells->cells[0]));
64 	cells->alloc_len = alloc_len;
65 
66 	return cells;
67 }
68 
69 static void
_vte_cells_free(VteCells * cells)70 _vte_cells_free (VteCells *cells)
71 {
72 	_vte_debug_print(VTE_DEBUG_RING, "Freeing cell array of %d cells\n", cells->alloc_len);
73 	g_free (cells);
74 }
75 
76 
77 /*
78  * VteRowData: A row's data
79  */
80 
81 void
_vte_row_data_init(VteRowData * row)82 _vte_row_data_init (VteRowData *row)
83 {
84 	memset (row, 0, sizeof (*row));
85 }
86 
87 void
_vte_row_data_clear(VteRowData * row)88 _vte_row_data_clear (VteRowData *row)
89 {
90 	VteCell *cells = row->cells;
91 	_vte_row_data_init (row);
92 	row->cells = cells;
93 }
94 
95 void
_vte_row_data_fini(VteRowData * row)96 _vte_row_data_fini (VteRowData *row)
97 {
98 	if (row->cells)
99 		_vte_cells_free (_vte_cells_for_cell_array (row->cells));
100 	row->cells = NULL;
101 }
102 
103 static inline gboolean
_vte_row_data_ensure(VteRowData * row,gulong len)104 _vte_row_data_ensure (VteRowData *row, gulong len)
105 {
106 	VteCells *cells = _vte_cells_for_cell_array (row->cells);
107 	if (G_LIKELY (cells && len <= cells->alloc_len))
108 		return TRUE;
109 
110 	if (G_UNLIKELY (len >= 0xFFFF))
111 		return FALSE;
112 
113 	row->cells = _vte_cells_realloc (cells, len)->cells;
114 
115 	return TRUE;
116 }
117 
118 void
_vte_row_data_insert(VteRowData * row,gulong col,const VteCell * cell)119 _vte_row_data_insert (VteRowData *row, gulong col, const VteCell *cell)
120 {
121 	gulong i;
122 
123 	if (G_UNLIKELY (!_vte_row_data_ensure (row, row->len + 1)))
124 		return;
125 
126 	for (i = row->len; i > col; i--)
127 		row->cells[i] = row->cells[i - 1];
128 
129 	row->cells[col] = *cell;
130 	row->len++;
131 }
132 
_vte_row_data_append(VteRowData * row,const VteCell * cell)133 void _vte_row_data_append (VteRowData *row, const VteCell *cell)
134 {
135 	if (G_UNLIKELY (!_vte_row_data_ensure (row, row->len + 1)))
136 		return;
137 
138 	row->cells[row->len] = *cell;
139 	row->len++;
140 }
141 
_vte_row_data_remove(VteRowData * row,gulong col)142 void _vte_row_data_remove (VteRowData *row, gulong col)
143 {
144 	gulong i;
145 
146 	for (i = col + 1; i < row->len; i++)
147 		row->cells[i - 1] = row->cells[i];
148 
149 	if (G_LIKELY (row->len))
150 		row->len--;
151 }
152 
_vte_row_data_fill(VteRowData * row,const VteCell * cell,gulong len)153 void _vte_row_data_fill (VteRowData *row, const VteCell *cell, gulong len)
154 {
155 	if (row->len < len) {
156 		gulong i;
157 
158 		if (G_UNLIKELY (!_vte_row_data_ensure (row, len)))
159 			return;
160 
161 		for (i = row->len; i < len; i++)
162 			row->cells[i] = *cell;
163 
164 		row->len = len;
165 	}
166 }
167 
_vte_row_data_shrink(VteRowData * row,gulong max_len)168 void _vte_row_data_shrink (VteRowData *row, gulong max_len)
169 {
170 	if (max_len < row->len)
171 		row->len = max_len;
172 }
173 
_vte_row_data_copy(const VteRowData * src,VteRowData * dst)174 void _vte_row_data_copy (const VteRowData *src, VteRowData *dst)
175 {
176         _vte_row_data_ensure (dst, src->len);
177         dst->len = src->len;
178         dst->attr = src->attr;
179         memcpy(dst->cells, src->cells, src->len * sizeof (src->cells[0]));
180 }
181 
182 /* Get the length, ignoring trailing empty cells (with a custom background color). */
_vte_row_data_nonempty_length(const VteRowData * row)183 guint16 _vte_row_data_nonempty_length (const VteRowData *row)
184 {
185         guint16 len;
186         const VteCell *cell;
187         for (len = row->len; len > 0; len--) {
188                 cell = &row->cells[len - 1];
189                 if (cell->attr.fragment() || cell->c != 0)
190                         break;
191         }
192         return len;
193 }
194 
195