1217309Snwhitehorn/* 2251843Sbapt * $Id: columns.c,v 1.10 2011/10/20 20:53:55 tom Exp $ 3217309Snwhitehorn * 4217309Snwhitehorn * columns.c -- implements column-alignment 5217309Snwhitehorn * 6220749Snwhitehorn * Copyright 2008-2010,2011 Thomas E. Dickey 7217309Snwhitehorn * 8217309Snwhitehorn * This program is free software; you can redistribute it and/or modify 9217309Snwhitehorn * it under the terms of the GNU Lesser General Public License, version 2.1 10217309Snwhitehorn * as published by the Free Software Foundation. 11217309Snwhitehorn * 12217309Snwhitehorn * This program is distributed in the hope that it will be useful, but 13217309Snwhitehorn * WITHOUT ANY WARRANTY; without even the implied warranty of 14217309Snwhitehorn * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15217309Snwhitehorn * Lesser General Public License for more details. 16217309Snwhitehorn * 17217309Snwhitehorn * You should have received a copy of the GNU Lesser General Public 18217309Snwhitehorn * License along with this program; if not, write to 19217309Snwhitehorn * Free Software Foundation, Inc. 20217309Snwhitehorn * 51 Franklin St., Fifth Floor 21217309Snwhitehorn * Boston, MA 02110, USA. 22217309Snwhitehorn */ 23217309Snwhitehorn 24217309Snwhitehorn#include <dialog.h> 25217309Snwhitehorn 26217309Snwhitehorn#define each(row, data) \ 27217309Snwhitehorn row = 0, data = target; \ 28224014Snwhitehorn row < num_rows; \ 29217309Snwhitehorn ++row, data = next_row(data, per_row) 30217309Snwhitehorn 31217309Snwhitehornstatic char * 32217309Snwhitehorncolumn_separator(void) 33217309Snwhitehorn{ 34217309Snwhitehorn char *result = 0; 35217309Snwhitehorn 36217309Snwhitehorn if ((result = dialog_vars.column_separator) != 0) { 37217309Snwhitehorn if (*result == '\0') 38217309Snwhitehorn result = 0; 39217309Snwhitehorn } 40217309Snwhitehorn return result; 41217309Snwhitehorn} 42217309Snwhitehorn 43217309Snwhitehornstatic char ** 44217309Snwhitehornnext_row(char **target, int per_row) 45217309Snwhitehorn{ 46217309Snwhitehorn char *result = (char *) target; 47217309Snwhitehorn result += per_row; 48251843Sbapt return (char **) (void *) result; 49217309Snwhitehorn} 50217309Snwhitehorn 51217309Snwhitehornstatic char * 52217309Snwhitehornnext_col(char *source, unsigned offset) 53217309Snwhitehorn{ 54217309Snwhitehorn char *mark = column_separator(); 55217309Snwhitehorn char *result = source + offset; 56217309Snwhitehorn if (offset) 57217309Snwhitehorn result += strlen(mark); 58217309Snwhitehorn return strstr(result, mark); 59217309Snwhitehorn} 60217309Snwhitehorn 61217309Snwhitehorn/* 62217309Snwhitehorn * Parse the source string, storing the offsets and widths of each column in 63217309Snwhitehorn * the corresponding arrays. Return the number of columns. 64217309Snwhitehorn */ 65217309Snwhitehornstatic unsigned 66217309Snwhitehornsplit_row(char *source, unsigned *offsets, unsigned *widths) 67217309Snwhitehorn{ 68217309Snwhitehorn int mark = (int) strlen(column_separator()); 69217309Snwhitehorn char *next = 0; 70217309Snwhitehorn unsigned result = 0; 71217309Snwhitehorn unsigned offset = 0; 72217309Snwhitehorn 73217309Snwhitehorn do { 74217309Snwhitehorn if (result) { 75217309Snwhitehorn offset = (unsigned) (mark + next - source); 76217309Snwhitehorn widths[result - 1] = offset - offsets[result - 1] - (unsigned) mark; 77217309Snwhitehorn } 78217309Snwhitehorn offsets[result] = offset; 79217309Snwhitehorn ++result; 80217309Snwhitehorn } while ((next = next_col(source, offset)) != 0); 81217309Snwhitehorn 82220749Snwhitehorn offset = (unsigned) strlen(source); 83217309Snwhitehorn widths[result - 1] = offset - offsets[result - 1]; 84217309Snwhitehorn 85217309Snwhitehorn return result; 86217309Snwhitehorn} 87217309Snwhitehorn 88217309Snwhitehorn/* 89217309Snwhitehorn * The caller passes a pointer to a struct or array containing pointers 90217309Snwhitehorn * to strings that we may want to copy and reformat according to the column 91217309Snwhitehorn * separator. 92217309Snwhitehorn */ 93217309Snwhitehornvoid 94217309Snwhitehorndlg_align_columns(char **target, int per_row, int num_rows) 95217309Snwhitehorn{ 96217309Snwhitehorn int row; 97217309Snwhitehorn 98217309Snwhitehorn if (column_separator()) { 99217309Snwhitehorn char **value; 100217309Snwhitehorn unsigned numcols = 1; 101220749Snwhitehorn size_t maxcols = 0; 102217309Snwhitehorn unsigned *widths; 103217309Snwhitehorn unsigned *offsets; 104217309Snwhitehorn unsigned *maxwidth; 105217309Snwhitehorn unsigned realwidth; 106217309Snwhitehorn unsigned n; 107217309Snwhitehorn 108217309Snwhitehorn /* first allocate arrays for workspace */ 109217309Snwhitehorn for (each(row, value)) { 110220749Snwhitehorn size_t len = strlen(*value); 111217309Snwhitehorn if (maxcols < len) 112217309Snwhitehorn maxcols = len; 113217309Snwhitehorn } 114217309Snwhitehorn ++maxcols; 115217309Snwhitehorn widths = dlg_calloc(unsigned, maxcols); 116217309Snwhitehorn offsets = dlg_calloc(unsigned, maxcols); 117217309Snwhitehorn maxwidth = dlg_calloc(unsigned, maxcols); 118217309Snwhitehorn 119217309Snwhitehorn assert_ptr(widths, "dlg_align_columns"); 120217309Snwhitehorn assert_ptr(offsets, "dlg_align_columns"); 121217309Snwhitehorn assert_ptr(maxwidth, "dlg_align_columns"); 122217309Snwhitehorn 123217309Snwhitehorn /* now, determine the number of columns and the column-widths */ 124217309Snwhitehorn for (each(row, value)) { 125217309Snwhitehorn unsigned cols = split_row(*value, offsets, widths); 126217309Snwhitehorn if (numcols < cols) 127217309Snwhitehorn numcols = cols; 128217309Snwhitehorn for (n = 0; n < cols; ++n) { 129217309Snwhitehorn if (maxwidth[n] < widths[n]) 130217309Snwhitehorn maxwidth[n] = widths[n]; 131217309Snwhitehorn } 132217309Snwhitehorn } 133217309Snwhitehorn realwidth = numcols - 1; 134217309Snwhitehorn for (n = 0; n < numcols; ++n) { 135217309Snwhitehorn realwidth += maxwidth[n]; 136217309Snwhitehorn } 137217309Snwhitehorn 138217309Snwhitehorn /* finally, construct reformatted strings */ 139217309Snwhitehorn for (each(row, value)) { 140217309Snwhitehorn unsigned cols = split_row(*value, offsets, widths); 141217309Snwhitehorn unsigned offset = 0; 142217309Snwhitehorn char *text = dlg_malloc(char, realwidth + 1); 143217309Snwhitehorn 144217309Snwhitehorn assert_ptr(text, "dlg_align_columns"); 145217309Snwhitehorn 146220749Snwhitehorn memset(text, ' ', (size_t) realwidth); 147217309Snwhitehorn for (n = 0; n < cols; ++n) { 148220749Snwhitehorn memcpy(text + offset, *value + offsets[n], (size_t) widths[n]); 149217309Snwhitehorn offset += maxwidth[n] + 1; 150217309Snwhitehorn } 151251843Sbapt text[realwidth] = 0; 152217309Snwhitehorn *value = text; 153217309Snwhitehorn } 154217309Snwhitehorn 155217309Snwhitehorn free(widths); 156217309Snwhitehorn free(offsets); 157217309Snwhitehorn free(maxwidth); 158217309Snwhitehorn } 159217309Snwhitehorn} 160217309Snwhitehorn 161217309Snwhitehorn/* 162217309Snwhitehorn * Free temporary storage used while making column-aligned data. 163217309Snwhitehorn */ 164217309Snwhitehornvoid 165217309Snwhitehorndlg_free_columns(char **target, int per_row, int num_rows) 166217309Snwhitehorn{ 167217309Snwhitehorn int row; 168217309Snwhitehorn char **value; 169217309Snwhitehorn 170217309Snwhitehorn if (column_separator()) { 171217309Snwhitehorn for (each(row, value)) { 172217309Snwhitehorn free(*value); 173217309Snwhitehorn } 174217309Snwhitehorn } 175217309Snwhitehorn} 176