xref: /aosp_15_r20/external/toybox/toys/posix/fold.c (revision cf5a6c84e2b8763fc1a7db14496fd4742913b199)
1 /* fold.c - Line wrap input.
2  *
3  * Copyright 2023 Rob Landley <[email protected]>
4  *
5  * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/fold.html
6 
7 USE_FOLD(NEWTOY(fold, "bsw#<1=80", TOYFLAG_USR|TOYFLAG_BIN))
8 
9 config FOLD
10   bool "fold"
11   default y
12   help
13     usage: fold [-bs] [-w WIDTH] [FILE...]
14 
15     Break long lines by inserting newlines.
16 
17     -b	Count bytes instead of utf-8 unicode columns
18     -s	Wrap at whitespace when possible
19     -w	Break at WIDTH columns (default 80)
20 */
21 
22 #define FOR_fold
23 #include "toys.h"
24 
GLOBALS(long w;)25 GLOBALS(
26   long w;
27 )
28 
29 // wcwidth utf8towc
30 void do_fold(int fd, char *name)
31 {
32   FILE *fp = fd ? fdopen(fd, "r") : stdin;
33   char *rr, *ss;
34   long ii, bb, ww, width, space;
35   unsigned cc;
36 
37   // Note: not bothering to handle embedded NUL bytes, they truncate the line.
38 
39   // Loop reading/printing lines
40   while ((ss = rr = xgetdelim(fp, '\n'))) for (ii = width = space = 0;;) {
41     // Parse next character's byte length and column width
42     bb = ww = 1;
43     if (ss[ii]<32) ww = FLAG(b);
44     if (FLAG(b)) cc = ss[ii];
45     else {
46       if ((bb = utf8towc(&cc, ss+ii, 4))>0 && (ww = wcwidth(cc))<0) ww = 0;
47       if (cc=='\t') ww = 8-(width&7);
48     }
49 
50     // Did line end?
51     if (!cc || cc=='\r' || cc=='\n') {
52       if (cc) ii++;
53       if (ii) {
54         xwrite(1, ss, ii);
55         ss += ii;
56         ii = width = space = 0;
57       } else {
58         free(rr);
59 
60         break;
61       }
62 
63     // backspace?
64     } else if (!FLAG(b) && cc=='\b') {
65       if (width) width--;
66       ii++;
67 
68     // Is it time to wrap?
69 
70     } else if (width+ww>TT.w && ss[ii+bb]!='\b'
71                && (ii || !strchr("\r\n", ss[ii+bb])))
72     {
73       if (!ii) ii += bb;
74       if (!space) space = ii;
75 
76       cc = ss[space];
77       ss[space] = '\n';
78       xwrite(1, ss, space+1);
79       ss += space;
80       *ss = cc;
81       ii = width = space = 0;
82 
83     // move the cursor
84     } else {
85       ii += bb;
86       width += ww;
87       if (FLAG(s) && iswspace(cc)) space = ii;
88     }
89   }
90   if (fp != stdin) fclose(fp);
91 }
92 
fold_main(void)93 void fold_main(void)
94 {
95   loopfiles(toys.optargs, do_fold);
96   loopfiles_rw(toys.optargs, O_RDONLY|WARN_ONLY, 0, do_fold);
97 }
98