1 /* 2 * ReactOS Win32 Applications 3 * Copyright (C) 2005 ReactOS Team 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 18 */ 19 /* 20 * PROJECT: ReactOS Comp utility 21 * COPYRIGHT: See COPYING in the top level directory 22 * FILE: base/applications/cmdutils/comp/comp.c 23 * PURPOSE: Compares the contents of two files 24 * PROGRAMMERS: Ged Murphy (gedmurphy@gmail.com) 25 */ 26 27 #include <stdio.h> 28 #include <stdlib.h> 29 #include <assert.h> 30 31 #define WIN32_NO_STATUS 32 #include <windef.h> 33 #include <winbase.h> 34 35 #include <conutils.h> 36 37 #include "resource.h" 38 39 #define STRBUF 1024 40 41 /* getline: read a line, return length */ 42 INT GetBuff(PBYTE buff, FILE* in) 43 { 44 return fread(buff, sizeof(BYTE), STRBUF, in); 45 } 46 47 INT FileSize(FILE* fd) 48 { 49 INT result = -1; 50 if (fseek(fd, 0, SEEK_END) == 0 && (result = ftell(fd)) != -1) 51 { 52 /* Restoring file pointer */ 53 rewind(fd); 54 } 55 return result; 56 } 57 58 59 int wmain(int argc, WCHAR* argv[]) 60 { 61 INT i; 62 63 /* File pointers */ 64 FILE *fp1 = NULL; 65 FILE *fp2 = NULL; 66 67 INT BufLen1, BufLen2; 68 PBYTE Buff1 = NULL; 69 PBYTE Buff2 = NULL; 70 WCHAR File1[_MAX_PATH + 1], // File paths 71 File2[_MAX_PATH + 1]; 72 BOOL bAscii = FALSE, // /A switch 73 bLineNos = FALSE; // /L switch 74 UINT LineNumber; 75 UINT Offset; 76 INT FileSizeFile1; 77 INT FileSizeFile2; 78 INT NumberOfOptions = 0; 79 INT FilesOK = 1; 80 INT Status = EXIT_SUCCESS; 81 82 /* Initialize the Console Standard Streams */ 83 ConInitStdStreams(); 84 85 /* Parse command line for options */ 86 for (i = 1; i < argc; i++) 87 { 88 if (argv[i][0] == L'/') 89 { 90 switch (towlower(argv[i][1])) 91 { 92 case L'a': 93 bAscii = TRUE; 94 NumberOfOptions++; 95 break; 96 97 case L'l': 98 bLineNos = TRUE; 99 NumberOfOptions++; 100 break; 101 102 case L'?': 103 ConResPuts(StdOut, IDS_HELP); 104 return EXIT_SUCCESS; 105 106 default: 107 ConResPrintf(StdErr, IDS_INVALIDSWITCH, argv[i][1]); 108 ConResPuts(StdOut, IDS_HELP); 109 return EXIT_FAILURE; 110 } 111 } 112 } 113 114 if (argc - NumberOfOptions == 3) 115 { 116 wcsncpy(File1, argv[1 + NumberOfOptions], _MAX_PATH); 117 wcsncpy(File2, argv[2 + NumberOfOptions], _MAX_PATH); 118 } 119 else 120 { 121 ConResPuts(StdErr, IDS_BADSYNTAX); 122 return EXIT_FAILURE; 123 } 124 125 Buff1 = (PBYTE)malloc(STRBUF); 126 if (Buff1 == NULL) 127 { 128 ConPuts(StdErr, L"Can't get free memory for Buff1\n"); 129 Status = EXIT_FAILURE; 130 goto Cleanup; 131 } 132 133 Buff2 = (PBYTE)malloc(STRBUF); 134 if (Buff2 == NULL) 135 { 136 ConPuts(StdErr, L"Can't get free memory for Buff2\n"); 137 Status = EXIT_FAILURE; 138 goto Cleanup; 139 } 140 141 if ((fp1 = _wfopen(File1, L"rb")) == NULL) 142 { 143 ConResPrintf(StdErr, IDS_FILEERROR, File1); 144 Status = EXIT_FAILURE; 145 goto Cleanup; 146 } 147 if ((fp2 = _wfopen(File2, L"rb")) == NULL) 148 { 149 ConResPrintf(StdErr, IDS_FILEERROR, File2); 150 Status = EXIT_FAILURE; 151 goto Cleanup; 152 } 153 154 ConResPrintf(StdOut, IDS_COMPARING, File1, File2); 155 156 FileSizeFile1 = FileSize(fp1); 157 if (FileSizeFile1 == -1) 158 { 159 ConResPrintf(StdErr, IDS_FILESIZEERROR, File1); 160 Status = EXIT_FAILURE; 161 goto Cleanup; 162 } 163 164 FileSizeFile2 = FileSize(fp2); 165 if (FileSizeFile2 == -1) 166 { 167 ConResPrintf(StdErr, IDS_FILESIZEERROR, File2); 168 Status = EXIT_FAILURE; 169 goto Cleanup; 170 } 171 172 if (FileSizeFile1 != FileSizeFile2) 173 { 174 ConResPuts(StdOut, IDS_SIZEDIFFERS); 175 Status = EXIT_FAILURE; 176 goto Cleanup; 177 } 178 179 LineNumber = 1; 180 Offset = 0; 181 while (1) 182 { 183 BufLen1 = GetBuff(Buff1, fp1); 184 BufLen2 = GetBuff(Buff2, fp2); 185 186 if (ferror(fp1) || ferror(fp2)) 187 { 188 ConResPuts(StdErr, IDS_READERROR); 189 Status = EXIT_FAILURE; 190 goto Cleanup; 191 } 192 193 if (!BufLen1 && !BufLen2) 194 break; 195 196 assert(BufLen1 == BufLen2); 197 for (i = 0; i < BufLen1; i++) 198 { 199 if (Buff1[i] != Buff2[i]) 200 { 201 FilesOK = 0; 202 203 /* Reporting here a mismatch */ 204 if (bLineNos) 205 ConResPrintf(StdOut, IDS_MISMATCHLINE, LineNumber); 206 else 207 ConResPrintf(StdOut, IDS_MISMATCHOFFSET, Offset); 208 209 if (bAscii) 210 { 211 ConResPrintf(StdOut, IDS_ASCIIDIFF, 1, Buff1[i]); 212 ConResPrintf(StdOut, IDS_ASCIIDIFF, 2, Buff2[i]); 213 } 214 else 215 { 216 ConResPrintf(StdOut, IDS_HEXADECIMALDIFF, 1, Buff1[i]); 217 ConResPrintf(StdOut, IDS_HEXADECIMALDIFF, 2, Buff2[i]); 218 } 219 } 220 221 Offset++; 222 223 if (Buff1[i] == '\n') 224 LineNumber++; 225 } 226 } 227 228 if (FilesOK) 229 ConResPuts(StdOut, IDS_MATCH); 230 231 Cleanup: 232 if (fp2) 233 fclose(fp2); 234 if (fp1) 235 fclose(fp1); 236 237 if (Buff2) 238 free(Buff2); 239 if (Buff1) 240 free(Buff1); 241 242 return Status; 243 } 244 245 /* EOF */ 246