11590Srgrimes/*
21590Srgrimes * Copyright (c) 1980, 1993
31590Srgrimes *	The Regents of the University of California.  All rights reserved.
41590Srgrimes *
51590Srgrimes * Redistribution and use in source and binary forms, with or without
61590Srgrimes * modification, are permitted provided that the following conditions
71590Srgrimes * are met:
81590Srgrimes * 1. Redistributions of source code must retain the above copyright
91590Srgrimes *    notice, this list of conditions and the following disclaimer.
101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111590Srgrimes *    notice, this list of conditions and the following disclaimer in the
121590Srgrimes *    documentation and/or other materials provided with the distribution.
131590Srgrimes * 4. Neither the name of the University nor the names of its contributors
141590Srgrimes *    may be used to endorse or promote products derived from this software
151590Srgrimes *    without specific prior written permission.
161590Srgrimes *
171590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
181590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
191590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
201590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
211590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
221590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
231590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
241590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
251590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
261590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
271590Srgrimes * SUCH DAMAGE.
281590Srgrimes */
291590Srgrimes
301590Srgrimes#ifndef lint
3141568Sarchiestatic const char copyright[] =
321590Srgrimes"@(#) Copyright (c) 1980, 1993\n\
331590Srgrimes	The Regents of the University of California.  All rights reserved.\n";
341590Srgrimes#endif /* not lint */
351590Srgrimes
361590Srgrimes#ifndef lint
3727147Scharnier#if 0
381590Srgrimesstatic char sccsid[] = "@(#)expand.c	8.1 (Berkeley) 6/9/93";
3958606Scharnier#endif
401590Srgrimes#endif /* not lint */
4199112Sobrien#include <sys/cdefs.h>
4299112Sobrien__FBSDID("$FreeBSD$");
431590Srgrimes
4427147Scharnier#include <ctype.h>
4558606Scharnier#include <err.h>
4698251Stjr#include <locale.h>
471590Srgrimes#include <stdio.h>
4878718Sdd#include <stdlib.h>
4927147Scharnier#include <unistd.h>
50131051Stjr#include <wchar.h>
51200462Sdelphij#include <wctype.h>
5227147Scharnier
531590Srgrimes/*
541590Srgrimes * expand - expand tabs to equivalent spaces
551590Srgrimes */
56227238Sedstatic int	nstops;
57227238Sedstatic int	tabstops[100];
581590Srgrimes
5992920Simpstatic void getstops(char *);
6092920Simpstatic void usage(void);
6127147Scharnier
6227147Scharnierint
63102944Sdwmalonemain(int argc, char *argv[])
641590Srgrimes{
65131051Stjr	const char *curfile;
66131051Stjr	wint_t wc;
67102944Sdwmalone	int c, column;
68102944Sdwmalone	int n;
6997216Stjr	int rval;
70131051Stjr	int width;
711590Srgrimes
7298251Stjr	setlocale(LC_CTYPE, "");
7398251Stjr
7427147Scharnier	/* handle obsolete syntax */
7598251Stjr	while (argc > 1 && argv[1][0] == '-' &&
7698251Stjr	    isdigit((unsigned char)argv[1][1])) {
7727147Scharnier		getstops(&argv[1][1]);
7827147Scharnier		argc--; argv++;
7927147Scharnier	}
8027147Scharnier
8127147Scharnier	while ((c = getopt (argc, argv, "t:")) != -1) {
8227147Scharnier		switch (c) {
8327147Scharnier		case 't':
8427147Scharnier			getstops(optarg);
8527147Scharnier			break;
8627147Scharnier		case '?':
8727147Scharnier		default:
8827147Scharnier			usage();
8927147Scharnier			/* NOTREACHED */
9027147Scharnier		}
9127147Scharnier	}
9227147Scharnier	argc -= optind;
9327147Scharnier	argv += optind;
9427147Scharnier
9597216Stjr	rval = 0;
961590Srgrimes	do {
971590Srgrimes		if (argc > 0) {
9897216Stjr			if (freopen(argv[0], "r", stdin) == NULL) {
9997216Stjr				warn("%s", argv[0]);
10097216Stjr				rval = 1;
10197216Stjr				argc--, argv++;
10297216Stjr				continue;
10397216Stjr			}
104131051Stjr			curfile = argv[0];
1051590Srgrimes			argc--, argv++;
106131051Stjr		} else
107131051Stjr			curfile = "stdin";
1081590Srgrimes		column = 0;
109131051Stjr		while ((wc = getwchar()) != WEOF) {
110131051Stjr			switch (wc) {
1111590Srgrimes			case '\t':
1121590Srgrimes				if (nstops == 0) {
1131590Srgrimes					do {
114131051Stjr						putwchar(' ');
1151590Srgrimes						column++;
1161590Srgrimes					} while (column & 07);
1171590Srgrimes					continue;
1181590Srgrimes				}
1191590Srgrimes				if (nstops == 1) {
1201590Srgrimes					do {
121131051Stjr						putwchar(' ');
1221590Srgrimes						column++;
1231590Srgrimes					} while (((column - 1) % tabstops[0]) != (tabstops[0] - 1));
1241590Srgrimes					continue;
1251590Srgrimes				}
1261590Srgrimes				for (n = 0; n < nstops; n++)
1271590Srgrimes					if (tabstops[n] > column)
1281590Srgrimes						break;
1291590Srgrimes				if (n == nstops) {
130131051Stjr					putwchar(' ');
1311590Srgrimes					column++;
1321590Srgrimes					continue;
1331590Srgrimes				}
1341590Srgrimes				while (column < tabstops[n]) {
135131051Stjr					putwchar(' ');
1361590Srgrimes					column++;
1371590Srgrimes				}
1381590Srgrimes				continue;
1391590Srgrimes
1401590Srgrimes			case '\b':
1411590Srgrimes				if (column)
1421590Srgrimes					column--;
143131051Stjr				putwchar('\b');
1441590Srgrimes				continue;
1451590Srgrimes
1461590Srgrimes			default:
147131051Stjr				putwchar(wc);
148131051Stjr				if ((width = wcwidth(wc)) > 0)
149131051Stjr					column += width;
1501590Srgrimes				continue;
1511590Srgrimes
1521590Srgrimes			case '\n':
153131051Stjr				putwchar(wc);
1541590Srgrimes				column = 0;
1551590Srgrimes				continue;
1561590Srgrimes			}
1571590Srgrimes		}
158131051Stjr		if (ferror(stdin)) {
159131051Stjr			warn("%s", curfile);
160131051Stjr			rval = 1;
161131051Stjr		}
1621590Srgrimes	} while (argc > 0);
16397216Stjr	exit(rval);
1641590Srgrimes}
1651590Srgrimes
16627147Scharnierstatic void
167102944Sdwmalonegetstops(char *cp)
1681590Srgrimes{
169102944Sdwmalone	int i;
1701590Srgrimes
1711590Srgrimes	nstops = 0;
1721590Srgrimes	for (;;) {
1731590Srgrimes		i = 0;
1741590Srgrimes		while (*cp >= '0' && *cp <= '9')
1751590Srgrimes			i = i * 10 + *cp++ - '0';
17678482Sdd		if (i <= 0)
17758606Scharnier			errx(1, "bad tab stop spec");
1781590Srgrimes		if (nstops > 0 && i <= tabstops[nstops-1])
17958606Scharnier			errx(1, "bad tab stop spec");
18091740Sru		if (nstops == sizeof(tabstops) / sizeof(*tabstops))
18191740Sru			errx(1, "too many tab stops");
1821590Srgrimes		tabstops[nstops++] = i;
1831590Srgrimes		if (*cp == 0)
1841590Srgrimes			break;
18598251Stjr		if (*cp != ',' && !isblank((unsigned char)*cp))
18658606Scharnier			errx(1, "bad tab stop spec");
18727147Scharnier		cp++;
1881590Srgrimes	}
1891590Srgrimes}
19027147Scharnier
19127147Scharnierstatic void
192102944Sdwmaloneusage(void)
19327147Scharnier{
19427147Scharnier	(void)fprintf (stderr, "usage: expand [-t tablist] [file ...]\n");
19527147Scharnier	exit(1);
19627147Scharnier}
197