Home | History | Annotate | Download | only in pending
      1 /* fold.c - fold text
      2  *
      3  * Copyright 2014 Samuel Holland <samuel (at) sholland.net>
      4  *
      5  * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/fold.html
      6 
      7 USE_FOLD(NEWTOY(fold, "bsuw#<1", TOYFLAG_USR|TOYFLAG_BIN))
      8 
      9 config 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 
     27 GLOBALS(
     28   int width;
     29 )
     30 
     31 // wcwidth mbrtowc
     32 void 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 
     94 void fold_main(void)
     95 {
     96   loopfiles(toys.optargs, do_fold);
     97 }
     98