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