Add expand(1)

Signed-off-by: Christoph Lohmann <20h@r-36.net>
This commit is contained in:
stateless 2013-06-17 12:00:36 +01:00 committed by Christoph Lohmann
parent 12116cccc4
commit e28c17c7cc
3 changed files with 130 additions and 0 deletions

View File

@ -35,6 +35,7 @@ SRC = \
dirname.c \
echo.c \
env.c \
expand.c \
false.c \
fold.c \
grep.c \

21
expand.1 Normal file
View 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
View 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;
}