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 7USE_FOLD(NEWTOY(fold, "bsuw#<1", TOYFLAG_USR|TOYFLAG_BIN)) 8 9config 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 27GLOBALS( 28 int width; 29) 30 31// wcwidth mbrtowc 32void 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 94void fold_main(void) 95{ 96 loopfiles(toys.optargs, do_fold); 97} 98