1547c8d980bb5ae37f8002aead4e155cc5554dfcaSamuel Holland/* fold.c - fold text
2547c8d980bb5ae37f8002aead4e155cc5554dfcaSamuel Holland *
3547c8d980bb5ae37f8002aead4e155cc5554dfcaSamuel Holland * Copyright 2014 Samuel Holland <samuel@sholland.net>
4547c8d980bb5ae37f8002aead4e155cc5554dfcaSamuel Holland *
5547c8d980bb5ae37f8002aead4e155cc5554dfcaSamuel Holland * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/fold.html
6547c8d980bb5ae37f8002aead4e155cc5554dfcaSamuel Holland
742cc29c7883c852462c6c740c72eff06bca8acccHyejin KimUSE_FOLD(NEWTOY(fold, "bsuw#<1", TOYFLAG_USR|TOYFLAG_BIN))
8547c8d980bb5ae37f8002aead4e155cc5554dfcaSamuel Holland
9547c8d980bb5ae37f8002aead4e155cc5554dfcaSamuel Hollandconfig FOLD
10547c8d980bb5ae37f8002aead4e155cc5554dfcaSamuel Holland  bool "fold"
11547c8d980bb5ae37f8002aead4e155cc5554dfcaSamuel Holland  default n
12547c8d980bb5ae37f8002aead4e155cc5554dfcaSamuel Holland  help
13aac4222dd8dcce3e7a782111ac7d7d9d0bfb2972Samuel Holland    usage: fold [-bsu] [-w WIDTH] [FILE...]
14547c8d980bb5ae37f8002aead4e155cc5554dfcaSamuel Holland
157bcaf03f1506d338cde2f6d1b953d6ba6e5a7ea7Rob Landley    Folds (wraps) or unfolds ascii text by adding or removing newlines.
16aac4222dd8dcce3e7a782111ac7d7d9d0bfb2972Samuel Holland    Default line width is 80 columns for folding and infinite for unfolding.
17547c8d980bb5ae37f8002aead4e155cc5554dfcaSamuel Holland
187bcaf03f1506d338cde2f6d1b953d6ba6e5a7ea7Rob Landley    -b	Fold based on bytes instead of columns
197bcaf03f1506d338cde2f6d1b953d6ba6e5a7ea7Rob Landley    -s	Fold/unfold at whitespace boundaries if possible
207bcaf03f1506d338cde2f6d1b953d6ba6e5a7ea7Rob Landley    -u	Unfold text (and refold if -w is given)
217bcaf03f1506d338cde2f6d1b953d6ba6e5a7ea7Rob Landley    -w	Set lines to WIDTH columns or bytes
22547c8d980bb5ae37f8002aead4e155cc5554dfcaSamuel Holland*/
23547c8d980bb5ae37f8002aead4e155cc5554dfcaSamuel Holland
24547c8d980bb5ae37f8002aead4e155cc5554dfcaSamuel Holland#define FOR_fold
25547c8d980bb5ae37f8002aead4e155cc5554dfcaSamuel Holland#include "toys.h"
26547c8d980bb5ae37f8002aead4e155cc5554dfcaSamuel Holland
27547c8d980bb5ae37f8002aead4e155cc5554dfcaSamuel HollandGLOBALS(
28aac4222dd8dcce3e7a782111ac7d7d9d0bfb2972Samuel Holland  int width;
29547c8d980bb5ae37f8002aead4e155cc5554dfcaSamuel Holland)
30547c8d980bb5ae37f8002aead4e155cc5554dfcaSamuel Holland
317bcaf03f1506d338cde2f6d1b953d6ba6e5a7ea7Rob Landley// wcwidth mbrtowc
32547c8d980bb5ae37f8002aead4e155cc5554dfcaSamuel Hollandvoid do_fold(int fd, char *name)
33547c8d980bb5ae37f8002aead4e155cc5554dfcaSamuel Holland{
347bcaf03f1506d338cde2f6d1b953d6ba6e5a7ea7Rob Landley  int bufsz, len = 0, maxlen;
35547c8d980bb5ae37f8002aead4e155cc5554dfcaSamuel Holland
367bcaf03f1506d338cde2f6d1b953d6ba6e5a7ea7Rob Landley  if (toys.optflags & FLAG_w) maxlen = TT.width;
377bcaf03f1506d338cde2f6d1b953d6ba6e5a7ea7Rob Landley  else if (toys.optflags & FLAG_u) maxlen = 0;
387bcaf03f1506d338cde2f6d1b953d6ba6e5a7ea7Rob Landley  else maxlen = 80;
39547c8d980bb5ae37f8002aead4e155cc5554dfcaSamuel Holland
40aac4222dd8dcce3e7a782111ac7d7d9d0bfb2972Samuel Holland  while ((bufsz = read(fd, toybuf, sizeof(toybuf))) > 0) {
417bcaf03f1506d338cde2f6d1b953d6ba6e5a7ea7Rob Landley    char *buf = toybuf;
427bcaf03f1506d338cde2f6d1b953d6ba6e5a7ea7Rob Landley    int pos = 0, split = -1;
43547c8d980bb5ae37f8002aead4e155cc5554dfcaSamuel Holland
44aac4222dd8dcce3e7a782111ac7d7d9d0bfb2972Samuel Holland    while (pos < bufsz) {
45aac4222dd8dcce3e7a782111ac7d7d9d0bfb2972Samuel Holland      switch (buf[pos]) {
46547c8d980bb5ae37f8002aead4e155cc5554dfcaSamuel Holland        case '\n':
477bcaf03f1506d338cde2f6d1b953d6ba6e5a7ea7Rob Landley          // print everything but the \n, then move on to the next buffer
48aac4222dd8dcce3e7a782111ac7d7d9d0bfb2972Samuel Holland          if ((toys.optflags & FLAG_u) && buf[pos-1] != '\n'
49aac4222dd8dcce3e7a782111ac7d7d9d0bfb2972Samuel Holland                                       && buf[pos+1] != '\n') {
50aac4222dd8dcce3e7a782111ac7d7d9d0bfb2972Samuel Holland              xwrite(1, buf, pos);
51aac4222dd8dcce3e7a782111ac7d7d9d0bfb2972Samuel Holland              bufsz -= pos + 1;
52aac4222dd8dcce3e7a782111ac7d7d9d0bfb2972Samuel Holland              buf += pos + 1;
53aac4222dd8dcce3e7a782111ac7d7d9d0bfb2972Samuel Holland              pos = 0;
54aac4222dd8dcce3e7a782111ac7d7d9d0bfb2972Samuel Holland              split = -1;
557bcaf03f1506d338cde2f6d1b953d6ba6e5a7ea7Rob Landley          // reset len, FLAG_b or not; just print multiple lines at once
567bcaf03f1506d338cde2f6d1b953d6ba6e5a7ea7Rob Landley          } else len = 0;
57aac4222dd8dcce3e7a782111ac7d7d9d0bfb2972Samuel Holland          break;
58547c8d980bb5ae37f8002aead4e155cc5554dfcaSamuel Holland        case '\b':
597bcaf03f1506d338cde2f6d1b953d6ba6e5a7ea7Rob Landley          // len cannot be negative; not allowed to wrap after backspace
60547c8d980bb5ae37f8002aead4e155cc5554dfcaSamuel Holland          if (toys.optflags & FLAG_b) len++;
61547c8d980bb5ae37f8002aead4e155cc5554dfcaSamuel Holland          else if (len > 0) len--;
62aac4222dd8dcce3e7a782111ac7d7d9d0bfb2972Samuel Holland          break;
63547c8d980bb5ae37f8002aead4e155cc5554dfcaSamuel Holland        case '\r':
647bcaf03f1506d338cde2f6d1b953d6ba6e5a7ea7Rob Landley          // not allowed to wrap after carriage return
65547c8d980bb5ae37f8002aead4e155cc5554dfcaSamuel Holland          if (toys.optflags & FLAG_b) len++;
66547c8d980bb5ae37f8002aead4e155cc5554dfcaSamuel Holland          else len = 0;
67aac4222dd8dcce3e7a782111ac7d7d9d0bfb2972Samuel Holland          break;
68547c8d980bb5ae37f8002aead4e155cc5554dfcaSamuel Holland        case '\t':
697bcaf03f1506d338cde2f6d1b953d6ba6e5a7ea7Rob Landley          // round to 8, but we add one after falling through
707bcaf03f1506d338cde2f6d1b953d6ba6e5a7ea7Rob Landley          // (because of whitespace, but it also takes care of FLAG_b)
717bcaf03f1506d338cde2f6d1b953d6ba6e5a7ea7Rob Landley          if (!(toys.optflags & FLAG_b)) len = (len & ~7) + 7;
72547c8d980bb5ae37f8002aead4e155cc5554dfcaSamuel Holland        case ' ':
73aac4222dd8dcce3e7a782111ac7d7d9d0bfb2972Samuel Holland          split = pos;
74547c8d980bb5ae37f8002aead4e155cc5554dfcaSamuel Holland        default:
75547c8d980bb5ae37f8002aead4e155cc5554dfcaSamuel Holland          len++;
76547c8d980bb5ae37f8002aead4e155cc5554dfcaSamuel Holland      }
77547c8d980bb5ae37f8002aead4e155cc5554dfcaSamuel Holland
787bcaf03f1506d338cde2f6d1b953d6ba6e5a7ea7Rob Landley      // we don't want to double up \n; not allowed to wrap before \b
79aac4222dd8dcce3e7a782111ac7d7d9d0bfb2972Samuel Holland      if (maxlen > 0 && len >= maxlen && buf[pos+1] != '\n' && buf[pos+1] != '\b') {
80aac4222dd8dcce3e7a782111ac7d7d9d0bfb2972Samuel Holland        if (!(toys.optflags & FLAG_s) || split < 0) split = pos;
81aac4222dd8dcce3e7a782111ac7d7d9d0bfb2972Samuel Holland        xwrite(1, buf, split + 1);
82aac4222dd8dcce3e7a782111ac7d7d9d0bfb2972Samuel Holland        xputc('\n');
83aac4222dd8dcce3e7a782111ac7d7d9d0bfb2972Samuel Holland        bufsz -= split + 1;
84aac4222dd8dcce3e7a782111ac7d7d9d0bfb2972Samuel Holland        buf += split + 1;
85aac4222dd8dcce3e7a782111ac7d7d9d0bfb2972Samuel Holland        len = pos = 0;
86aac4222dd8dcce3e7a782111ac7d7d9d0bfb2972Samuel Holland        split = -1;
877bcaf03f1506d338cde2f6d1b953d6ba6e5a7ea7Rob Landley      } else pos++;
88547c8d980bb5ae37f8002aead4e155cc5554dfcaSamuel Holland    }
89aac4222dd8dcce3e7a782111ac7d7d9d0bfb2972Samuel Holland    xwrite(1, buf, bufsz);
90547c8d980bb5ae37f8002aead4e155cc5554dfcaSamuel Holland  }
91aac4222dd8dcce3e7a782111ac7d7d9d0bfb2972Samuel Holland  xputc('\n');
92547c8d980bb5ae37f8002aead4e155cc5554dfcaSamuel Holland}
93547c8d980bb5ae37f8002aead4e155cc5554dfcaSamuel Holland
94547c8d980bb5ae37f8002aead4e155cc5554dfcaSamuel Hollandvoid fold_main(void)
95547c8d980bb5ae37f8002aead4e155cc5554dfcaSamuel Holland{
96547c8d980bb5ae37f8002aead4e155cc5554dfcaSamuel Holland  loopfiles(toys.optargs, do_fold);
97547c8d980bb5ae37f8002aead4e155cc5554dfcaSamuel Holland}
98