#define F_UNTABIFY 16u
#define F_TABIFY 32u
#define F_VERBOSE 64u
+#define F_TBLANK 128u
static void usage(FILE *fp)
- { fprintf(fp, "Usage: %s [-cmtuv] [-i[BKP]] [FILE...]\n\n", ego); }
+ { fprintf(fp, "Usage: %s [-clmtuv] [-i[BKP]] [FILE...]\n\n", ego); }
static char *augment(const char *name, const char *suffix)
{
return (0);
}
-typedef struct buf {
+struct buf {
char *b;
size_t n;
size_t sz;
-} buf;
+};
#define BUF_INIT { 0, 0, 0 }
-static void reset(buf *b) { b->n = 0; }
+static void reset(struct buf *b) { b->n = 0; }
-static int put(buf *b, int ch)
+static int put(struct buf *b, int ch)
{
size_t w;
static int space(const char *name)
{
- static buf b = BUF_INIT;
+ static struct buf b = BUF_INIT;
FILE *fin, *fout = stdout;
char *newname = 0, *oldname = 0;
int rc = TROUBLE, status = OK;
int last = '\n';
- unsigned nsp = 0, nwsp = 0, hpos = 0, ohpos = 0, nhpos = 0, nl = 1;
+ unsigned nsp = 0, nwsp = 0, nnl = 0;
+ unsigned hpos = 0, ohpos = 0, nhpos = 0, nl = 1;
unsigned i;
#define f_newline 1u
#define f_warnspacetab 2u
#define f_tab 32u
#define f_bad 64u
#define f_forced 128u
- unsigned f = f_newline | (flags & F_TABIFY ? f_tabify : 0);
+#define f_begin 256u
+ unsigned f = f_newline | f_begin | (flags & F_TABIFY ? f_tabify : 0);
int ch;
if (strcmp(name, "-") == 0) {
break;
case '\t':
if (flags & F_UNTABIFY) {
- if ((flags & F_CHECK) && !(f & f_warntabs)) {
+ if ((flags & F_VERBOSE) && !(f & f_warntabs)) {
fprintf(stderr, "%s:%u: found tab\n", name, nl);
f |= f_warntabs;
- status = BADNESS;
}
+ status = BADNESS;
} else if (((flags & F_MIDLINETABS) || (f & f_newline)) && nsp) {
if ((flags & F_VERBOSE) && !(f & f_warnspacetab)) {
fprintf(stderr, "%s:%u: space followed by tab\n", name, nl);
f |= f_warnspacetab;
- status = BADNESS;
}
+ status = BADNESS;
f |= f_tabify | f_forced;
}
f |= f_tab;
if (put(&b, '\t')) goto done_2;
break;
case EOF:
- if (nwsp || !(f & f_newline)) {
- if (flags & F_VERBOSE)
- fprintf(stderr, "%s:%u: file ends in mid-line\n", name, nl);
- status = BADNESS;
- if (fout) putc('\n', fout);
+ if (!(f & f_begin)) {
+ if (!(f & f_newline)) {
+ if (flags & F_VERBOSE)
+ fprintf(stderr, "%s:%u: file ends in mid-line\n", name, nl);
+ status = BADNESS;
+ nnl = 1;
+ } else if (nnl > 1) {
+ if (flags & F_TBLANK) {
+ if (flags & F_VERBOSE) {
+ fprintf(stderr, "%s:%u: file has trailing blank lines\n",
+ name, nl - nnl + 1);
+ }
+ status = BADNESS;
+ nnl = 1;
+ }
+ }
+ if (fout) while (nnl--) putc('\n', fout); else nnl = 0;
}
goto end;
case '\n':
case '\v':
- if (nwsp && (flags & F_VERBOSE)) {
- fprintf(stderr, "%s:%u: trailing whitespace\n", name, nl);
+ if (nwsp) {
+ if (flags & F_VERBOSE)
+ fprintf(stderr, "%s:%u: trailing whitespace\n", name, nl);
status = BADNESS;
}
- if (fout) putc('\n', fout);
reset(&b);
nsp = nwsp = hpos = ohpos = 0; nl++;
+ if (ch == '\n')
+ nnl++;
+ else if (fout) {
+ while (nnl) { putc('\n', fout); nnl--; }
+ putc(ch, fout);
+ } else
+ nnl = 0;
f |= f_newline;
f &= ~(f_tab | f_warnspacetab | f_warntabs | f_warnspaces);
if (flags & F_TABIFY)
last = '\n';
break;
default:
+ if (fout) while (nnl) { putc('\n', fout); nnl--; } else nnl = 0;
if (nwsp) {
if (flags & F_UNTABIFY) {
if (fout) for (; ohpos < hpos; ohpos++) putc(' ', fout);
last = ch;
break;
}
+ f &= ~f_begin;
}
end:;
ego++;
for (;;) {
- if ((i = getopt(argc, argv, "h" "cmtuv" "i::")) < 0)
+ if ((i = getopt(argc, argv, "h" "clmtuv" "i::")) < 0)
break;
switch (i) {
case 'h':
fputs("Options:\n\
-h Print this help text\n\
-c Check files for badness, but don't produce other output\n\
+ -l Check for, and/or remove, trailing blank lines\n\
-m Fix spaces followed by tabs in mid-line\n\
-t Tabify file completely\n\
-u Untabify file completely\n\
+ -v Report verbose messages\n\
-i[BKP] Modify files in place; leave FILEBKP as copy of old FILE\n\
", stdout);
exit(0);
case 'c':
flags |= F_CHECK;
break;
+ case 'l':
+ flags |= F_TBLANK;
+ break;
case 't':
flags |= F_TABIFY;
break;