tr.c revision 28368
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
341590Srgrimes#ifndef lint
3528368Scharnierstatic const char copyright[] =
361590Srgrimes"@(#) Copyright (c) 1988, 1993\n\
371590Srgrimes	The Regents of the University of California.  All rights reserved.\n";
381590Srgrimes#endif /* not lint */
391590Srgrimes
401590Srgrimes#ifndef lint
4128368Scharnier#if 0
4223693Speterstatic char sccsid[] = "@(#)tr.c	8.2 (Berkeley) 5/4/95";
4328368Scharnier#endif
4428368Scharnierstatic const char rcsid[] =
4528368Scharnier	"$Id$";
461590Srgrimes#endif /* not lint */
471590Srgrimes
4811895Sache#include <locale.h>
491590Srgrimes#include <sys/types.h>
5023693Speter
5128368Scharnier#include <err.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
971590Srgrimesstatic void setup __P((int *, char *, STR *, int));
981590Srgrimesstatic void usage __P((void));
991590Srgrimes
1001590Srgrimesint
1011590Srgrimesmain(argc, argv)
1021590Srgrimes	int argc;
1031590Srgrimes	char **argv;
1041590Srgrimes{
1051590Srgrimes	register int ch, cnt, lastch, *p;
1061590Srgrimes	int cflag, dflag, sflag, isstring2;
1071590Srgrimes
10811895Sache	(void) setlocale(LC_CTYPE, "");
10911895Sache
1101590Srgrimes	cflag = dflag = sflag = 0;
11124360Simp	while ((ch = getopt(argc, argv, "cds")) != -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;
1221590Srgrimes		case '?':
1231590Srgrimes		default:
1241590Srgrimes			usage();
1251590Srgrimes		}
1261590Srgrimes	argc -= optind;
1271590Srgrimes	argv += optind;
1281590Srgrimes
1291590Srgrimes	switch(argc) {
1301590Srgrimes	case 0:
1311590Srgrimes	default:
1321590Srgrimes		usage();
1331590Srgrimes		/* NOTREACHED */
1341590Srgrimes	case 1:
1351590Srgrimes		isstring2 = 0;
1361590Srgrimes		break;
1371590Srgrimes	case 2:
1381590Srgrimes		isstring2 = 1;
1391590Srgrimes		break;
1401590Srgrimes	}
1411590Srgrimes
1421590Srgrimes	/*
1431590Srgrimes	 * tr -ds [-c] string1 string2
1441590Srgrimes	 * Delete all characters (or complemented characters) in string1.
1451590Srgrimes	 * Squeeze all characters in string2.
1461590Srgrimes	 */
1471590Srgrimes	if (dflag && sflag) {
1481590Srgrimes		if (!isstring2)
1491590Srgrimes			usage();
1501590Srgrimes
1511590Srgrimes		setup(string1, argv[0], &s1, cflag);
1521590Srgrimes		setup(string2, argv[1], &s2, 0);
1538874Srgrimes
1541590Srgrimes		for (lastch = OOBCH; (ch = getchar()) != EOF;)
1551590Srgrimes			if (!string1[ch] && (!string2[ch] || lastch != ch)) {
1561590Srgrimes				lastch = ch;
1571590Srgrimes				(void)putchar(ch);
1581590Srgrimes			}
1591590Srgrimes		exit(0);
1601590Srgrimes	}
1611590Srgrimes
1621590Srgrimes	/*
1631590Srgrimes	 * tr -d [-c] string1
1641590Srgrimes	 * Delete all characters (or complemented characters) in string1.
1651590Srgrimes	 */
1661590Srgrimes	if (dflag) {
1671590Srgrimes		if (isstring2)
1681590Srgrimes			usage();
1691590Srgrimes
1701590Srgrimes		setup(string1, argv[0], &s1, cflag);
1711590Srgrimes
1721590Srgrimes		while ((ch = getchar()) != EOF)
1731590Srgrimes			if (!string1[ch])
1741590Srgrimes				(void)putchar(ch);
1751590Srgrimes		exit(0);
1761590Srgrimes	}
1771590Srgrimes
1781590Srgrimes	/*
1791590Srgrimes	 * tr -s [-c] string1
1801590Srgrimes	 * Squeeze all characters (or complemented characters) in string1.
1811590Srgrimes	 */
1821590Srgrimes	if (sflag && !isstring2) {
1831590Srgrimes		setup(string1, argv[0], &s1, cflag);
1841590Srgrimes
1851590Srgrimes		for (lastch = OOBCH; (ch = getchar()) != EOF;)
1861590Srgrimes			if (!string1[ch] || lastch != ch) {
1871590Srgrimes				lastch = ch;
1881590Srgrimes				(void)putchar(ch);
1891590Srgrimes			}
1901590Srgrimes		exit(0);
1911590Srgrimes	}
1921590Srgrimes
1931590Srgrimes	/*
1941590Srgrimes	 * tr [-cs] string1 string2
1951590Srgrimes	 * Replace all characters (or complemented characters) in string1 with
1961590Srgrimes	 * the character in the same position in string2.  If the -s option is
1971590Srgrimes	 * specified, squeeze all the characters in string2.
1981590Srgrimes	 */
1991590Srgrimes	if (!isstring2)
2001590Srgrimes		usage();
2011590Srgrimes
2021590Srgrimes	s1.str = argv[0];
2031590Srgrimes	s2.str = argv[1];
2041590Srgrimes
2051590Srgrimes	if (cflag)
2061590Srgrimes		for (cnt = NCHARS, p = string1; cnt--;)
2071590Srgrimes			*p++ = OOBCH;
2081590Srgrimes
2091590Srgrimes	if (!next(&s2))
21028368Scharnier		errx(1, "empty string2");
2111590Srgrimes
2121590Srgrimes	/* If string2 runs out of characters, use the last one specified. */
2131590Srgrimes	if (sflag)
2141590Srgrimes		while (next(&s1)) {
2151590Srgrimes			string1[s1.lastch] = ch = s2.lastch;
2161590Srgrimes			string2[ch] = 1;
2171590Srgrimes			(void)next(&s2);
2181590Srgrimes		}
2191590Srgrimes	else
2201590Srgrimes		while (next(&s1)) {
2211590Srgrimes			string1[s1.lastch] = ch = s2.lastch;
2221590Srgrimes			(void)next(&s2);
2231590Srgrimes		}
2241590Srgrimes
2251590Srgrimes	if (cflag)
2261590Srgrimes		for (cnt = 0, p = string1; cnt < NCHARS; ++p, ++cnt)
2271590Srgrimes			*p = *p == OOBCH ? ch : cnt;
2281590Srgrimes
2291590Srgrimes	if (sflag)
2301590Srgrimes		for (lastch = OOBCH; (ch = getchar()) != EOF;) {
2311590Srgrimes			ch = string1[ch];
2321590Srgrimes			if (!string2[ch] || lastch != ch) {
2331590Srgrimes				lastch = ch;
2341590Srgrimes				(void)putchar(ch);
2351590Srgrimes			}
2361590Srgrimes		}
2371590Srgrimes	else
2381590Srgrimes		while ((ch = getchar()) != EOF)
2391590Srgrimes			(void)putchar(string1[ch]);
2401590Srgrimes	exit (0);
2411590Srgrimes}
2421590Srgrimes
2431590Srgrimesstatic void
2441590Srgrimessetup(string, arg, str, cflag)
2451590Srgrimes	int *string;
2461590Srgrimes	char *arg;
2471590Srgrimes	STR *str;
2481590Srgrimes	int cflag;
2491590Srgrimes{
2501590Srgrimes	register int cnt, *p;
2511590Srgrimes
2521590Srgrimes	str->str = arg;
2531590Srgrimes	bzero(string, NCHARS * sizeof(int));
2541590Srgrimes	while (next(str))
2551590Srgrimes		string[str->lastch] = 1;
2561590Srgrimes	if (cflag)
2571590Srgrimes		for (p = string, cnt = NCHARS; cnt--; ++p)
2581590Srgrimes			*p = !*p;
2591590Srgrimes}
2601590Srgrimes
2611590Srgrimesstatic void
2621590Srgrimesusage()
2631590Srgrimes{
26428368Scharnier	(void)fprintf(stderr, "%s\n%s\n%s\n%s\n",
26528368Scharnier		"usage: tr [-cs] string1 string2",
26628368Scharnier		"       tr [-c] -d string1",
26728368Scharnier		"       tr [-c] -s string1",
26828368Scharnier		"       tr [-c] -ds string1 string2");
2691590Srgrimes	exit(1);
2701590Srgrimes}
271