1/* fmt.c - Text formatter
2 *
3 * Copyright 2017 The Android Open Source Project
4 *
5 * Deviations from original:
6 *   we treat all whitespace as equal (no tab expansion, no runs of spaces)
7 *   we don't try to recognize ends of sentences to double-space after ./?/!
8
9USE_FMT(NEWTOY(fmt, "w#", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE))
10
11config FMT
12  bool "fmt"
13  default y
14  help
15    usage: fmt [-w WIDTH] [FILE...]
16
17    Reformat input to not exceed a maximum line length.
18
19    -w WIDTH	maximum characters per line (default 75)
20*/
21
22#define FOR_fmt
23#include "toys.h"
24
25GLOBALS(
26  int width;
27)
28
29static void do_fmt(int fd, char *name)
30{
31  FILE *fp = xfdopen(fd, "re");
32  char *line = NULL;
33  size_t allocated_length = 0;
34  int cols = 0, is_first = 1, indent_end = 0, line_length;
35
36  while ((line_length = getline(&line, &allocated_length, fp)) > 0) {
37    int b = 0, e, w;
38
39    while (b < line_length && isspace(line[b])) b++;
40    if (b == line_length) {
41      if (cols > 0) xputc('\n');
42      xputc('\n');
43      is_first = 1;
44      cols = 0;
45      continue;
46    }
47    if (is_first) indent_end = b;
48
49    for (; b < line_length; b = e + 1) {
50      while (isspace(line[b])) b++;
51      for (e = b + 1; e < line_length && !isspace(line[e]);) e++;
52      if (e >= line_length) break;
53
54      line[e] = 0;
55      w = utf8len(line + b);
56
57      if (!is_first && (cols + (is_first?indent_end:1) + w) >= TT.width) {
58        xputc('\n');
59        is_first = 1;
60        cols = 0;
61      }
62      xprintf("%.*s%.*s",is_first?indent_end:1,is_first?line:" ",(e-b),line+b);
63      cols += (is_first?indent_end:1) + w;
64      b = e + 1;
65      is_first = 0;
66    }
67  }
68  if (cols > 0) xputc('\n');
69  fclose(fp);
70}
71
72void fmt_main(void)
73{
74  if (TT.width < 0) error_exit("negative width: %d", TT.width);
75  if (!TT.width) TT.width = 75;
76
77  loopfiles(toys.optargs, do_fmt);
78}
79