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