diff options
| author | roy <roy@NetBSD.org> | 2008-12-11 11:14:36 +0000 |
|---|---|---|
| committer | roy <roy@NetBSD.org> | 2008-12-11 11:14:36 +0000 |
| commit | aa751245215303d91e0b6a5059940d05ee1789ea (patch) | |
| tree | 6db4e4c4ba0d84c200e0b4fd50dc77c1d440c650 /usr.bin/tabs | |
| parent | 5d7029bf64c76edccb8d7edf2279879b41f79e25 (diff) | |
Add the tabs utility, conforming to IEEE Std 1003.1 (``POSIX.1'').
Fixes PR bin/11227
No objection on tech-userland, ok: martin
Diffstat (limited to 'usr.bin/tabs')
| -rw-r--r-- | usr.bin/tabs/Makefile | 9 | ||||
| -rw-r--r-- | usr.bin/tabs/tabs.1 | 170 | ||||
| -rw-r--r-- | usr.bin/tabs/tabs.c | 242 |
3 files changed, 421 insertions, 0 deletions
diff --git a/usr.bin/tabs/Makefile b/usr.bin/tabs/Makefile new file mode 100644 index 00000000000..b0203e872df --- /dev/null +++ b/usr.bin/tabs/Makefile @@ -0,0 +1,9 @@ +# $NetBSD: Makefile,v 1.1 2008/12/11 11:18:35 roy Exp $ + +PROG= tabs +DPADD= ${LIBTERMCAP} +LDADD= -ltermcap + +WARNS?= 4 + +.include <bsd.prog.mk> diff --git a/usr.bin/tabs/tabs.1 b/usr.bin/tabs/tabs.1 new file mode 100644 index 00000000000..ef4697d2a9c --- /dev/null +++ b/usr.bin/tabs/tabs.1 @@ -0,0 +1,170 @@ +.\" Copyright (c) 2008 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to The NetBSD Foundation +.\" by Roy Marples. +.\" +.\" 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. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. +.\" +.Dd December 09, 2008 +.Dt TABS 1 +.Os +.Sh NAME +.Nm tabs +.Nd set terminal tabs +.Sh SYNOPSIS +.Nm +.Op Fl n Ns | Ns Fl a Ns | Ns Fl a2 Ns | Ns Fl c Ns | Ns Fl c2 \ +Ns | Ns Fl c3 Ns | Ns Fl f Ns | Ns Fl p Ns | Ns Fl s Ns | Ns Fl u +.Op +m Ns Op n +.Op Fl T Ar type +.Nm +.Op Fl T Ar type +.Op + Ns Op n +.Ar n1 Ns Op , Ns Ar n2 Ns , Ns Ar ... +.Sh DESCRIPTION +The +.Nm +utility displays a series of characters that first clears the hardware terminal +tab settings and then initializes the tab stops at the specified positions +and optionally adjusts the margin. +.Pp +The phrase "tab-stop position N" means that, from the start of a line of +output, tabbing to position N shall cause the next character output to be in +the (N+1)th column on that line. +.Pp +The following options are supported: +.Bl -tag -width Fl +.It Fl Ar n +Specifies repetitive tab stops separated by a uniform number of columns, +.Ar n , +where +.Ar n +is a single digit decimal number. +The default usage of +.Nm +with no arguments is equivalent to +.Nm +.Fl 8 . +When +.Fl 0 +is used, the tab stops are cleared and no new ones set. +.It Fl a +Assembler, applicable to some mainframes. +Equivalent to +.Nm +1,10,16,36,72 . +.It Fl a2 +Assembler, applicable to some mainframes. +Equivalent to +.Nm +1,10,16,40,72 +.It Fl c +.Tn COBOL , +normal format. +Equivalent to +.Nm +1,8,12,16,20,55 +.It Fl c2 +.Tn COBOL , +compact format (columns 1 to 6 omitted). +Equivalent to +.Nm +1,6,10,14,49 +.It Fl c3 +.Tn COBOL , +compact format (columns 1 to 6 omitted), with more tabs than +.Fl c2 . +Equivalent to +.Nm +1,6,10,14,18,22,26,30,34,38,42,46,50,54,58,62,67 +.It Fl f +.Tn FORTRAN . +Equivalent to +.Nm +1,7,11,15,19,23 +.It Fl p +.Tn PL/1 . +Equivalent to +.Nm +1,5,9,13,17,21,25,29,33,37,41,45,49,53,57,61 +.It Fl s +.Tn SNOBOL . +Equivalent to +.Nm +1,10,55 +.It Fl u +Assembler, applicable to some mainframes. +Equivalent to +.Nm +1,12,20,44 +.It Fl T Ar type +Indicates the type of terminal. +.El +.Sh ENVIRONMENT +The +.Ev COLUMNS +and +.Ev TERM +environment variables affect the execution of +.Nm +as described in +.Xr environ 7 . +.Pp +The +.Fl T +option overrides +.Ev TERM . +If neither +.Ev TERM +nor the +.Fl T +option are present, +.Nm +will fail. +.Sh SEE ALSO +.Xr expand 1 , +.Xr stty 1 , +.Xr tput 1 , +.Xr unexpand 1 , +.Xr termcap 5 +.Sh EXIT STATUS +.Ex -std +.Sh STANDARDS +The +.Nm +utility conforms to +.St -p1003.1 . +.Sh HISTORY +A +.Nm +utility first appeared in PWB UNIX. +This implementation was introduced in +.Nx 6.0 . +.Sh BUGS +The current +.Xr termcap 5 +database does not define the set left soft margin +.Ql ML +capability for any terminals. +.Sh AUTHORS +.An Roy Marples <roy@NetBSD.org> diff --git a/usr.bin/tabs/tabs.c b/usr.bin/tabs/tabs.c new file mode 100644 index 00000000000..e0aab96a403 --- /dev/null +++ b/usr.bin/tabs/tabs.c @@ -0,0 +1,242 @@ +/* $NetBSD: tabs.c,v 1.1 2008/12/11 11:18:35 roy Exp $ */ + +/*- + * Copyright (c) 2008 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Roy Marples. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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) 2008 \ +The NetBSD Foundation, inc. All rights reserved."); +__RCSID("$NetBSD: tabs.c,v 1.1 2008/12/11 11:18:35 roy Exp $"); +#endif /* not lint */ + +#include <sys/ioctl.h> +#include <sys/types.h> + +#include <ctype.h> +#include <err.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termcap.h> +#include <unistd.h> + +#define NSTOPS 20 + +struct tabspec { + const char *opt; + const char *spec; +}; +static const struct tabspec tabspecs[] = { + {"a", "1,10,16,36,72"}, + {"a2", "1,10,16,40,72"}, + {"c", "1,8,12,16,20,55"}, + {"c2", "1,6,10,14,49"}, + {"c3", "1,6,10,14,18,22,26,30,34,38,42,46,50,54,58,62,67"}, + {"f", "1,7,11,15,19,23"}, + {"p", "1,5,9,13,17,21,25,29,33,37,41,45,49,53,57,61"}, + {"s", "1,10,55"}, + {"u", "1,12,20,44"} +}; +static const size_t ntabspecs = sizeof(tabspecs) / sizeof(tabspecs[0]); + +static char tbuf[2048]; + +static void +usage(void) +{ + fprintf(stderr, + "usage: tabs [-n|-a|-a2|-c|-c2|-c3|-f|-p|-s|-u] [+m[n]]" + " [-T type]\n" + " tabs [-T type] [+[n]] n1[,n2,...]\n"); + exit(EXIT_FAILURE); + /* NOTREACHED */ +} + +int +main(int argc, char **argv) +{ + char *term, *arg, *tbp, *token, *end, *tabs = NULL, *p; + const char *cr, *ct, *st, *ML, *spec = NULL; + int i, j, n, inc = 8, stops[NSTOPS], nstops, last, cols, margin = 0; + struct winsize ws; + + term = getenv("TERM"); + for (i = 1; i < argc; i++) { + if (argv[i][0] == '+') { + arg = argv[i] + 1; + if (arg[0] == 'm') + arg++; + if (arg[0] == '\0') + margin = 10; + else { + errno = 0; + margin = strtol(arg, &end, 10); + if (errno != 0 || *end != '\0' || margin < 0) + errx(EXIT_FAILURE, + "%s: invalid margin", arg); + } + continue; + } + if (argv[i][0] != '-') { + tabs = argv[i]; + break; + } + arg = argv[i] + 1; + if (arg[0] == '\0') + usage(); + if (arg[0] == '-' && arg[1] == '\0') { + if (argv[i + 1] != '\0') + tabs = argv[i + 1]; + break; + } + if (arg[0] == 'T' && arg[1] == '\0') { + term = argv[++i]; + if (term == NULL) + usage(); + continue; + } + if (isdigit((int)arg[0])) { + if (arg[1] != '\0') + errx(EXIT_FAILURE, + "%s: invalid increament", arg); + inc = arg[0] - '0'; + continue; + } + for (j = 0; j < ntabspecs; j++) { + if (arg[0] == tabspecs[j].opt[0] && + arg[1] == tabspecs[j].opt[1]) + { + spec = tabspecs[j].spec; + break; + } + } + if (j == ntabspecs) + usage(); + } + if (tabs == NULL && spec != NULL) + tabs = strdup(spec); + + if (tabs != NULL) + last = nstops = 0; + else + nstops = -1; + p = tabs; + while ((token = strsep(&p, ", ")) != NULL) { + if (*token == '\0') + continue; + if (nstops >= NSTOPS) + errx(EXIT_FAILURE, + "too many tab stops (max %d)", NSTOPS); + errno = 0; + n = strtol(token, &end, 10); + if (errno != 0 || *end != '\0' || n <= 0) + errx(EXIT_FAILURE, "%s: invalid tab stop", token); + if (*token == '+') { + if (nstops == 0) + errx(EXIT_FAILURE, + "first tab stop may not be relative"); + n += last; + } + if (last > n) + errx(EXIT_FAILURE, "tab stops may not go backwards"); + last = stops[nstops++] = n; + } + + if (term == NULL) + errx(EXIT_FAILURE, "no value for $TERM and -T not given"); + switch (tgetent(tbuf, term)) { + case -1: + err(EXIT_FAILURE, "termcap database"); + case 0: + errx(EXIT_FAILURE, "%s: no termcap entry", term); + } + tbp = tbuf; + cr = tgetstr("cr", &tbp); + if (cr == NULL) + cr = "\r"; + ct = tgetstr("ct", &tbp); + if (ct == NULL) + errx(EXIT_FAILURE, "terminal cannot clear tabs"); + st = tgetstr("st", &tbp); + if (st == NULL) + errx(EXIT_FAILURE, "terminal cannot set tabs"); + ML = tgetstr("ML", &tbp); + + /* Clear existing tabs */ + tputs(cr, 1, putchar); + tputs(ct, 1, putchar); + tputs(cr, 1, putchar); + + if (ML != NULL) { + printf("%*s", margin, ""); + tputs(ML, 1, putchar); + } else if (margin != 0) + warnx("terminal cannot set left margin"); + + if (nstops >= 0) { + printf("%*s", stops[0] - 1, ""); + tputs(st, 1, putchar); + for (i = 1; i < nstops; i++) { + printf("%*s", stops[i] - stops[i - 1], ""); + tputs(st, 1, putchar); + } + } else if (inc > 0) { + cols = 0; + term = getenv("COLUMNS"); + if (term != NULL) { + errno = 0; + cols = strtol(term, &end, 10); + if (errno != 0 || *end != '\0' || cols < 0) + cols = 0; + } + if (cols == 0) { + if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == 0) + cols = ws.ws_col; + else { + cols = tgetnum("co"); + if (cols == 0) { + cols = 80; + warnx("terminal does not specify number" + "columns; defaulting to %d", + cols); + } + } + } + for (i = 0; i < cols / inc; i++) { + printf("%*s", inc, ""); + tputs(st, 1, putchar); + } + } + tputs(cr, 1, putchar); + + exit(EXIT_SUCCESS); + /* NOTREACHED */ +} |
