1 |
pippijn |
1.1 |
/* |
2 |
|
|
* table.C: Table rendering class. |
3 |
|
|
* Rights to this code are documented in doc/LICENSE. |
4 |
|
|
* |
5 |
|
|
* NOTE: This is a work in progress and will probably change considerably |
6 |
|
|
* later on. |
7 |
|
|
* |
8 |
|
|
* Copyright © 2005-2007 Atheme Project (http://www.atheme.org) |
9 |
|
|
*/ |
10 |
|
|
|
11 |
|
|
static char const rcsid[] = "$Id"; |
12 |
|
|
|
13 |
|
|
#include "atheme.h" |
14 |
|
|
|
15 |
|
|
static void |
16 |
|
|
table_destroy (void *obj) |
17 |
|
|
{ |
18 |
|
|
table_t *table = (table_t *) obj; |
19 |
|
|
node_t *n, *tn; |
20 |
|
|
|
21 |
|
|
return_if_fail (table != NULL); |
22 |
|
|
|
23 |
|
|
LIST_FOREACH_SAFE (n, tn, table->rows.head) |
24 |
|
|
{ |
25 |
|
|
table_row_t *r = (table_row_t *) n->data; |
26 |
|
|
node_t *n2, *tn2; |
27 |
|
|
|
28 |
|
|
return_if_fail (r != NULL); |
29 |
|
|
|
30 |
|
|
LIST_FOREACH_SAFE (n2, tn2, r->cells.head) |
31 |
|
|
{ |
32 |
|
|
table_cell_t *c = (table_cell_t *) n2->data; |
33 |
|
|
|
34 |
|
|
free (c->name); |
35 |
|
|
free (c->value); |
36 |
|
|
free (c); |
37 |
|
|
node_del (n2, &r->cells); |
38 |
|
|
node_free (n2); |
39 |
|
|
} |
40 |
|
|
|
41 |
|
|
free (r); |
42 |
|
|
|
43 |
|
|
node_del (n, &table->rows); |
44 |
|
|
node_free (n); |
45 |
|
|
} |
46 |
|
|
|
47 |
|
|
free (table); |
48 |
|
|
} |
49 |
|
|
|
50 |
|
|
/* |
51 |
|
|
* table_new(const char *fmt, ...) |
52 |
|
|
* |
53 |
|
|
* Table constructor. |
54 |
|
|
* |
55 |
|
|
* Inputs: |
56 |
|
|
* - printf-style string to name the table with. |
57 |
|
|
* |
58 |
|
|
* Outputs: |
59 |
|
|
* - a table object. |
60 |
|
|
* |
61 |
|
|
* Side Effects: |
62 |
|
|
* - none |
63 |
|
|
*/ |
64 |
|
|
table_t * |
65 |
|
|
table_new (const char *fmt, ...) |
66 |
|
|
{ |
67 |
|
|
va_list vl; |
68 |
|
|
char *buf; |
69 |
|
|
table_t *out; |
70 |
|
|
|
71 |
|
|
return_val_if_fail (fmt != NULL, NULL); |
72 |
|
|
|
73 |
|
|
va_start (vl, fmt); |
74 |
|
|
vasprintf (&buf, fmt, vl); |
75 |
|
|
va_end (vl); |
76 |
|
|
|
77 |
|
|
out = static_cast<table_t *> (scalloc (sizeof (table_t), 1)); |
78 |
|
|
object_init (&out->parent, buf, table_destroy); |
79 |
|
|
free (buf); |
80 |
|
|
|
81 |
|
|
return out; |
82 |
|
|
} |
83 |
|
|
|
84 |
|
|
/* |
85 |
|
|
* table_row_new |
86 |
|
|
* |
87 |
|
|
* Creates a table row. This isn't an object. |
88 |
|
|
* |
89 |
|
|
* Inputs: |
90 |
|
|
* - table to associate to. |
91 |
|
|
* |
92 |
|
|
* Outputs: |
93 |
|
|
* - a table row |
94 |
|
|
* |
95 |
|
|
* Side Effects: |
96 |
|
|
* - none |
97 |
|
|
*/ |
98 |
|
|
table_row_t * |
99 |
|
|
table_row_new (table_t * t) |
100 |
|
|
{ |
101 |
|
|
table_row_t *out; |
102 |
|
|
|
103 |
|
|
return_val_if_fail (t != NULL, NULL); |
104 |
|
|
|
105 |
|
|
out = static_cast<table_row_t *> (scalloc (sizeof (table_row_t), 1)); |
106 |
|
|
|
107 |
|
|
node_add (out, node_create (), &t->rows); |
108 |
|
|
|
109 |
|
|
return out; |
110 |
|
|
} |
111 |
|
|
|
112 |
|
|
/* |
113 |
|
|
* table_cell_associate |
114 |
|
|
* |
115 |
|
|
* Associates a cell with a row. |
116 |
|
|
* |
117 |
|
|
* Inputs: |
118 |
|
|
* - row to add cell to. |
119 |
|
|
* |
120 |
|
|
* Outputs: |
121 |
|
|
* - nothing |
122 |
|
|
* |
123 |
|
|
* Side Effects: |
124 |
|
|
* - none |
125 |
|
|
*/ |
126 |
|
|
void |
127 |
|
|
table_cell_associate (table_row_t * r, const char *name, const char *value) |
128 |
|
|
{ |
129 |
|
|
table_cell_t *c; |
130 |
|
|
|
131 |
|
|
return_if_fail (r != NULL); |
132 |
|
|
return_if_fail (name != NULL); |
133 |
|
|
return_if_fail (value != NULL); |
134 |
|
|
|
135 |
|
|
c = static_cast<table_cell_t *> (scalloc (sizeof (table_cell_t), 1)); |
136 |
|
|
|
137 |
|
|
c->name = sstrdup (name); |
138 |
|
|
c->value = sstrdup (value); |
139 |
|
|
|
140 |
|
|
node_add (c, node_create (), &r->cells); |
141 |
|
|
} |
142 |
|
|
|
143 |
|
|
/* |
144 |
|
|
* table_render |
145 |
|
|
* |
146 |
|
|
* Renders a table. This is a two-pass operation, the first one to find out |
147 |
|
|
* the width of each cell, and then the second to render the data. |
148 |
|
|
* |
149 |
|
|
* Inputs: |
150 |
|
|
* - a table |
151 |
|
|
* - a callback function |
152 |
|
|
* - opaque data |
153 |
|
|
* |
154 |
|
|
* Outputs: |
155 |
|
|
* - none |
156 |
|
|
* |
157 |
|
|
* Side Effects: |
158 |
|
|
* - a callback function is called for each row of the table. |
159 |
|
|
*/ |
160 |
|
|
void |
161 |
|
|
table_render (table_t * t, void (*callback) (const char *line, void *data), void *data) |
162 |
|
|
{ |
163 |
|
|
node_t *n; |
164 |
|
|
table_row_t *f; |
165 |
|
|
size_t bufsz = 0; |
166 |
|
|
char *buf = NULL; |
167 |
|
|
char *p; |
168 |
|
|
int i; |
169 |
|
|
|
170 |
|
|
return_if_fail (t != NULL); |
171 |
|
|
return_if_fail (callback != NULL); |
172 |
|
|
|
173 |
|
|
f = (table_row_t *) t->rows.head->data; |
174 |
|
|
|
175 |
|
|
LIST_FOREACH (n, t->rows.head) |
176 |
|
|
{ |
177 |
|
|
table_row_t *r = (table_row_t *) n->data; |
178 |
|
|
node_t *n2, *rn; |
179 |
|
|
|
180 |
|
|
/* we, uhh... we don't provide a macro for dealing with two lists at once ;) */ |
181 |
|
|
for (n2 = r->cells.head, rn = f->cells.head; n2 != NULL && rn != NULL; n2 = n2->next, rn = rn->next) |
182 |
|
|
{ |
183 |
|
|
table_cell_t *c, *rc; |
184 |
|
|
size_t sz; |
185 |
|
|
|
186 |
|
|
c = (table_cell_t *) n2->data; |
187 |
|
|
rc = (table_cell_t *) rn->data; |
188 |
|
|
|
189 |
|
|
if ((sz = strlen (c->name)) > (size_t) rc->width) |
190 |
|
|
rc->width = sz; |
191 |
|
|
|
192 |
|
|
if ((sz = strlen (c->value)) > (size_t) rc->width) |
193 |
|
|
rc->width = sz; |
194 |
|
|
} |
195 |
|
|
} |
196 |
|
|
|
197 |
|
|
/* now total up the result. */ |
198 |
|
|
LIST_FOREACH (n, f->cells.head) |
199 |
|
|
{ |
200 |
|
|
table_cell_t *c = (table_cell_t *) n->data; |
201 |
|
|
bufsz += c->width + 1; |
202 |
|
|
} |
203 |
|
|
|
204 |
|
|
buf = static_cast<char *> (smalloc (bufsz)); |
205 |
|
|
*buf = '\0'; |
206 |
|
|
|
207 |
|
|
/* start outputting the header. */ |
208 |
|
|
callback (asobject (t)->name, data); |
209 |
|
|
LIST_FOREACH (n, f->cells.head) |
210 |
|
|
{ |
211 |
|
|
table_cell_t *c = (table_cell_t *) n->data; |
212 |
|
|
char fmtbuf[12]; |
213 |
|
|
char buf2[1024]; |
214 |
|
|
|
215 |
|
|
/* dynamically generate the format string based on width. */ |
216 |
|
|
snprintf (fmtbuf, 12, n->next != NULL ? "%%-%ds " : "%%s", c->width); |
217 |
|
|
snprintf (buf2, 1024, fmtbuf, c->name); |
218 |
|
|
|
219 |
|
|
strlcat (buf, buf2, bufsz); |
220 |
|
|
} |
221 |
|
|
callback (buf, data); |
222 |
|
|
*buf = '\0'; |
223 |
|
|
|
224 |
|
|
/* separator line */ |
225 |
|
|
p = buf; |
226 |
|
|
LIST_FOREACH (n, f->cells.head) |
227 |
|
|
{ |
228 |
|
|
table_cell_t *c = (table_cell_t *) n->data; |
229 |
|
|
|
230 |
|
|
if (n->next != NULL) |
231 |
|
|
{ |
232 |
|
|
for (i = 0; i < c->width; i++) |
233 |
|
|
*p++ = '-'; |
234 |
|
|
*p++ = ' '; |
235 |
|
|
} |
236 |
|
|
else |
237 |
|
|
for (i = 0; i < (int) strlen (c->name); i++) |
238 |
|
|
*p++ = '-'; |
239 |
|
|
} |
240 |
|
|
*p = '\0'; |
241 |
|
|
callback (buf, data); |
242 |
|
|
*buf = '\0'; |
243 |
|
|
|
244 |
|
|
LIST_FOREACH (n, t->rows.head) |
245 |
|
|
{ |
246 |
|
|
table_row_t *r = (table_row_t *) n->data; |
247 |
|
|
node_t *n2, *rn; |
248 |
|
|
|
249 |
|
|
for (n2 = r->cells.head, rn = f->cells.head; n2 != NULL && rn != NULL; n2 = n2->next, rn = rn->next) |
250 |
|
|
{ |
251 |
|
|
table_cell_t *c, *rc; |
252 |
|
|
char fmtbuf[12]; |
253 |
|
|
char buf2[1024]; |
254 |
|
|
|
255 |
|
|
c = (table_cell_t *) n2->data; |
256 |
|
|
rc = (table_cell_t *) rn->data; |
257 |
|
|
|
258 |
|
|
/* dynamically generate the format string based on width. */ |
259 |
|
|
snprintf (fmtbuf, 12, n2->next != NULL ? "%%-%ds " : "%%s", rc->width); |
260 |
|
|
snprintf (buf2, 1024, fmtbuf, c->value); |
261 |
|
|
|
262 |
|
|
strlcat (buf, buf2, bufsz); |
263 |
|
|
} |
264 |
|
|
callback (buf, data); |
265 |
|
|
*buf = '\0'; |
266 |
|
|
} |
267 |
|
|
|
268 |
|
|
/* separator line */ |
269 |
|
|
p = buf; |
270 |
|
|
LIST_FOREACH (n, f->cells.head) |
271 |
|
|
{ |
272 |
|
|
table_cell_t *c = (table_cell_t *) n->data; |
273 |
|
|
|
274 |
|
|
if (n->next != NULL) |
275 |
|
|
{ |
276 |
|
|
for (i = 0; i < c->width; i++) |
277 |
|
|
*p++ = '-'; |
278 |
|
|
*p++ = ' '; |
279 |
|
|
} |
280 |
|
|
else |
281 |
|
|
for (i = 0; i < (int) strlen (c->name); i++) |
282 |
|
|
*p++ = '-'; |
283 |
|
|
} |
284 |
|
|
*p = '\0'; |
285 |
|
|
callback (buf, data); |
286 |
|
|
*buf = '\0'; |
287 |
|
|
} |
288 |
|
|
|
289 |
|
|
/* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs |
290 |
|
|
* vim:ts=8 |
291 |
|
|
* vim:sw=8 |
292 |
|
|
* vim:noexpandtab |
293 |
|
|
*/ |