11590Srgrimes/* 21590Srgrimes * Copyright (c) 1989, 1993, 1994 31590Srgrimes * The Regents of the University of California. All rights reserved. 41590Srgrimes * 51590Srgrimes * This code is derived from software contributed to Berkeley by 61590Srgrimes * Case Larsen. 71590Srgrimes * 81590Srgrimes * Redistribution and use in source and binary forms, with or without 91590Srgrimes * modification, are permitted provided that the following conditions 101590Srgrimes * are met: 111590Srgrimes * 1. Redistributions of source code must retain the above copyright 121590Srgrimes * notice, this list of conditions and the following disclaimer. 131590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 141590Srgrimes * notice, this list of conditions and the following disclaimer in the 151590Srgrimes * documentation and/or other materials provided with the distribution. 161590Srgrimes * 4. Neither the name of the University nor the names of its contributors 171590Srgrimes * may be used to endorse or promote products derived from this software 181590Srgrimes * without specific prior written permission. 191590Srgrimes * 201590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 211590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 221590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 231590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 241590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 251590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 261590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 271590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 281590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 291590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 301590Srgrimes * SUCH DAMAGE. 311590Srgrimes */ 321590Srgrimes 331590Srgrimes#ifndef lint 3441568Sarchiestatic const char copyright[] = 351590Srgrimes"@(#) Copyright (c) 1989, 1993, 1994\n\ 361590Srgrimes The Regents of the University of California. All rights reserved.\n"; 3787246Smarkm#endif 381590Srgrimes 3987628Sdwmalone#if 0 401590Srgrimes#ifndef lint 4187628Sdwmalonestatic char sccsid[] = "From: @(#)comm.c 8.4 (Berkeley) 5/4/95"; 4229207Sjoerg#endif 4387628Sdwmalone#endif 441590Srgrimes 4587628Sdwmalone#include <sys/cdefs.h> 4687628Sdwmalone__FBSDID("$FreeBSD$"); 4787628Sdwmalone 4827094Scharnier#include <err.h> 491590Srgrimes#include <limits.h> 5052453Sache#include <locale.h> 51200604Sjh#include <stdint.h> 52204896Sache#define _WITH_GETLINE 531590Srgrimes#include <stdio.h> 5478718Sdd#include <stdlib.h> 551590Srgrimes#include <string.h> 5623690Speter#include <unistd.h> 57131497Stjr#include <wchar.h> 58131497Stjr#include <wctype.h> 591590Srgrimes 60227235Sedstatic int iflag; 61227235Sedstatic const char *tabs[] = { "", "\t", "\t\t" }; 621590Srgrimes 63227235Sedstatic FILE *file(const char *); 64227235Sedstatic wchar_t *convert(const char *); 65227235Sedstatic void show(FILE *, const char *, const char *, char **, size_t *); 6692920Simpstatic void usage(void); 671590Srgrimes 681590Srgrimesint 69100819Sdwmalonemain(int argc, char *argv[]) 701590Srgrimes{ 71179374Sghelmer int comp, read1, read2; 72204896Sache int ch, flag1, flag2, flag3; 731590Srgrimes FILE *fp1, *fp2; 74204896Sache const char *col1, *col2, *col3; 75179374Sghelmer size_t line1len, line2len; 76204896Sache char *line1, *line2; 77204896Sache ssize_t n1, n2; 78204896Sache wchar_t *tline1, *tline2; 79204896Sache const char **p; 801590Srgrimes 81204896Sache (void) setlocale(LC_ALL, ""); 82204896Sache 831590Srgrimes flag1 = flag2 = flag3 = 1; 8429207Sjoerg 8597393Stjr while ((ch = getopt(argc, argv, "123i")) != -1) 861590Srgrimes switch(ch) { 871590Srgrimes case '1': 881590Srgrimes flag1 = 0; 891590Srgrimes break; 901590Srgrimes case '2': 911590Srgrimes flag2 = 0; 921590Srgrimes break; 931590Srgrimes case '3': 941590Srgrimes flag3 = 0; 951590Srgrimes break; 9629207Sjoerg case 'i': 9729207Sjoerg iflag = 1; 9829207Sjoerg break; 991590Srgrimes case '?': 1001590Srgrimes default: 1011590Srgrimes usage(); 1021590Srgrimes } 10397393Stjr argc -= optind; 1041590Srgrimes argv += optind; 1051590Srgrimes 1061590Srgrimes if (argc != 2) 1071590Srgrimes usage(); 1081590Srgrimes 1091590Srgrimes fp1 = file(argv[0]); 1101590Srgrimes fp2 = file(argv[1]); 1111590Srgrimes 1121590Srgrimes /* for each column printed, add another tab offset */ 1131590Srgrimes p = tabs; 1141590Srgrimes col1 = col2 = col3 = NULL; 1151590Srgrimes if (flag1) 1161590Srgrimes col1 = *p++; 1171590Srgrimes if (flag2) 1181590Srgrimes col2 = *p++; 1191590Srgrimes if (flag3) 1201590Srgrimes col3 = *p; 1211590Srgrimes 122204896Sache line1len = line2len = 0; 123204896Sache line1 = line2 = NULL; 124204896Sache n1 = n2 = -1; 125204896Sache 1261590Srgrimes for (read1 = read2 = 1;;) { 1271590Srgrimes /* read next line, check for EOF */ 128131497Stjr if (read1) { 129204896Sache n1 = getline(&line1, &line1len, fp1); 130204896Sache if (n1 < 0 && ferror(fp1)) 131131497Stjr err(1, "%s", argv[0]); 132204896Sache if (n1 > 0 && line1[n1 - 1] == '\n') 133204896Sache line1[n1 - 1] = '\0'; 134204896Sache 135131497Stjr } 136131497Stjr if (read2) { 137204896Sache n2 = getline(&line2, &line2len, fp2); 138204896Sache if (n2 < 0 && ferror(fp2)) 139131497Stjr err(1, "%s", argv[1]); 140204896Sache if (n2 > 0 && line2[n2 - 1] == '\n') 141204896Sache line2[n2 - 1] = '\0'; 142131497Stjr } 1431590Srgrimes 1441590Srgrimes /* if one file done, display the rest of the other file */ 145204896Sache if (n1 < 0) { 146204896Sache if (n2 >= 0 && col2 != NULL) 147204896Sache show(fp2, argv[1], col2, &line2, &line2len); 1481590Srgrimes break; 1491590Srgrimes } 150204896Sache if (n2 < 0) { 151204896Sache if (n1 >= 0 && col1 != NULL) 152204896Sache show(fp1, argv[0], col1, &line1, &line1len); 1531590Srgrimes break; 1541590Srgrimes } 1551590Srgrimes 156204896Sache tline2 = NULL; 157204896Sache if ((tline1 = convert(line1)) != NULL) 158204896Sache tline2 = convert(line2); 159204896Sache if (tline1 == NULL || tline2 == NULL) 160204896Sache comp = strcmp(line1, line2); 16129207Sjoerg else 162204896Sache comp = wcscoll(tline1, tline2); 163204896Sache if (tline1 != NULL) 164204896Sache free(tline1); 165204896Sache if (tline2 != NULL) 166204896Sache free(tline2); 16729207Sjoerg 168204896Sache /* lines are the same */ 16929207Sjoerg if (!comp) { 1701590Srgrimes read1 = read2 = 1; 171179374Sghelmer if (col3 != NULL) 172204896Sache (void)printf("%s%s\n", col3, line1); 1731590Srgrimes continue; 1741590Srgrimes } 1751590Srgrimes 1761590Srgrimes /* lines are different */ 1771590Srgrimes if (comp < 0) { 1781590Srgrimes read1 = 1; 1791590Srgrimes read2 = 0; 180179374Sghelmer if (col1 != NULL) 181204896Sache (void)printf("%s%s\n", col1, line1); 1821590Srgrimes } else { 1831590Srgrimes read1 = 0; 1841590Srgrimes read2 = 1; 185179374Sghelmer if (col2 != NULL) 186204896Sache (void)printf("%s%s\n", col2, line2); 1871590Srgrimes } 1881590Srgrimes } 1891590Srgrimes exit(0); 1901590Srgrimes} 1911590Srgrimes 192227235Sedstatic wchar_t * 193204896Sacheconvert(const char *str) 194179374Sghelmer{ 195204896Sache size_t n; 196204896Sache wchar_t *buf, *p; 197179374Sghelmer 198204896Sache if ((n = mbstowcs(NULL, str, 0)) == (size_t)-1) 199204896Sache return (NULL); 200204928Sache if (SIZE_MAX / sizeof(*buf) < n + 1) 201204928Sache errx(1, "conversion buffer length overflow"); 202204896Sache if ((buf = malloc((n + 1) * sizeof(*buf))) == NULL) 203204896Sache err(1, "malloc"); 204204896Sache if (mbstowcs(buf, str, n + 1) != n) 205204896Sache errx(1, "internal mbstowcs() error"); 206204896Sache 207204896Sache if (iflag) { 208204896Sache for (p = buf; *p != L'\0'; p++) 209204896Sache *p = towlower(*p); 210200442Sjh } 211179374Sghelmer 212204896Sache return (buf); 213179374Sghelmer} 214179374Sghelmer 215227235Sedstatic void 216204896Sacheshow(FILE *fp, const char *fn, const char *offset, char **bufp, size_t *buflenp) 2171590Srgrimes{ 218204896Sache ssize_t n; 2191590Srgrimes 2201590Srgrimes do { 221204896Sache (void)printf("%s%s\n", offset, *bufp); 222204896Sache if ((n = getline(bufp, buflenp, fp)) < 0) 223204896Sache break; 224204896Sache if (n > 0 && (*bufp)[n - 1] == '\n') 225204896Sache (*bufp)[n - 1] = '\0'; 226204896Sache } while (1); 227131497Stjr if (ferror(fp)) 228131497Stjr err(1, "%s", fn); 2291590Srgrimes} 2301590Srgrimes 231227235Sedstatic FILE * 232100819Sdwmalonefile(const char *name) 2331590Srgrimes{ 2341590Srgrimes FILE *fp; 2351590Srgrimes 2361590Srgrimes if (!strcmp(name, "-")) 2371590Srgrimes return (stdin); 2381590Srgrimes if ((fp = fopen(name, "r")) == NULL) { 23927094Scharnier err(1, "%s", name); 2401590Srgrimes } 2411590Srgrimes return (fp); 2421590Srgrimes} 2431590Srgrimes 24427094Scharnierstatic void 245100819Sdwmaloneusage(void) 2461590Srgrimes{ 24729207Sjoerg (void)fprintf(stderr, "usage: comm [-123i] file1 file2\n"); 2481590Srgrimes exit(1); 2491590Srgrimes} 250