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