OSDN Git Service

Add fmt.
authorElliott Hughes <enh@google.com>
Sun, 24 Dec 2017 07:44:04 +0000 (23:44 -0800)
committerRob Landley <rob@landley.net>
Sun, 24 Dec 2017 17:21:12 +0000 (11:21 -0600)
A very simple implementation of fmt, good enough for my daily use of !!fmt
in vi to reflow checkin comments like this.

tests/fmt.test [new file with mode: 0755]
toys/pending/fmt.c [new file with mode: 0644]

diff --git a/tests/fmt.test b/tests/fmt.test
new file mode 100755 (executable)
index 0000000..0d5c5bd
--- /dev/null
@@ -0,0 +1,21 @@
+#!/bin/bash
+
+[ -f testing.sh ] && . testing.sh
+
+echo "hello world " > en.txt
+echo "this is some text    " >> en.txt
+# https://en.wikipedia.org/wiki/Aegukga
+echo "동해물과 백두산이 마르고 닳도록" > kr.txt
+echo "하나님이 보우하사 우리나라 만세." >> kr.txt
+
+#testing "name" "command" "result" "infile" "stdin"
+
+testing "join" "fmt en.txt" "hello world this is some text\n" "" ""
+testing "split" "fmt -w 10 en.txt" "hello\nworld\nthis is\nsome text\n" "" ""
+testing "no room" "echo 'hello world' | fmt -w 1" "hello\nworld\n" "" ""
+testing "blank line" "echo -e 'first paragraph of text\n\nand another' | fmt -w 10" "first\nparagraph\nof text\n\nand\nanother\n" "" ""
+testing "ws-only line" "echo -e 'hello\n  \nworld' | fmt -w 10" "hello\n\nworld\n" "" ""
+testing "leading space" "echo '  hello world' | fmt -w 5" "  hello\n  world\n" "" ""
+testing "utf8" "fmt -w 10 kr.txt" "동해물과\n백두산이\n마르고\n닳도록\n하나님이\n보우하사\n우리나라\n만세.\n" "" ""
+
+rm en.txt kr.txt
diff --git a/toys/pending/fmt.c b/toys/pending/fmt.c
new file mode 100644 (file)
index 0000000..618642a
--- /dev/null
@@ -0,0 +1,78 @@
+/* fmt.c - Text formatter
+ *
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Deviations from original:
+ *   we treat all whitespace as equal (no tab expansion, no runs of spaces)
+ *   we don't try to recognize ends of sentences to double-space after ./?/!
+
+USE_FMT(NEWTOY(fmt, "w#", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE))
+
+config FMT
+  bool "fmt"
+  default y
+  help
+    usage: fmt [-w WIDTH] [FILE...]
+
+    Reformat input to not exceed a maximum line length.
+
+    -w WIDTH   maximum characters per line (default 75)
+*/
+
+#define FOR_fmt
+#include "toys.h"
+
+GLOBALS(
+  int width;
+)
+
+static void do_fmt(int fd, char *name)
+{
+  FILE *fp = xfdopen(fd, "re");
+  char *line = NULL;
+  size_t allocated_length = 0;
+  int cols = 0, is_first = 1, indent_end = 0, line_length;
+
+  while ((line_length = getline(&line, &allocated_length, fp)) > 0) {
+    int b = 0, e, w;
+
+    while (b < line_length && isspace(line[b])) b++;
+    if (b == line_length) {
+      if (cols > 0) xputc('\n');
+      xputc('\n');
+      is_first = 1;
+      cols = 0;
+      continue;
+    }
+    if (is_first) indent_end = b;
+
+    for (; b < line_length; b = e + 1) {
+      while (isspace(line[b])) b++;
+      for (e = b + 1; e < line_length && !isspace(line[e]);) e++;
+      if (e >= line_length) break;
+
+      line[e] = 0;
+      w = utf8len(line + b);
+
+      if (!is_first && (cols + (is_first?indent_end:1) + w) >= TT.width) {
+        xputc('\n');
+        is_first = 1;
+        cols = 0;
+      }
+      xprintf("%.*s%.*s",is_first?indent_end:1,is_first?line:" ",(e-b),line+b);
+      cols += (is_first?indent_end:1) + w;
+      b = e + 1;
+      is_first = 0;
+    }
+  }
+  if (cols > 0) xputc('\n');
+  fclose(fp);
+}
+
+void fmt_main(void)
+{
+  if (TT.width < 0) error_exit("negative width: %d", TT.width);
+  if (!TT.width) TT.width = 75;
+
+  loopfiles(toys.optargs, do_fmt);
+}