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