1da2e3ebdSchin /*********************************************************************** 2da2e3ebdSchin * * 3da2e3ebdSchin * This software is part of the ast package * 4*34f9b3eeSRoland Mainz * Copyright (c) 1992-2009 AT&T Intellectual Property * 5da2e3ebdSchin * and is licensed under the * 6da2e3ebdSchin * Common Public License, Version 1.0 * 77c2fbfb3SApril Chin * by AT&T Intellectual Property * 8da2e3ebdSchin * * 9da2e3ebdSchin * A copy of the License is available at * 10da2e3ebdSchin * http://www.opensource.org/licenses/cpl1.0.txt * 11da2e3ebdSchin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 12da2e3ebdSchin * * 13da2e3ebdSchin * Information and Software Systems Research * 14da2e3ebdSchin * AT&T Research * 15da2e3ebdSchin * Florham Park NJ * 16da2e3ebdSchin * * 17da2e3ebdSchin * Glenn Fowler <gsf@research.att.com> * 18da2e3ebdSchin * David Korn <dgk@research.att.com> * 19da2e3ebdSchin * * 20da2e3ebdSchin ***********************************************************************/ 21da2e3ebdSchin #pragma prototyped 22da2e3ebdSchin /* 23da2e3ebdSchin * David Korn 24da2e3ebdSchin * Glenn Fowler 25da2e3ebdSchin * AT&T Bell Laboratories 26da2e3ebdSchin * 27da2e3ebdSchin * cmp 28da2e3ebdSchin */ 29da2e3ebdSchin 30da2e3ebdSchin static const char usage[] = 31*34f9b3eeSRoland Mainz "[-?\n@(#)$Id: cmp (AT&T Research) 2009-01-05 $\n]" 32da2e3ebdSchin USAGE_LICENSE 33da2e3ebdSchin "[+NAME?cmp - compare two files]" 34da2e3ebdSchin "[+DESCRIPTION?\bcmp\b compares two files \afile1\a and \afile2\a. " 35da2e3ebdSchin "\bcmp\b writes no output if the files are the same. By default, " 36da2e3ebdSchin "if the files differ, the byte and line number at which the " 37da2e3ebdSchin "first difference occurred are written to standard output. Bytes " 38da2e3ebdSchin "and lines are numbered beginning with 1.]" 39da2e3ebdSchin "[+?If \askip1\a or \askip2\a are specified, or the \b-i\b option is " 40da2e3ebdSchin "specified, initial bytes of the corresponding file are skipped " 41da2e3ebdSchin "before beginning the compare. The skip values are in bytes or " 42da2e3ebdSchin "can have a suffix of \bk\b for kilobytes or \bm\b for megabytes.]" 43da2e3ebdSchin "[+?If either \afile1\a or \afiles2\a is \b-\b, \bcmp\b " 44da2e3ebdSchin "uses standard input starting at the current location.]" 45da2e3ebdSchin "[c:print-chars?Writes control characters as a \b^\b followed by a letter of " 46da2e3ebdSchin "the alphabet and precede characters that have the high bit set with " 47da2e3ebdSchin "\bM-\b as with \bcat\b(1).]" 48da2e3ebdSchin "[i:ignore-initial]#[skip:=0?Sets default skip values for the operands " 49da2e3ebdSchin "\askip1\a and \askip2\a to \askip\a.]" 50da2e3ebdSchin "[l:verbose?Write the decimal byte number and the differing bytes (in octal) " 51da2e3ebdSchin "for each difference.]" 52da2e3ebdSchin "[s:quiet|silent?Write nothing for differing files; return non-zero " 53da2e3ebdSchin "exit status only.] ]" 54da2e3ebdSchin "\n" 55da2e3ebdSchin "\nfile1 file2 [skip1 [skip2]]\n" 56da2e3ebdSchin "\n" 57da2e3ebdSchin "[+EXIT STATUS?]{" 58da2e3ebdSchin "[+0?The files or portions compared are identical.]" 59da2e3ebdSchin "[+1?The files are different.]" 60da2e3ebdSchin "[+>1?An error occurred.]" 61da2e3ebdSchin "}" 62da2e3ebdSchin "[+SEE ALSO?\bcomm\b(1), \bdiff\b(1), \bcat\b(1)]" 63da2e3ebdSchin ; 64da2e3ebdSchin 65da2e3ebdSchin 66da2e3ebdSchin #include <cmd.h> 67da2e3ebdSchin #include <ls.h> 68da2e3ebdSchin #include <ctype.h> 69da2e3ebdSchin 70da2e3ebdSchin #define CMP_VERBOSE 1 71da2e3ebdSchin #define CMP_SILENT 2 72da2e3ebdSchin #define CMP_CHARS 4 73da2e3ebdSchin 74da2e3ebdSchin #define cntl(x) (x&037) 75da2e3ebdSchin #define printchar(c) ((c) ^ ('A'-cntl('A'))) 76da2e3ebdSchin 77da2e3ebdSchin static void outchar(Sfio_t *out, register int c, int delim) 78da2e3ebdSchin { 79da2e3ebdSchin if(c&0200) 80da2e3ebdSchin { 81da2e3ebdSchin sfputc(out,'M'); 82da2e3ebdSchin sfputc(out,'-'); 83da2e3ebdSchin c &= ~0200; 84da2e3ebdSchin } 85da2e3ebdSchin else if(!isprint(c)) 86da2e3ebdSchin { 87da2e3ebdSchin sfputc(out,'^'); 88da2e3ebdSchin c = printchar(c); 89da2e3ebdSchin } 90da2e3ebdSchin sfputc(out,c); 91da2e3ebdSchin sfputc(out,delim); 92da2e3ebdSchin } 93da2e3ebdSchin 94da2e3ebdSchin /* 95da2e3ebdSchin * compare two files 96da2e3ebdSchin */ 97da2e3ebdSchin 98da2e3ebdSchin static int 99da2e3ebdSchin cmp(const char* file1, Sfio_t* f1, const char* file2, Sfio_t* f2, int flags) 100da2e3ebdSchin { 101da2e3ebdSchin register int c1; 102da2e3ebdSchin register int c2; 103da2e3ebdSchin register unsigned char* p1 = 0; 104da2e3ebdSchin register unsigned char* p2 = 0; 105da2e3ebdSchin register Sfoff_t lines = 1; 106da2e3ebdSchin register unsigned char* e1 = 0; 107da2e3ebdSchin register unsigned char* e2 = 0; 108da2e3ebdSchin Sfoff_t pos = 0; 109da2e3ebdSchin int ret = 0; 110da2e3ebdSchin unsigned char* last; 111da2e3ebdSchin 112da2e3ebdSchin for (;;) 113da2e3ebdSchin { 114da2e3ebdSchin if ((c1 = e1 - p1) <= 0) 115da2e3ebdSchin { 116da2e3ebdSchin if (!(p1 = (unsigned char*)sfreserve(f1, SF_UNBOUND, 0)) || (c1 = sfvalue(f1)) <= 0) 117da2e3ebdSchin { 118da2e3ebdSchin if ((e2 - p2) > 0 || sfreserve(f2, SF_UNBOUND, 0) && sfvalue(f2) > 0) 119da2e3ebdSchin { 120da2e3ebdSchin ret = 1; 121da2e3ebdSchin if (!(flags & CMP_SILENT)) 122*34f9b3eeSRoland Mainz error(ERROR_exit(1), "EOF on %s", file1); 123da2e3ebdSchin } 124da2e3ebdSchin return(ret); 125da2e3ebdSchin } 126da2e3ebdSchin e1 = p1 + c1; 127da2e3ebdSchin } 128da2e3ebdSchin if ((c2 = e2 - p2) <= 0) 129da2e3ebdSchin { 130da2e3ebdSchin if (!(p2 = (unsigned char*)sfreserve(f2, SF_UNBOUND, 0)) || (c2 = sfvalue(f2)) <= 0) 131da2e3ebdSchin { 132da2e3ebdSchin if (!(flags & CMP_SILENT)) 133*34f9b3eeSRoland Mainz error(ERROR_exit(1), "EOF on %s", file2); 134da2e3ebdSchin return(1); 135da2e3ebdSchin } 136da2e3ebdSchin e2 = p2 + c2; 137da2e3ebdSchin } 138da2e3ebdSchin if (c1 > c2) 139da2e3ebdSchin c1 = c2; 140da2e3ebdSchin pos += c1; 141da2e3ebdSchin if (flags & CMP_SILENT) 142da2e3ebdSchin { 143da2e3ebdSchin if (memcmp(p1, p2, c1)) 144da2e3ebdSchin return(1); 145da2e3ebdSchin p1 += c1; 146da2e3ebdSchin p2 += c1; 147da2e3ebdSchin } 148da2e3ebdSchin else 149da2e3ebdSchin { 150da2e3ebdSchin last = p1 + c1; 151da2e3ebdSchin while (p1 < last) 152da2e3ebdSchin { 153da2e3ebdSchin if ((c1 = *p1++) != *p2++) 154da2e3ebdSchin { 155da2e3ebdSchin if (flags) 156da2e3ebdSchin { 157da2e3ebdSchin ret = 1; 158da2e3ebdSchin if(flags&CMP_CHARS) 159da2e3ebdSchin { 160da2e3ebdSchin sfprintf(sfstdout, "%6I*d ", sizeof(pos), pos - (last - p1)); 161da2e3ebdSchin outchar(sfstdout,c1,' '); 162da2e3ebdSchin outchar(sfstdout,*(p2-1),'\n'); 163da2e3ebdSchin } 164da2e3ebdSchin else 165da2e3ebdSchin sfprintf(sfstdout, "%6I*d %3o %3o\n", sizeof(pos), pos - (last - p1), c1, *(p2 - 1)); 166da2e3ebdSchin } 167da2e3ebdSchin else 168da2e3ebdSchin { 169da2e3ebdSchin sfprintf(sfstdout, "%s %s differ: char %I*d, line %I*u\n", file1, file2, sizeof(pos), pos - (last - p1), sizeof(lines), lines); 170da2e3ebdSchin return(1); 171da2e3ebdSchin } 172da2e3ebdSchin } 173da2e3ebdSchin if (c1 == '\n') 174da2e3ebdSchin lines++; 175da2e3ebdSchin } 176da2e3ebdSchin } 177da2e3ebdSchin } 178da2e3ebdSchin } 179da2e3ebdSchin 180da2e3ebdSchin int 181da2e3ebdSchin b_cmp(int argc, register char** argv, void* context) 182da2e3ebdSchin { 183da2e3ebdSchin char* s; 184da2e3ebdSchin char* e; 185da2e3ebdSchin Sfio_t* f1 = 0; 186da2e3ebdSchin Sfio_t* f2 = 0; 187da2e3ebdSchin char* file1; 188da2e3ebdSchin char* file2; 189da2e3ebdSchin int n; 190da2e3ebdSchin off_t o1 = 0; 191da2e3ebdSchin off_t o2 = 0; 192da2e3ebdSchin struct stat s1; 193da2e3ebdSchin struct stat s2; 194da2e3ebdSchin 195da2e3ebdSchin int flags = 0; 196da2e3ebdSchin 197da2e3ebdSchin NoP(argc); 198da2e3ebdSchin cmdinit(argc, argv, context, ERROR_CATALOG, 0); 199da2e3ebdSchin while (n = optget(argv, usage)) switch (n) 200da2e3ebdSchin { 201da2e3ebdSchin case 'l': 202da2e3ebdSchin flags |= CMP_VERBOSE; 203da2e3ebdSchin break; 204da2e3ebdSchin case 's': 205da2e3ebdSchin flags |= CMP_SILENT; 206da2e3ebdSchin break; 207da2e3ebdSchin case 'c': 208da2e3ebdSchin flags |= CMP_CHARS; 209da2e3ebdSchin break; 210da2e3ebdSchin case 'i': 211da2e3ebdSchin o1 = o2 = opt_info.num; 212da2e3ebdSchin break; 213da2e3ebdSchin case ':': 214da2e3ebdSchin error(2, "%s", opt_info.arg); 215da2e3ebdSchin break; 216da2e3ebdSchin case '?': 217da2e3ebdSchin error(ERROR_usage(2), "%s", opt_info.arg); 218da2e3ebdSchin break; 219da2e3ebdSchin } 220da2e3ebdSchin argv += opt_info.index; 221da2e3ebdSchin if (error_info.errors || !(file1 = *argv++) || !(file2 = *argv++)) 222da2e3ebdSchin error(ERROR_usage(2), "%s", optusage(NiL)); 223da2e3ebdSchin n = 2; 224da2e3ebdSchin if (streq(file1, "-")) 225da2e3ebdSchin f1 = sfstdin; 226da2e3ebdSchin else if (!(f1 = sfopen(NiL, file1, "r"))) 227da2e3ebdSchin { 228da2e3ebdSchin if (!(flags & CMP_SILENT)) 229da2e3ebdSchin error(ERROR_system(0), "%s: cannot open", file1); 230da2e3ebdSchin goto done; 231da2e3ebdSchin } 232da2e3ebdSchin if (streq(file2, "-")) 233da2e3ebdSchin f2 = sfstdin; 234da2e3ebdSchin else if (!(f2 = sfopen(NiL, file2, "r"))) 235da2e3ebdSchin { 236da2e3ebdSchin if (!(flags & CMP_SILENT)) 237da2e3ebdSchin error(ERROR_system(0), "%s: cannot open", file2); 238da2e3ebdSchin goto done; 239da2e3ebdSchin } 240da2e3ebdSchin if (s = *argv++) 241da2e3ebdSchin { 242da2e3ebdSchin o1 = strtol(s, &e, 0); 243da2e3ebdSchin if (*e) 244da2e3ebdSchin { 245da2e3ebdSchin error(ERROR_exit(0), "%s: %s: invalid skip", file1, s); 246da2e3ebdSchin goto done; 247da2e3ebdSchin } 248da2e3ebdSchin if (s = *argv++) 249da2e3ebdSchin { 250da2e3ebdSchin o2 = strtol(s, &e, 0); 251da2e3ebdSchin if (*e) 252da2e3ebdSchin { 253da2e3ebdSchin error(ERROR_exit(0), "%s: %s: invalid skip", file2, s); 254da2e3ebdSchin goto done; 255da2e3ebdSchin } 256da2e3ebdSchin } 257da2e3ebdSchin if (*argv) 258da2e3ebdSchin { 259da2e3ebdSchin error(ERROR_usage(0), "%s", optusage(NiL)); 260da2e3ebdSchin goto done; 261da2e3ebdSchin } 262da2e3ebdSchin } 263da2e3ebdSchin if (o1 && sfseek(f1, o1, SEEK_SET) != o1) 264da2e3ebdSchin { 265da2e3ebdSchin if (!(flags & CMP_SILENT)) 266*34f9b3eeSRoland Mainz error(ERROR_exit(0), "EOF on %s", file1); 267da2e3ebdSchin n = 1; 268da2e3ebdSchin goto done; 269da2e3ebdSchin } 270da2e3ebdSchin if (o2 && sfseek(f2, o2, SEEK_SET) != o2) 271da2e3ebdSchin { 272da2e3ebdSchin if (!(flags & CMP_SILENT)) 273*34f9b3eeSRoland Mainz error(ERROR_exit(0), "EOF on %s", file2); 274da2e3ebdSchin n = 1; 275da2e3ebdSchin goto done; 276da2e3ebdSchin } 277da2e3ebdSchin if (fstat(sffileno(f1), &s1)) 278da2e3ebdSchin error(ERROR_system(0), "%s: cannot stat", file1); 279da2e3ebdSchin else if (fstat(sffileno(f2), &s2)) 280da2e3ebdSchin error(ERROR_system(0), "%s: cannot stat", file1); 281da2e3ebdSchin else if (s1.st_ino == s2.st_ino && s1.st_dev == s2.st_dev && o1 == o2) 282da2e3ebdSchin n = 0; 283*34f9b3eeSRoland Mainz else 284*34f9b3eeSRoland Mainz n = ((flags & CMP_SILENT) && S_ISREG(s1.st_mode) && S_ISREG(s2.st_mode) && (s1.st_size - o1) != (s2.st_size - o2)) ? 1 : cmp(file1, f1, file2, f2, flags); 285da2e3ebdSchin done: 286da2e3ebdSchin if (f1 && f1 != sfstdin) sfclose(f1); 287da2e3ebdSchin if (f2 && f2 != sfstdin) sfclose(f2); 288da2e3ebdSchin return(n); 289da2e3ebdSchin } 290