10f66f451Sopenharmony_ci/* fmt.c - Text formatter 20f66f451Sopenharmony_ci * 30f66f451Sopenharmony_ci * Copyright 2017 The Android Open Source Project 40f66f451Sopenharmony_ci * 50f66f451Sopenharmony_ci * No standard. 60f66f451Sopenharmony_ci * 70f66f451Sopenharmony_ci * Only counts space and tab for indent level (eats other low ascii chars, 80f66f451Sopenharmony_ci * treats all UTF8 chars as non-whitespace), preserves indentation but squashes 90f66f451Sopenharmony_ci * together runs of whitespace. No header/footer logic, no end-of-sentence 100f66f451Sopenharmony_ci * double-space, preserves initial tab/space mix when indenting new lines. 110f66f451Sopenharmony_ci 120f66f451Sopenharmony_ciUSE_FMT(NEWTOY(fmt, "w#<0=75", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE)) 130f66f451Sopenharmony_ci 140f66f451Sopenharmony_ciconfig FMT 150f66f451Sopenharmony_ci bool "fmt" 160f66f451Sopenharmony_ci default y 170f66f451Sopenharmony_ci help 180f66f451Sopenharmony_ci usage: fmt [-w WIDTH] [FILE...] 190f66f451Sopenharmony_ci 200f66f451Sopenharmony_ci Reformat input to wordwrap at a given line length, preserving existing 210f66f451Sopenharmony_ci indentation level, writing to stdout. 220f66f451Sopenharmony_ci 230f66f451Sopenharmony_ci -w WIDTH Maximum characters per line (default 75) 240f66f451Sopenharmony_ci*/ 250f66f451Sopenharmony_ci 260f66f451Sopenharmony_ci#define FOR_fmt 270f66f451Sopenharmony_ci#include "toys.h" 280f66f451Sopenharmony_ci 290f66f451Sopenharmony_ciGLOBALS( 300f66f451Sopenharmony_ci int width; 310f66f451Sopenharmony_ci 320f66f451Sopenharmony_ci int level, pos; 330f66f451Sopenharmony_ci) 340f66f451Sopenharmony_ci 350f66f451Sopenharmony_cistatic void newline(void) 360f66f451Sopenharmony_ci{ 370f66f451Sopenharmony_ci if (TT.pos) xputc('\n'); 380f66f451Sopenharmony_ci TT.pos = 0; 390f66f451Sopenharmony_ci} 400f66f451Sopenharmony_ci 410f66f451Sopenharmony_ci// Process lines of input, with (0,0) flush between files 420f66f451Sopenharmony_cistatic void fmt_line(char **pline, long len) 430f66f451Sopenharmony_ci{ 440f66f451Sopenharmony_ci char *line; 450f66f451Sopenharmony_ci int idx, indent, count; 460f66f451Sopenharmony_ci 470f66f451Sopenharmony_ci // Flush line on EOF 480f66f451Sopenharmony_ci if (!pline) return newline(); 490f66f451Sopenharmony_ci 500f66f451Sopenharmony_ci // Measure indentation 510f66f451Sopenharmony_ci for (line = *pline, idx = count = 0; isspace(line[idx]); idx++) { 520f66f451Sopenharmony_ci if (line[idx]=='\t') count += 8-(count&7); 530f66f451Sopenharmony_ci else if (line[idx]==' ') count++; 540f66f451Sopenharmony_ci } 550f66f451Sopenharmony_ci indent = idx; 560f66f451Sopenharmony_ci 570f66f451Sopenharmony_ci // Blank lines (even with same indentation) flush line 580f66f451Sopenharmony_ci if (idx==len) { 590f66f451Sopenharmony_ci xputc('\n'); 600f66f451Sopenharmony_ci TT.level = 0; 610f66f451Sopenharmony_ci 620f66f451Sopenharmony_ci return newline(); 630f66f451Sopenharmony_ci } 640f66f451Sopenharmony_ci 650f66f451Sopenharmony_ci // Did indentation change? 660f66f451Sopenharmony_ci if (count!=TT.level) newline(); 670f66f451Sopenharmony_ci TT.level = count; 680f66f451Sopenharmony_ci 690f66f451Sopenharmony_ci // Loop through words 700f66f451Sopenharmony_ci while (idx<len) { 710f66f451Sopenharmony_ci char *word = line+idx; 720f66f451Sopenharmony_ci 730f66f451Sopenharmony_ci // Measure this word (unicode width) and end 740f66f451Sopenharmony_ci while (idx<len && !isspace(line[idx])) idx++; 750f66f451Sopenharmony_ci line[idx++] = 0; 760f66f451Sopenharmony_ci count = utf8len(word); 770f66f451Sopenharmony_ci if (TT.pos+count+!!TT.pos>=TT.width) newline(); 780f66f451Sopenharmony_ci 790f66f451Sopenharmony_ci // When indenting a new line, preserve tab/space mixture of input 800f66f451Sopenharmony_ci if (!TT.pos) { 810f66f451Sopenharmony_ci TT.pos = TT.level; 820f66f451Sopenharmony_ci if (indent) printf("%.*s", indent, line); 830f66f451Sopenharmony_ci } else count++; 840f66f451Sopenharmony_ci printf(" %s"+!(TT.pos!=TT.level), word); 850f66f451Sopenharmony_ci TT.pos += count; 860f66f451Sopenharmony_ci while (isspace(line[idx])) idx++; 870f66f451Sopenharmony_ci } 880f66f451Sopenharmony_ci} 890f66f451Sopenharmony_ci 900f66f451Sopenharmony_civoid fmt_main(void) 910f66f451Sopenharmony_ci{ 920f66f451Sopenharmony_ci loopfiles_lines(toys.optargs, fmt_line); 930f66f451Sopenharmony_ci} 94