xref: /freebsd/contrib/dialog/columns.c (revision 19718649)
14c8945a0SNathan Whitehorn /*
219718649SNathan Whitehorn  *  $Id: columns.c,v 1.11 2019/07/25 00:06:38 tom Exp $
34c8945a0SNathan Whitehorn  *
44c8945a0SNathan Whitehorn  *  columns.c -- implements column-alignment
54c8945a0SNathan Whitehorn  *
67a1c0d96SNathan Whitehorn  *  Copyright 2008-2011,2019	Thomas E. Dickey
74c8945a0SNathan Whitehorn  *
84c8945a0SNathan Whitehorn  *  This program is free software; you can redistribute it and/or modify
94c8945a0SNathan Whitehorn  *  it under the terms of the GNU Lesser General Public License, version 2.1
104c8945a0SNathan Whitehorn  *  as published by the Free Software Foundation.
114c8945a0SNathan Whitehorn  *
124c8945a0SNathan Whitehorn  *  This program is distributed in the hope that it will be useful, but
134c8945a0SNathan Whitehorn  *  WITHOUT ANY WARRANTY; without even the implied warranty of
144c8945a0SNathan Whitehorn  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
154c8945a0SNathan Whitehorn  *  Lesser General Public License for more details.
164c8945a0SNathan Whitehorn  *
174c8945a0SNathan Whitehorn  *  You should have received a copy of the GNU Lesser General Public
184c8945a0SNathan Whitehorn  *  License along with this program; if not, write to
194c8945a0SNathan Whitehorn  *	Free Software Foundation, Inc.
204c8945a0SNathan Whitehorn  *	51 Franklin St., Fifth Floor
214c8945a0SNathan Whitehorn  *	Boston, MA 02110, USA.
224c8945a0SNathan Whitehorn  */
234c8945a0SNathan Whitehorn 
244c8945a0SNathan Whitehorn #include <dialog.h>
254c8945a0SNathan Whitehorn 
264c8945a0SNathan Whitehorn #define each(row, data) \
274c8945a0SNathan Whitehorn  		row = 0, data = target; \
28682c9e0fSNathan Whitehorn  		row < num_rows; \
294c8945a0SNathan Whitehorn 		++row, data = next_row(data, per_row)
304c8945a0SNathan Whitehorn 
314c8945a0SNathan Whitehorn static char *
column_separator(void)324c8945a0SNathan Whitehorn column_separator(void)
334c8945a0SNathan Whitehorn {
344c8945a0SNathan Whitehorn     char *result = 0;
354c8945a0SNathan Whitehorn 
364c8945a0SNathan Whitehorn     if ((result = dialog_vars.column_separator) != 0) {
374c8945a0SNathan Whitehorn 	if (*result == '\0')
384c8945a0SNathan Whitehorn 	    result = 0;
394c8945a0SNathan Whitehorn     }
404c8945a0SNathan Whitehorn     return result;
414c8945a0SNathan Whitehorn }
424c8945a0SNathan Whitehorn 
434c8945a0SNathan Whitehorn static char **
next_row(char ** target,int per_row)444c8945a0SNathan Whitehorn next_row(char **target, int per_row)
454c8945a0SNathan Whitehorn {
464c8945a0SNathan Whitehorn     char *result = (char *) target;
474c8945a0SNathan Whitehorn     result += per_row;
4819718649SNathan Whitehorn     return (char **) (void *) result;
494c8945a0SNathan Whitehorn }
504c8945a0SNathan Whitehorn 
514c8945a0SNathan Whitehorn static char *
next_col(char * source,unsigned offset)524c8945a0SNathan Whitehorn next_col(char *source, unsigned offset)
534c8945a0SNathan Whitehorn {
544c8945a0SNathan Whitehorn     char *mark = column_separator();
554c8945a0SNathan Whitehorn     char *result = source + offset;
564c8945a0SNathan Whitehorn     if (offset)
574c8945a0SNathan Whitehorn 	result += strlen(mark);
584c8945a0SNathan Whitehorn     return strstr(result, mark);
594c8945a0SNathan Whitehorn }
604c8945a0SNathan Whitehorn 
614c8945a0SNathan Whitehorn /*
624c8945a0SNathan Whitehorn  * Parse the source string, storing the offsets and widths of each column in
634c8945a0SNathan Whitehorn  * the corresponding arrays.  Return the number of columns.
644c8945a0SNathan Whitehorn  */
654c8945a0SNathan Whitehorn static unsigned
split_row(char * source,unsigned * offsets,unsigned * widths)664c8945a0SNathan Whitehorn split_row(char *source, unsigned *offsets, unsigned *widths)
674c8945a0SNathan Whitehorn {
684c8945a0SNathan Whitehorn     int mark = (int) strlen(column_separator());
694c8945a0SNathan Whitehorn     char *next = 0;
704c8945a0SNathan Whitehorn     unsigned result = 0;
714c8945a0SNathan Whitehorn     unsigned offset = 0;
724c8945a0SNathan Whitehorn 
734c8945a0SNathan Whitehorn     do {
744c8945a0SNathan Whitehorn 	if (result) {
754c8945a0SNathan Whitehorn 	    offset = (unsigned) (mark + next - source);
764c8945a0SNathan Whitehorn 	    widths[result - 1] = offset - offsets[result - 1] - (unsigned) mark;
774c8945a0SNathan Whitehorn 	}
784c8945a0SNathan Whitehorn 	offsets[result] = offset;
794c8945a0SNathan Whitehorn 	++result;
804c8945a0SNathan Whitehorn     } while ((next = next_col(source, offset)) != 0);
814c8945a0SNathan Whitehorn 
827a1c0d96SNathan Whitehorn     offset = (unsigned) strlen(source);
834c8945a0SNathan Whitehorn     widths[result - 1] = offset - offsets[result - 1];
844c8945a0SNathan Whitehorn 
854c8945a0SNathan Whitehorn     return result;
864c8945a0SNathan Whitehorn }
874c8945a0SNathan Whitehorn 
884c8945a0SNathan Whitehorn /*
894c8945a0SNathan Whitehorn  * The caller passes a pointer to a struct or array containing pointers
904c8945a0SNathan Whitehorn  * to strings that we may want to copy and reformat according to the column
914c8945a0SNathan Whitehorn  * separator.
924c8945a0SNathan Whitehorn  */
934c8945a0SNathan Whitehorn void
dlg_align_columns(char ** target,int per_row,int num_rows)944c8945a0SNathan Whitehorn dlg_align_columns(char **target, int per_row, int num_rows)
954c8945a0SNathan Whitehorn {
964c8945a0SNathan Whitehorn     if (column_separator()) {
974c8945a0SNathan Whitehorn 	char **value;
984c8945a0SNathan Whitehorn 	unsigned numcols = 1;
994c8945a0SNathan Whitehorn 	size_t maxcols = 0;
1004c8945a0SNathan Whitehorn 	unsigned *widths;
1017a1c0d96SNathan Whitehorn 	unsigned *offsets;
1024c8945a0SNathan Whitehorn 	unsigned *maxwidth;
1034c8945a0SNathan Whitehorn 	unsigned realwidth;
1044c8945a0SNathan Whitehorn 	unsigned n;
1054c8945a0SNathan Whitehorn 	int row;
1064c8945a0SNathan Whitehorn 
1074c8945a0SNathan Whitehorn 	/* first allocate arrays for workspace */
1084c8945a0SNathan Whitehorn 	for (each(row, value)) {
1094c8945a0SNathan Whitehorn 	    size_t len = strlen(*value);
1107a1c0d96SNathan Whitehorn 	    if (maxcols < len)
1114c8945a0SNathan Whitehorn 		maxcols = len;
1124c8945a0SNathan Whitehorn 	}
1134c8945a0SNathan Whitehorn 	++maxcols;
1144c8945a0SNathan Whitehorn 	widths = dlg_calloc(unsigned, maxcols);
1154c8945a0SNathan Whitehorn 	offsets = dlg_calloc(unsigned, maxcols);
1164c8945a0SNathan Whitehorn 	maxwidth = dlg_calloc(unsigned, maxcols);
1174c8945a0SNathan Whitehorn 
1184c8945a0SNathan Whitehorn 	assert_ptr(widths, "dlg_align_columns");
1194c8945a0SNathan Whitehorn 	assert_ptr(offsets, "dlg_align_columns");
1204c8945a0SNathan Whitehorn 	assert_ptr(maxwidth, "dlg_align_columns");
1214c8945a0SNathan Whitehorn 
1224c8945a0SNathan Whitehorn 	/* now, determine the number of columns and the column-widths */
1234c8945a0SNathan Whitehorn 	for (each(row, value)) {
1244c8945a0SNathan Whitehorn 	    unsigned cols = split_row(*value, offsets, widths);
1254c8945a0SNathan Whitehorn 	    if (numcols < cols)
1264c8945a0SNathan Whitehorn 		numcols = cols;
1274c8945a0SNathan Whitehorn 	    for (n = 0; n < cols; ++n) {
1284c8945a0SNathan Whitehorn 		if (maxwidth[n] < widths[n])
1294c8945a0SNathan Whitehorn 		    maxwidth[n] = widths[n];
1304c8945a0SNathan Whitehorn 	    }
1314c8945a0SNathan Whitehorn 	}
1324c8945a0SNathan Whitehorn 	realwidth = numcols - 1;
1334c8945a0SNathan Whitehorn 	for (n = 0; n < numcols; ++n) {
1344c8945a0SNathan Whitehorn 	    realwidth += maxwidth[n];
1354c8945a0SNathan Whitehorn 	}
1364c8945a0SNathan Whitehorn 
1374c8945a0SNathan Whitehorn 	/* finally, construct reformatted strings */
1384c8945a0SNathan Whitehorn 	for (each(row, value)) {
1394c8945a0SNathan Whitehorn 	    unsigned cols = split_row(*value, offsets, widths);
1404c8945a0SNathan Whitehorn 	    unsigned offset = 0;
1414c8945a0SNathan Whitehorn 	    char *text = dlg_malloc(char, realwidth + 1);
1424c8945a0SNathan Whitehorn 
1434c8945a0SNathan Whitehorn 	    assert_ptr(text, "dlg_align_columns");
1444c8945a0SNathan Whitehorn 
1454c8945a0SNathan Whitehorn 	    memset(text, ' ', (size_t) realwidth);
1467a1c0d96SNathan Whitehorn 	    for (n = 0; n < cols; ++n) {
1474c8945a0SNathan Whitehorn 		memcpy(text + offset, *value + offsets[n], (size_t) widths[n]);
1487a1c0d96SNathan Whitehorn 		offset += maxwidth[n] + 1;
1494c8945a0SNathan Whitehorn 	    }
1504c8945a0SNathan Whitehorn 	    text[realwidth] = 0;
1514c8945a0SNathan Whitehorn 	    *value = text;
1524c8945a0SNathan Whitehorn 	}
1534c8945a0SNathan Whitehorn 
1544c8945a0SNathan Whitehorn 	free(widths);
1554c8945a0SNathan Whitehorn 	free(offsets);
1564c8945a0SNathan Whitehorn 	free(maxwidth);
1574c8945a0SNathan Whitehorn     }
1584c8945a0SNathan Whitehorn }
1594c8945a0SNathan Whitehorn 
1604c8945a0SNathan Whitehorn /*
1614c8945a0SNathan Whitehorn  * Free temporary storage used while making column-aligned data.
1624c8945a0SNathan Whitehorn  */
1634c8945a0SNathan Whitehorn void
dlg_free_columns(char ** target,int per_row,int num_rows)1644c8945a0SNathan Whitehorn dlg_free_columns(char **target, int per_row, int num_rows)
1654c8945a0SNathan Whitehorn {
1664c8945a0SNathan Whitehorn     if (column_separator()) {
1674c8945a0SNathan Whitehorn 	int row;
1684c8945a0SNathan Whitehorn 	char **value;
1694c8945a0SNathan Whitehorn 
1704c8945a0SNathan Whitehorn 	for (each(row, value)) {
1714c8945a0SNathan Whitehorn 	    free(*value);
1724c8945a0SNathan Whitehorn 	}
1734c8945a0SNathan Whitehorn     }
1744c8945a0SNathan Whitehorn }
175