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);