fold.c - sbase - suckless unix tools
(HTM) git clone git://git.suckless.org/sbase
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) README
(DIR) LICENSE
---
fold.c (2616B)
---
1 /* See LICENSE file for copyright and license details. */
2 #include <ctype.h>
3 #include <stdint.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7
8 #include "text.h"
9 #include "util.h"
10 #include "utf.h"
11
12 static int bflag = 0;
13 static int sflag = 0;
14 static size_t width = 80;
15
16 static void
17 foldline(struct line *l, const char *fname) {
18 size_t i, col, last, spacesect, len;
19 Rune r;
20 int runelen;
21
22 for (i = 0, last = 0, col = 0, spacesect = 0; i < l->len; i += runelen) {
23 if (col >= width && ((l->data[i] != '\r' && l->data[i] != '\b') || bflag)) {
24 if (bflag && col > width)
25 i -= runelen; /* never split a character */
26 len = ((sflag && spacesect) ? spacesect : i) - last;
27 if (fwrite(l->data + last, 1, len, stdout) != len)
28 eprintf("fwrite <stdout>:");
29 if (l->data[i] != '\n')
30 putchar('\n');
31 if (sflag && spacesect)
32 i = spacesect;
33 last = i;
34 col = 0;
35 spacesect = 0;
36 }
37 runelen = charntorune(&r, l->data + i, l->len - i);
38 if (!runelen || r == Runeerror)
39 eprintf("charntorune: %s: invalid utf\n", fname);
40 if (sflag && isblankrune(r))
41 spacesect = i + runelen;
42 if (!bflag && iscntrl(l->data[i])) {
43 switch(l->data[i]) {
44 case '\b':
45 col -= (col > 0);
46 break;
47 case '\r':
48 col = 0;
49 break;
50 case '\t':
51 col += (8 - (col % 8));
52 if (col >= width)
53 i--;
54 break;
55 }
56 } else {
57 col += bflag ? runelen : 1;
58 }
59 }
60 if (l->len - last)
61 fwrite(l->data + last, 1, l->len - last, stdout);
62 }
63
64 static void
65 fold(FILE *fp, const char *fname)
66 {
67 static struct line line;
68 static size_t size = 0;
69 ssize_t len;
70
71 while ((len = getline(&line.data, &size, fp)) > 0) {
72 line.len = len;
73 foldline(&line, fname);
74 }
75 if (ferror(fp))
76 eprintf("getline %s:", fname);
77 }
78
79 static void
80 usage(void)
81 {
82 eprintf("usage: %s [-bs] [-w num | -num] [FILE ...]\n", argv0);
83 }
84
85 int
86 main(int argc, char *argv[])
87 {
88 FILE *fp;
89 int ret = 0;
90
91 ARGBEGIN {
92 case 'b':
93 bflag = 1;
94 break;
95 case 's':
96 sflag = 1;
97 break;
98 case 'w':
99 width = estrtonum(EARGF(usage()), 1, MIN(LLONG_MAX, SIZE_MAX));
100 break;
101 ARGNUM:
102 if (!(width = ARGNUMF()))
103 eprintf("illegal width value, too small\n");
104 break;
105 default:
106 usage();
107 } ARGEND
108
109 if (!argc) {
110 fold(stdin, "<stdin>");
111 } else {
112 for (; *argv; argc--, argv++) {
113 if (!strcmp(*argv, "-")) {
114 *argv = "<stdin>";
115 fp = stdin;
116 } else if (!(fp = fopen(*argv, "r"))) {
117 weprintf("fopen %s:", *argv);
118 ret = 1;
119 continue;
120 }
121 fold(fp, *argv);
122 if (fp != stdin && fshut(fp, *argv))
123 ret = 1;
124 }
125 }
126
127 ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
128
129 return ret;
130 }