1 /*
2  * Copyright (C) 2002,2009 Red Hat, Inc.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (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 GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
17  *
18  * Red Hat Author(s): Nalin Dahyabhai, Behdad Esfahbod
19  */
20 
21 #include <vice.h>
22 
23 #include "debug.h"
24 #include "vterowdata.h"
25 
26 #include <string.h>
27 
28 
29 /*
30  * VteCells: A row's cell array
31  */
32 
33 typedef struct _VteCells VteCells;
34 struct _VteCells {
35     guint32 alloc_len;
36     VteCell cells[1];
37 };
38 
_vte_cells_for_cell_array(VteCell * cells)39 static inline VteCells *_vte_cells_for_cell_array (VteCell *cells)
40 {
41     if (G_UNLIKELY (!cells)) {
42         return NULL;
43     }
44 
45     return (VteCells *) (((guchar *) cells) - G_STRUCT_OFFSET (VteCells, cells));
46 }
47 
_vte_cells_realloc(VteCells * cells,guint32 len)48 static VteCells *_vte_cells_realloc (VteCells *cells, guint32 len)
49 {
50     guint32 alloc_len = (1 << g_bit_storage (MAX (len, 80))) - 1;
51 
52     _vte_debug_print(VTE_DEBUG_RING, "Enlarging cell array of %d cells to %d cells\n", cells ? cells->alloc_len : 0, alloc_len);
53     cells = (VteCells *)g_realloc (cells, G_STRUCT_OFFSET (VteCells, cells) + alloc_len * sizeof (cells->cells[0]));
54     cells->alloc_len = alloc_len;
55 
56     return cells;
57 }
58 
_vte_cells_free(VteCells * cells)59 static void _vte_cells_free (VteCells *cells)
60 {
61     _vte_debug_print(VTE_DEBUG_RING, "Freeing cell array of %d cells\n", cells->alloc_len);
62     g_free (cells);
63 }
64 
65 
66 /*
67  * VteRowData: A row's data
68  */
69 
_vte_row_data_init(VteRowData * row)70 void _vte_row_data_init (VteRowData *row)
71 {
72     memset (row, 0, sizeof (*row));
73 }
74 
_vte_row_data_clear(VteRowData * row)75 void _vte_row_data_clear (VteRowData *row)
76 {
77     VteCell *cells = row->cells;
78     _vte_row_data_init (row);
79     row->cells = cells;
80 }
81 
_vte_row_data_fini(VteRowData * row)82 void _vte_row_data_fini (VteRowData *row)
83 {
84     if (row->cells) {
85         _vte_cells_free (_vte_cells_for_cell_array (row->cells));
86     }
87     row->cells = NULL;
88 }
89 
_vte_row_data_ensure(VteRowData * row,gulong len)90 static inline gboolean _vte_row_data_ensure (VteRowData *row, gulong len)
91 {
92     VteCells *cells = _vte_cells_for_cell_array (row->cells);
93     if (G_LIKELY (cells && len <= cells->alloc_len)) {
94         return TRUE;
95     }
96 
97     if (G_UNLIKELY (len >= 0xFFFF)) {
98         return FALSE;
99     }
100 
101     row->cells = _vte_cells_realloc (cells, len)->cells;
102 
103     return TRUE;
104 }
105 
_vte_row_data_insert(VteRowData * row,gulong col,const VteCell * cell)106 void _vte_row_data_insert (VteRowData *row, gulong col, const VteCell *cell)
107 {
108     gulong i;
109 
110     if (G_UNLIKELY (!_vte_row_data_ensure (row, row->len + 1))) {
111         return;
112     }
113 
114     for (i = row->len; i > col; i--) {
115         row->cells[i] = row->cells[i - 1];
116     }
117 
118     row->cells[col] = *cell;
119     row->len++;
120 }
121 
_vte_row_data_append(VteRowData * row,const VteCell * cell)122 void _vte_row_data_append (VteRowData *row, const VteCell *cell)
123 {
124     if (G_UNLIKELY (!_vte_row_data_ensure (row, row->len + 1))) {
125         return;
126     }
127 
128     row->cells[row->len] = *cell;
129     row->len++;
130 }
131 
_vte_row_data_remove(VteRowData * row,gulong col)132 void _vte_row_data_remove (VteRowData *row, gulong col)
133 {
134     gulong i;
135 
136     for (i = col + 1; i < row->len; i++) {
137         row->cells[i - 1] = row->cells[i];
138     }
139 
140     if (G_LIKELY (row->len)) {
141         row->len--;
142     }
143 }
144 
_vte_row_data_fill(VteRowData * row,const VteCell * cell,gulong len)145 void _vte_row_data_fill (VteRowData *row, const VteCell *cell, gulong len)
146 {
147     if (row->len < len) {
148         gulong i;
149 
150         if (G_UNLIKELY (!_vte_row_data_ensure (row, len))) {
151             return;
152         }
153 
154         for (i = row->len; i < len; i++) {
155             row->cells[i] = *cell;
156         }
157 
158         row->len = len;
159     }
160 }
161 
_vte_row_data_shrink(VteRowData * row,gulong max_len)162 void _vte_row_data_shrink (VteRowData *row, gulong max_len)
163 {
164     if (max_len < row->len) {
165         row->len = max_len;
166     }
167 }
168 
169