1*163bd69bSGarrett D'Amore /* 2*163bd69bSGarrett D'Amore * Copyright (c) 1988, 1993 3*163bd69bSGarrett D'Amore * The Regents of the University of California. All rights reserved. 4*163bd69bSGarrett D'Amore * 5*163bd69bSGarrett D'Amore * Redistribution and use in source and binary forms, with or without 6*163bd69bSGarrett D'Amore * modification, are permitted provided that the following conditions 7*163bd69bSGarrett D'Amore * are met: 8*163bd69bSGarrett D'Amore * 1. Redistributions of source code must retain the above copyright 9*163bd69bSGarrett D'Amore * notice, this list of conditions and the following disclaimer. 10*163bd69bSGarrett D'Amore * 2. Redistributions in binary form must reproduce the above copyright 11*163bd69bSGarrett D'Amore * notice, this list of conditions and the following disclaimer in the 12*163bd69bSGarrett D'Amore * documentation and/or other materials provided with the distribution. 13*163bd69bSGarrett D'Amore * 3. All advertising materials mentioning features or use of this software 14*163bd69bSGarrett D'Amore * must display the following acknowledgement: 15*163bd69bSGarrett D'Amore * This product includes software developed by the University of 16*163bd69bSGarrett D'Amore * California, Berkeley and its contributors. 17*163bd69bSGarrett D'Amore * 4. Neither the name of the University nor the names of its contributors 18*163bd69bSGarrett D'Amore * may be used to endorse or promote products derived from this software 19*163bd69bSGarrett D'Amore * without specific prior written permission. 20*163bd69bSGarrett D'Amore * 21*163bd69bSGarrett D'Amore * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22*163bd69bSGarrett D'Amore * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23*163bd69bSGarrett D'Amore * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24*163bd69bSGarrett D'Amore * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25*163bd69bSGarrett D'Amore * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26*163bd69bSGarrett D'Amore * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27*163bd69bSGarrett D'Amore * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28*163bd69bSGarrett D'Amore * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29*163bd69bSGarrett D'Amore * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30*163bd69bSGarrett D'Amore * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31*163bd69bSGarrett D'Amore * SUCH DAMAGE. 32*163bd69bSGarrett D'Amore */ 33*163bd69bSGarrett D'Amore 34*163bd69bSGarrett D'Amore #include <sys/types.h> 35*163bd69bSGarrett D'Amore 36*163bd69bSGarrett D'Amore #include <ctype.h> 37*163bd69bSGarrett D'Amore #include <err.h> 38*163bd69bSGarrett D'Amore #include <limits.h> 39*163bd69bSGarrett D'Amore #include <locale.h> 40*163bd69bSGarrett D'Amore #include <stdio.h> 41*163bd69bSGarrett D'Amore #include <stdlib.h> 42*163bd69bSGarrett D'Amore #include <string.h> 43*163bd69bSGarrett D'Amore #include <unistd.h> 44*163bd69bSGarrett D'Amore #include <wchar.h> 45*163bd69bSGarrett D'Amore #include <wctype.h> 46*163bd69bSGarrett D'Amore 47*163bd69bSGarrett D'Amore #include "cmap.h" 48*163bd69bSGarrett D'Amore #include "cset.h" 49*163bd69bSGarrett D'Amore #include "extern.h" 50*163bd69bSGarrett D'Amore 51*163bd69bSGarrett D'Amore STR s1 = { STRING1, NORMAL, 0, OOBCH, 0, { 0, OOBCH }, NULL, NULL }; 52*163bd69bSGarrett D'Amore STR s2 = { STRING2, NORMAL, 0, OOBCH, 0, { 0, OOBCH }, NULL, NULL }; 53*163bd69bSGarrett D'Amore 54*163bd69bSGarrett D'Amore static struct cset *setup(char *, STR *, int, int); 55*163bd69bSGarrett D'Amore static void usage(void); 56*163bd69bSGarrett D'Amore 57*163bd69bSGarrett D'Amore static wint_t 58*163bd69bSGarrett D'Amore cmap_lookup(struct cmap *cm, wint_t from) 59*163bd69bSGarrett D'Amore { 60*163bd69bSGarrett D'Amore 61*163bd69bSGarrett D'Amore if (from < CM_CACHE_SIZE && cm->cm_havecache) 62*163bd69bSGarrett D'Amore return (cm->cm_cache[from]); 63*163bd69bSGarrett D'Amore return (cmap_lookup_hard(cm, from)); 64*163bd69bSGarrett D'Amore } 65*163bd69bSGarrett D'Amore 66*163bd69bSGarrett D'Amore static wint_t 67*163bd69bSGarrett D'Amore cmap_max(struct cmap *cm) 68*163bd69bSGarrett D'Amore { 69*163bd69bSGarrett D'Amore return (cm->cm_max); 70*163bd69bSGarrett D'Amore } 71*163bd69bSGarrett D'Amore 72*163bd69bSGarrett D'Amore static inline bool 73*163bd69bSGarrett D'Amore cset_in(struct cset *cs, wchar_t ch) 74*163bd69bSGarrett D'Amore { 75*163bd69bSGarrett D'Amore 76*163bd69bSGarrett D'Amore if (ch < CS_CACHE_SIZE && cs->cs_havecache) 77*163bd69bSGarrett D'Amore return (cs->cs_cache[ch]); 78*163bd69bSGarrett D'Amore return (cset_in_hard(cs, ch)); 79*163bd69bSGarrett D'Amore } 80*163bd69bSGarrett D'Amore 81*163bd69bSGarrett D'Amore int 82*163bd69bSGarrett D'Amore main(int argc, char **argv) 83*163bd69bSGarrett D'Amore { 84*163bd69bSGarrett D'Amore static int carray[NCHARS_SB]; 85*163bd69bSGarrett D'Amore struct cmap *map; 86*163bd69bSGarrett D'Amore struct cset *delete, *squeeze; 87*163bd69bSGarrett D'Amore int n, *p; 88*163bd69bSGarrett D'Amore int Cflag, cflag, dflag, sflag, isstring2; 89*163bd69bSGarrett D'Amore wint_t ch, cnt, lastch; 90*163bd69bSGarrett D'Amore 91*163bd69bSGarrett D'Amore (void) setlocale(LC_ALL, ""); 92*163bd69bSGarrett D'Amore 93*163bd69bSGarrett D'Amore Cflag = cflag = dflag = sflag = 0; 94*163bd69bSGarrett D'Amore while ((ch = getopt(argc, argv, "Ccdsu")) != -1) 95*163bd69bSGarrett D'Amore switch ((char)ch) { 96*163bd69bSGarrett D'Amore case 'C': 97*163bd69bSGarrett D'Amore Cflag = 1; 98*163bd69bSGarrett D'Amore cflag = 0; 99*163bd69bSGarrett D'Amore break; 100*163bd69bSGarrett D'Amore case 'c': 101*163bd69bSGarrett D'Amore cflag = 1; 102*163bd69bSGarrett D'Amore Cflag = 0; 103*163bd69bSGarrett D'Amore break; 104*163bd69bSGarrett D'Amore case 'd': 105*163bd69bSGarrett D'Amore dflag = 1; 106*163bd69bSGarrett D'Amore break; 107*163bd69bSGarrett D'Amore case 's': 108*163bd69bSGarrett D'Amore sflag = 1; 109*163bd69bSGarrett D'Amore break; 110*163bd69bSGarrett D'Amore case 'u': 111*163bd69bSGarrett D'Amore setbuf(stdout, (char *)NULL); 112*163bd69bSGarrett D'Amore break; 113*163bd69bSGarrett D'Amore case '?': 114*163bd69bSGarrett D'Amore default: 115*163bd69bSGarrett D'Amore usage(); 116*163bd69bSGarrett D'Amore } 117*163bd69bSGarrett D'Amore argc -= optind; 118*163bd69bSGarrett D'Amore argv += optind; 119*163bd69bSGarrett D'Amore 120*163bd69bSGarrett D'Amore switch (argc) { 121*163bd69bSGarrett D'Amore case 0: 122*163bd69bSGarrett D'Amore default: 123*163bd69bSGarrett D'Amore usage(); 124*163bd69bSGarrett D'Amore /* NOTREACHED */ 125*163bd69bSGarrett D'Amore case 1: 126*163bd69bSGarrett D'Amore isstring2 = 0; 127*163bd69bSGarrett D'Amore break; 128*163bd69bSGarrett D'Amore case 2: 129*163bd69bSGarrett D'Amore isstring2 = 1; 130*163bd69bSGarrett D'Amore break; 131*163bd69bSGarrett D'Amore } 132*163bd69bSGarrett D'Amore 133*163bd69bSGarrett D'Amore /* 134*163bd69bSGarrett D'Amore * tr -ds [-Cc] string1 string2 135*163bd69bSGarrett D'Amore * Delete all characters (or complemented characters) in string1. 136*163bd69bSGarrett D'Amore * Squeeze all characters in string2. 137*163bd69bSGarrett D'Amore */ 138*163bd69bSGarrett D'Amore if (dflag && sflag) { 139*163bd69bSGarrett D'Amore if (!isstring2) 140*163bd69bSGarrett D'Amore usage(); 141*163bd69bSGarrett D'Amore 142*163bd69bSGarrett D'Amore delete = setup(argv[0], &s1, cflag, Cflag); 143*163bd69bSGarrett D'Amore squeeze = setup(argv[1], &s2, 0, 0); 144*163bd69bSGarrett D'Amore 145*163bd69bSGarrett D'Amore for (lastch = OOBCH; (ch = getwchar()) != WEOF; ) 146*163bd69bSGarrett D'Amore if (!cset_in(delete, ch) && 147*163bd69bSGarrett D'Amore (lastch != ch || !cset_in(squeeze, ch))) { 148*163bd69bSGarrett D'Amore lastch = ch; 149*163bd69bSGarrett D'Amore (void) putwchar(ch); 150*163bd69bSGarrett D'Amore } 151*163bd69bSGarrett D'Amore if (ferror(stdin)) 152*163bd69bSGarrett D'Amore err(1, NULL); 153*163bd69bSGarrett D'Amore exit(0); 154*163bd69bSGarrett D'Amore } 155*163bd69bSGarrett D'Amore 156*163bd69bSGarrett D'Amore /* 157*163bd69bSGarrett D'Amore * tr -d [-Cc] string1 158*163bd69bSGarrett D'Amore * Delete all characters (or complemented characters) in string1. 159*163bd69bSGarrett D'Amore */ 160*163bd69bSGarrett D'Amore if (dflag) { 161*163bd69bSGarrett D'Amore if (isstring2) 162*163bd69bSGarrett D'Amore usage(); 163*163bd69bSGarrett D'Amore 164*163bd69bSGarrett D'Amore delete = setup(argv[0], &s1, cflag, Cflag); 165*163bd69bSGarrett D'Amore 166*163bd69bSGarrett D'Amore while ((ch = getwchar()) != WEOF) 167*163bd69bSGarrett D'Amore if (!cset_in(delete, ch)) 168*163bd69bSGarrett D'Amore (void) putwchar(ch); 169*163bd69bSGarrett D'Amore if (ferror(stdin)) 170*163bd69bSGarrett D'Amore err(1, NULL); 171*163bd69bSGarrett D'Amore exit(0); 172*163bd69bSGarrett D'Amore } 173*163bd69bSGarrett D'Amore 174*163bd69bSGarrett D'Amore /* 175*163bd69bSGarrett D'Amore * tr -s [-Cc] string1 176*163bd69bSGarrett D'Amore * Squeeze all characters (or complemented characters) in string1. 177*163bd69bSGarrett D'Amore */ 178*163bd69bSGarrett D'Amore if (sflag && !isstring2) { 179*163bd69bSGarrett D'Amore squeeze = setup(argv[0], &s1, cflag, Cflag); 180*163bd69bSGarrett D'Amore 181*163bd69bSGarrett D'Amore for (lastch = OOBCH; (ch = getwchar()) != WEOF; ) 182*163bd69bSGarrett D'Amore if (lastch != ch || !cset_in(squeeze, ch)) { 183*163bd69bSGarrett D'Amore lastch = ch; 184*163bd69bSGarrett D'Amore (void) putwchar(ch); 185*163bd69bSGarrett D'Amore } 186*163bd69bSGarrett D'Amore if (ferror(stdin)) 187*163bd69bSGarrett D'Amore err(1, NULL); 188*163bd69bSGarrett D'Amore exit(0); 189*163bd69bSGarrett D'Amore } 190*163bd69bSGarrett D'Amore 191*163bd69bSGarrett D'Amore /* 192*163bd69bSGarrett D'Amore * tr [-Ccs] string1 string2 193*163bd69bSGarrett D'Amore * Replace all characters (or complemented characters) in string1 with 194*163bd69bSGarrett D'Amore * the character in the same position in string2. If the -s option is 195*163bd69bSGarrett D'Amore * specified, squeeze all the characters in string2. 196*163bd69bSGarrett D'Amore */ 197*163bd69bSGarrett D'Amore if (!isstring2) 198*163bd69bSGarrett D'Amore usage(); 199*163bd69bSGarrett D'Amore 200*163bd69bSGarrett D'Amore map = cmap_alloc(); 201*163bd69bSGarrett D'Amore if (map == NULL) 202*163bd69bSGarrett D'Amore err(1, NULL); 203*163bd69bSGarrett D'Amore squeeze = cset_alloc(); 204*163bd69bSGarrett D'Amore if (squeeze == NULL) 205*163bd69bSGarrett D'Amore err(1, NULL); 206*163bd69bSGarrett D'Amore 207*163bd69bSGarrett D'Amore s1.str = argv[0]; 208*163bd69bSGarrett D'Amore 209*163bd69bSGarrett D'Amore if (Cflag || cflag) { 210*163bd69bSGarrett D'Amore (void) cmap_default(map, OOBCH); 211*163bd69bSGarrett D'Amore if ((s2.str = strdup(argv[1])) == NULL) 212*163bd69bSGarrett D'Amore errx(1, "strdup(argv[1])"); 213*163bd69bSGarrett D'Amore } else 214*163bd69bSGarrett D'Amore s2.str = argv[1]; 215*163bd69bSGarrett D'Amore 216*163bd69bSGarrett D'Amore if (!next(&s2)) 217*163bd69bSGarrett D'Amore errx(1, "empty string2"); 218*163bd69bSGarrett D'Amore 219*163bd69bSGarrett D'Amore /* 220*163bd69bSGarrett D'Amore * For -s result will contain only those characters defined 221*163bd69bSGarrett D'Amore * as the second characters in each of the toupper or tolower 222*163bd69bSGarrett D'Amore * pairs. 223*163bd69bSGarrett D'Amore */ 224*163bd69bSGarrett D'Amore 225*163bd69bSGarrett D'Amore /* If string2 runs out of characters, use the last one specified. */ 226*163bd69bSGarrett D'Amore while (next(&s1)) { 227*163bd69bSGarrett D'Amore again: 228*163bd69bSGarrett D'Amore if (s1.state == CCLASS_LOWER && 229*163bd69bSGarrett D'Amore s2.state == CCLASS_UPPER && 230*163bd69bSGarrett D'Amore s1.cnt == 1 && s2.cnt == 1) { 231*163bd69bSGarrett D'Amore do { 232*163bd69bSGarrett D'Amore ch = towupper(s1.lastch); 233*163bd69bSGarrett D'Amore (void) cmap_add(map, s1.lastch, ch); 234*163bd69bSGarrett D'Amore if (sflag && iswupper(ch)) 235*163bd69bSGarrett D'Amore (void) cset_add(squeeze, ch); 236*163bd69bSGarrett D'Amore if (!next(&s1)) 237*163bd69bSGarrett D'Amore goto endloop; 238*163bd69bSGarrett D'Amore } while (s1.state == CCLASS_LOWER && s1.cnt > 1); 239*163bd69bSGarrett D'Amore /* skip upper set */ 240*163bd69bSGarrett D'Amore do { 241*163bd69bSGarrett D'Amore if (!next(&s2)) 242*163bd69bSGarrett D'Amore break; 243*163bd69bSGarrett D'Amore } while (s2.state == CCLASS_UPPER && s2.cnt > 1); 244*163bd69bSGarrett D'Amore goto again; 245*163bd69bSGarrett D'Amore } else if (s1.state == CCLASS_UPPER && 246*163bd69bSGarrett D'Amore s2.state == CCLASS_LOWER && 247*163bd69bSGarrett D'Amore s1.cnt == 1 && s2.cnt == 1) { 248*163bd69bSGarrett D'Amore do { 249*163bd69bSGarrett D'Amore ch = towlower(s1.lastch); 250*163bd69bSGarrett D'Amore (void) cmap_add(map, s1.lastch, ch); 251*163bd69bSGarrett D'Amore if (sflag && iswlower(ch)) 252*163bd69bSGarrett D'Amore (void) cset_add(squeeze, ch); 253*163bd69bSGarrett D'Amore if (!next(&s1)) 254*163bd69bSGarrett D'Amore goto endloop; 255*163bd69bSGarrett D'Amore } while (s1.state == CCLASS_UPPER && s1.cnt > 1); 256*163bd69bSGarrett D'Amore /* skip lower set */ 257*163bd69bSGarrett D'Amore do { 258*163bd69bSGarrett D'Amore if (!next(&s2)) 259*163bd69bSGarrett D'Amore break; 260*163bd69bSGarrett D'Amore } while (s2.state == CCLASS_LOWER && s2.cnt > 1); 261*163bd69bSGarrett D'Amore goto again; 262*163bd69bSGarrett D'Amore } else { 263*163bd69bSGarrett D'Amore (void) cmap_add(map, s1.lastch, s2.lastch); 264*163bd69bSGarrett D'Amore if (sflag) 265*163bd69bSGarrett D'Amore (void) cset_add(squeeze, s2.lastch); 266*163bd69bSGarrett D'Amore } 267*163bd69bSGarrett D'Amore (void) next(&s2); 268*163bd69bSGarrett D'Amore } 269*163bd69bSGarrett D'Amore endloop: 270*163bd69bSGarrett D'Amore if (cflag || (Cflag && MB_CUR_MAX > 1)) { 271*163bd69bSGarrett D'Amore /* 272*163bd69bSGarrett D'Amore * This is somewhat tricky: since the character set is 273*163bd69bSGarrett D'Amore * potentially huge, we need to avoid allocating a map 274*163bd69bSGarrett D'Amore * entry for every character. Our strategy is to set the 275*163bd69bSGarrett D'Amore * default mapping to the last character of string #2 276*163bd69bSGarrett D'Amore * (= the one that gets automatically repeated), then to 277*163bd69bSGarrett D'Amore * add back identity mappings for characters that should 278*163bd69bSGarrett D'Amore * remain unchanged. We don't waste space on identity mappings 279*163bd69bSGarrett D'Amore * for non-characters with the -C option; those are simulated 280*163bd69bSGarrett D'Amore * in the I/O loop. 281*163bd69bSGarrett D'Amore */ 282*163bd69bSGarrett D'Amore s2.str = argv[1]; 283*163bd69bSGarrett D'Amore s2.state = NORMAL; 284*163bd69bSGarrett D'Amore for (cnt = 0; cnt < WCHAR_MAX; cnt++) { 285*163bd69bSGarrett D'Amore if (Cflag && !iswrune(cnt)) 286*163bd69bSGarrett D'Amore continue; 287*163bd69bSGarrett D'Amore if (cmap_lookup(map, cnt) == OOBCH) { 288*163bd69bSGarrett D'Amore if (next(&s2)) 289*163bd69bSGarrett D'Amore (void) cmap_add(map, cnt, s2.lastch); 290*163bd69bSGarrett D'Amore if (sflag) 291*163bd69bSGarrett D'Amore (void) cset_add(squeeze, s2.lastch); 292*163bd69bSGarrett D'Amore } else 293*163bd69bSGarrett D'Amore (void) cmap_add(map, cnt, cnt); 294*163bd69bSGarrett D'Amore if ((s2.state == EOS || s2.state == INFINITE) && 295*163bd69bSGarrett D'Amore cnt >= cmap_max(map)) 296*163bd69bSGarrett D'Amore break; 297*163bd69bSGarrett D'Amore } 298*163bd69bSGarrett D'Amore (void) cmap_default(map, s2.lastch); 299*163bd69bSGarrett D'Amore } else if (Cflag) { 300*163bd69bSGarrett D'Amore for (p = carray, cnt = 0; cnt < NCHARS_SB; cnt++) { 301*163bd69bSGarrett D'Amore if (cmap_lookup(map, cnt) == OOBCH && iswrune(cnt)) 302*163bd69bSGarrett D'Amore *p++ = cnt; 303*163bd69bSGarrett D'Amore else 304*163bd69bSGarrett D'Amore (void) cmap_add(map, cnt, cnt); 305*163bd69bSGarrett D'Amore } 306*163bd69bSGarrett D'Amore n = p - carray; 307*163bd69bSGarrett D'Amore if (Cflag && n > 1) 308*163bd69bSGarrett D'Amore (void) qsort(carray, n, sizeof (*carray), charcoll); 309*163bd69bSGarrett D'Amore 310*163bd69bSGarrett D'Amore s2.str = argv[1]; 311*163bd69bSGarrett D'Amore s2.state = NORMAL; 312*163bd69bSGarrett D'Amore for (cnt = 0; cnt < n; cnt++) { 313*163bd69bSGarrett D'Amore (void) next(&s2); 314*163bd69bSGarrett D'Amore (void) cmap_add(map, carray[cnt], s2.lastch); 315*163bd69bSGarrett D'Amore /* 316*163bd69bSGarrett D'Amore * Chars taken from s2 can be different this time 317*163bd69bSGarrett D'Amore * due to lack of complex upper/lower processing, 318*163bd69bSGarrett D'Amore * so fill string2 again to not miss some. 319*163bd69bSGarrett D'Amore */ 320*163bd69bSGarrett D'Amore if (sflag) 321*163bd69bSGarrett D'Amore (void) cset_add(squeeze, s2.lastch); 322*163bd69bSGarrett D'Amore } 323*163bd69bSGarrett D'Amore } 324*163bd69bSGarrett D'Amore 325*163bd69bSGarrett D'Amore cset_cache(squeeze); 326*163bd69bSGarrett D'Amore cmap_cache(map); 327*163bd69bSGarrett D'Amore 328*163bd69bSGarrett D'Amore if (sflag) 329*163bd69bSGarrett D'Amore for (lastch = OOBCH; (ch = getwchar()) != WEOF; ) { 330*163bd69bSGarrett D'Amore if (!Cflag || iswrune(ch)) 331*163bd69bSGarrett D'Amore ch = cmap_lookup(map, ch); 332*163bd69bSGarrett D'Amore if (lastch != ch || !cset_in(squeeze, ch)) { 333*163bd69bSGarrett D'Amore lastch = ch; 334*163bd69bSGarrett D'Amore (void) putwchar(ch); 335*163bd69bSGarrett D'Amore } 336*163bd69bSGarrett D'Amore } 337*163bd69bSGarrett D'Amore else 338*163bd69bSGarrett D'Amore while ((ch = getwchar()) != WEOF) { 339*163bd69bSGarrett D'Amore if (!Cflag || iswrune(ch)) 340*163bd69bSGarrett D'Amore ch = cmap_lookup(map, ch); 341*163bd69bSGarrett D'Amore (void) putwchar(ch); 342*163bd69bSGarrett D'Amore } 343*163bd69bSGarrett D'Amore if (ferror(stdin)) 344*163bd69bSGarrett D'Amore err(1, NULL); 345*163bd69bSGarrett D'Amore exit(0); 346*163bd69bSGarrett D'Amore } 347*163bd69bSGarrett D'Amore 348*163bd69bSGarrett D'Amore static struct cset * 349*163bd69bSGarrett D'Amore setup(char *arg, STR *str, int cflag, int Cflag) 350*163bd69bSGarrett D'Amore { 351*163bd69bSGarrett D'Amore struct cset *cs; 352*163bd69bSGarrett D'Amore 353*163bd69bSGarrett D'Amore cs = cset_alloc(); 354*163bd69bSGarrett D'Amore if (cs == NULL) 355*163bd69bSGarrett D'Amore err(1, NULL); 356*163bd69bSGarrett D'Amore str->str = arg; 357*163bd69bSGarrett D'Amore while (next(str)) 358*163bd69bSGarrett D'Amore (void) cset_add(cs, str->lastch); 359*163bd69bSGarrett D'Amore if (Cflag) 360*163bd69bSGarrett D'Amore (void) cset_addclass(cs, wctype("rune"), true); 361*163bd69bSGarrett D'Amore if (cflag || Cflag) 362*163bd69bSGarrett D'Amore cset_invert(cs); 363*163bd69bSGarrett D'Amore cset_cache(cs); 364*163bd69bSGarrett D'Amore return (cs); 365*163bd69bSGarrett D'Amore } 366*163bd69bSGarrett D'Amore 367*163bd69bSGarrett D'Amore int 368*163bd69bSGarrett D'Amore charcoll(const void *a, const void *b) 369*163bd69bSGarrett D'Amore { 370*163bd69bSGarrett D'Amore static char sa[2], sb[2]; 371*163bd69bSGarrett D'Amore 372*163bd69bSGarrett D'Amore sa[0] = *(const int *)a; 373*163bd69bSGarrett D'Amore sb[0] = *(const int *)b; 374*163bd69bSGarrett D'Amore return (strcoll(sa, sb)); 375*163bd69bSGarrett D'Amore } 376*163bd69bSGarrett D'Amore 377*163bd69bSGarrett D'Amore static void 378*163bd69bSGarrett D'Amore usage(void) 379*163bd69bSGarrett D'Amore { 380*163bd69bSGarrett D'Amore (void) fprintf(stderr, "%s\n%s\n%s\n%s\n", 381*163bd69bSGarrett D'Amore "usage: tr [-Ccsu] string1 string2", 382*163bd69bSGarrett D'Amore " tr [-Ccu] -d string1", 383*163bd69bSGarrett D'Amore " tr [-Ccu] -s string1", 384*163bd69bSGarrett D'Amore " tr [-Ccu] -ds string1 string2"); 385*163bd69bSGarrett D'Amore exit(1); 386*163bd69bSGarrett D'Amore } 387