1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1992-2012 AT&T Intellectual Property * 5 * and is licensed under the * 6 * Eclipse Public License, Version 1.0 * 7 * by AT&T Intellectual Property * 8 * * 9 * A copy of the License is available at * 10 * http://www.eclipse.org/org/documents/epl-v10.html * 11 * (with md5 checksum b35adb5213ca9657e911e9befb180842) * 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[], Shbltin_t* context) 149 { 150 register int mode = C_FILE1|C_FILE2|C_COMMON; 151 register char *cp; 152 Sfio_t *f1, *f2; 153 154 cmdinit(argc, argv, context, ERROR_CATALOG, 0); 155 for (;;) 156 { 157 switch (optget(argv, usage)) 158 { 159 case '1': 160 mode &= ~C_FILE1; 161 continue; 162 case '2': 163 mode &= ~C_FILE2; 164 continue; 165 case '3': 166 mode &= ~C_COMMON; 167 continue; 168 case ':': 169 error(2, "%s",opt_info.arg); 170 break; 171 case '?': 172 error(ERROR_usage(2), "%s",opt_info.arg); 173 break; 174 } 175 break; 176 } 177 argv += opt_info.index; 178 argc -= opt_info.index; 179 if(error_info.errors || argc!=2) 180 error(ERROR_usage(2),"%s",optusage(NiL)); 181 cp = *argv++; 182 if(streq(cp,"-")) 183 f1 = sfstdin; 184 else if(!(f1 = sfopen(NiL, cp,"r"))) 185 error(ERROR_system(1),"%s: cannot open",cp); 186 cp = *argv; 187 if(streq(cp,"-")) 188 f2 = sfstdin; 189 else if(!(f2 = sfopen(NiL, cp,"r"))) 190 error(ERROR_system(1),"%s: cannot open",cp); 191 if(mode) 192 { 193 if(comm(f1,f2,sfstdout,mode) < 0) 194 error(ERROR_system(1)," write error"); 195 } 196 else if(f1==sfstdin || f2==sfstdin) 197 sfseek(sfstdin,(Sfoff_t)0,SEEK_END); 198 if(f1!=sfstdin) 199 sfclose(f1); 200 if(f2!=sfstdin) 201 sfclose(f2); 202 return error_info.errors; 203 } 204