aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorElliott Hughes <enh@google.com>2017-12-23 23:44:04 -0800
committerRob Landley <rob@landley.net>2017-12-24 11:21:12 -0600
commit4335501bf3269ac86b7bfdf236aa763d380327e2 (patch)
tree7dc5a0742fd40bba26efb628e77757434755c986
parent17bcad9d44600d3f9f62d88e5a53cd037c8dec13 (diff)
downloadtoybox-4335501bf3269ac86b7bfdf236aa763d380327e2.tar.gz
Add fmt.
A very simple implementation of fmt, good enough for my daily use of !!fmt in vi to reflow checkin comments like this.
-rwxr-xr-xtests/fmt.test21
-rw-r--r--toys/pending/fmt.c78
2 files changed, 99 insertions, 0 deletions
diff --git a/tests/fmt.test b/tests/fmt.test
new file mode 100755
index 00000000..0d5c5bd4
--- /dev/null
+++ b/tests/fmt.test
@@ -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
index 00000000..618642a2
--- /dev/null
+++ b/toys/pending/fmt.c
@@ -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);
+}