xref: /titanic_50/usr/src/lib/libcmd/common/comm.c (revision d29b2c4438482eb00488be49a1f5d6835f455546)
1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *           Copyright (c) 1992-2007 AT&T Knowledge Ventures            *
5 *                      and is licensed under the                       *
6 *                  Common Public License, Version 1.0                  *
7 *                      by AT&T Knowledge Ventures                      *
8 *                                                                      *
9 *                A copy of the License is available at                 *
10 *            http://www.opensource.org/licenses/cpl1.0.txt             *
11 *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12 *                                                                      *
13 *              Information and Software Systems Research               *
14 *                            AT&T Research                             *
15 *                           Florham Park NJ                            *
16 *                                                                      *
17 *                 Glenn Fowler <gsf@research.att.com>                  *
18 *                  David Korn <dgk@research.att.com>                   *
19 *                                                                      *
20 ***********************************************************************/
21 #pragma prototyped
22 /*
23  * David Korn
24  * AT&T Bell Laboratories
25  *
26  * comm
27  */
28 
29 static const char usage[] =
30 "[-?\n@(#)$Id: comm (AT&T Research) 1999-04-28 $\n]"
31 USAGE_LICENSE
32 "[+NAME?comm - select or reject lines common to two files]"
33 "[+DESCRIPTION?\bcomm\b reads two files \afile1\a and \afile2\a "
34 	"which should be ordered in the collating sequence of the "
35 	"current locale, and produces three text columns as output:]{"
36 	"[+1?Lines only in \afile1\a.]"
37 	"[+2?Lines only in \afile2\a.]"
38 	"[+3?Lines in both files.]"
39 	"}"
40 "[+?If lines in either file are not ordered according to the collating "
41 	"sequence of the current locale, the results are not specified.]"
42 "[+?If either \afile1\a or \afile2\a is \b-\b, \bcomm\b "
43         "uses standard input starting at the current location.]"
44 
45 "[1?Suppress the output column of lines unique to \afile1\a.]"
46 "[2?Suppress the output column of lines unique to \afile2\a.]"
47 "[3?Suppress the output column of lines duplicate in \afile1\a and \afile2\a.]"
48 "\n"
49 "\nfile1 file2\n"
50 "\n"
51 "[+EXIT STATUS?]{"
52 	"[+0?Both files processed successfully.]"
53 	"[+>0?An error occurred.]"
54 "}"
55 "[+SEE ALSO?\bcmp\b(1), \bdiff\b(1)]"
56 ;
57 
58 
59 #include <cmd.h>
60 
61 #define C_FILE1		1
62 #define C_FILE2		2
63 #define C_COMMON	4
64 #define C_ALL		(C_FILE1|C_FILE2|C_COMMON)
65 
66 static int comm(Sfio_t *in1, Sfio_t *in2, register Sfio_t *out,register int mode)
67 {
68 	register char *cp1, *cp2;
69 	register int n1, n2, n, comp;
70 	if(cp1 = sfgetr(in1,'\n',0))
71 		n1 = sfvalue(in1);
72 	if(cp2 = sfgetr(in2,'\n',0))
73 		n2 = sfvalue(in2);
74 	while(cp1 && cp2)
75 	{
76 		n=(n1<n2?n1:n2);
77 		if((comp=memcmp(cp1,cp2,n-1))==0 && (comp=n1-n2)==0)
78 		{
79 			if(mode&C_COMMON)
80 			{
81 				if(mode!=C_COMMON)
82 				{
83 					sfputc(out,'\t');
84 					if(mode==C_ALL)
85 						sfputc(out,'\t');
86 				}
87 				if(sfwrite(out,cp1,n) < 0)
88 					return(-1);
89 			}
90 			if(cp1 = sfgetr(in1,'\n',0))
91 				n1 = sfvalue(in1);
92 			if(cp2 = sfgetr(in2,'\n',0))
93 				n2 = sfvalue(in2);
94 		}
95 		else if(comp > 0)
96 		{
97 			if(mode&C_FILE2)
98 			{
99 				if(mode&C_FILE1)
100 					sfputc(out,'\t');
101 				if(sfwrite(out,cp2,n2) < 0)
102 					return(-1);
103 			}
104 			if(cp2 = sfgetr(in2,'\n',0))
105 				n2 = sfvalue(in2);
106 		}
107 		else
108 		{
109 			if((mode&C_FILE1) && sfwrite(out,cp1,n1) < 0)
110 				return(-1);
111 			if(cp1 = sfgetr(in1,'\n',0))
112 				n1 = sfvalue(in1);
113 		}
114 	}
115 	n = 0;
116 	if(cp2)
117 	{
118 		cp1 = cp2;
119 		in1 = in2;
120 		n1 = n2;
121 		if(mode&C_FILE1)
122 			n = 1;
123 		mode &= C_FILE2;
124 	}
125 	else
126 		mode &= C_FILE1;
127 	if(!mode || !cp1)
128 	{
129 		if(cp1 && in1==sfstdin)
130 			sfseek(in1,(Sfoff_t)0,SEEK_END);
131 		return(0);
132 	}
133 	/* process the remaining stream */
134 	while(1)
135 	{
136 		if(n)
137 			sfputc(out,'\t');
138 		if(sfwrite(out,cp1,n1) < 0)
139 			return(-1);
140 		if(!(cp1 = sfgetr(in1,'\n',0)))
141 			return(0);
142 		n1 = sfvalue(in1);
143 	}
144 	/* NOT REACHED */
145 }
146 
147 int
148 b_comm(int argc, char *argv[], void* context)
149 {
150 	register int n;
151 	register int mode = C_FILE1|C_FILE2|C_COMMON;
152 	register char *cp;
153 	Sfio_t *f1, *f2;
154 
155 	cmdinit(argc, argv, context, ERROR_CATALOG, 0);
156 	while (n = optget(argv, usage)) switch (n)
157 	{
158  	    case '1':
159 		mode &= ~C_FILE1;
160 		break;
161 	    case '2':
162 		mode &= ~C_FILE2;
163 		break;
164 	    case '3':
165 		mode &= ~C_COMMON;
166 		break;
167 	    case ':':
168 		error(2, "%s",opt_info.arg);
169 		break;
170 	    case '?':
171 		error(ERROR_usage(2), "%s",opt_info.arg);
172 		break;
173 	}
174 	argv += opt_info.index;
175 	argc -= opt_info.index;
176 	if(error_info.errors || argc!=2)
177 		error(ERROR_usage(2),"%s",optusage(NiL));
178 	cp = *argv++;
179 	if(streq(cp,"-"))
180 		f1 = sfstdin;
181 	else if(!(f1 = sfopen(NiL, cp,"r")))
182 		error(ERROR_system(1),"%s: cannot open",cp);
183 	cp = *argv;
184 	if(streq(cp,"-"))
185 		f2 = sfstdin;
186 	else if(!(f2 = sfopen(NiL, cp,"r")))
187 		error(ERROR_system(1),"%s: cannot open",cp);
188 	if(mode)
189 	{
190 		if(comm(f1,f2,sfstdout,mode) < 0)
191 			error(ERROR_system(1)," write error");
192 	}
193 	else if(f1==sfstdin || f2==sfstdin)
194 		sfseek(sfstdin,(Sfoff_t)0,SEEK_END);
195 	if(f1!=sfstdin)
196 		sfclose(f1);
197 	if(f2!=sfstdin)
198 		sfclose(f2);
199 	return(error_info.errors);
200 }
201 
202