12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697 |
- /* 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);
- }
|