diff options
author | Elliott Hughes <enh@google.com> | 2017-12-23 23:44:04 -0800 |
---|---|---|
committer | Rob Landley <rob@landley.net> | 2017-12-24 11:21:12 -0600 |
commit | 4335501bf3269ac86b7bfdf236aa763d380327e2 (patch) | |
tree | 7dc5a0742fd40bba26efb628e77757434755c986 | |
parent | 17bcad9d44600d3f9f62d88e5a53cd037c8dec13 (diff) | |
download | toybox-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-x | tests/fmt.test | 21 | ||||
-rw-r--r-- | toys/pending/fmt.c | 78 |
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); +} |