/* fold.c - fold text * * Copyright 2014 Samuel Holland <samuel@sholland.net> * * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/fold.html USE_FOLD(NEWTOY(fold, "bsuw#<1", TOYFLAG_USR|TOYFLAG_BIN)) config FOLD bool "fold" default n help usage: fold [-bsu] [-w WIDTH] [FILE...] Folds (wraps) or unfolds ascii text by adding or removing newlines. Default line width is 80 columns for folding and infinite for unfolding. -b Fold based on bytes instead of columns -s Fold/unfold at whitespace boundaries if possible -u Unfold text (and refold if -w is given) -w Set lines to WIDTH columns or bytes */ #define FOR_fold #include "toys.h" GLOBALS( int width; ) // wcwidth mbrtowc void do_fold(int fd, char *name) { int bufsz, len = 0, maxlen; if (toys.optflags & FLAG_w) maxlen = TT.width; else if (toys.optflags & FLAG_u) maxlen = 0; else maxlen = 80; while ((bufsz = read(fd, toybuf, sizeof(toybuf))) > 0) { char *buf = toybuf; int pos = 0, split = -1; while (pos < bufsz) { switch (buf[pos]) { case '\n': // print everything but the \n, then move on to the next buffer if ((toys.optflags & FLAG_u) && buf[pos-1] != '\n' && buf[pos+1] != '\n') { xwrite(1, buf, pos); bufsz -= pos + 1; buf += pos + 1; pos = 0; split = -1; // reset len, FLAG_b or not; just print multiple lines at once } else len = 0; break; case '\b': // len cannot be negative; not allowed to wrap after backspace if (toys.optflags & FLAG_b) len++; else if (len > 0) len--; break; case '\r': // not allowed to wrap after carriage return if (toys.optflags & FLAG_b) len++; else len = 0; break; case '\t': // round to 8, but we add one after falling through // (because of whitespace, but it also takes care of FLAG_b) if (!(toys.optflags & FLAG_b)) len = (len & ~7) + 7; case ' ': split = pos; default: len++; } // we don't want to double up \n; not allowed to wrap before \b if (maxlen > 0 && len >= maxlen && buf[pos+1] != '\n' && buf[pos+1] != '\b') { if (!(toys.optflags & FLAG_s) || split < 0) split = pos; xwrite(1, buf, split + 1); xputc('\n'); bufsz -= split + 1; buf += split + 1; len = pos = 0; split = -1; } else pos++; } xwrite(1, buf, bufsz); } xputc('\n'); } void fold_main(void) { loopfiles(toys.optargs, do_fold); }