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