]> git.ozlabs.org Git - petitboot/blob - lib/fold/fold.c
Make read-only guarantee user-settable
[petitboot] / lib / fold / fold.c
1
2 #define _GNU_SOURCE
3
4 #include <assert.h>
5 #include <string.h>
6 #include <stdio.h>
7 #include <wchar.h>
8 #include <wctype.h>
9
10 #include "fold/fold.h"
11
12 void fold_text(const char *text,
13                 int linelen,
14                 int line_cb(void *arg, const char *start, int len),
15                 void *arg)
16 {
17         const char *start, *end, *sep;
18         size_t sep_bytes, len;
19         int col, rc = 0;
20         mbstate_t ps;
21
22         /* start, end and sep are byte-positions in the string, and should always
23          * lie on the start of a multibyte sequence */
24         start = end = sep = text;
25         sep_bytes = 0;
26         col = 0;
27         len = strlen(text);
28         memset(&ps, 0, sizeof(ps));
29
30         while (!rc) {
31                 size_t bytes;
32                 wchar_t wc;
33                 int width;
34
35                 bytes = mbrtowc(&wc, end, len - (end - text), &ps);
36
37                 assert(bytes != (size_t)-1);
38
39                 /* we'll get a zero size for the nul terminator */
40                 if (!bytes) {
41                         line_cb(arg, start, end - start);
42                         break;
43                 }
44
45                 if (wc == L'\n') {
46                         rc = line_cb(arg, start, end - start);
47                         start = sep = end += bytes;
48                         sep_bytes = 0;
49                         col = 0;
50                         continue;
51                 }
52
53                 width = wcwidth(wc);
54
55                 /* we should have caught this in the !bytes check... */
56                 if (width == 0) {
57                         line_cb(arg, start, end - start);
58                         break;
59                 }
60
61                 /* unprintable character? just add it to the current line */
62                 if (width < 0) {
63                         end += bytes;
64                         continue;
65                 }
66
67                 col += width;
68
69                 if (col > linelen) {
70                         if (sep != start) {
71                                 /* split on a previous word boundary, if
72                                  * possible */
73                                 rc = line_cb(arg, start, sep - start);
74                                 end = sep + sep_bytes;
75                         } else {
76                                 /* otherwise, break the word */
77                                 rc = line_cb(arg, start, end - start);
78                         }
79                         sep_bytes = 0;
80                         start = sep = end;
81                         col = 0;
82
83                 } else {
84                         /* record our last separator */
85                         if (wc == L' ') {
86                                 sep = end;
87                                 sep_bytes = bytes;
88                         }
89                         end += bytes;
90                 }
91         }
92 }