Add expand(1)
Signed-off-by: Christoph Lohmann <20h@r-36.net>
This commit is contained in:
parent
12116cccc4
commit
e28c17c7cc
1
Makefile
1
Makefile
|
@ -35,6 +35,7 @@ SRC = \
|
||||||
dirname.c \
|
dirname.c \
|
||||||
echo.c \
|
echo.c \
|
||||||
env.c \
|
env.c \
|
||||||
|
expand.c \
|
||||||
false.c \
|
false.c \
|
||||||
fold.c \
|
fold.c \
|
||||||
grep.c \
|
grep.c \
|
||||||
|
|
21
expand.1
Normal file
21
expand.1
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
.TH EXPAND 1 sbase\-VERSION
|
||||||
|
.SH NAME
|
||||||
|
expand \- expand tabs to spaces
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B expand
|
||||||
|
.RB [ \-t
|
||||||
|
.IR n ]
|
||||||
|
.RI [ file ...]
|
||||||
|
.SH DESCRIPTION
|
||||||
|
expand processes the named files or the standard input, writing the
|
||||||
|
standard output with tabs changed into spaces. Backspace characters
|
||||||
|
are preserved into the output and decrement the column count for tab
|
||||||
|
calculations.
|
||||||
|
.SH OPTIONS
|
||||||
|
.TP
|
||||||
|
.BI \-t " n"
|
||||||
|
Expand tabs to
|
||||||
|
.I n
|
||||||
|
spaces. We currently support only a single numerical argument.
|
||||||
|
.SH SEE ALSO
|
||||||
|
.IR fold (1)
|
108
expand.c
Normal file
108
expand.c
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <wchar.h>
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
FILE *fp;
|
||||||
|
const char *name;
|
||||||
|
} Fdescr;
|
||||||
|
|
||||||
|
static int expand(Fdescr *f, int tabstop);
|
||||||
|
|
||||||
|
static void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
eprintf("usage: %s [-t n] [file...]\n", argv0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
Fdescr dsc;
|
||||||
|
FILE *fp;
|
||||||
|
int tabstop = 8;
|
||||||
|
|
||||||
|
ARGBEGIN {
|
||||||
|
case 't':
|
||||||
|
tabstop = estrtol(EARGF(usage()), 0);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
} ARGEND;
|
||||||
|
|
||||||
|
if (argc == 0) {
|
||||||
|
dsc.name = "<stdin>";
|
||||||
|
dsc.fp = stdin;
|
||||||
|
expand(&dsc, tabstop);
|
||||||
|
} else {
|
||||||
|
for (; argc > 0; argc--) {
|
||||||
|
if (!(fp = fopen(*argv, "r"))) {
|
||||||
|
eprintf("fopen %s:", *argv);
|
||||||
|
}
|
||||||
|
dsc.name = *argv;
|
||||||
|
dsc.fp = fp;
|
||||||
|
expand(&dsc, tabstop);
|
||||||
|
fclose(fp);
|
||||||
|
argv++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static wint_t
|
||||||
|
in(Fdescr *f)
|
||||||
|
{
|
||||||
|
wint_t c = fgetwc(f->fp);
|
||||||
|
|
||||||
|
if (c == WEOF && ferror(f->fp))
|
||||||
|
eprintf("'%s' read error:", f->name);
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
out(wint_t c)
|
||||||
|
{
|
||||||
|
putwchar(c);
|
||||||
|
if (ferror(stdout))
|
||||||
|
eprintf("write error:");
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
expand(Fdescr *dsc, int tabstop)
|
||||||
|
{
|
||||||
|
int col = 0;
|
||||||
|
wint_t c;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
c = in(dsc);
|
||||||
|
if (c == WEOF)
|
||||||
|
break;
|
||||||
|
|
||||||
|
switch (c) {
|
||||||
|
case '\t':
|
||||||
|
do {
|
||||||
|
col++;
|
||||||
|
out(' ');
|
||||||
|
} while (col & (tabstop - 1));
|
||||||
|
break;
|
||||||
|
case '\b':
|
||||||
|
if (col)
|
||||||
|
col--;
|
||||||
|
out(c);
|
||||||
|
break;
|
||||||
|
case '\n':
|
||||||
|
col = 0;
|
||||||
|
out(c);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
col++;
|
||||||
|
out(c);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user