columns.c revision 267654
11556Srgrimes/* 21556Srgrimes * $Id: columns.c,v 1.8 2011/06/28 09:26:23 tom Exp $ 31556Srgrimes * 41556Srgrimes * columns.c -- implements column-alignment 51556Srgrimes * 61556Srgrimes * Copyright 2008-2010,2011 Thomas E. Dickey 71556Srgrimes * 81556Srgrimes * This program is free software; you can redistribute it and/or modify 91556Srgrimes * it under the terms of the GNU Lesser General Public License, version 2.1 101556Srgrimes * as published by the Free Software Foundation. 111556Srgrimes * 121556Srgrimes * This program is distributed in the hope that it will be useful, but 131556Srgrimes * WITHOUT ANY WARRANTY; without even the implied warranty of 141556Srgrimes * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 151556Srgrimes * Lesser General Public License for more details. 161556Srgrimes * 171556Srgrimes * You should have received a copy of the GNU Lesser General Public 181556Srgrimes * License along with this program; if not, write to 191556Srgrimes * Free Software Foundation, Inc. 201556Srgrimes * 51 Franklin St., Fifth Floor 211556Srgrimes * Boston, MA 02110, USA. 221556Srgrimes */ 231556Srgrimes 241556Srgrimes#include <dialog.h> 251556Srgrimes 261556Srgrimes#define each(row, data) \ 271556Srgrimes row = 0, data = target; \ 281556Srgrimes row < num_rows; \ 291556Srgrimes ++row, data = next_row(data, per_row) 3090143Smarkm 311556Srgrimesstatic char * 3236049Scharniercolumn_separator(void) 3390143Smarkm{ 3436049Scharnier char *result = 0; 35110391Scharnier 3699110Sobrien if ((result = dialog_vars.column_separator) != 0) { 3799110Sobrien if (*result == '\0') 381556Srgrimes result = 0; 391556Srgrimes } 401556Srgrimes return result; 411556Srgrimes} 421556Srgrimes 431556Srgrimesstatic char ** 441556Srgrimesnext_row(char **target, int per_row) 45105831Srwatson{ 4611890Sphk char *result = (char *) target; 471556Srgrimes result += per_row; 48217192Skib return (char **) result; 491556Srgrimes} 501556Srgrimes 5190878Simpstatic char * 5273369Sachenext_col(char *source, unsigned offset) 5372343Sache{ 541556Srgrimes char *mark = column_separator(); 551556Srgrimes char *result = source + offset; 5690878Simp if (offset) 571556Srgrimes result += strlen(mark); 58205271Sjmallett return strstr(result, mark); 591556Srgrimes} 601556Srgrimes 6190143Smarkm/* 6216835Speter * Parse the source string, storing the offsets and widths of each column in 631556Srgrimes * the corresponding arrays. Return the number of columns. 641556Srgrimes */ 651556Srgrimesstatic unsigned 661556Srgrimessplit_row(char *source, unsigned *offsets, unsigned *widths) 67225868Strasz{ 68225868Strasz int mark = (int) strlen(column_separator()); 69225868Strasz char *next = 0; 70103274Speter unsigned result = 0; 7190143Smarkm unsigned offset = 0; 721556Srgrimes 7390110Simp do { 741556Srgrimes if (result) { 751556Srgrimes offset = (unsigned) (mark + next - source); 761556Srgrimes widths[result - 1] = offset - offsets[result - 1] - (unsigned) mark; 771556Srgrimes } 78130999Sgad offsets[result] = offset; 79130999Sgad ++result; 80106251Stjr } while ((next = next_col(source, offset)) != 0); 81130999Sgad 82106251Stjr offset = (unsigned) strlen(source); 83130999Sgad widths[result - 1] = offset - offsets[result - 1]; 84130999Sgad 851556Srgrimes return result; 861556Srgrimes} 87130999Sgad 88109504Sjmallett/* 891556Srgrimes * The caller passes a pointer to a struct or array containing pointers 90109504Sjmallett * to strings that we may want to copy and reformat according to the column 911556Srgrimes * separator. 92109504Sjmallett */ 93130999Sgadvoid 941556Srgrimesdlg_align_columns(char **target, int per_row, int num_rows) 951556Srgrimes{ 961556Srgrimes int row; 971556Srgrimes 981556Srgrimes if (column_separator()) { 99225868Strasz char **value; 10097958Sjmallett unsigned numcols = 1; 10197958Sjmallett size_t maxcols = 0; 102225868Strasz unsigned *widths; 10397958Sjmallett unsigned *offsets; 10497958Sjmallett unsigned *maxwidth; 10597958Sjmallett unsigned realwidth; 10697958Sjmallett unsigned n; 107225868Strasz 108225868Strasz /* first allocate arrays for workspace */ 109225868Strasz for (each(row, value)) { 110225868Strasz size_t len = strlen(*value); 111225868Strasz if (maxcols < len) 11297958Sjmallett maxcols = len; 11397958Sjmallett } 114225868Strasz ++maxcols; 11590110Simp widths = dlg_calloc(unsigned, maxcols); 1161556Srgrimes offsets = dlg_calloc(unsigned, maxcols); 117225868Strasz maxwidth = dlg_calloc(unsigned, maxcols); 1181556Srgrimes 11919068Speter assert_ptr(widths, "dlg_align_columns"); 120130999Sgad assert_ptr(offsets, "dlg_align_columns"); 121173004Sjulian assert_ptr(maxwidth, "dlg_align_columns"); 122225868Strasz 123225868Strasz /* now, determine the number of columns and the column-widths */ 124225868Strasz for (each(row, value)) { 125225868Strasz unsigned cols = split_row(*value, offsets, widths); 126225868Strasz if (numcols < cols) 127173004Sjulian numcols = cols; 128225868Strasz for (n = 0; n < cols; ++n) { 129225868Strasz if (maxwidth[n] < widths[n]) 130225868Strasz maxwidth[n] = widths[n]; 13119068Speter } 1321556Srgrimes } 13397877Sjmallett realwidth = numcols - 1; 1341556Srgrimes for (n = 0; n < numcols; ++n) { 1351556Srgrimes realwidth += maxwidth[n]; 136130999Sgad } 1371556Srgrimes 138192239Sbrian /* finally, construct reformatted strings */ 139192239Sbrian for (each(row, value)) { 140192239Sbrian unsigned cols = split_row(*value, offsets, widths); 141192239Sbrian unsigned offset = 0; 142192239Sbrian char *text = dlg_malloc(char, realwidth + 1); 143192239Sbrian 144192239Sbrian assert_ptr(text, "dlg_align_columns"); 145192239Sbrian 146192239Sbrian memset(text, ' ', (size_t) realwidth); 147192239Sbrian for (n = 0; n < cols; ++n) { 148225868Strasz memcpy(text + offset, *value + offsets[n], (size_t) widths[n]); 149225868Strasz offset += maxwidth[n] + 1; 150225868Strasz } 151225868Strasz *value = text; 152225868Strasz } 153225868Strasz 154192239Sbrian free(widths); 155192239Sbrian free(offsets); 156225868Strasz free(maxwidth); 157225868Strasz } 158192239Sbrian} 159225868Strasz 160225868Strasz/* 161225868Strasz * Free temporary storage used while making column-aligned data. 162225868Strasz */ 163225868Straszvoid 164225868Straszdlg_free_columns(char **target, int per_row, int num_rows) 165225868Strasz{ 1661556Srgrimes int row; 1671556Srgrimes char **value; 168225868Strasz 16990110Simp if (column_separator()) { 1701556Srgrimes for (each(row, value)) { 171225868Strasz free(*value); 1721556Srgrimes } 173173004Sjulian } 174225868Strasz} 175225868Strasz