tr.c revision 98210
11590Srgrimes/*
21590Srgrimes * Copyright (c) 1988, 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 * 3. All advertising materials mentioning features or use of this software
141590Srgrimes *    must display the following acknowledgement:
151590Srgrimes *	This product includes software developed by the University of
161590Srgrimes *	California, Berkeley and its contributors.
171590Srgrimes * 4. Neither the name of the University nor the names of its contributors
181590Srgrimes *    may be used to endorse or promote products derived from this software
191590Srgrimes *    without specific prior written permission.
201590Srgrimes *
211590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311590Srgrimes * SUCH DAMAGE.
321590Srgrimes */
331590Srgrimes
3487705Smarkm#include <sys/cdefs.h>
3587705Smarkm
3687705Smarkm__FBSDID("$FreeBSD: head/usr.bin/tr/tr.c 98210 2002-06-14 07:37:08Z tjr $");
3787705Smarkm
381590Srgrimes#ifndef lint
3928368Scharnierstatic const char copyright[] =
401590Srgrimes"@(#) Copyright (c) 1988, 1993\n\
411590Srgrimes	The Regents of the University of California.  All rights reserved.\n";
4287705Smarkm#endif
431590Srgrimes
441590Srgrimes#ifndef lint
4587705Smarkmstatic const char sccsid[] = "@(#)tr.c	8.2 (Berkeley) 5/4/95";
4628368Scharnier#endif
471590Srgrimes
481590Srgrimes#include <sys/types.h>
4923693Speter
5028368Scharnier#include <err.h>
5187705Smarkm#include <locale.h>
521590Srgrimes#include <stdio.h>
531590Srgrimes#include <stdlib.h>
541590Srgrimes#include <string.h>
5523693Speter#include <unistd.h>
5623693Speter
571590Srgrimes#include "extern.h"
581590Srgrimes
591590Srgrimesstatic int string1[NCHARS] = {
601590Srgrimes	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,		/* ASCII */
611590Srgrimes	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
621590Srgrimes	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
631590Srgrimes	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
641590Srgrimes	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
651590Srgrimes	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
661590Srgrimes	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
671590Srgrimes	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
681590Srgrimes	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
691590Srgrimes	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
701590Srgrimes	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
711590Srgrimes	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
721590Srgrimes	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
731590Srgrimes	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
741590Srgrimes	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
751590Srgrimes	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
761590Srgrimes	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
771590Srgrimes	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
781590Srgrimes	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
791590Srgrimes	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
801590Srgrimes	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
811590Srgrimes	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
821590Srgrimes	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
831590Srgrimes	0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
841590Srgrimes	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
851590Srgrimes	0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
861590Srgrimes	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
871590Srgrimes	0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
881590Srgrimes	0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
891590Srgrimes	0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
901590Srgrimes	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
911590Srgrimes	0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
921590Srgrimes}, string2[NCHARS];
931590Srgrimes
941590SrgrimesSTR s1 = { STRING1, NORMAL, 0, OOBCH, { 0, OOBCH }, NULL, NULL };
951590SrgrimesSTR s2 = { STRING2, NORMAL, 0, OOBCH, { 0, OOBCH }, NULL, NULL };
961590Srgrimes
9792922Simpstatic void setup(int *, char *, STR *, int);
9892922Simpstatic void usage(void);
991590Srgrimes
1001590Srgrimesint
1011590Srgrimesmain(argc, argv)
1021590Srgrimes	int argc;
1031590Srgrimes	char **argv;
1041590Srgrimes{
10587705Smarkm	int ch, cnt, lastch, *p;
1061590Srgrimes	int cflag, dflag, sflag, isstring2;
1071590Srgrimes
10898210Stjr	(void)setlocale(LC_ALL, "");
10911895Sache
1101590Srgrimes	cflag = dflag = sflag = 0;
11130322Shelbig	while ((ch = getopt(argc, argv, "cdsu")) != -1)
1121590Srgrimes		switch((char)ch) {
1131590Srgrimes		case 'c':
1141590Srgrimes			cflag = 1;
1151590Srgrimes			break;
1161590Srgrimes		case 'd':
1171590Srgrimes			dflag = 1;
1181590Srgrimes			break;
1191590Srgrimes		case 's':
1201590Srgrimes			sflag = 1;
1211590Srgrimes			break;
12230322Shelbig		case 'u':
12330322Shelbig			setbuf(stdout, (char *)NULL);
12430322Shelbig			break;
1251590Srgrimes		case '?':
1261590Srgrimes		default:
1271590Srgrimes			usage();
1281590Srgrimes		}
1291590Srgrimes	argc -= optind;
1301590Srgrimes	argv += optind;
1311590Srgrimes
1321590Srgrimes	switch(argc) {
1331590Srgrimes	case 0:
1341590Srgrimes	default:
1351590Srgrimes		usage();
1361590Srgrimes		/* NOTREACHED */
1371590Srgrimes	case 1:
1381590Srgrimes		isstring2 = 0;
1391590Srgrimes		break;
1401590Srgrimes	case 2:
1411590Srgrimes		isstring2 = 1;
1421590Srgrimes		break;
1431590Srgrimes	}
1441590Srgrimes
1451590Srgrimes	/*
1461590Srgrimes	 * tr -ds [-c] string1 string2
1471590Srgrimes	 * Delete all characters (or complemented characters) in string1.
1481590Srgrimes	 * Squeeze all characters in string2.
1491590Srgrimes	 */
1501590Srgrimes	if (dflag && sflag) {
1511590Srgrimes		if (!isstring2)
1521590Srgrimes			usage();
1531590Srgrimes
1541590Srgrimes		setup(string1, argv[0], &s1, cflag);
1551590Srgrimes		setup(string2, argv[1], &s2, 0);
1568874Srgrimes
1571590Srgrimes		for (lastch = OOBCH; (ch = getchar()) != EOF;)
1581590Srgrimes			if (!string1[ch] && (!string2[ch] || lastch != ch)) {
1591590Srgrimes				lastch = ch;
1601590Srgrimes				(void)putchar(ch);
1611590Srgrimes			}
1621590Srgrimes		exit(0);
1631590Srgrimes	}
1641590Srgrimes
1651590Srgrimes	/*
1661590Srgrimes	 * tr -d [-c] string1
1671590Srgrimes	 * Delete all characters (or complemented characters) in string1.
1681590Srgrimes	 */
1691590Srgrimes	if (dflag) {
1701590Srgrimes		if (isstring2)
1711590Srgrimes			usage();
1721590Srgrimes
1731590Srgrimes		setup(string1, argv[0], &s1, cflag);
1741590Srgrimes
1751590Srgrimes		while ((ch = getchar()) != EOF)
1761590Srgrimes			if (!string1[ch])
1771590Srgrimes				(void)putchar(ch);
1781590Srgrimes		exit(0);
1791590Srgrimes	}
1801590Srgrimes
1811590Srgrimes	/*
1821590Srgrimes	 * tr -s [-c] string1
1831590Srgrimes	 * Squeeze all characters (or complemented characters) in string1.
1841590Srgrimes	 */
1851590Srgrimes	if (sflag && !isstring2) {
1861590Srgrimes		setup(string1, argv[0], &s1, cflag);
1871590Srgrimes
1881590Srgrimes		for (lastch = OOBCH; (ch = getchar()) != EOF;)
1891590Srgrimes			if (!string1[ch] || lastch != ch) {
1901590Srgrimes				lastch = ch;
1911590Srgrimes				(void)putchar(ch);
1921590Srgrimes			}
1931590Srgrimes		exit(0);
1941590Srgrimes	}
1951590Srgrimes
1961590Srgrimes	/*
1971590Srgrimes	 * tr [-cs] string1 string2
1981590Srgrimes	 * Replace all characters (or complemented characters) in string1 with
1991590Srgrimes	 * the character in the same position in string2.  If the -s option is
2001590Srgrimes	 * specified, squeeze all the characters in string2.
2011590Srgrimes	 */
2021590Srgrimes	if (!isstring2)
2031590Srgrimes		usage();
2041590Srgrimes
2051590Srgrimes	s1.str = argv[0];
2061590Srgrimes	s2.str = argv[1];
2071590Srgrimes
2081590Srgrimes	if (cflag)
2091590Srgrimes		for (cnt = NCHARS, p = string1; cnt--;)
2101590Srgrimes			*p++ = OOBCH;
2111590Srgrimes
2121590Srgrimes	if (!next(&s2))
21328368Scharnier		errx(1, "empty string2");
2141590Srgrimes
21591562Salfred	ch = s2.lastch;
2161590Srgrimes	/* If string2 runs out of characters, use the last one specified. */
2171590Srgrimes	if (sflag)
2181590Srgrimes		while (next(&s1)) {
2191590Srgrimes			string1[s1.lastch] = ch = s2.lastch;
2201590Srgrimes			string2[ch] = 1;
2211590Srgrimes			(void)next(&s2);
2221590Srgrimes		}
2231590Srgrimes	else
2241590Srgrimes		while (next(&s1)) {
2251590Srgrimes			string1[s1.lastch] = ch = s2.lastch;
2261590Srgrimes			(void)next(&s2);
2271590Srgrimes		}
2281590Srgrimes
2291590Srgrimes	if (cflag)
2301590Srgrimes		for (cnt = 0, p = string1; cnt < NCHARS; ++p, ++cnt)
2311590Srgrimes			*p = *p == OOBCH ? ch : cnt;
2321590Srgrimes
2331590Srgrimes	if (sflag)
2341590Srgrimes		for (lastch = OOBCH; (ch = getchar()) != EOF;) {
2351590Srgrimes			ch = string1[ch];
2361590Srgrimes			if (!string2[ch] || lastch != ch) {
2371590Srgrimes				lastch = ch;
2381590Srgrimes				(void)putchar(ch);
2391590Srgrimes			}
2401590Srgrimes		}
2411590Srgrimes	else
2421590Srgrimes		while ((ch = getchar()) != EOF)
2431590Srgrimes			(void)putchar(string1[ch]);
2441590Srgrimes	exit (0);
2451590Srgrimes}
2461590Srgrimes
2471590Srgrimesstatic void
2481590Srgrimessetup(string, arg, str, cflag)
2491590Srgrimes	int *string;
2501590Srgrimes	char *arg;
2511590Srgrimes	STR *str;
2521590Srgrimes	int cflag;
2531590Srgrimes{
25487705Smarkm	int cnt, *p;
2551590Srgrimes
2561590Srgrimes	str->str = arg;
2571590Srgrimes	bzero(string, NCHARS * sizeof(int));
2581590Srgrimes	while (next(str))
2591590Srgrimes		string[str->lastch] = 1;
2601590Srgrimes	if (cflag)
2611590Srgrimes		for (p = string, cnt = NCHARS; cnt--; ++p)
2621590Srgrimes			*p = !*p;
2631590Srgrimes}
2641590Srgrimes
2651590Srgrimesstatic void
2661590Srgrimesusage()
2671590Srgrimes{
26828368Scharnier	(void)fprintf(stderr, "%s\n%s\n%s\n%s\n",
26930322Shelbig		"usage: tr [-csu] string1 string2",
27030322Shelbig		"       tr [-cu] -d string1",
27130322Shelbig		"       tr [-cu] -s string1",
27230322Shelbig		"       tr [-cu] -ds string1 string2");
2731590Srgrimes	exit(1);
2741590Srgrimes}
275