tr.c revision 1590
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
351590Srgrimesstatic 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
411590Srgrimesstatic char sccsid[] = "@(#)tr.c	8.1 (Berkeley) 6/6/93";
421590Srgrimes#endif /* not lint */
431590Srgrimes
441590Srgrimes#include <sys/types.h>
451590Srgrimes#include <stdio.h>
461590Srgrimes#include <stdlib.h>
471590Srgrimes#include <string.h>
481590Srgrimes#include "extern.h"
491590Srgrimes
501590Srgrimesstatic int string1[NCHARS] = {
511590Srgrimes	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,		/* ASCII */
521590Srgrimes	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
531590Srgrimes	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
541590Srgrimes	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
551590Srgrimes	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
561590Srgrimes	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
571590Srgrimes	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
581590Srgrimes	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
591590Srgrimes	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
601590Srgrimes	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
611590Srgrimes	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
621590Srgrimes	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
631590Srgrimes	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
641590Srgrimes	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
651590Srgrimes	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
661590Srgrimes	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
671590Srgrimes	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
681590Srgrimes	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
691590Srgrimes	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
701590Srgrimes	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
711590Srgrimes	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
721590Srgrimes	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
731590Srgrimes	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
741590Srgrimes	0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
751590Srgrimes	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
761590Srgrimes	0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
771590Srgrimes	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
781590Srgrimes	0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
791590Srgrimes	0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
801590Srgrimes	0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
811590Srgrimes	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
821590Srgrimes	0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
831590Srgrimes}, string2[NCHARS];
841590Srgrimes
851590SrgrimesSTR s1 = { STRING1, NORMAL, 0, OOBCH, { 0, OOBCH }, NULL, NULL };
861590SrgrimesSTR s2 = { STRING2, NORMAL, 0, OOBCH, { 0, OOBCH }, NULL, NULL };
871590Srgrimes
881590Srgrimesstatic void setup __P((int *, char *, STR *, int));
891590Srgrimesstatic void usage __P((void));
901590Srgrimes
911590Srgrimesint
921590Srgrimesmain(argc, argv)
931590Srgrimes	int argc;
941590Srgrimes	char **argv;
951590Srgrimes{
961590Srgrimes	register int ch, cnt, lastch, *p;
971590Srgrimes	int cflag, dflag, sflag, isstring2;
981590Srgrimes
991590Srgrimes	cflag = dflag = sflag = 0;
1001590Srgrimes	while ((ch = getopt(argc, argv, "cds")) != EOF)
1011590Srgrimes		switch((char)ch) {
1021590Srgrimes		case 'c':
1031590Srgrimes			cflag = 1;
1041590Srgrimes			break;
1051590Srgrimes		case 'd':
1061590Srgrimes			dflag = 1;
1071590Srgrimes			break;
1081590Srgrimes		case 's':
1091590Srgrimes			sflag = 1;
1101590Srgrimes			break;
1111590Srgrimes		case '?':
1121590Srgrimes		default:
1131590Srgrimes			usage();
1141590Srgrimes		}
1151590Srgrimes	argc -= optind;
1161590Srgrimes	argv += optind;
1171590Srgrimes
1181590Srgrimes	switch(argc) {
1191590Srgrimes	case 0:
1201590Srgrimes	default:
1211590Srgrimes		usage();
1221590Srgrimes		/* NOTREACHED */
1231590Srgrimes	case 1:
1241590Srgrimes		isstring2 = 0;
1251590Srgrimes		break;
1261590Srgrimes	case 2:
1271590Srgrimes		isstring2 = 1;
1281590Srgrimes		break;
1291590Srgrimes	}
1301590Srgrimes
1311590Srgrimes	/*
1321590Srgrimes	 * tr -ds [-c] string1 string2
1331590Srgrimes	 * Delete all characters (or complemented characters) in string1.
1341590Srgrimes	 * Squeeze all characters in string2.
1351590Srgrimes	 */
1361590Srgrimes	if (dflag && sflag) {
1371590Srgrimes		if (!isstring2)
1381590Srgrimes			usage();
1391590Srgrimes
1401590Srgrimes		setup(string1, argv[0], &s1, cflag);
1411590Srgrimes		setup(string2, argv[1], &s2, 0);
1421590Srgrimes
1431590Srgrimes		for (lastch = OOBCH; (ch = getchar()) != EOF;)
1441590Srgrimes			if (!string1[ch] && (!string2[ch] || lastch != ch)) {
1451590Srgrimes				lastch = ch;
1461590Srgrimes				(void)putchar(ch);
1471590Srgrimes			}
1481590Srgrimes		exit(0);
1491590Srgrimes	}
1501590Srgrimes
1511590Srgrimes	/*
1521590Srgrimes	 * tr -d [-c] string1
1531590Srgrimes	 * Delete all characters (or complemented characters) in string1.
1541590Srgrimes	 */
1551590Srgrimes	if (dflag) {
1561590Srgrimes		if (isstring2)
1571590Srgrimes			usage();
1581590Srgrimes
1591590Srgrimes		setup(string1, argv[0], &s1, cflag);
1601590Srgrimes
1611590Srgrimes		while ((ch = getchar()) != EOF)
1621590Srgrimes			if (!string1[ch])
1631590Srgrimes				(void)putchar(ch);
1641590Srgrimes		exit(0);
1651590Srgrimes	}
1661590Srgrimes
1671590Srgrimes	/*
1681590Srgrimes	 * tr -s [-c] string1
1691590Srgrimes	 * Squeeze all characters (or complemented characters) in string1.
1701590Srgrimes	 */
1711590Srgrimes	if (sflag && !isstring2) {
1721590Srgrimes		setup(string1, argv[0], &s1, cflag);
1731590Srgrimes
1741590Srgrimes		for (lastch = OOBCH; (ch = getchar()) != EOF;)
1751590Srgrimes			if (!string1[ch] || lastch != ch) {
1761590Srgrimes				lastch = ch;
1771590Srgrimes				(void)putchar(ch);
1781590Srgrimes			}
1791590Srgrimes		exit(0);
1801590Srgrimes	}
1811590Srgrimes
1821590Srgrimes	/*
1831590Srgrimes	 * tr [-cs] string1 string2
1841590Srgrimes	 * Replace all characters (or complemented characters) in string1 with
1851590Srgrimes	 * the character in the same position in string2.  If the -s option is
1861590Srgrimes	 * specified, squeeze all the characters in string2.
1871590Srgrimes	 */
1881590Srgrimes	if (!isstring2)
1891590Srgrimes		usage();
1901590Srgrimes
1911590Srgrimes	s1.str = argv[0];
1921590Srgrimes	s2.str = argv[1];
1931590Srgrimes
1941590Srgrimes	if (cflag)
1951590Srgrimes		for (cnt = NCHARS, p = string1; cnt--;)
1961590Srgrimes			*p++ = OOBCH;
1971590Srgrimes
1981590Srgrimes	if (!next(&s2))
1991590Srgrimes		err("empty string2");
2001590Srgrimes
2011590Srgrimes	/* If string2 runs out of characters, use the last one specified. */
2021590Srgrimes	if (sflag)
2031590Srgrimes		while (next(&s1)) {
2041590Srgrimes			string1[s1.lastch] = ch = s2.lastch;
2051590Srgrimes			string2[ch] = 1;
2061590Srgrimes			(void)next(&s2);
2071590Srgrimes		}
2081590Srgrimes	else
2091590Srgrimes		while (next(&s1)) {
2101590Srgrimes			string1[s1.lastch] = ch = s2.lastch;
2111590Srgrimes			(void)next(&s2);
2121590Srgrimes		}
2131590Srgrimes
2141590Srgrimes	if (cflag)
2151590Srgrimes		for (cnt = 0, p = string1; cnt < NCHARS; ++p, ++cnt)
2161590Srgrimes			*p = *p == OOBCH ? ch : cnt;
2171590Srgrimes
2181590Srgrimes	if (sflag)
2191590Srgrimes		for (lastch = OOBCH; (ch = getchar()) != EOF;) {
2201590Srgrimes			ch = string1[ch];
2211590Srgrimes			if (!string2[ch] || lastch != ch) {
2221590Srgrimes				lastch = ch;
2231590Srgrimes				(void)putchar(ch);
2241590Srgrimes			}
2251590Srgrimes		}
2261590Srgrimes	else
2271590Srgrimes		while ((ch = getchar()) != EOF)
2281590Srgrimes			(void)putchar(string1[ch]);
2291590Srgrimes	exit (0);
2301590Srgrimes}
2311590Srgrimes
2321590Srgrimesstatic void
2331590Srgrimessetup(string, arg, str, cflag)
2341590Srgrimes	int *string;
2351590Srgrimes	char *arg;
2361590Srgrimes	STR *str;
2371590Srgrimes	int cflag;
2381590Srgrimes{
2391590Srgrimes	register int cnt, *p;
2401590Srgrimes
2411590Srgrimes	str->str = arg;
2421590Srgrimes	bzero(string, NCHARS * sizeof(int));
2431590Srgrimes	while (next(str))
2441590Srgrimes		string[str->lastch] = 1;
2451590Srgrimes	if (cflag)
2461590Srgrimes		for (p = string, cnt = NCHARS; cnt--; ++p)
2471590Srgrimes			*p = !*p;
2481590Srgrimes}
2491590Srgrimes
2501590Srgrimesstatic void
2511590Srgrimesusage()
2521590Srgrimes{
2531590Srgrimes	(void)fprintf(stderr, "usage: tr [-cs] string1 string2\n");
2541590Srgrimes	(void)fprintf(stderr, "       tr [-c] -d string1\n");
2551590Srgrimes	(void)fprintf(stderr, "       tr [-c] -s string1\n");
2561590Srgrimes	(void)fprintf(stderr, "       tr [-c] -ds string1 string2\n");
2571590Srgrimes	exit(1);
2581590Srgrimes}
2591590Srgrimes
2601590Srgrimes#if __STDC__
2611590Srgrimes#include <stdarg.h>
2621590Srgrimes#else
2631590Srgrimes#include <varargs.h>
2641590Srgrimes#endif
2651590Srgrimes
2661590Srgrimesvoid
2671590Srgrimes#if __STDC__
2681590Srgrimeserr(const char *fmt, ...)
2691590Srgrimes#else
2701590Srgrimeserr(fmt, va_alist)
2711590Srgrimes	char *fmt;
2721590Srgrimes        va_dcl
2731590Srgrimes#endif
2741590Srgrimes{
2751590Srgrimes	va_list ap;
2761590Srgrimes#if __STDC__
2771590Srgrimes	va_start(ap, fmt);
2781590Srgrimes#else
2791590Srgrimes	va_start(ap);
2801590Srgrimes#endif
2811590Srgrimes	(void)fprintf(stderr, "tr: ");
2821590Srgrimes	(void)vfprintf(stderr, fmt, ap);
2831590Srgrimes	va_end(ap);
2841590Srgrimes	(void)fprintf(stderr, "\n");
2851590Srgrimes	exit(1);
2861590Srgrimes	/* NOTREACHED */
2871590Srgrimes}
288