Importing usr.bin/unexpand
Change-Id: I2bab349ebccc28b14db446689171bce7dede8a9d
This commit is contained in:
parent
563dd2c8f4
commit
3dab66925c
8 changed files with 231 additions and 160 deletions
|
@ -27,7 +27,7 @@ SUBDIR= add_route arp ash at backup btrace \
|
|||
stty svclog svrctl swifi synctree sysenv \
|
||||
syslogd tail tcpd tcpdp tcpstat tee telnet \
|
||||
telnetd term termcap tget time touch tr \
|
||||
truncate tty udpstat umount uname unexpand \
|
||||
truncate tty udpstat umount uname \
|
||||
unstack update uud uue version vol \
|
||||
whereis which write writeisofs fetch \
|
||||
xargs zdump zmodem pkgin_cd pkgin_all \
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
PROG= unexpand
|
||||
MAN=
|
||||
|
||||
.include <bsd.prog.mk>
|
|
@ -1,121 +0,0 @@
|
|||
/* unexpand - convert spaces to tabs Author: Terrence W. Holm */
|
||||
|
||||
/* Usage: unexpand [ -a ] [ file ... ] */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define TAB 8
|
||||
|
||||
|
||||
int column = 0; /* Current column, retained between files */
|
||||
int spaces = 0; /* Spaces since last tab stop */
|
||||
int leading_blank = 1; /* Only unexpand leading blanks, */
|
||||
/* Overruled by -a option */
|
||||
|
||||
int main(int argc, char **argv);
|
||||
void Unexpand(FILE *f, int all);
|
||||
|
||||
int main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
|
||||
{
|
||||
int all = 0; /* -a flag means unexpand all spaces */
|
||||
int i;
|
||||
FILE *f;
|
||||
|
||||
if (argc > 1 && argv[1][0] == '-') {
|
||||
if (strcmp(argv[1], "-a") == 0)
|
||||
all = 1;
|
||||
else {
|
||||
fprintf(stderr, "Usage: unexpand [ -a ] [ file ... ]\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
--argc;
|
||||
++argv;
|
||||
}
|
||||
if (argc == 1)
|
||||
Unexpand(stdin, all);
|
||||
else
|
||||
for (i = 1; i < argc; ++i) {
|
||||
if ((f = fopen(argv[i], "r")) == NULL) {
|
||||
perror(argv[i]);
|
||||
exit(1);
|
||||
}
|
||||
Unexpand(f, all);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
|
||||
/* If there are pending spaces print them. */
|
||||
|
||||
while (spaces > 0) {
|
||||
putchar(' ');
|
||||
--spaces;
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
void Unexpand(f, all)
|
||||
FILE *f;
|
||||
int all;
|
||||
|
||||
{
|
||||
int c;
|
||||
|
||||
while ((c = getc(f)) != EOF) {
|
||||
if (c == ' ' && (all || leading_blank)) {
|
||||
++column;
|
||||
++spaces;
|
||||
|
||||
/* If we have white space up to a tab stop, then output */
|
||||
/* A tab. If only one space is required, use a ' '. */
|
||||
|
||||
if (column % TAB == 0) {
|
||||
if (spaces == 1)
|
||||
putchar(' ');
|
||||
else
|
||||
putchar('\t');
|
||||
|
||||
spaces = 0;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If a tab character is encountered in the input then */
|
||||
/* Simply echo it. Any accumulated spaces can only be */
|
||||
/* Since the last tab stop, so ignore them. */
|
||||
if (c == '\t') {
|
||||
column = (column / TAB + 1) * TAB;
|
||||
spaces = 0;
|
||||
putchar('\t');
|
||||
continue;
|
||||
}
|
||||
|
||||
/* A non-space character is to be printed. If there */
|
||||
/* Are pending spaces, then print them. There will be */
|
||||
/* At most TAB-1 spaces to print. */
|
||||
while (spaces > 0) {
|
||||
putchar(' ');
|
||||
--spaces;
|
||||
}
|
||||
|
||||
if (c == '\n' || c == '\r') {
|
||||
column = 0;
|
||||
leading_blank = 1;
|
||||
putchar(c);
|
||||
continue;
|
||||
}
|
||||
if (c == '\b')
|
||||
column = column > 0 ? column - 1 : 0;
|
||||
else
|
||||
++column;
|
||||
|
||||
leading_blank = 0;
|
||||
putchar(c);
|
||||
}
|
||||
}
|
|
@ -19,7 +19,7 @@ MAN= ash.1 at.1 \
|
|||
split.1 stty.1 svc.1 svrctl.1 \
|
||||
synctree.1 sysenv.1 sz.1 tail.1 tee.1 telnet.1 template.1 \
|
||||
term.1 termcap.1 tget.1 time.1 tr.1 true.1 \
|
||||
truncate.1 tty.1 umount.1 uname.1 unexpand.1 \
|
||||
truncate.1 tty.1 umount.1 uname.1 \
|
||||
uud.1 uue.1 vol.1 whereis.1 which.1 \
|
||||
write.1 xargs.1 yap.1 linkfarm.1 pkg_view.1
|
||||
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
.TH UNEXPAND 1
|
||||
.SH NAME
|
||||
unexpand \- convert spaces to tabs
|
||||
.SH SYNOPSIS
|
||||
\fBunexpand\fR [\fB\-a\fR]\fR
|
||||
.br
|
||||
.de FL
|
||||
.TP
|
||||
\\fB\\$1\\fR
|
||||
\\$2
|
||||
..
|
||||
.de EX
|
||||
.TP 20
|
||||
\\fB\\$1\\fR
|
||||
# \\$2
|
||||
..
|
||||
.SH OPTIONS
|
||||
.TP 5
|
||||
.B \-a
|
||||
# All spaces are unexpanded
|
||||
.SH EXAMPLES
|
||||
.TP 20
|
||||
.B unexpand oldfile >newfile
|
||||
# Convert leading spaces to tabs
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
\fIUnexpand\fR replaces spaces in the named files with tabs.
|
||||
If no files are listed, \fIstdin\fR is given.
|
||||
The \fB\-a\fR flag is used to force all sequences of spaces to be
|
||||
expanded, instead of just leading spaces (the default).
|
||||
.SH "SEE ALSO"
|
||||
.BR expand (1).
|
|
@ -26,7 +26,7 @@ SUBDIR= \
|
|||
shuffle sed seq \
|
||||
sort stat su \
|
||||
tic tput \
|
||||
tsort \
|
||||
tsort unexpand \
|
||||
toproto \
|
||||
uniq \
|
||||
\
|
||||
|
|
10
usr.bin/unexpand/Makefile
Normal file
10
usr.bin/unexpand/Makefile
Normal file
|
@ -0,0 +1,10 @@
|
|||
# $NetBSD: Makefile,v 1.8 2009/04/14 22:15:28 lukem Exp $
|
||||
# @(#)Makefile 8.1 (Berkeley) 6/6/93
|
||||
|
||||
NOMAN= # defined
|
||||
|
||||
PROG= unexpand
|
||||
LDADD+=-lutil
|
||||
DPADD+=${LIBUTIL}
|
||||
|
||||
.include <bsd.prog.mk>
|
218
usr.bin/unexpand/unexpand.c
Normal file
218
usr.bin/unexpand/unexpand.c
Normal file
|
@ -0,0 +1,218 @@
|
|||
/* $NetBSD: unexpand.c,v 1.14 2008/12/21 02:33:13 christos Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1980, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__COPYRIGHT("@(#) Copyright (c) 1980, 1993\
|
||||
The Regents of the University of California. All rights reserved.");
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)unexpand.c 8.1 (Berkeley) 6/6/93";
|
||||
#endif
|
||||
__RCSID("$NetBSD: unexpand.c,v 1.14 2008/12/21 02:33:13 christos Exp $");
|
||||
#endif /* not lint */
|
||||
|
||||
/*
|
||||
* unexpand - put tabs into a file replacing blanks
|
||||
*/
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <err.h>
|
||||
#include <util.h>
|
||||
|
||||
|
||||
#define DSTOP 8
|
||||
static int all;
|
||||
static size_t nstops;
|
||||
static size_t maxstops;
|
||||
static size_t *tabstops;
|
||||
|
||||
static void tabify(const char *, size_t);
|
||||
static void usage(void) __attribute__((__noreturn__));
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
(void)fprintf(stderr, "Usage: %s [-a] [-t tabstop] [file ...]\n",
|
||||
getprogname());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int c;
|
||||
char *ep, *tab;
|
||||
char *line;
|
||||
size_t len;
|
||||
unsigned long i;
|
||||
|
||||
setprogname(argv[0]);
|
||||
|
||||
while ((c = getopt(argc, argv, "at:")) != -1) {
|
||||
switch (c) {
|
||||
case 'a':
|
||||
if (nstops)
|
||||
usage();
|
||||
all++;
|
||||
break;
|
||||
case 't':
|
||||
if (all)
|
||||
usage();
|
||||
while ((tab = strsep(&optarg, ", \t")) != NULL) {
|
||||
if (*tab == '\0')
|
||||
continue;
|
||||
errno = 0;
|
||||
i = strtoul(tab, &ep, 0);
|
||||
if (*ep || (errno == ERANGE && i == ULONG_MAX))
|
||||
errx(EXIT_FAILURE,
|
||||
"Invalid tabstop `%s'", tab);
|
||||
if (nstops >= maxstops) {
|
||||
maxstops += 20;
|
||||
tabstops = erealloc(tabstops, maxstops);
|
||||
}
|
||||
if (nstops && tabstops[nstops - 1] >= (size_t)i)
|
||||
errx(EXIT_FAILURE,
|
||||
"Bad tabstop spec `%s', must be "
|
||||
"greater than the previous `%zu'",
|
||||
tab, tabstops[nstops - 1]);
|
||||
tabstops[nstops++] = i;
|
||||
}
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
for (i = 0; i < nstops; i++)
|
||||
fprintf(stderr, "%lu %zu\n", i, tabstops[i]);
|
||||
|
||||
do {
|
||||
if (argc > 0) {
|
||||
if (freopen(argv[0], "r", stdin) == NULL)
|
||||
err(EXIT_FAILURE, "Cannot open `%s'", argv[0]);
|
||||
argc--, argv++;
|
||||
}
|
||||
while ((line = fgetln(stdin, &len)) != NULL)
|
||||
tabify(line, len);
|
||||
} while (argc > 0);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
static void
|
||||
tabify(const char *line, size_t len)
|
||||
{
|
||||
const char *e, *p;
|
||||
size_t dcol, ocol, limit, n;
|
||||
|
||||
dcol = ocol = 0;
|
||||
limit = nstops == 0 ? UINT_MAX : tabstops[nstops - 1] - 1;
|
||||
e = line + len;
|
||||
for (p = line; p < e; p++) {
|
||||
if (*p == ' ') {
|
||||
dcol++;
|
||||
continue;
|
||||
} else if (*p == '\t') {
|
||||
if (nstops == 0) {
|
||||
dcol = (1 + dcol / DSTOP) * DSTOP;
|
||||
continue;
|
||||
} else {
|
||||
for (n = 0; tabstops[n] - 1 < dcol &&
|
||||
n < nstops; n++)
|
||||
continue;
|
||||
if (n < nstops - 1 && tabstops[n] - 1 < limit) {
|
||||
dcol = tabstops[n];
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Output our tabs */
|
||||
if (nstops == 0) {
|
||||
while (((ocol + DSTOP) / DSTOP) <= (dcol / DSTOP)) {
|
||||
if (dcol - ocol < 2)
|
||||
break;
|
||||
if (putchar('\t') == EOF)
|
||||
goto out;
|
||||
ocol = (1 + ocol / DSTOP) * DSTOP;
|
||||
}
|
||||
} else {
|
||||
for (n = 0; tabstops[n] <= ocol && n < nstops; n++)
|
||||
continue;
|
||||
while (tabstops[n] <= dcol && ocol < dcol &&
|
||||
n < nstops && ocol < limit) {
|
||||
if (putchar('\t') == EOF)
|
||||
goto out;
|
||||
ocol = tabstops[n++];
|
||||
}
|
||||
}
|
||||
|
||||
/* Output remaining spaces */
|
||||
while (ocol < dcol && ocol < limit) {
|
||||
if (putchar(' ') == EOF)
|
||||
goto out;
|
||||
ocol++;
|
||||
}
|
||||
|
||||
/* Output our char */
|
||||
if (putchar(*p) == EOF)
|
||||
goto out;
|
||||
if (*p == '\b') {
|
||||
if (ocol > 0) {
|
||||
ocol--;
|
||||
dcol--;
|
||||
}
|
||||
} else {
|
||||
ocol++;
|
||||
dcol++;
|
||||
}
|
||||
|
||||
/* Output remainder of line */
|
||||
if (!all || dcol >= limit) {
|
||||
for (p++; p < e; p++)
|
||||
if (putchar(*p) == EOF)
|
||||
goto out;
|
||||
return;
|
||||
}
|
||||
}
|
||||
return;
|
||||
out:
|
||||
err(EXIT_FAILURE, "write failed");
|
||||
}
|
Loading…
Reference in a new issue