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