comm.c revision 204896
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 * 3. All advertising materials mentioning features or use of this software
171590Srgrimes *    must display the following acknowledgement:
181590Srgrimes *	This product includes software developed by the University of
191590Srgrimes *	California, Berkeley and its contributors.
201590Srgrimes * 4. Neither the name of the University nor the names of its contributors
211590Srgrimes *    may be used to endorse or promote products derived from this software
221590Srgrimes *    without specific prior written permission.
231590Srgrimes *
241590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
251590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
261590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
271590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
281590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
291590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
301590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
311590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
321590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
331590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
341590Srgrimes * SUCH DAMAGE.
351590Srgrimes */
361590Srgrimes
371590Srgrimes#ifndef lint
3841568Sarchiestatic const char copyright[] =
391590Srgrimes"@(#) Copyright (c) 1989, 1993, 1994\n\
401590Srgrimes	The Regents of the University of California.  All rights reserved.\n";
4187246Smarkm#endif
421590Srgrimes
4387628Sdwmalone#if 0
441590Srgrimes#ifndef lint
4587628Sdwmalonestatic char sccsid[] = "From: @(#)comm.c	8.4 (Berkeley) 5/4/95";
4629207Sjoerg#endif
4787628Sdwmalone#endif
481590Srgrimes
4987628Sdwmalone#include <sys/cdefs.h>
5087628Sdwmalone__FBSDID("$FreeBSD: head/usr.bin/comm/comm.c 204896 2010-03-08 22:27:46Z ache $");
5187628Sdwmalone
5227094Scharnier#include <err.h>
531590Srgrimes#include <limits.h>
5452453Sache#include <locale.h>
55200604Sjh#include <stdint.h>
56204896Sache#define _WITH_GETLINE
571590Srgrimes#include <stdio.h>
5878718Sdd#include <stdlib.h>
591590Srgrimes#include <string.h>
6023690Speter#include <unistd.h>
61131497Stjr#include <wchar.h>
62131497Stjr#include <wctype.h>
631590Srgrimes
64204896Sacheint iflag;
65204896Sacheconst char *tabs[] = { "", "\t", "\t\t" };
661590Srgrimes
67100819SdwmaloneFILE   *file(const char *);
68204896Sachewchar_t	*convert(const char *);
69204896Sachevoid	show(FILE *, const char *, const char *, char **, size_t *);
7092920Simpstatic void	usage(void);
711590Srgrimes
721590Srgrimesint
73100819Sdwmalonemain(int argc, char *argv[])
741590Srgrimes{
75179374Sghelmer	int comp, read1, read2;
76204896Sache	int ch, flag1, flag2, flag3;
771590Srgrimes	FILE *fp1, *fp2;
78204896Sache	const char *col1, *col2, *col3;
79179374Sghelmer	size_t line1len, line2len;
80204896Sache	char *line1, *line2;
81204896Sache	ssize_t n1, n2;
82204896Sache	wchar_t *tline1, *tline2;
83204896Sache	const char **p;
841590Srgrimes
85204896Sache	(void) setlocale(LC_ALL, "");
86204896Sache
871590Srgrimes	flag1 = flag2 = flag3 = 1;
8829207Sjoerg
8997393Stjr	while ((ch = getopt(argc, argv, "123i")) != -1)
901590Srgrimes		switch(ch) {
911590Srgrimes		case '1':
921590Srgrimes			flag1 = 0;
931590Srgrimes			break;
941590Srgrimes		case '2':
951590Srgrimes			flag2 = 0;
961590Srgrimes			break;
971590Srgrimes		case '3':
981590Srgrimes			flag3 = 0;
991590Srgrimes			break;
10029207Sjoerg		case 'i':
10129207Sjoerg			iflag = 1;
10229207Sjoerg			break;
1031590Srgrimes		case '?':
1041590Srgrimes		default:
1051590Srgrimes			usage();
1061590Srgrimes		}
10797393Stjr	argc -= optind;
1081590Srgrimes	argv += optind;
1091590Srgrimes
1101590Srgrimes	if (argc != 2)
1111590Srgrimes		usage();
1121590Srgrimes
1131590Srgrimes	fp1 = file(argv[0]);
1141590Srgrimes	fp2 = file(argv[1]);
1151590Srgrimes
1161590Srgrimes	/* for each column printed, add another tab offset */
1171590Srgrimes	p = tabs;
1181590Srgrimes	col1 = col2 = col3 = NULL;
1191590Srgrimes	if (flag1)
1201590Srgrimes		col1 = *p++;
1211590Srgrimes	if (flag2)
1221590Srgrimes		col2 = *p++;
1231590Srgrimes	if (flag3)
1241590Srgrimes		col3 = *p;
1251590Srgrimes
126204896Sache	line1len = line2len = 0;
127204896Sache	line1 = line2 = NULL;
128204896Sache	n1 = n2 = -1;
129204896Sache
1301590Srgrimes	for (read1 = read2 = 1;;) {
1311590Srgrimes		/* read next line, check for EOF */
132131497Stjr		if (read1) {
133204896Sache			n1 = getline(&line1, &line1len, fp1);
134204896Sache			if (n1 < 0 && ferror(fp1))
135131497Stjr				err(1, "%s", argv[0]);
136204896Sache			if (n1 > 0 && line1[n1 - 1] == '\n')
137204896Sache				line1[n1 - 1] = '\0';
138204896Sache
139131497Stjr		}
140131497Stjr		if (read2) {
141204896Sache			n2 = getline(&line2, &line2len, fp2);
142204896Sache			if (n2 < 0 && ferror(fp2))
143131497Stjr				err(1, "%s", argv[1]);
144204896Sache			if (n2 > 0 && line2[n2 - 1] == '\n')
145204896Sache				line2[n2 - 1] = '\0';
146131497Stjr		}
1471590Srgrimes
1481590Srgrimes		/* if one file done, display the rest of the other file */
149204896Sache		if (n1 < 0) {
150204896Sache			if (n2 >= 0 && col2 != NULL)
151204896Sache				show(fp2, argv[1], col2, &line2, &line2len);
1521590Srgrimes			break;
1531590Srgrimes		}
154204896Sache		if (n2 < 0) {
155204896Sache			if (n1 >= 0 && col1 != NULL)
156204896Sache				show(fp1, argv[0], col1, &line1, &line1len);
1571590Srgrimes			break;
1581590Srgrimes		}
1591590Srgrimes
160204896Sache		tline2 = NULL;
161204896Sache		if ((tline1 = convert(line1)) != NULL)
162204896Sache			tline2 = convert(line2);
163204896Sache		if (tline1 == NULL || tline2 == NULL)
164204896Sache			comp = strcmp(line1, line2);
16529207Sjoerg		else
166204896Sache			comp = wcscoll(tline1, tline2);
167204896Sache		if (tline1 != NULL)
168204896Sache			free(tline1);
169204896Sache		if (tline2 != NULL)
170204896Sache			free(tline2);
17129207Sjoerg
172204896Sache		/* lines are the same */
17329207Sjoerg		if (!comp) {
1741590Srgrimes			read1 = read2 = 1;
175179374Sghelmer			if (col3 != NULL)
176204896Sache				(void)printf("%s%s\n", col3, line1);
1771590Srgrimes			continue;
1781590Srgrimes		}
1791590Srgrimes
1801590Srgrimes		/* lines are different */
1811590Srgrimes		if (comp < 0) {
1821590Srgrimes			read1 = 1;
1831590Srgrimes			read2 = 0;
184179374Sghelmer			if (col1 != NULL)
185204896Sache				(void)printf("%s%s\n", col1, line1);
1861590Srgrimes		} else {
1871590Srgrimes			read1 = 0;
1881590Srgrimes			read2 = 1;
189179374Sghelmer			if (col2 != NULL)
190204896Sache				(void)printf("%s%s\n", col2, line2);
1911590Srgrimes		}
1921590Srgrimes	}
1931590Srgrimes	exit(0);
1941590Srgrimes}
1951590Srgrimes
196179374Sghelmerwchar_t *
197204896Sacheconvert(const char *str)
198179374Sghelmer{
199204896Sache	size_t n;
200204896Sache	wchar_t *buf, *p;
201179374Sghelmer
202204896Sache	if ((n = mbstowcs(NULL, str, 0)) == (size_t)-1)
203204896Sache		return (NULL);
204204896Sache	if ((buf = malloc((n + 1) * sizeof(*buf))) == NULL)
205204896Sache		err(1, "malloc");
206204896Sache	if (mbstowcs(buf, str, n + 1) != n)
207204896Sache		errx(1, "internal mbstowcs() error");
208204896Sache
209204896Sache	if (iflag) {
210204896Sache		for (p = buf; *p != L'\0'; p++)
211204896Sache			*p = towlower(*p);
212200442Sjh	}
213179374Sghelmer
214204896Sache	return (buf);
215179374Sghelmer}
216179374Sghelmer
2171590Srgrimesvoid
218204896Sacheshow(FILE *fp, const char *fn, const char *offset, char **bufp, size_t *buflenp)
2191590Srgrimes{
220204896Sache	ssize_t n;
2211590Srgrimes
2221590Srgrimes	do {
223204896Sache		(void)printf("%s%s\n", offset, *bufp);
224204896Sache		if ((n = getline(bufp, buflenp, fp)) < 0)
225204896Sache			break;
226204896Sache		if (n > 0 && (*bufp)[n - 1] == '\n')
227204896Sache			(*bufp)[n - 1] = '\0';
228204896Sache	} while (1);
229131497Stjr	if (ferror(fp))
230131497Stjr		err(1, "%s", fn);
2311590Srgrimes}
2321590Srgrimes
2331590SrgrimesFILE *
234100819Sdwmalonefile(const char *name)
2351590Srgrimes{
2361590Srgrimes	FILE *fp;
2371590Srgrimes
2381590Srgrimes	if (!strcmp(name, "-"))
2391590Srgrimes		return (stdin);
2401590Srgrimes	if ((fp = fopen(name, "r")) == NULL) {
24127094Scharnier		err(1, "%s", name);
2421590Srgrimes	}
2431590Srgrimes	return (fp);
2441590Srgrimes}
2451590Srgrimes
24627094Scharnierstatic void
247100819Sdwmaloneusage(void)
2481590Srgrimes{
24929207Sjoerg	(void)fprintf(stderr, "usage: comm [-123i] file1 file2\n");
2501590Srgrimes	exit(1);
2511590Srgrimes}
252