Home | History | Annotate | Line # | Download | only in tabs
tabs.c revision 1.4.42.1
      1  1.4.42.1  christos /* $NetBSD: tabs.c,v 1.4.42.1 2019/06/10 22:10:24 christos Exp $ */
      2       1.1       roy 
      3       1.1       roy /*-
      4       1.1       roy  * Copyright (c) 2008 The NetBSD Foundation, Inc.
      5       1.1       roy  * All rights reserved.
      6       1.1       roy  *
      7       1.1       roy  * This code is derived from software contributed to The NetBSD Foundation
      8       1.1       roy  * by Roy Marples.
      9       1.1       roy  *
     10       1.1       roy  * Redistribution and use in source and binary forms, with or without
     11       1.1       roy  * modification, are permitted provided that the following conditions
     12       1.1       roy  * are met:
     13       1.1       roy  * 1. Redistributions of source code must retain the above copyright
     14       1.1       roy  *    notice, this list of conditions and the following disclaimer.
     15       1.1       roy  * 2. Redistributions in binary form must reproduce the above copyright
     16       1.1       roy  *    notice, this list of conditions and the following disclaimer in the
     17       1.1       roy  *    documentation and/or other materials provided with the distribution.
     18       1.1       roy  *
     19       1.1       roy  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20       1.1       roy  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21       1.1       roy  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22       1.1       roy  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23       1.1       roy  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24       1.1       roy  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25       1.1       roy  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26       1.1       roy  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27       1.1       roy  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28       1.1       roy  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29       1.1       roy  * POSSIBILITY OF SUCH DAMAGE.
     30       1.1       roy  */
     31       1.1       roy 
     32       1.1       roy #include <sys/cdefs.h>
     33       1.1       roy #ifndef lint
     34       1.1       roy __COPYRIGHT("@(#) Copyright (c) 2008 \
     35       1.1       roy The NetBSD Foundation, inc. All rights reserved.");
     36  1.4.42.1  christos __RCSID("$NetBSD: tabs.c,v 1.4.42.1 2019/06/10 22:10:24 christos Exp $");
     37       1.1       roy #endif /* not lint */
     38       1.1       roy 
     39       1.1       roy #include <sys/ioctl.h>
     40       1.1       roy #include <sys/types.h>
     41       1.1       roy 
     42       1.1       roy #include <ctype.h>
     43       1.1       roy #include <err.h>
     44       1.1       roy #include <errno.h>
     45       1.1       roy #include <stdio.h>
     46       1.1       roy #include <stdlib.h>
     47       1.1       roy #include <string.h>
     48       1.3       roy #include <term.h>
     49       1.1       roy #include <unistd.h>
     50       1.1       roy 
     51       1.1       roy #define NSTOPS 20
     52       1.1       roy 
     53       1.1       roy struct tabspec {
     54       1.1       roy 	const char *opt;
     55       1.1       roy 	const char *spec;
     56       1.1       roy };
     57       1.1       roy static const struct tabspec tabspecs[] = {
     58       1.1       roy 	{"a",	"1,10,16,36,72"},
     59       1.1       roy 	{"a2",	"1,10,16,40,72"},
     60       1.1       roy 	{"c",	"1,8,12,16,20,55"},
     61       1.1       roy 	{"c2",	"1,6,10,14,49"},
     62       1.1       roy 	{"c3",	"1,6,10,14,18,22,26,30,34,38,42,46,50,54,58,62,67"},
     63       1.1       roy 	{"f",	"1,7,11,15,19,23"},
     64       1.1       roy 	{"p",	"1,5,9,13,17,21,25,29,33,37,41,45,49,53,57,61"},
     65       1.1       roy 	{"s",	"1,10,55"},
     66       1.1       roy 	{"u",	"1,12,20,44"}
     67       1.1       roy };
     68       1.1       roy static const size_t ntabspecs = sizeof(tabspecs) / sizeof(tabspecs[0]);
     69       1.1       roy 
     70       1.4     joerg __dead static void
     71       1.1       roy usage(void)
     72       1.1       roy {
     73       1.1       roy 	fprintf(stderr,
     74       1.1       roy 		"usage: tabs [-n|-a|-a2|-c|-c2|-c3|-f|-p|-s|-u] [+m[n]]"
     75       1.1       roy 		" [-T type]\n"
     76       1.1       roy 		"       tabs [-T type] [+[n]] n1[,n2,...]\n");
     77       1.1       roy 	exit(EXIT_FAILURE);
     78       1.1       roy 	/* NOTREACHED */
     79       1.1       roy }
     80       1.1       roy 
     81       1.1       roy int
     82       1.1       roy main(int argc, char **argv)
     83       1.1       roy {
     84       1.3       roy 	char *term, *arg, *token, *end, *tabs = NULL, *p;
     85       1.3       roy 	const char *cr, *spec = NULL;
     86       1.2     lukem 	int i, n, inc = 8, stops[NSTOPS], nstops, last, cols, margin = 0;
     87       1.2     lukem 	size_t j;
     88       1.1       roy 	struct winsize ws;
     89       1.1       roy 
     90       1.2     lukem 	term = getenv("TERM");
     91       1.2     lukem 	for (i = 1; i < argc; i++) {
     92       1.1       roy 		if (argv[i][0] == '+') {
     93       1.1       roy 			arg = argv[i] + 1;
     94       1.1       roy 			if (arg[0] == 'm')
     95       1.1       roy 				arg++;
     96       1.1       roy 			if (arg[0] == '\0')
     97       1.1       roy 				margin = 10;
     98       1.1       roy 			else {
     99       1.1       roy 				errno = 0;
    100       1.1       roy 				margin = strtol(arg, &end, 10);
    101       1.1       roy 				if (errno != 0 || *end != '\0' || margin < 0)
    102       1.1       roy 					errx(EXIT_FAILURE,
    103       1.1       roy 					     "%s: invalid margin", arg);
    104       1.1       roy 			}
    105       1.1       roy 			continue;
    106       1.1       roy 		}
    107       1.1       roy 		if (argv[i][0] != '-') {
    108       1.1       roy 			tabs = argv[i];
    109       1.1       roy 			break;
    110       1.1       roy 		}
    111       1.1       roy 		arg = argv[i] + 1;
    112       1.1       roy 		if (arg[0] == '\0')
    113       1.1       roy 			usage();
    114       1.1       roy 		if (arg[0] == '-' && arg[1] == '\0') {
    115  1.4.42.1  christos 			if (argv[i + 1] != NULL)
    116       1.1       roy 				tabs = argv[i + 1];
    117       1.1       roy 			break;
    118       1.1       roy 		}
    119       1.1       roy 		if (arg[0] == 'T' && arg[1] == '\0') {
    120       1.1       roy 			term = argv[++i];
    121       1.1       roy 			if (term == NULL)
    122       1.1       roy 				usage();
    123       1.1       roy 			continue;
    124       1.1       roy 		}
    125       1.1       roy 		if (isdigit((int)arg[0])) {
    126       1.1       roy 			if (arg[1] != '\0')
    127       1.1       roy 				errx(EXIT_FAILURE,
    128       1.1       roy 				     "%s: invalid increament", arg);
    129       1.1       roy 			inc = arg[0] - '0';
    130       1.1       roy 			continue;
    131       1.1       roy 		}
    132       1.1       roy 		for (j = 0; j < ntabspecs; j++) {
    133       1.1       roy 			if (arg[0] == tabspecs[j].opt[0] &&
    134       1.2     lukem 			    arg[1] == tabspecs[j].opt[1]) {
    135       1.1       roy 				spec = tabspecs[j].spec;
    136       1.1       roy 				break;
    137       1.1       roy 			}
    138       1.1       roy 		}
    139       1.1       roy 		if (j == ntabspecs)
    140       1.1       roy 			usage();
    141       1.1       roy 	}
    142       1.1       roy 	if (tabs == NULL && spec != NULL)
    143       1.1       roy 		tabs = strdup(spec);
    144       1.1       roy 
    145       1.1       roy 	if (tabs != NULL)
    146       1.1       roy 		last = nstops = 0;
    147       1.1       roy 	else
    148       1.1       roy 		nstops = -1;
    149       1.1       roy 	p = tabs;
    150       1.1       roy 	while ((token = strsep(&p, ", ")) != NULL) {
    151       1.1       roy 		if (*token == '\0')
    152       1.1       roy 			continue;
    153       1.1       roy 		if (nstops >= NSTOPS)
    154       1.1       roy 			errx(EXIT_FAILURE,
    155       1.1       roy 			     "too many tab stops (max %d)", NSTOPS);
    156       1.1       roy 		errno = 0;
    157       1.1       roy 		n = strtol(token, &end, 10);
    158       1.1       roy 		if (errno != 0 || *end != '\0' || n <= 0)
    159       1.1       roy 			errx(EXIT_FAILURE, "%s: invalid tab stop", token);
    160       1.1       roy 		if (*token == '+') {
    161       1.1       roy 			if (nstops == 0)
    162       1.1       roy 				errx(EXIT_FAILURE,
    163       1.1       roy 				     "first tab stop may not be relative");
    164       1.1       roy 			n += last;
    165       1.1       roy 		}
    166       1.1       roy 		if (last > n)
    167       1.1       roy 			errx(EXIT_FAILURE, "tab stops may not go backwards");
    168       1.1       roy 		last = stops[nstops++] = n;
    169       1.1       roy 	}
    170       1.1       roy 
    171       1.1       roy 	if (term == NULL)
    172       1.1       roy 		errx(EXIT_FAILURE, "no value for $TERM and -T not given");
    173       1.3       roy 	if (setupterm(term, STDOUT_FILENO, NULL) != 0)
    174       1.3       roy 		err(EXIT_FAILURE, "setupterm:");
    175       1.3       roy 	cr = carriage_return;
    176       1.1       roy 	if (cr == NULL)
    177       1.1       roy 		cr = "\r";
    178       1.3       roy 	if (clear_all_tabs == NULL)
    179       1.1       roy 		errx(EXIT_FAILURE, "terminal cannot clear tabs");
    180       1.3       roy 	if (set_tab == NULL)
    181       1.1       roy 		errx(EXIT_FAILURE, "terminal cannot set tabs");
    182       1.1       roy 
    183       1.1       roy 	/* Clear existing tabs */
    184       1.3       roy 	putp(cr);
    185       1.3       roy 	putp(clear_all_tabs);
    186       1.3       roy 	putp(cr);
    187       1.1       roy 
    188       1.3       roy 	if (set_lr_margin != NULL) {
    189       1.1       roy 		printf("%*s", margin, "");
    190       1.3       roy 		putp(set_lr_margin);
    191       1.1       roy 	} else if (margin != 0)
    192       1.1       roy 		warnx("terminal cannot set left margin");
    193       1.1       roy 
    194       1.1       roy 	if (nstops >= 0) {
    195       1.1       roy 		printf("%*s", stops[0] - 1, "");
    196       1.3       roy 		putp(set_tab);
    197       1.1       roy 		for (i = 1; i < nstops; i++) {
    198       1.1       roy 			printf("%*s", stops[i] - stops[i - 1], "");
    199       1.3       roy 			putp(set_tab);
    200       1.1       roy 		}
    201       1.1       roy 	} else if (inc > 0) {
    202       1.1       roy 		cols = 0;
    203       1.1       roy 		term = getenv("COLUMNS");
    204       1.1       roy 		if (term != NULL) {
    205       1.1       roy 			errno = 0;
    206       1.1       roy 			cols = strtol(term, &end, 10);
    207       1.1       roy 			if (errno != 0 || *end != '\0' || cols < 0)
    208       1.1       roy 				cols = 0;
    209       1.1       roy 		}
    210       1.1       roy 		if (cols == 0) {
    211       1.1       roy 			if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == 0)
    212       1.1       roy 				cols = ws.ws_col;
    213       1.1       roy 			else {
    214       1.3       roy 				cols = tigetnum("cols");
    215       1.1       roy 				if (cols == 0) {
    216       1.1       roy 					cols = 80;
    217       1.1       roy 					warnx("terminal does not specify number"
    218       1.1       roy 					      "columns; defaulting to %d",
    219       1.1       roy 					      cols);
    220       1.1       roy 				}
    221       1.1       roy 			}
    222       1.1       roy 		}
    223       1.1       roy 		for (i = 0; i < cols / inc; i++) {
    224       1.1       roy 			printf("%*s", inc, "");
    225       1.3       roy 			putp(set_tab);
    226       1.1       roy 		}
    227       1.1       roy 	}
    228       1.3       roy 	putp(cr);
    229       1.1       roy 
    230       1.1       roy 	exit(EXIT_SUCCESS);
    231       1.1       roy 	/* NOTREACHED */
    232       1.1       roy }
    233