sbase

suckless unix tools
git clone git://git.2f30.org/sbase
Log | Files | Refs | README | LICENSE

commit e28c17c7cc4955dd0a4b1b2d9f17faa05f9b238e
parent 12116cccc40df6b04edb57bb3e74ef12204aad80
Author: stateless <stateless@archlinux.us>
Date:   Mon, 17 Jun 2013 12:00:36 +0100

Add expand(1)

Signed-off-by: Christoph Lohmann <20h@r-36.net>

Diffstat:
MMakefile | 1+
Aexpand.1 | 21+++++++++++++++++++++
Aexpand.c | 108+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 130 insertions(+), 0 deletions(-)

diff --git a/Makefile b/Makefile @@ -35,6 +35,7 @@ SRC = \ dirname.c \ echo.c \ env.c \ + expand.c \ false.c \ fold.c \ grep.c \ diff --git a/expand.1 b/expand.1 @@ -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) diff --git a/expand.c b/expand.c @@ -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; +}