1 /* fold.c - fold text
2 *
3 * Copyright 2014 Samuel Holland <samuel@sholland.net>
4 *
5 * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/fold.html
6
7 USE_FOLD(NEWTOY(fold, "bsuw#<1", TOYFLAG_USR|TOYFLAG_BIN))
8
9 config FOLD
10 bool "fold"
11 default n
12 help
13 usage: fold [-bsu] [-w WIDTH] [FILE...]
14
15 Folds (wraps) or unfolds ascii text by adding or removing newlines.
16 Default line width is 80 columns for folding and infinite for unfolding.
17
18 -b Fold based on bytes instead of columns
19 -s Fold/unfold at whitespace boundaries if possible
20 -u Unfold text (and refold if -w is given)
21 -w Set lines to WIDTH columns or bytes
22 */
23
24 #define FOR_fold
25 #include "toys.h"
26
GLOBALS(int width;)27 GLOBALS(
28 int width;
29 )
30
31 // wcwidth mbrtowc
32 void do_fold(int fd, char *name)
33 {
34 int bufsz, len = 0, maxlen;
35
36 if (toys.optflags & FLAG_w) maxlen = TT.width;
37 else if (toys.optflags & FLAG_u) maxlen = 0;
38 else maxlen = 80;
39
40 while ((bufsz = read(fd, toybuf, sizeof(toybuf))) > 0) {
41 char *buf = toybuf;
42 int pos = 0, split = -1;
43
44 while (pos < bufsz) {
45 switch (buf[pos]) {
46 case '\n':
47 // print everything but the \n, then move on to the next buffer
48 if ((toys.optflags & FLAG_u) && buf[pos-1] != '\n'
49 && buf[pos+1] != '\n') {
50 xwrite(1, buf, pos);
51 bufsz -= pos + 1;
52 buf += pos + 1;
53 pos = 0;
54 split = -1;
55 // reset len, FLAG_b or not; just print multiple lines at once
56 } else len = 0;
57 break;
58 case '\b':
59 // len cannot be negative; not allowed to wrap after backspace
60 if (toys.optflags & FLAG_b) len++;
61 else if (len > 0) len--;
62 break;
63 case '\r':
64 // not allowed to wrap after carriage return
65 if (toys.optflags & FLAG_b) len++;
66 else len = 0;
67 break;
68 case '\t':
69 // round to 8, but we add one after falling through
70 // (because of whitespace, but it also takes care of FLAG_b)
71 if (!(toys.optflags & FLAG_b)) len = (len & ~7) + 7;
72 case ' ':
73 split = pos;
74 default:
75 len++;
76 }
77
78 // we don't want to double up \n; not allowed to wrap before \b
79 if (maxlen > 0 && len >= maxlen && buf[pos+1] != '\n' && buf[pos+1] != '\b') {
80 if (!(toys.optflags & FLAG_s) || split < 0) split = pos;
81 xwrite(1, buf, split + 1);
82 xputc('\n');
83 bufsz -= split + 1;
84 buf += split + 1;
85 len = pos = 0;
86 split = -1;
87 } else pos++;
88 }
89 xwrite(1, buf, bufsz);
90 }
91 xputc('\n');
92 }
93
fold_main(void)94 void fold_main(void)
95 {
96 loopfiles(toys.optargs, do_fold);
97 }
98