| /* |
| * This program is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU General Public |
| * License v2 as published by the Free Software Foundation. |
| * |
| * 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., 59 Temple Place - Suite 330, |
| * Boston, MA 021110-1307, USA. |
| */ |
| |
| #include <stdlib.h> |
| #include <string.h> |
| #include <stdio.h> |
| #include <stdarg.h> |
| #include "common/messages.h" |
| #include "common/string-table.h" |
| #include "common/internal.h" |
| |
| /* |
| * Create an array of char* which will point to table cell strings |
| */ |
| struct string_table *table_create(unsigned int columns, unsigned int rows) |
| { |
| struct string_table *tab; |
| size_t size; |
| |
| size = sizeof(struct string_table) + rows * columns * sizeof(char*); |
| tab = calloc(1, size); |
| |
| if (!tab) |
| return NULL; |
| |
| tab->ncols = columns; |
| tab->nrows = rows; |
| tab->spacing = STRING_TABLE_SPACING_1; |
| |
| return tab; |
| } |
| |
| /* |
| * This is like a vprintf, but stores the results in a cell of the table. |
| */ |
| __attribute__ ((format (printf, 4, 0))) |
| char *table_vprintf(struct string_table *tab, unsigned int column, unsigned int row, |
| const char *fmt, va_list ap) |
| { |
| unsigned int idx = tab->ncols * row + column; |
| char *msg = calloc(100, 1); |
| |
| if (!msg) |
| return NULL; |
| |
| if (column >= tab->ncols || row >= tab->nrows) { |
| free(msg); |
| error("attempt to write outside of table: col %u row %u fmt %s", |
| column, row, fmt); |
| return NULL; |
| } |
| |
| if (tab->cells[idx]) |
| free(tab->cells[idx]); |
| tab->cells[idx] = msg; |
| vsnprintf(msg, 99, fmt, ap); |
| |
| return msg; |
| } |
| |
| /* |
| * This is like a printf, but stores the results in a cell of the table. |
| */ |
| __attribute__ ((format (printf, 4, 5))) |
| char *table_printf(struct string_table *tab, unsigned int column, unsigned int row, |
| const char *fmt, ...) |
| { |
| va_list ap; |
| char *ret; |
| |
| va_start(ap, fmt); |
| ret = table_vprintf(tab, column, row, fmt, ap); |
| va_end(ap); |
| |
| return ret; |
| } |
| |
| /* |
| * Print the table to stdout, interpret the alignment and expand specifiers. |
| * @from: row from which to start |
| * @to: upper row limit (not inclusive), 0 for the whole table |
| * |
| * Formatting: |
| * <TEXT - the TEXT is left aligned |
| * >TEXT - the TEXT is right aligned |
| * = - the cell text will be filled by ===== (column width) |
| * *C - the cell text will be filled by character C (column width) |
| */ |
| void table_dump_range(struct string_table *tab, unsigned int from, unsigned int to) |
| { |
| unsigned int sizes[tab->ncols]; |
| unsigned int i, j; |
| unsigned int prescan; |
| |
| if (to == 0) |
| to = tab->nrows; |
| |
| if (from > to) { |
| error("invalid range for table dump %u > %u", from, to); |
| return; |
| } |
| |
| prescan = max_t(unsigned int, 100, to); |
| prescan = min_t(unsigned int, tab->nrows, prescan); |
| |
| for (i = 0; i < tab->ncols; i++) { |
| sizes[i] = 0; |
| for (j = 0; j < prescan; j++) { |
| int idx = i + j * tab->ncols; |
| int len; |
| |
| if (!tab->cells[idx]) |
| continue; |
| |
| len = strlen(tab->cells[idx]) - 1; |
| if (len == 0 || tab->cells[idx][0] == '*') |
| continue; |
| |
| if (len > sizes[i]) |
| sizes[i] = len; |
| } |
| } |
| |
| for (j = from; j < to; j++) { |
| for (i = 0; i < tab->ncols; i++) { |
| int idx = i + j * tab->ncols; |
| char *cell = tab->cells[idx]; |
| |
| if (!cell || !strlen(cell)) { |
| printf("%*s", sizes[i], ""); |
| } else if (cell && cell[0] == '*' && cell[1]) { |
| int k = sizes[i]; |
| |
| while (k--) |
| putchar(cell[1]); |
| } else { |
| printf("%*s", |
| cell[0] == '<' ? -sizes[i] : sizes[i], |
| cell + 1); |
| } |
| if (i != (tab->ncols - 1)) { |
| putchar(' '); |
| if (tab->spacing == STRING_TABLE_SPACING_2) |
| putchar(' '); |
| } |
| } |
| putchar('\n'); |
| } |
| } |
| |
| /* |
| * Deallocate a table and all of its content |
| */ |
| void table_free(struct string_table *tab) |
| { |
| unsigned int i, count; |
| |
| count = tab->ncols * tab->nrows; |
| |
| for (i = 0; i < count; i++) |
| if (tab->cells[i]) |
| free(tab->cells[i]); |
| |
| free(tab); |
| } |
| |
| void table_clear_range(struct string_table *tab, unsigned int from, unsigned int to) |
| { |
| unsigned int row, col; |
| |
| if (to == 0) |
| to = tab->nrows; |
| |
| for (row = from; row < to; row++) { |
| char **rowstart = &tab->cells[row * tab->ncols]; |
| |
| for (col = 0; col < tab->ncols; col++) { |
| free(rowstart[col]); |
| rowstart[col] = NULL; |
| } |
| } |
| } |