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 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 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 90 void fmt_main(void) 91 { 92 loopfiles_lines(toys.optargs, fmt_line); 93 } 94