/*
* TODO: - make right and centered alignment possible
*/
/*
parted - a frontend to libparted
Copyright (C) 2006-2014, 2019-2021 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#include
#include
#include
#include
#include
#include
#include "xalloc.h"
#include "strlist.h"
#ifdef ENABLE_NLS
# define L_(str) L##str
#else
# define L_(str) str
# define wcslen strlen
# define wcswidth strnlen
# define wcscat strcat
# define wcsdup xstrdup
#endif
static const unsigned int MAX_WIDTH = 512;
static const wchar_t* DELIMITER = L_(" ");
static const wchar_t* COLSUFFIX = L_("\n");
typedef struct
{
unsigned int ncols;
unsigned int nrows;
wchar_t*** rows;
int* widths;
} Table;
Table* table_new(int ncols)
{
assert ( ncols >= 0 );
Table *t = xmalloc (sizeof(*t));
t->ncols = ncols;
t->nrows = 0;
t->rows = (wchar_t***)NULL;
t->widths = NULL;
return t;
}
void table_destroy (Table* t)
{
unsigned int r, c;
assert (t);
assert (t->ncols > 0);
for (r = 0; r < t->nrows; ++r)
{
for (c = 0; c < t->ncols; ++c)
free (t->rows[r][c]);
free (t->rows[r]);
}
free (t->rows);
free (t->widths);
free (t);
}
static int max (int x, int y)
{
return x > y ? x : y;
}
static void table_calc_column_widths (Table* t)
{
unsigned int r, c;
assert(t);
assert(t->ncols > 0);
if (!t->widths)
t->widths = xmalloc (t->ncols * sizeof(t->widths[0]));
for (c = 0; c < t->ncols; ++c)
t->widths[c] = 0;
for (r = 0; r < t->nrows; ++r)
for (c = 0; c < t->ncols; ++c)
{
t->widths[c] = max ( t->widths[c],
wcswidth(t->rows[r][c],
MAX_WIDTH) );
}
}
/*
* add a row which is a string array of ncols elements.
* 'row' will get freed by table_destroy; you must not free it
* yourself.
*/
void table_add_row (Table* t, wchar_t** row)
{
assert(t);
/*unsigned int i;
fputs ("adding row: ", stdout);
for (i = 0; i < t->ncols; ++i)
printf("[%s]", row[i]);
putchar ('\n');*/
t->rows = xrealloc (t->rows, (t->nrows + 1) * sizeof(*(t->rows)));
t->rows[t->nrows] = row;
++t->nrows;
table_calc_column_widths (t);
}
void table_add_row_from_strlist (Table* t, StrList* list)
{
wchar_t** row = xmalloc (str_list_length(list) * sizeof(*row));
int i = 0;
while (list)
{
row[i] = wcsdup (list->str);
if (row[i] == NULL)
xalloc_die ();
list = list->next;
++i;
}
table_add_row (t, row);
}
/* render a row */
static void table_render_row (Table* t, int rownum, int ncols, wchar_t** s)
{
wchar_t** row = t->rows[rownum];
size_t len = 1, i;
size_t newsize;
assert(t);
assert(s != NULL);
for (i = 0; i < ncols; ++i)
len += t->widths[i] + wcslen(DELIMITER);
len += wcslen(COLSUFFIX);
newsize = (wcslen(*s) + len + 1) * sizeof(wchar_t);
*s = xrealloc (*s, newsize);
for (i = 0; i < ncols; ++i)
{
wcscat (*s, row[i]);
if (ncols <= i + 1)
break;
int j;
int nspaces = max(t->widths[i] - wcswidth(row[i], MAX_WIDTH),
0);
wchar_t* pad = xmalloc ((nspaces + 1) * sizeof(*pad));
for (j = 0; j < nspaces; ++j)
pad[j] = L' ';
pad[nspaces] = L_('\0');
wcscat (*s, pad);
if (i + 1 < ncols)
wcscat (*s, DELIMITER);
free (pad);
}
/* Remove any trailing blanks. */
wchar_t *p = *s;
size_t k = wcslen (p);
while (k && p[k-1] == L_(' '))
--k;
p[k] = L_('\0');
wcscat (*s, COLSUFFIX);
}
/*
* Render the rows.
* \p s must be a null-terminated string.
*/
static void table_render_rows (Table* t, wchar_t** s)
{
unsigned int i;
assert (**s == L_('\0'));
for (i = 0; i < t->nrows; ++i)
table_render_row (t, i, t->ncols, s);
}
/*
* Render the table to a string.
* You are responsible for freeing the returned string.
*/
wchar_t* table_render(Table* t)
{
wchar_t* s = xmalloc (sizeof(*s));
*s = L_('\0');
table_render_rows (t, &s);
return s;
}