fmt.c 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  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. USE_FMT(NEWTOY(fmt, "w#<0=75", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE))
  12. config FMT
  13. bool "fmt"
  14. default y
  15. help
  16. usage: fmt [-w WIDTH] [FILE...]
  17. Reformat input to wordwrap at a given line length, preserving existing
  18. indentation level, writing to stdout.
  19. -w WIDTH Maximum characters per line (default 75)
  20. */
  21. #define FOR_fmt
  22. #include "toys.h"
  23. GLOBALS(
  24. int width;
  25. int level, pos;
  26. )
  27. static void newline(void)
  28. {
  29. if (TT.pos) xputc('\n');
  30. TT.pos = 0;
  31. }
  32. // Process lines of input, with (0,0) flush between files
  33. static void fmt_line(char **pline, long len)
  34. {
  35. char *line;
  36. int idx, indent, count;
  37. // Flush line on EOF
  38. if (!pline) return newline();
  39. // Measure indentation
  40. for (line = *pline, idx = count = 0; isspace(line[idx]); idx++) {
  41. if (line[idx]=='\t') count += 8-(count&7);
  42. else if (line[idx]==' ') count++;
  43. }
  44. indent = idx;
  45. // Blank lines (even with same indentation) flush line
  46. if (idx==len) {
  47. xputc('\n');
  48. TT.level = 0;
  49. return newline();
  50. }
  51. // Did indentation change?
  52. if (count!=TT.level) newline();
  53. TT.level = count;
  54. // Loop through words
  55. while (idx<len) {
  56. char *word = line+idx;
  57. // Measure this word (unicode width) and end
  58. while (idx<len && !isspace(line[idx])) idx++;
  59. line[idx++] = 0;
  60. count = utf8len(word);
  61. if (TT.pos+count+!!TT.pos>=TT.width) newline();
  62. // When indenting a new line, preserve tab/space mixture of input
  63. if (!TT.pos) {
  64. TT.pos = TT.level;
  65. if (indent) printf("%.*s", indent, line);
  66. } else count++;
  67. printf(" %s"+!(TT.pos!=TT.level), word);
  68. TT.pos += count;
  69. while (isspace(line[idx])) idx++;
  70. }
  71. }
  72. void fmt_main(void)
  73. {
  74. loopfiles_lines(toys.optargs, fmt_line);
  75. }