toybox/toys/pending/fold.c
<<
>>
Prefs
   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