"Fossies" - the Fresh Open Source Software Archive 
Member "dirdiff-2.1/filecmp.c" (19 Apr 2005, 7406 Bytes) of package /linux/privat/old/dirdiff-2.1.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "filecmp.c" see the
Fossies "Dox" file reference documentation.
1 /*
2 * Tcl command procedure to compare two files and report whether
3 * they are identical.
4 *
5 * P. Mackerras 17/7/96.
6 *
7 * $Id: filecmp.c,v 1.3 2001/08/15 11:12:44 paulus Exp $
8 */
9 #include <stdio.h>
10 #include <string.h>
11 #include <ctype.h>
12 #include <tcl.h>
13 #include <sys/fcntl.h>
14
15 #define BSIZE 32768
16 #define MAXTAGLEN 512 /* max tag length for sanity, < BSIZE */
17
18 #ifdef NO_MEMMOVE
19 #define memmove(t, f, n) bcopy(f, t, n)
20 #endif
21
22 char *rcs_ignores[] = {
23 "Log", /* must be at index 0! */
24 "Id",
25 "Revision",
26 "Source",
27 "Author",
28 "Date",
29 "State",
30 "Header",
31 NULL
32 };
33
34 char *comment_leaders[] = {
35 " *",
36 "#",
37 NULL
38 };
39
40 /*
41 * See if the text starting at p, for n chars, looks like an RCS tag.
42 * We already know p[0] == '$' and n >= 4.
43 * Return 0 if it isn't a tag, -1 if it looks like a tag but is incomplete,
44 * or the length of the tag.
45 */
46 int
47 tag_length(p, n)
48 char *p;
49 int n;
50 {
51 int i, j, k, l;
52 int maybe;
53 char *t, *cl;
54
55 /* check through list of tags */
56 for (i = 0; (t = rcs_ignores[i]) != NULL; ++i) {
57 for (j = 1; *t != 0; ++j, ++t) {
58 if (j >= n)
59 return -1;
60 if (p[j] != *t)
61 break;
62 }
63 if (*t == 0)
64 break;
65 }
66 if (t == NULL) /* if tag wasn't in list */
67 return 0;
68 if (j >= n) /* if we got to the end of the buffer */
69 return -1;
70 if (p[j] == '$') /* for the \dollar Id\dollar case */
71 return j + 1;
72 if (p[j] != ':') /* tag word must be followed by $ or : */
73 return 0;
74 while (++j < n) { /* if by :, matching $ must appear before \n */
75 if (p[j] == '\n')
76 return 0; /* got \n without $: not a tag */
77 if (p[j] == '$') {
78 if (i != 0) /* got $: if the tag wasn't \dollar Log, */
79 return j + 1; /* that's the end of the tag */
80 /* here we skip lines that start with ' * ' or '# '. */
81 for (;;) {
82 /* skip to \n */
83 while (++j < n && p[j] != '\n')
84 ;
85 if (++j >= n)
86 break;
87 maybe = 0;
88 l = n - j;
89 if (l >= 3 && p[j] == ' ' && p[j+1] == '*' && p[j+2] != '/')
90 continue; /* C-style comment leader */
91 if (p[j] == '#')
92 continue; /* Script comment leader */
93 if (l < 3 && p[j] == ' ' && (l < 2 || p[j] == '*'))
94 maybe = 1; /* may be C-style comment leader */
95 if (maybe)
96 break;
97 return j; /* we've found the end of the tag */
98 }
99 /* Incomplete tag following \dollar Log;
100 the complete tag could be quite long. */
101 if (n >= BSIZE)
102 return 0;
103 return -1;
104 }
105 }
106 if (n > MAXTAGLEN) /* incomplete tag too long: not a tag */
107 return 0;
108 return -1; /* incomplete tag */
109 }
110
111 int rcscmp(char *p1, int *k1p, char *p2, int *k2p, int e1, int e2)
112 {
113 int k1 = *k1p, k2 = *k2p;
114 int i, t1, t2;
115
116 for (;;) {
117 for (i = 0; i < k1 && i < k2; ++i) {
118 if (p1[i] != p2[i])
119 return 0;
120 if (p1[i] == '$')
121 break;
122 }
123 p1 += i;
124 k1 -= i;
125 p2 += i;
126 k2 -= i;
127 /* 4 == strlen("<dollar>Id<dollar>") */
128 if (k1 < 4 && !e1 || k2 < 4 && !e2)
129 break;
130 if (k1 < 4 || k2 < 4) {
131 /* near the end of one or both files */
132 if (k1 != k2 || memcmp(p1, p2, k1) != 0)
133 return 0;
134 k1 = k2 = 0;
135 break;
136 }
137 /* check that the tags look the same (1st 2 chars at least) */
138 if (p1[1] != p2[1] || p1[2] != p2[2])
139 return 0;
140 t1 = tag_length(p1, k1);
141 if (t1 < 0 && e1)
142 t1 = 0;
143 if (t1 != 0) {
144 t2 = tag_length(p2, k2);
145 if (t2 < 0 && e2)
146 t2 = 0;
147 }
148 if (t1 == 0 || t2 == 0) {
149 /* one or other string isn't a tag */
150 p1 += 3;
151 k1 -= 3;
152 p2 += 3;
153 k2 -= 3;
154 continue;
155 }
156 if (t1 < 0 || t2 < 0)
157 break; /* one or other tag is incomplete */
158 p1 += t1;
159 k1 -= t1;
160 p2 += t2;
161 k2 -= t2;
162 if (k1 == 0 || k2 == 0)
163 break;
164 }
165 *k1p = k1;
166 *k2p = k2;
167 return 1;
168 }
169
170 static char bktag[] = "BK Id: ";
171 #define BKTAGLEN 7
172
173 int bkcmp(char *p1, int *k1p, char *p2, int *k2p, int e1, int e2)
174 {
175 int k1 = *k1p, k2 = *k2p;
176 int i, match, t1, t2;
177
178 for (;;) {
179 match = 0;
180 for (i = 0; i < k1 && i < k2; ++i) {
181 if (p1[i] != p2[i])
182 return 0;
183 if (p1[i] == bktag[match]) {
184 if (++match == BKTAGLEN) {
185 ++i;
186 break;
187 }
188 } else {
189 match = (p1[i] == bktag[0]);
190 }
191 }
192 p1 += i;
193 k1 -= i;
194 p2 += i;
195 k2 -= i;
196 if (match < BKTAGLEN) {
197 /* we have run out of one or other buffer */
198 if (k1 == 0 && e1 || k2 == 0 && e2) {
199 if (k1 == k2)
200 break;
201 return 0;
202 }
203 k1 += match;
204 k2 += match;
205 break;
206 }
207 /* found a tag, skip to eol on both files */
208 for (t1 = 0; t1 < k1; ++t1)
209 if (p1[t1] == '\n')
210 break;
211 for (t2 = 0; t2 < k2; ++t2)
212 if (p2[t2] == '\n')
213 break;
214 if (t1 < k1 && t2 < k2) {
215 p1 += t1;
216 k1 -= t1;
217 p2 += t2;
218 k2 -= t2;
219 continue;
220 }
221 /* ran out before eol on one or both files */
222 if (t1 == k1 && e1 || t2 == k2 && e2) {
223 k1 -= t1;
224 k2 -= t2;
225 if (k1 == k2)
226 break;
227 return 0;
228 }
229 /* not at eof on either file */
230 k1 += BKTAGLEN;
231 k2 += BKTAGLEN;
232 break;
233 }
234 *k1p = k1;
235 *k2p = k2;
236 return 1;
237 }
238
239 int
240 FileCmpCmd(clientData, interp, argc, argv)
241 ClientData clientData;
242 Tcl_Interp *interp;
243 int argc;
244 char **argv;
245 {
246 int i, fi;
247 int f1, f2;
248 char *b1, *b2;
249 int n1, n2, same;
250 int k1, k2, t1, t2;
251 int rcsflag, bkflag;
252 int e1, e2;
253
254 fi = 1;
255 rcsflag = 0;
256 bkflag = 0;
257 if (argc > 1 && strcmp(argv[1], "-rcs") == 0) {
258 ++fi;
259 rcsflag = 1;
260 } else if (argc > 1 && strcmp(argv[1], "-bk") == 0) {
261 ++fi;
262 bkflag = 1;
263 }
264 if (argc != fi + 2) {
265 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
266 " ?-rcs? file1 file2\"", (char *) NULL);
267 return TCL_ERROR;
268 }
269
270 if ((f1 = open(argv[fi], O_RDONLY)) == -1) {
271 Tcl_AppendResult(interp, "can't open \"", argv[fi], "\": ",
272 Tcl_PosixError(interp), (char *) NULL);
273 return TCL_ERROR;
274 }
275 if ((f2 = open(argv[fi+1], O_RDONLY)) == -1) {
276 Tcl_AppendResult(interp, "can't open \"", argv[fi+1], "\": ",
277 Tcl_PosixError(interp), (char *) NULL);
278 close(f1);
279 return TCL_ERROR;
280 }
281
282 b1 = (char *) ckalloc(BSIZE);
283 b2 = (char *) ckalloc(BSIZE);
284
285 same = 1;
286
287 k1 = k2 = 0;
288 e1 = e2 = 0;
289
290 for (;;) {
291 /* Here we already have k1 chars in b1 and k2 chars in b2. */
292 if (!e1 && k1 < BSIZE) {
293 n1 = read(f1, b1 + k1, BSIZE - k1);
294 if (n1 < 0) {
295 Tcl_AppendResult(interp, "error reading \"", argv[fi],
296 "\": ", Tcl_PosixError(interp),
297 (char *) NULL);
298 break;
299 }
300 k1 += n1;
301 if (k1 < BSIZE)
302 e1 = 1;
303 }
304 if (!e2 && k2 < BSIZE) {
305 n2 = read(f2, b2 + k2, BSIZE - k2);
306 if (n2 < 0) {
307 Tcl_AppendResult(interp, "error reading \"", argv[fi+1],
308 "\": ", Tcl_PosixError(interp),
309 (char *) NULL);
310 break;
311 }
312 k2 += n2;
313 if (k2 < BSIZE)
314 e2 = 1;
315 }
316 if (k1 == 0 && k2 == 0)
317 break;
318 t1 = k1;
319 t2 = k2;
320 if (rcsflag)
321 same = rcscmp(b1, &k1, b2, &k2, e1, e2);
322 else if (bkflag)
323 same = bkcmp(b1, &k1, b2, &k2, e1, e2);
324 else {
325 if (k1 != k2 || memcmp(b1, b2, k1) != 0)
326 same = 0;
327 k1 = k2 = 0;
328 }
329 if (!same || (e1 && e2))
330 break;
331 if (k1 > 0)
332 memmove(b1, b1 + t1 - k1, k1);
333 if (k2 > 0)
334 memmove(b2, b2 + t2 - k2, k2);
335 }
336
337 close(f1);
338 close(f2);
339 ckfree(b1);
340 ckfree(b2);
341 if (n1 < 0 || n2 < 0)
342 return TCL_ERROR;
343
344 sprintf(interp->result, "%d", same);
345 return TCL_OK;
346 }
347
348 int
349 Filecmp_Init(interp)
350 Tcl_Interp *interp;
351 {
352 Tcl_CreateCommand(interp, "filecmp", FileCmpCmd, NULL, NULL);
353 return TCL_OK;
354 }