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 
  50 static const unsigned int       MAX_WIDTH = 512;
  51 static const wchar_t*           DELIMITER = L_("  ");
  52 static const wchar_t*           COLSUFFIX = L_("\n");
  53 
  54 typedef struct
  55 {
  56         unsigned int    ncols;
  57         unsigned int    nrows;
  58         wchar_t***      rows;
  59         int*            widths;
  60 } Table;
  61 
  62 
  63 Table* 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 
  78 void 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 
 102 static int max (int x, int y)
 103 {
 104         return x > y ? x : y;
 105 }
 106 
 107 
 108 static 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  */
 136 void 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 
 156 void 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 */
 177 static 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  */
 223 static 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  */
 236 wchar_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 }