| /* |
| * TODO: - make right and centered alignment possible |
| */ |
| /* |
| parted - a frontend to libparted |
| Copyright (C) 2006, 2007 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 2 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, write to the Free Software |
| Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
| */ |
| |
| |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| |
| #include <assert.h> |
| |
| #include <config.h> |
| |
| #ifdef ENABLE_NLS |
| # include <wchar.h> |
| int wcswidth (const wchar_t *s, size_t n); |
| # define L_(str) L##str |
| #else |
| # define L_(str) str |
| # ifdef wchar_t |
| # undef wchar_t |
| # endif |
| # include <string.h> |
| # define wchar_t char |
| # define wcslen strlen |
| # define wcswidth strnlen |
| # define wcscat strcat |
| # define wcsdup strdup |
| size_t strnlen (const char *, size_t); |
| #endif |
| |
| #include "xalloc.h" |
| #include "strlist.h" |
| |
| |
| 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 = malloc(sizeof(Table)); |
| |
| 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]); |
| } |
| |
| if (t->rows) |
| free (t->rows); |
| |
| if (t->widths) |
| 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 = (int*)malloc(t->ncols * sizeof(int)); |
| |
| 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 = (wchar_t***)realloc (t->rows, (t->nrows + 1) |
| * sizeof(wchar_t***)); |
| |
| 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 = (wchar_t**)malloc(str_list_length(list) |
| * sizeof(wchar_t**)); |
| int i = 0; |
| |
| while (list) |
| { |
| row[i] = (wchar_t*)list->str; |
| |
| 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]; |
| int 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) |
| { |
| int j; |
| int nspaces = max(t->widths[i] - wcswidth(row[i], MAX_WIDTH), |
| 0); |
| wchar_t* pad = xmalloc ((nspaces + 1) * sizeof(wchar_t)); |
| |
| for (j = 0; j < nspaces; ++j) |
| pad[j] = L' '; |
| |
| pad[nspaces] = L_('\0'); |
| |
| wcscat (*s, row[i]); |
| wcscat (*s, pad); |
| if (i + 1 < ncols) |
| wcscat (*s, DELIMITER); |
| |
| free (pad); |
| pad = NULL; |
| } |
| |
| 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 = malloc(sizeof(wchar_t)); |
| |
| *s = L_('\0'); |
| table_render_rows (t, &s); |
| return s; |
| } |