[BTRFS]
[reactos.git] / base / applications / cmdutils / comp / comp.c
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 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS comp utility
22 * FILE: base/applications/cmdutils/comp/comp.c
23 * PURPOSE: Compares the contents of two files
24 * PROGRAMMERS: Ged Murphy (gedmurphy@gmail.com)
25 * REVISIONS:
26 * GM 25/09/05 Created
27 *
28 */
29
30 #include <windows.h>
31 #include <tchar.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <assert.h>
36
37 #define STRBUF 1024
38
39 /* getline: read a line, return length */
40 INT GetBuff(char *buff, FILE *in)
41 {
42 return fread(buff, 1, STRBUF, in);
43 }
44
45 INT FileSize(FILE * fd)
46 {
47 INT result = -1;
48 if (fseek(fd, 0, SEEK_END) == 0 && (result = ftell(fd)) != -1)
49 {
50 /* Restoring file pointer */
51 rewind(fd);
52 }
53 return result;
54 }
55
56 /* Print program usage */
57 VOID Usage(VOID)
58 {
59 _tprintf(_T("\nCompares the contents of two files or sets of files.\n\n"
60 "COMP [/L] [/A] [data1] [data2]\n\n"
61 " data1 Specifies location and name of first file to compare.\n"
62 " data2 Specifies location and name of second file to compare.\n"
63 " /A Display differences in ASCII characters.\n"
64 " /L Display line numbers for differences.\n"));
65 }
66
67
68 int _tmain (int argc, TCHAR *argv[])
69 {
70 INT i;
71
72 /* File pointers */
73 FILE *fp1 = NULL;
74 FILE *fp2 = NULL;
75
76 INT BufLen1, BufLen2;
77 PTCHAR Buff1 = NULL;
78 PTCHAR Buff2 = NULL;
79 TCHAR File1[_MAX_PATH + 1], // File paths
80 File2[_MAX_PATH + 1];
81 BOOL bAscii = FALSE, // /A switch
82 bLineNos = FALSE; // /L switch
83 UINT LineNumber;
84 UINT Offset;
85 INT FileSizeFile1;
86 INT FileSizeFile2;
87 INT NumberOfOptions = 0;
88 INT FilesOK = 1;
89 INT Status = EXIT_SUCCESS;
90
91 /* Parse command line for options */
92 for (i = 1; i < argc; i++)
93 {
94 if (argv[i][0] == '/')
95 {
96 switch (argv[i][1])
97 {
98 case 'A':
99 bAscii = TRUE;
100 NumberOfOptions++;
101 break;
102
103 case 'L':
104 bLineNos = TRUE;
105 NumberOfOptions++;
106 break;
107
108 case '?':
109 Usage();
110 return EXIT_SUCCESS;
111
112 default:
113 _tprintf(_T("Invalid switch - /%c\n"), argv[i][1]);
114 Usage();
115 return EXIT_FAILURE;
116 }
117 }
118 }
119
120 if (argc - NumberOfOptions == 3)
121 {
122 _tcsncpy(File1, argv[1 + NumberOfOptions], _MAX_PATH);
123 _tcsncpy(File2, argv[2 + NumberOfOptions], _MAX_PATH);
124 }
125 else
126 {
127 _tprintf(_T("Bad command line syntax\n"));
128 return EXIT_FAILURE;
129 }
130
131 Buff1 = (TCHAR *)malloc(STRBUF * sizeof(TCHAR));
132 if (Buff1 == NULL)
133 {
134 _tprintf(_T("Can't get free memory for Buff1\n"));
135 return EXIT_FAILURE;
136 }
137
138 Buff2 = (TCHAR *)malloc(STRBUF * sizeof(TCHAR));
139 if (Buff2 == NULL)
140 {
141 _tprintf(_T("Can't get free memory for Buff2\n"));
142 Status = EXIT_FAILURE;
143 goto Cleanup;
144 }
145
146 if ((fp1 = fopen(File1, "rb")) == NULL)
147 {
148 _tprintf(_T("Can't find/open file: %s\n"), File1);
149 Status = EXIT_FAILURE;
150 goto Cleanup;
151 }
152 if ((fp2 = fopen(File2, "rb")) == NULL)
153 {
154 _tprintf(_T("Can't find/open file: %s\n"), File2);
155 Status = EXIT_FAILURE;
156 goto Cleanup;
157 }
158
159
160 _tprintf(_T("Comparing %s and %s...\n"), File1, File2);
161
162 FileSizeFile1 = FileSize(fp1);
163 if (FileSizeFile1 == -1)
164 {
165 _tprintf(_T("Can't determine size of file: %s\n"), File1);
166 Status = EXIT_FAILURE;
167 goto Cleanup;
168 }
169
170 FileSizeFile2 = FileSize(fp2);
171 if (FileSizeFile2 == -1)
172 {
173 _tprintf(_T("Can't determine size of file: %s\n"), File2);
174 Status = EXIT_FAILURE;
175 goto Cleanup;
176 }
177
178 if (FileSizeFile1 != FileSizeFile2)
179 {
180 _tprintf(_T("Files are different sizes.\n"));
181 Status = EXIT_FAILURE;
182 goto Cleanup;
183 }
184
185 LineNumber = 1;
186 Offset = 0;
187 while (1)
188 {
189 BufLen1 = GetBuff(Buff1, fp1);
190 BufLen2 = GetBuff(Buff2, fp2);
191
192 if (ferror(fp1) || ferror(fp2))
193 {
194 _tprintf(_T("Files read error.\n"));
195 Status = EXIT_FAILURE;
196 goto Cleanup;
197 }
198
199 if (!BufLen1 && !BufLen2)
200 break;
201
202 assert(BufLen1 == BufLen2);
203 for (i = 0; i < BufLen1; i++)
204 {
205 if (Buff1[i] != Buff2[i])
206 {
207 FilesOK = 0;
208
209 /* Reporting here a mismatch */
210 if (bLineNos)
211 {
212 _tprintf(_T("Compare error at LINE %d\n"), LineNumber);
213 }
214 else
215 {
216 _tprintf(_T("Compare error at OFFSET %d\n"), Offset);
217 }
218
219 if (bAscii)
220 {
221 _tprintf(_T("file1 = %c\n"), Buff1[i]);
222 _tprintf(_T("file2 = %c\n"), Buff2[i]);
223 }
224 else
225 {
226 _tprintf(_T("file1 = %X\n"), Buff1[i]);
227 _tprintf(_T("file2 = %X\n"), Buff2[i]);
228 }
229
230 Offset++;
231
232 if (Buff1[i] == '\n')
233 LineNumber++;
234 }
235 }
236 }
237
238 if (FilesOK)
239 _tprintf(_T("Files compare OK\n"));
240
241 Cleanup:
242 if (fp1)
243 fclose(fp1);
244 if (fp2)
245 fclose(fp2);
246
247 if (Buff1)
248 free(Buff1);
249 if (Buff2)
250 free(Buff2);
251
252 return Status;
253 }
254
255 /* EOF */