Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/dialog/columns.c
39478 views
1
/*
2
* $Id: columns.c,v 1.11 2019/07/25 00:06:38 tom Exp $
3
*
4
* columns.c -- implements column-alignment
5
*
6
* Copyright 2008-2011,2019 Thomas E. Dickey
7
*
8
* This program is free software; you can redistribute it and/or modify
9
* it under the terms of the GNU Lesser General Public License, version 2.1
10
* as published by the Free Software Foundation.
11
*
12
* This program is distributed in the hope that it will be useful, but
13
* WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
* Lesser General Public License for more details.
16
*
17
* You should have received a copy of the GNU Lesser General Public
18
* License along with this program; if not, write to
19
* Free Software Foundation, Inc.
20
* 51 Franklin St., Fifth Floor
21
* Boston, MA 02110, USA.
22
*/
23
24
#include <dialog.h>
25
26
#define each(row, data) \
27
row = 0, data = target; \
28
row < num_rows; \
29
++row, data = next_row(data, per_row)
30
31
static char *
32
column_separator(void)
33
{
34
char *result = 0;
35
36
if ((result = dialog_vars.column_separator) != 0) {
37
if (*result == '\0')
38
result = 0;
39
}
40
return result;
41
}
42
43
static char **
44
next_row(char **target, int per_row)
45
{
46
char *result = (char *) target;
47
result += per_row;
48
return (char **) (void *) result;
49
}
50
51
static char *
52
next_col(char *source, unsigned offset)
53
{
54
char *mark = column_separator();
55
char *result = source + offset;
56
if (offset)
57
result += strlen(mark);
58
return strstr(result, mark);
59
}
60
61
/*
62
* Parse the source string, storing the offsets and widths of each column in
63
* the corresponding arrays. Return the number of columns.
64
*/
65
static unsigned
66
split_row(char *source, unsigned *offsets, unsigned *widths)
67
{
68
int mark = (int) strlen(column_separator());
69
char *next = 0;
70
unsigned result = 0;
71
unsigned offset = 0;
72
73
do {
74
if (result) {
75
offset = (unsigned) (mark + next - source);
76
widths[result - 1] = offset - offsets[result - 1] - (unsigned) mark;
77
}
78
offsets[result] = offset;
79
++result;
80
} while ((next = next_col(source, offset)) != 0);
81
82
offset = (unsigned) strlen(source);
83
widths[result - 1] = offset - offsets[result - 1];
84
85
return result;
86
}
87
88
/*
89
* The caller passes a pointer to a struct or array containing pointers
90
* to strings that we may want to copy and reformat according to the column
91
* separator.
92
*/
93
void
94
dlg_align_columns(char **target, int per_row, int num_rows)
95
{
96
if (column_separator()) {
97
char **value;
98
unsigned numcols = 1;
99
size_t maxcols = 0;
100
unsigned *widths;
101
unsigned *offsets;
102
unsigned *maxwidth;
103
unsigned realwidth;
104
unsigned n;
105
int row;
106
107
/* first allocate arrays for workspace */
108
for (each(row, value)) {
109
size_t len = strlen(*value);
110
if (maxcols < len)
111
maxcols = len;
112
}
113
++maxcols;
114
widths = dlg_calloc(unsigned, maxcols);
115
offsets = dlg_calloc(unsigned, maxcols);
116
maxwidth = dlg_calloc(unsigned, maxcols);
117
118
assert_ptr(widths, "dlg_align_columns");
119
assert_ptr(offsets, "dlg_align_columns");
120
assert_ptr(maxwidth, "dlg_align_columns");
121
122
/* now, determine the number of columns and the column-widths */
123
for (each(row, value)) {
124
unsigned cols = split_row(*value, offsets, widths);
125
if (numcols < cols)
126
numcols = cols;
127
for (n = 0; n < cols; ++n) {
128
if (maxwidth[n] < widths[n])
129
maxwidth[n] = widths[n];
130
}
131
}
132
realwidth = numcols - 1;
133
for (n = 0; n < numcols; ++n) {
134
realwidth += maxwidth[n];
135
}
136
137
/* finally, construct reformatted strings */
138
for (each(row, value)) {
139
unsigned cols = split_row(*value, offsets, widths);
140
unsigned offset = 0;
141
char *text = dlg_malloc(char, realwidth + 1);
142
143
assert_ptr(text, "dlg_align_columns");
144
145
memset(text, ' ', (size_t) realwidth);
146
for (n = 0; n < cols; ++n) {
147
memcpy(text + offset, *value + offsets[n], (size_t) widths[n]);
148
offset += maxwidth[n] + 1;
149
}
150
text[realwidth] = 0;
151
*value = text;
152
}
153
154
free(widths);
155
free(offsets);
156
free(maxwidth);
157
}
158
}
159
160
/*
161
* Free temporary storage used while making column-aligned data.
162
*/
163
void
164
dlg_free_columns(char **target, int per_row, int num_rows)
165
{
166
if (column_separator()) {
167
int row;
168
char **value;
169
170
for (each(row, value)) {
171
free(*value);
172
}
173
}
174
}
175
176