]>
Commit | Line | Data |
---|---|---|
6dbe3af9 KZ |
1 | /* |
2 | * Copyright (c) 1989, 1993, 1994 | |
3 | * The Regents of the University of California. All rights reserved. | |
4 | * | |
7d07df62 KZ |
5 | * Copyright (C) 2017 Karel Zak <kzak@redhat.com> |
6 | * | |
6dbe3af9 KZ |
7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions | |
9 | * are met: | |
10 | * 1. Redistributions of source code must retain the above copyright | |
11 | * notice, this list of conditions and the following disclaimer. | |
12 | * 2. Redistributions in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in the | |
14 | * documentation and/or other materials provided with the distribution. | |
15 | * 3. All advertising materials mentioning features or use of this software | |
16 | * must display the following acknowledgement: | |
17 | * This product includes software developed by the University of | |
18 | * California, Berkeley and its contributors. | |
19 | * 4. Neither the name of the University nor the names of its contributors | |
20 | * may be used to endorse or promote products derived from this software | |
21 | * without specific prior written permission. | |
22 | * | |
23 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
24 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
25 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
26 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
27 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
28 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
29 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
30 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
31 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
32 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
33 | * SUCH DAMAGE. | |
34 | */ | |
6dbe3af9 KZ |
35 | #include <sys/types.h> |
36 | #include <sys/ioctl.h> | |
37 | ||
38 | #include <ctype.h> | |
6dbe3af9 | 39 | #include <stdio.h> |
fd6b7a7f | 40 | #include <unistd.h> |
6dbe3af9 KZ |
41 | #include <stdlib.h> |
42 | #include <string.h> | |
a4cc8dfe SK |
43 | #include <errno.h> |
44 | #include <getopt.h> | |
6dbe3af9 | 45 | |
3b56eea7 | 46 | #include "nls.h" |
eb76ca98 | 47 | #include "c.h" |
9ea8ded3 | 48 | #include "widechar.h" |
a29e40ca | 49 | #include "xalloc.h" |
02b77f7b | 50 | #include "strutils.h" |
b87cbe84 | 51 | #include "closestream.h" |
3b56eea7 | 52 | #include "ttyutils.h" |
eb63b9b8 | 53 | |
06b04b23 | 54 | #ifdef HAVE_WIDECHAR |
eb63b9b8 KZ |
55 | static wchar_t *mbs_to_wcs(const char *); |
56 | #else | |
a29e40ca | 57 | #define mbs_to_wcs(s) xstrdup(s) |
eb63b9b8 KZ |
58 | static char *mtsafe_strtok(char *, const char *, char **); |
59 | #define wcstok mtsafe_strtok | |
60 | #endif | |
61 | ||
1ae90932 SK |
62 | #define DEFCOLS 25 |
63 | #define TAB 8 | |
64 | #define DEFNUM 1000 | |
65 | #define MAXLINELEN (LINE_MAX + 1) | |
66 | ||
1ae90932 SK |
67 | typedef struct _tbl { |
68 | wchar_t **list; | |
69 | int cols, *len; | |
70 | } TBL; | |
71 | ||
683ddbd5 | 72 | |
7d07df62 KZ |
73 | enum { |
74 | COLUMN_MODE_FILLCOLS = 0, | |
75 | COLUMN_MODE_FILLROWS, | |
76 | COLUMN_MODE_TABLE, | |
77 | COLUMN_MODE_SIMPLE | |
78 | }; | |
79 | ||
80 | struct column_control { | |
2593c139 KZ |
81 | int mode; /* COLUMN_MODE_* */ |
82 | int termwidth; | |
83 | ||
84 | int entries; /* number of records */ | |
85 | int maxlength; /* longest input record (line) */ | |
86 | wchar_t **list; /* array of pointers to records */ | |
7d07df62 KZ |
87 | }; |
88 | ||
2593c139 KZ |
89 | static int input(struct column_control *ctl, FILE *fp); |
90 | static void columnate_fillrows(struct column_control *ctl); | |
91 | static void columnate_fillcols(struct column_control *ctl); | |
92 | static wchar_t *local_wcstok(wchar_t *p, const wchar_t *separator, int greedy, wchar_t **wcstok_state); | |
93 | static void maketbl(struct column_control *ctl, wchar_t *separator, int greedy, wchar_t *colsep); | |
94 | static void print(struct column_control *ctl); | |
7d07df62 | 95 | |
683ddbd5 KZ |
96 | #ifdef HAVE_WIDECHAR |
97 | /* Don't use wcswidth(), we need to ignore non-printable chars. */ | |
98 | static int width(const wchar_t *str) | |
99 | { | |
100 | int x, width = 0; | |
101 | ||
102 | for (; *str != '\0'; str++) { | |
103 | x = wcwidth(*str); | |
104 | if (x > 0) | |
105 | width += x; | |
106 | } | |
107 | return width; | |
108 | } | |
109 | #else | |
110 | static int width(const char *str) | |
111 | { | |
112 | int width = 0; | |
113 | ||
114 | for (; *str != '\0'; str++) { | |
115 | if (isprint(*str)) | |
116 | width++; | |
117 | } | |
118 | return width; | |
119 | } | |
120 | #endif | |
121 | ||
a4cc8dfe SK |
122 | static void __attribute__((__noreturn__)) usage(int rc) |
123 | { | |
124 | FILE *out = rc == EXIT_FAILURE ? stderr : stdout; | |
125 | ||
3eed42f3 | 126 | fputs(USAGE_HEADER, out); |
4ce393f4 | 127 | fprintf(out, _(" %s [options] [<file>...]\n"), program_invocation_short_name); |
451dbcfa BS |
128 | |
129 | fputs(USAGE_SEPARATOR, out); | |
130 | fputs(_("Columnate lists.\n"), out); | |
131 | ||
3eed42f3 | 132 | fputs(USAGE_OPTIONS, out); |
d7a3bf94 KZ |
133 | fputs(_(" -t, --table create a table\n"), out); |
134 | fputs(_(" -s, --separator <string> possible table delimiters\n"), out); | |
135 | fputs(_(" -o, --output-separator <string> columns separator for table output\n" | |
136 | " (default is two spaces)\n"), out); | |
137 | fputs(_(" -c, --output-width <width> width of output in number of characters\n"), out); | |
138 | fputs(_(" -x, --fillrows fill rows before columns\n"), out); | |
3eed42f3 SK |
139 | fputs(USAGE_SEPARATOR, out); |
140 | fputs(USAGE_HELP, out); | |
141 | fputs(USAGE_VERSION, out); | |
142 | fprintf(out, USAGE_MAN_TAIL("column(1)")); | |
a4cc8dfe | 143 | |
a4cc8dfe SK |
144 | exit(rc); |
145 | } | |
1df29104 SK |
146 | |
147 | int main(int argc, char **argv) | |
6dbe3af9 | 148 | { |
2593c139 KZ |
149 | struct column_control ctl = { |
150 | .mode = COLUMN_MODE_FILLCOLS, | |
151 | .termwidth = 80 | |
152 | }; | |
7d07df62 KZ |
153 | |
154 | int ch; | |
6a41edfa | 155 | int i; |
daf093d2 | 156 | unsigned int eval = 0; /* exit value */ |
732e3dec | 157 | int greedy = 1; |
47bd8ddc | 158 | wchar_t *colsep; /* table column output separator */ |
a46e644e | 159 | |
daf093d2 SK |
160 | /* field separator for table option */ |
161 | wchar_t default_separator[] = { '\t', ' ', 0 }; | |
162 | wchar_t *separator = default_separator; | |
163 | ||
164 | static const struct option longopts[] = | |
165 | { | |
87918040 SK |
166 | { "columns", required_argument, NULL, 'c' }, /* deprecated */ |
167 | { "fillrows", no_argument, NULL, 'x' }, | |
168 | { "help", no_argument, NULL, 'h' }, | |
169 | { "output-separator", required_argument, NULL, 'o' }, | |
170 | { "output-width", required_argument, NULL, 'c' }, | |
171 | { "separator", required_argument, NULL, 's' }, | |
172 | { "table", no_argument, NULL, 't' }, | |
173 | { "version", no_argument, NULL, 'V' }, | |
174 | { NULL, 0, NULL, 0 }, | |
daf093d2 SK |
175 | }; |
176 | ||
7eda085c KZ |
177 | setlocale(LC_ALL, ""); |
178 | bindtextdomain(PACKAGE, LOCALEDIR); | |
179 | textdomain(PACKAGE); | |
b87cbe84 | 180 | atexit(close_stdout); |
6dbe3af9 | 181 | |
2593c139 | 182 | ctl.termwidth = get_terminal_width(80); |
47bd8ddc | 183 | colsep = mbs_to_wcs(" "); |
6dbe3af9 | 184 | |
47bd8ddc | 185 | while ((ch = getopt_long(argc, argv, "hVc:s:txo:", longopts, NULL)) != -1) |
6dbe3af9 | 186 | switch(ch) { |
a4cc8dfe | 187 | case 'h': |
1ae90932 SK |
188 | usage(EXIT_SUCCESS); |
189 | break; | |
4ef21375 | 190 | case 'V': |
f6277500 SK |
191 | printf(UTIL_LINUX_VERSION); |
192 | return EXIT_SUCCESS; | |
6dbe3af9 | 193 | case 'c': |
2593c139 | 194 | ctl.termwidth = strtou32_or_err(optarg, _("invalid columns argument")); |
6dbe3af9 KZ |
195 | break; |
196 | case 's': | |
eb63b9b8 | 197 | separator = mbs_to_wcs(optarg); |
732e3dec | 198 | greedy = 0; |
6dbe3af9 | 199 | break; |
47bd8ddc SK |
200 | case 'o': |
201 | free(colsep); | |
202 | colsep = mbs_to_wcs(optarg); | |
203 | break; | |
6dbe3af9 | 204 | case 't': |
7d07df62 | 205 | ctl.mode = COLUMN_MODE_TABLE; |
6dbe3af9 KZ |
206 | break; |
207 | case 'x': | |
7d07df62 | 208 | ctl.mode = COLUMN_MODE_FILLROWS; |
6dbe3af9 | 209 | break; |
6dbe3af9 | 210 | default: |
677ec86c | 211 | errtryhelp(EXIT_FAILURE); |
1df29104 | 212 | } |
6dbe3af9 KZ |
213 | argc -= optind; |
214 | argv += optind; | |
215 | ||
216 | if (!*argv) | |
2593c139 | 217 | eval += input(&ctl, stdin); |
1df29104 | 218 | else |
1ae90932 | 219 | for (; *argv; ++argv) { |
a46e644e KZ |
220 | FILE *fp; |
221 | ||
1ae90932 | 222 | if ((fp = fopen(*argv, "r")) != NULL) { |
2593c139 | 223 | eval += input(&ctl, fp); |
daf093d2 | 224 | fclose(fp); |
1ae90932 SK |
225 | } else { |
226 | warn("%s", *argv); | |
daf093d2 | 227 | eval += EXIT_FAILURE; |
1ae90932 | 228 | } |
6dbe3af9 KZ |
229 | } |
230 | ||
2593c139 | 231 | if (!ctl.entries) |
6dbe3af9 KZ |
232 | exit(eval); |
233 | ||
2593c139 | 234 | if (ctl.mode != COLUMN_MODE_TABLE && ctl.maxlength >= ctl.termwidth) |
7d07df62 KZ |
235 | ctl.mode = COLUMN_MODE_SIMPLE; |
236 | ||
237 | switch (ctl.mode) { | |
238 | case COLUMN_MODE_TABLE: | |
2593c139 | 239 | maketbl(&ctl, separator, greedy, colsep); |
7d07df62 KZ |
240 | break; |
241 | case COLUMN_MODE_FILLCOLS: | |
2593c139 | 242 | columnate_fillcols(&ctl); |
7d07df62 KZ |
243 | break; |
244 | case COLUMN_MODE_FILLROWS: | |
2593c139 | 245 | columnate_fillrows(&ctl); |
7d07df62 KZ |
246 | break; |
247 | case COLUMN_MODE_SIMPLE: | |
2593c139 | 248 | print(&ctl); |
7d07df62 KZ |
249 | break; |
250 | } | |
dcbca568 | 251 | |
2593c139 KZ |
252 | for (i = 0; i < ctl.entries; i++) |
253 | free(ctl.list[i]); | |
254 | free(ctl.list); | |
dcbca568 | 255 | |
7d07df62 | 256 | return eval == 0 ? EXIT_SUCCESS : EXIT_FAILURE; |
6dbe3af9 KZ |
257 | } |
258 | ||
2593c139 | 259 | static void columnate_fillrows(struct column_control *ctl) |
6dbe3af9 KZ |
260 | { |
261 | int chcnt, col, cnt, endcol, numcols; | |
eb63b9b8 | 262 | wchar_t **lp; |
6dbe3af9 | 263 | |
2593c139 KZ |
264 | ctl->maxlength = (ctl->maxlength + TAB) & ~(TAB - 1); |
265 | numcols = ctl->termwidth / ctl->maxlength; | |
266 | endcol = ctl->maxlength; | |
267 | for (chcnt = col = 0, lp = ctl->list;; ++lp) { | |
eb63b9b8 | 268 | fputws(*lp, stdout); |
683ddbd5 | 269 | chcnt += width(*lp); |
2593c139 | 270 | if (!--ctl->entries) |
6dbe3af9 KZ |
271 | break; |
272 | if (++col == numcols) { | |
273 | chcnt = col = 0; | |
2593c139 | 274 | endcol = ctl->maxlength; |
eb63b9b8 | 275 | putwchar('\n'); |
6dbe3af9 | 276 | } else { |
fd6b7a7f | 277 | while ((cnt = ((chcnt + TAB) & ~(TAB - 1))) <= endcol) { |
eb63b9b8 | 278 | putwchar('\t'); |
6dbe3af9 KZ |
279 | chcnt = cnt; |
280 | } | |
2593c139 | 281 | endcol += ctl->maxlength; |
6dbe3af9 KZ |
282 | } |
283 | } | |
284 | if (chcnt) | |
eb63b9b8 | 285 | putwchar('\n'); |
6dbe3af9 KZ |
286 | } |
287 | ||
2593c139 | 288 | static void columnate_fillcols(struct column_control *ctl) |
6dbe3af9 KZ |
289 | { |
290 | int base, chcnt, cnt, col, endcol, numcols, numrows, row; | |
291 | ||
2593c139 KZ |
292 | ctl->maxlength = (ctl->maxlength + TAB) & ~(TAB - 1); |
293 | numcols = ctl->termwidth / ctl->maxlength; | |
683ddbd5 | 294 | if (!numcols) |
1ae90932 | 295 | numcols = 1; |
2593c139 KZ |
296 | numrows = ctl->entries / numcols; |
297 | if (ctl->entries % numcols) | |
6dbe3af9 KZ |
298 | ++numrows; |
299 | ||
300 | for (row = 0; row < numrows; ++row) { | |
2593c139 | 301 | endcol = ctl->maxlength; |
6dbe3af9 | 302 | for (base = row, chcnt = col = 0; col < numcols; ++col) { |
2593c139 KZ |
303 | fputws(ctl->list[base], stdout); |
304 | chcnt += width(ctl->list[base]); | |
305 | if ((base += numrows) >= ctl->entries) | |
6dbe3af9 | 306 | break; |
fd6b7a7f | 307 | while ((cnt = ((chcnt + TAB) & ~(TAB - 1))) <= endcol) { |
eb63b9b8 | 308 | putwchar('\t'); |
6dbe3af9 KZ |
309 | chcnt = cnt; |
310 | } | |
2593c139 | 311 | endcol += ctl->maxlength; |
6dbe3af9 | 312 | } |
eb63b9b8 | 313 | putwchar('\n'); |
6dbe3af9 KZ |
314 | } |
315 | } | |
316 | ||
2593c139 | 317 | static void print(struct column_control *ctl) |
6dbe3af9 KZ |
318 | { |
319 | int cnt; | |
eb63b9b8 | 320 | wchar_t **lp; |
6dbe3af9 | 321 | |
2593c139 | 322 | for (cnt = ctl->entries, lp = ctl->list; cnt--; ++lp) { |
eb63b9b8 KZ |
323 | fputws(*lp, stdout); |
324 | putwchar('\n'); | |
325 | } | |
6dbe3af9 KZ |
326 | } |
327 | ||
2ba641e5 SK |
328 | static wchar_t *local_wcstok(wchar_t *p, const wchar_t *separator, int greedy, |
329 | wchar_t **wcstok_state) | |
732e3dec SK |
330 | { |
331 | wchar_t *result; | |
332 | if (greedy) | |
333 | return wcstok(p, separator, wcstok_state); | |
334 | ||
335 | if (p == NULL) { | |
336 | if (*wcstok_state == NULL) | |
337 | return NULL; | |
338 | else | |
339 | p = *wcstok_state; | |
340 | } | |
341 | result = p; | |
342 | p = wcspbrk(result, separator); | |
343 | if (p == NULL) | |
344 | *wcstok_state = NULL; | |
345 | else { | |
346 | *p = '\0'; | |
347 | *wcstok_state = p + 1; | |
348 | } | |
349 | return result; | |
350 | } | |
351 | ||
2593c139 | 352 | static void maketbl(struct column_control *ctl, wchar_t *separator, int greedy, wchar_t *colsep) |
6dbe3af9 KZ |
353 | { |
354 | TBL *t; | |
d2b7bc74 | 355 | int cnt; |
eb63b9b8 | 356 | wchar_t *p, **lp; |
4eaeb0ef SK |
357 | ssize_t *lens; |
358 | ssize_t maxcols = DEFCOLS, coloff; | |
6dbe3af9 | 359 | TBL *tbl; |
eb63b9b8 | 360 | wchar_t **cols; |
732e3dec | 361 | wchar_t *wcstok_state = NULL; |
6dbe3af9 | 362 | |
2593c139 | 363 | t = tbl = xcalloc(ctl->entries, sizeof(TBL)); |
12bef812 | 364 | cols = xcalloc(maxcols, sizeof(wchar_t *)); |
4eaeb0ef SK |
365 | lens = xcalloc(maxcols, sizeof(ssize_t)); |
366 | ||
2593c139 | 367 | for (lp = ctl->list, cnt = 0; cnt < ctl->entries; ++cnt, ++lp, ++t) { |
4eaeb0ef SK |
368 | coloff = 0; |
369 | p = *lp; | |
732e3dec | 370 | while ((cols[coloff] = local_wcstok(p, separator, greedy, &wcstok_state)) != NULL) { |
1ae90932 | 371 | if (++coloff == maxcols) { |
1ae90932 | 372 | maxcols += DEFCOLS; |
4eaeb0ef SK |
373 | cols = xrealloc(cols, maxcols * sizeof(wchar_t *)); |
374 | lens = xrealloc(lens, maxcols * sizeof(ssize_t)); | |
375 | /* zero fill only new memory */ | |
26ae00a7 JM |
376 | memset(lens + (maxcols - DEFCOLS), 0, |
377 | DEFCOLS * sizeof(*lens)); | |
1ae90932 | 378 | } |
4eaeb0ef | 379 | p = NULL; |
1ae90932 | 380 | } |
12bef812 SK |
381 | t->list = xcalloc(coloff, sizeof(wchar_t *)); |
382 | t->len = xcalloc(coloff, sizeof(int)); | |
1ae90932 SK |
383 | for (t->cols = coloff; --coloff >= 0;) { |
384 | t->list[coloff] = cols[coloff]; | |
683ddbd5 | 385 | t->len[coloff] = width(cols[coloff]); |
1ae90932 SK |
386 | if (t->len[coloff] > lens[coloff]) |
387 | lens[coloff] = t->len[coloff]; | |
6dbe3af9 KZ |
388 | } |
389 | } | |
4eaeb0ef | 390 | |
2593c139 | 391 | for (t = tbl, cnt = 0; cnt < ctl->entries; ++cnt, ++t) { |
1ae90932 SK |
392 | for (coloff = 0; coloff < t->cols - 1; ++coloff) { |
393 | fputws(t->list[coloff], stdout); | |
683ddbd5 | 394 | #ifdef HAVE_WIDECHAR |
d2b7bc74 | 395 | wprintf(L"%*s", lens[coloff] - t->len[coloff], ""); |
683ddbd5 KZ |
396 | #else |
397 | printf("%*s", (int) lens[coloff] - t->len[coloff], ""); | |
398 | #endif | |
47bd8ddc | 399 | fputws(colsep, stdout); |
1ae90932 | 400 | } |
3f7fc4d4 KZ |
401 | if (coloff < t->cols) { |
402 | fputws(t->list[coloff], stdout); | |
403 | putwchar('\n'); | |
404 | } | |
6dbe3af9 | 405 | } |
dcbca568 | 406 | |
2593c139 | 407 | for (cnt = 0; cnt < ctl->entries; ++cnt) { |
dcbca568 SK |
408 | free((tbl+cnt)->list); |
409 | free((tbl+cnt)->len); | |
410 | } | |
411 | free(cols); | |
412 | free(lens); | |
413 | free(tbl); | |
6dbe3af9 KZ |
414 | } |
415 | ||
2593c139 | 416 | static int input(struct column_control *ctl, FILE *fp) |
6dbe3af9 | 417 | { |
12bef812 | 418 | static int maxentry = DEFNUM; |
daf093d2 | 419 | int len, lineno = 1, reportedline = 0, eval = 0; |
eb63b9b8 | 420 | wchar_t *p, buf[MAXLINELEN]; |
2593c139 KZ |
421 | wchar_t **local_list = ctl->list; |
422 | int local_entries = ctl->entries; | |
daf093d2 SK |
423 | |
424 | if (!local_list) | |
425 | local_list = xcalloc(maxentry, sizeof(wchar_t *)); | |
6dbe3af9 | 426 | |
acb5f9b5 SK |
427 | while (1) { |
428 | if (fgetws(buf, MAXLINELEN, fp) == NULL) { | |
429 | if (feof(fp)) | |
430 | break; | |
431 | else | |
432 | err(EXIT_FAILURE, _("read failed")); | |
433 | } | |
1df29104 SK |
434 | for (p = buf; *p && iswspace(*p); ++p) |
435 | ; | |
6dbe3af9 KZ |
436 | if (!*p) |
437 | continue; | |
80fa094c | 438 | if (!(p = wcschr(p, '\n')) && !feof(fp)) { |
bf90b8a6 | 439 | if (reportedline < lineno) { |
1ae90932 SK |
440 | warnx(_("line %d is too long, output will be truncated"), |
441 | lineno); | |
bf90b8a6 SK |
442 | reportedline = lineno; |
443 | } | |
daf093d2 | 444 | eval = 1; |
6dbe3af9 KZ |
445 | continue; |
446 | } | |
bf90b8a6 | 447 | lineno++; |
c630db89 | 448 | if (!feof(fp) && p) |
80fa094c | 449 | *p = '\0'; |
683ddbd5 | 450 | len = width(buf); /* len = p - buf; */ |
2593c139 KZ |
451 | if (ctl->maxlength < len) |
452 | ctl->maxlength = len; | |
daf093d2 | 453 | if (local_entries == maxentry) { |
6dbe3af9 | 454 | maxentry += DEFNUM; |
daf093d2 SK |
455 | local_list = xrealloc(local_list, |
456 | (u_int)maxentry * sizeof(wchar_t *)); | |
6dbe3af9 | 457 | } |
daf093d2 | 458 | local_list[local_entries++] = wcsdup(buf); |
6dbe3af9 | 459 | } |
daf093d2 | 460 | |
2593c139 KZ |
461 | ctl->list = local_list; |
462 | ctl->entries = local_entries; | |
daf093d2 SK |
463 | |
464 | return eval; | |
6dbe3af9 KZ |
465 | } |
466 | ||
06b04b23 | 467 | #ifdef HAVE_WIDECHAR |
eb63b9b8 KZ |
468 | static wchar_t *mbs_to_wcs(const char *s) |
469 | { | |
395801be | 470 | ssize_t n; |
eb63b9b8 KZ |
471 | wchar_t *wcs; |
472 | ||
473 | n = mbstowcs((wchar_t *)0, s, 0); | |
474 | if (n < 0) | |
475 | return NULL; | |
cce4d25a | 476 | wcs = xmalloc((n + 1) * sizeof(wchar_t)); |
395801be | 477 | n = mbstowcs(wcs, s, n + 1); |
cd70a460 KZ |
478 | if (n < 0) { |
479 | free(wcs); | |
eb63b9b8 | 480 | return NULL; |
cd70a460 | 481 | } |
eb63b9b8 KZ |
482 | return wcs; |
483 | } | |
484 | #endif | |
485 | ||
06b04b23 | 486 | #ifndef HAVE_WIDECHAR |
eb63b9b8 KZ |
487 | static char *mtsafe_strtok(char *str, const char *delim, char **ptr) |
488 | { | |
489 | if (str == NULL) { | |
490 | str = *ptr; | |
491 | if (str == NULL) | |
492 | return NULL; | |
493 | } | |
494 | str += strspn(str, delim); | |
495 | if (*str == '\0') { | |
496 | *ptr = NULL; | |
497 | return NULL; | |
498 | } else { | |
499 | char *token_end = strpbrk(str, delim); | |
500 | if (token_end) { | |
501 | *token_end = '\0'; | |
502 | *ptr = token_end + 1; | |
503 | } else | |
504 | *ptr = NULL; | |
505 | return str; | |
506 | } | |
507 | } | |
508 | #endif |