• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* fmt.c - Text formatter
2  *
3  * Copyright 2017 The Android Open Source Project
4  *
5  * No standard.
6  *
7  * Only counts space and tab for indent level (eats other low ascii chars,
8  * treats all UTF8 chars as non-whitespace), preserves indentation but squashes
9  * together runs of whitespace. No header/footer logic, no end-of-sentence
10  * double-space, preserves initial tab/space mix when indenting new lines.
11 
12 USE_FMT(NEWTOY(fmt, "w#<0=75", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE))
13 
14 config FMT
15   bool "fmt"
16   default y
17   help
18     usage: fmt [-w WIDTH] [FILE...]
19 
20     Reformat input to wordwrap at a given line length, preserving existing
21     indentation level, writing to stdout.
22 
23     -w WIDTH	Maximum characters per line (default 75)
24 */
25 
26 #define FOR_fmt
27 #include "toys.h"
28 
GLOBALS(int width;int level,pos;)29 GLOBALS(
30   int width;
31 
32   int level, pos;
33 )
34 
35 static void newline(void)
36 {
37   if (TT.pos) xputc('\n');
38   TT.pos = 0;
39 }
40 
41 // Process lines of input, with (0,0) flush between files
fmt_line(char ** pline,long len)42 static void fmt_line(char **pline, long len)
43 {
44   char *line;
45   int idx, indent, count;
46 
47   // Flush line on EOF
48   if (!pline) return newline();
49 
50   // Measure indentation
51   for (line = *pline, idx = count = 0; isspace(line[idx]); idx++) {
52     if (line[idx]=='\t') count += 8-(count&7);
53     else if (line[idx]==' ') count++;
54   }
55   indent = idx;
56 
57   // Blank lines (even with same indentation) flush line
58   if (idx==len) {
59     xputc('\n');
60     TT.level = 0;
61 
62     return newline();
63   }
64 
65   // Did indentation change?
66   if (count!=TT.level) newline();
67   TT.level = count;
68 
69   // Loop through words
70   while (idx<len) {
71     char *word = line+idx;
72 
73     // Measure this word (unicode width) and end
74     while (idx<len && !isspace(line[idx])) idx++;
75     line[idx++] = 0;
76     count = utf8len(word);
77     if (TT.pos+count+!!TT.pos>=TT.width) newline();
78 
79     // When indenting a new line, preserve tab/space mixture of input
80     if (!TT.pos) {
81       TT.pos = TT.level;
82       if (indent) printf("%.*s", indent, line);
83     } else count++;
84     printf(" %s"+!(TT.pos!=TT.level), word);
85     TT.pos += count;
86     while (isspace(line[idx])) idx++;
87   }
88 }
89 
fmt_main(void)90 void fmt_main(void)
91 {
92   loopfiles_lines(toys.optargs, fmt_line);
93 }
94