1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1992-2009 AT&T Intellectual Property * 5 * and is licensed under the * 6 * Common Public License, Version 1.0 * 7 * by AT&T Intellectual Property * 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