aboutsummaryrefslogtreecommitdiff
path: root/toys/other/fmt.c
diff options
context:
space:
mode:
Diffstat (limited to 'toys/other/fmt.c')
-rw-r--r--toys/other/fmt.c93
1 files changed, 93 insertions, 0 deletions
diff --git a/toys/other/fmt.c b/toys/other/fmt.c
new file mode 100644
index 00000000..764fe2b7
--- /dev/null
+++ b/toys/other/fmt.c
@@ -0,0 +1,93 @@
+/* fmt.c - Text formatter
+ *
+ * Copyright 2017 The Android Open Source Project
+ *
+ * No standard.
+ *
+ * Only counts space and tab for indent level (eats other low ascii chars,
+ * treats all UTF8 chars as non-whitespace), preserves indentation but squashes
+ * together runs of whitespace. No header/footer logic, no end-of-sentence
+ * double-space, preserves initial tab/space mix when indenting new lines.
+
+USE_FMT(NEWTOY(fmt, "w#<0=75", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE))
+
+config FMT
+ bool "fmt"
+ default y
+ help
+ usage: fmt [-w WIDTH] [FILE...]
+
+ Reformat input to wordwrap at a given line length, preserving existing
+ indentation level, writing to stdout.
+
+ -w WIDTH maximum characters per line (default 75)
+*/
+
+#define FOR_fmt
+#include "toys.h"
+
+GLOBALS(
+ int width;
+
+ int level, pos;
+)
+
+static void newline(void)
+{
+ if (TT.pos) xputc('\n');
+ TT.pos = 0;
+}
+
+// Process lines of input, with (0,0) flush between files
+static void fmt_line(char **pline, long len)
+{
+ char *line;
+ int idx, indent, count;
+
+ // Flush line on EOF
+ if (!pline) return newline();
+
+ // Measure indentation
+ for (line = *pline, idx = count = 0; isspace(line[idx]); idx++) {
+ if (line[idx]=='\t') count += 8-(count&7);
+ else if (line[idx]==' ') count++;
+ }
+ indent = idx;
+
+ // Blank lines (even with same indentation) flush line
+ if (idx==len) {
+ xputc('\n');
+ TT.level = 0;
+
+ return newline();
+ }
+
+ // Did indentation change?
+ if (count!=TT.level) newline();
+ TT.level = count;
+
+ // Loop through words
+ while (idx<len) {
+ char *word = line+idx;
+
+ // Measure this word (unicode width) and end
+ while (idx<len && !isspace(line[idx])) idx++;
+ line[idx++] = 0;
+ count = utf8len(word);
+ if (TT.pos+count+!!TT.pos>=TT.width) newline();
+
+ // When indenting a new line, preserve tab/space mixture of input
+ if (!TT.pos) {
+ TT.pos = TT.level;
+ if (indent) printf("%.*s", indent, line);
+ } else count++;
+ printf(" %s"+!(TT.pos!=TT.level), word);
+ TT.pos += count;
+ while (isspace(line[idx])) idx++;
+ }
+}
+
+void fmt_main(void)
+{
+ loopfiles_lines(toys.optargs, fmt_line);
+}