table.c revision 9663:ace9a2ac3683
1/*
2 * TODO: - make right and centered alignment possible
3 */
4/*
5    parted - a frontend to libparted
6    Copyright (C) 2006, 2007 Free Software Foundation, Inc.
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20*/
21
22
23#include <config.h>
24
25#include <stdio.h>
26#include <stdlib.h>
27
28#include <assert.h>
29#include <wchar.h>
30#include <string.h>
31
32#include "xalloc.h"
33#include "strlist.h"
34
35#ifdef ENABLE_NLS
36#	define L_(str) L##str
37#else
38#	define L_(str) str
39#       ifdef wchar_t
40#               undef wchar_t
41#       endif
42#       define wchar_t char
43#       define wcslen strlen
44#       define wcswidth strnlen
45#       define wcscat strcat
46#       define wcsdup xstrdup
47#endif
48
49
50static const unsigned int       MAX_WIDTH = 512;
51static const wchar_t*           DELIMITER = L_("  ");
52static const wchar_t*           COLSUFFIX = L_("\n");
53
54typedef struct
55{
56        unsigned int    ncols;
57        unsigned int    nrows;
58        wchar_t***      rows;
59        int*            widths;
60} Table;
61
62
63Table* table_new(int ncols)
64{
65        assert ( ncols >= 0 );
66
67        Table *t = xmalloc (sizeof(*t));
68
69        t->ncols = ncols;
70        t->nrows = 0;
71        t->rows = (wchar_t***)NULL;
72        t->widths = NULL;
73
74        return t;
75}
76
77
78void table_destroy (Table* t)
79{
80        unsigned int r, c;
81
82        assert (t);
83        assert (t->ncols > 0);
84
85        for (r = 0; r < t->nrows; ++r)
86        {
87                for (c = 0; c < t->ncols; ++c)
88                        free (t->rows[r][c]);
89                free (t->rows[r]);
90        }
91
92        if (t->rows)
93                free (t->rows);
94
95        if (t->widths)
96                free (t->widths);
97
98        free (t);
99}
100
101
102static int max (int x, int y)
103{
104        return x > y ? x : y;
105}
106
107
108static void table_calc_column_widths (Table* t)
109{
110        unsigned int r, c;
111
112        assert(t);
113        assert(t->ncols > 0);
114
115        if (!t->widths)
116                t->widths = xmalloc (t->ncols * sizeof(t->widths[0]));
117
118        for (c = 0; c < t->ncols; ++c)
119                t->widths[c] = 0;
120
121        for (r = 0; r < t->nrows; ++r)
122                for (c = 0; c < t->ncols; ++c)
123                {
124                        t->widths[c] = max ( t->widths[c],
125                                             wcswidth(t->rows[r][c],
126                                                      MAX_WIDTH) );
127                }
128}
129
130
131/*
132 * add a row which is a string array of ncols elements.
133 * 'row' will get freed by table_destroy;  you must not free it
134 * yourself.
135 */
136void table_add_row (Table* t, wchar_t** row)
137{
138        assert(t);
139
140        /*unsigned int i;
141        fputs ("adding row: ", stdout);
142        for (i = 0; i < t->ncols; ++i)
143                printf("[%s]", row[i]);
144        putchar ('\n');*/
145
146        t->rows = xrealloc (t->rows, (t->nrows + 1) * sizeof(wchar_t***));
147
148        t->rows[t->nrows] = row;
149
150        ++t->nrows;
151
152        table_calc_column_widths (t);
153}
154
155
156void table_add_row_from_strlist (Table* t, StrList* list)
157{
158        wchar_t** row = xmalloc (str_list_length(list) * sizeof(*row));
159        int i = 0;
160
161        while (list)
162        {
163                row[i] = wcsdup (list->str);
164                if (row[i] == NULL)
165                        xalloc_die ();
166
167
168                list = list->next;
169                ++i;
170        }
171
172        table_add_row (t, row);
173}
174
175
176/* render a row */
177static void table_render_row (Table* t, int rownum, int ncols, wchar_t** s)
178{
179        wchar_t** row = t->rows[rownum];
180        int len = 1, i;
181        size_t newsize;
182
183        assert(t);
184        assert(s != NULL);
185
186        for (i = 0; i < ncols; ++i)
187                len += t->widths[i] + wcslen(DELIMITER);
188
189        len += wcslen(COLSUFFIX);
190
191        newsize = (wcslen(*s) + len + 1) * sizeof(wchar_t);
192        *s = xrealloc (*s, newsize);
193
194        for (i = 0; i < ncols; ++i)
195        {
196                int j;
197                int nspaces = max(t->widths[i] - wcswidth(row[i], MAX_WIDTH),
198                                  0);
199                wchar_t* pad = xmalloc ((nspaces + 1) * sizeof(*pad));
200
201                for (j = 0; j < nspaces; ++j)
202                       pad[j] = L' ';
203
204                pad[nspaces] = L_('\0');
205
206                wcscat (*s, row[i]);
207                wcscat (*s, pad);
208                if (i + 1 < ncols)
209                        wcscat (*s, DELIMITER);
210
211                free (pad);
212                pad = NULL;
213        }
214
215        wcscat (*s, COLSUFFIX);
216}
217
218
219/*
220 * Render the rows.
221 * \p s must be a null-terminated string.
222 */
223static void table_render_rows (Table* t, wchar_t** s)
224{
225        unsigned int i;
226
227        assert (**s == L_('\0'));
228        for (i = 0; i < t->nrows; ++i)
229                table_render_row (t, i, t->ncols, s);
230}
231
232/*
233 * Render the table to a string.
234 * You are responsible for freeing the returned string.
235 */
236wchar_t* table_render(Table* t)
237{
238        wchar_t* s = xmalloc (sizeof(*s));
239
240        *s = L_('\0');
241        table_render_rows (t, &s);
242        return s;
243}
244