source: trunk/dll/grep.c@ 1880

Last change on this file since 1880 was 1880, checked in by Gregg Young, 10 years ago

Remove dead code and comments from remaining c files. #if 0 and #if NEVER were not addressed

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 45.0 KB
Line 
1
2/***********************************************************************
3
4 $Id: grep.c 1880 2015-10-12 18:26:16Z gyoung $
5
6 grep tools
7
8 Copyright (c) 1993-98 M. Kimes
9 Copyright (c) 2001, 2014 Steven H. Levine
10
11 12 Feb 03 SHL InsertGrepFile: standardize EA math
12 12 Feb 03 SHL doonefile: standardize EA math
13 25 May 05 SHL Rework for ULONGLONG
14 25 May 05 SHL Rework for FillInRecordFromFFB
15 06 Jun 05 SHL Drop unused code
16 24 Oct 05 SHL dononefile: do not free EA list twice
17 22 Jul 06 SHL Use Runtime_Error
18 26 Jul 06 SHL Check more run time errors
19 19 Oct 06 SHL Correct . and .. detect
20 03 Nov 06 SHL Count thread usage
21 03 Aug 07 GKY Enlarged and made setable everywhere Findbuf (speed file loading)
22 06 Aug 07 GKY Reduce DosSleep times (ticket 148)
23 13 Aug 07 SHL Avoid pointer errors; sanitize code
24 13 Aug 07 SHL Move #pragma alloc_text to end for OpenWatcom compat
25 15 Aug 07 SHL Use FilesToGet directly
26 26 Aug 07 GKY Improved performance of FillDups
27 26 Aug 07 GKY DosSleep(1) in loops changed to (0)
28 21 Sep 07 GKY Fix trap on search that includes filenames that exceed maxpath
29 07 Feb 08 SHL Use ITIMER_DESC to control sleeps and reporting
30 29 Feb 08 GKY Use xfree where appropriate
31 29 Nov 08 GKY Remove or replace with a mutex semaphore DosEnterCriSec where appropriate.
32 07 Feb 09 GKY Allow user to turn off alert and/or error beeps in settings notebook.
33 08 Mar 09 GKY Additional strings move to String Table
34 28 Jun 09 GKY Added AddBackslashToPath() to remove repeatative code.
35 17 JAN 10 GKY Changes to get working with Watcom 1.9 Beta (1/16/10).
36 Mostly cast CHAR CONSTANT * as CHAR *.
37 29 May 10 GKY Suppress ERROR_FILENAME_EXCED_RANGE error because of problem with NTFS
38 30 May 11 GKY Fixed potential trap caused by passing a nonexistant pci to FillInRecordFromFFB
39 in DoInsertion because pci is limited to 65535 files. (nRecord is a USHORT)
40 SHL's single loop fix.
41 05 Aug 12 GKY Replace SleepIfNeeded with IdleIfNeeded to improve IU response during long searches; it
42 will switch between normal and idle priority and back.
43 05 Aug 12 GKY Always sort "Find Dups" by filename in the collector.
44 08 Feb 14 SHL Support Ignore SVN option
45 28 Jun 14 GKY Fix errors identified with CPPCheck
46
47***********************************************************************/
48
49#include <stdlib.h>
50#include <string.h>
51#include <ctype.h>
52#include <share.h>
53#include <limits.h>
54
55#define INCL_DOS
56#define INCL_DOSERRORS
57#define INCL_WIN
58#define INCL_LONGLONG
59
60#include "fm3dll.h"
61#include "fm3dll2.h" // #define's for UM_*, control id's, etc.
62#include "notebook.h" // Data declaration(s)
63#include "newview.h" // Data declarations
64#include "fm3str.h"
65#include "grep.h"
66#include "pathutil.h" // BldFullPathName
67#include "filldir.h" // FillInRecordFromFFB
68#include "makelist.h" // AddToList
69#include "errutil.h" // Dos_Error...
70#include "strutil.h" // GetPString
71#include "tmrsvcs.h" // ITIMER_DESC
72#include "common.h" // DecrThreadUsage, IncrThreadUsage
73#include "valid.h" // MakeFullName
74#include "literal.h" // wildcard
75#include "wrappers.h" // xDosFindNext
76#include "eas.h" // Free_FEAList
77#include "stristr.h" // findstring
78#include "misc.h" // PostMsg
79#include "fortify.h"
80#include "init.h" // Golbal semaphore
81#include "sortcnr.h" // SortCollectorCnr
82#include "collect.h"
83
84static VOID DoAllSubdirs(GREP *grep,
85 CHAR *searchPath,
86 BOOL recursing,
87 char **fileMasks,
88 UINT numFileMasks,
89 ITIMER_DESC *pitdSleep,
90 ITIMER_DESC *pitdReport);
91static INT DoMatchingFiles(GREP *grep,
92 CHAR *path,
93 CHAR **fileMasks,
94 UINT numFileMasks,
95 ITIMER_DESC *pitdSleep,
96 ITIMER_DESC *pitdReport);
97static BOOL DoOneFile(GREP *grep,
98 CHAR *fileName,
99 FILEFINDBUF4L *pffb,
100 ITIMER_DESC *pitdSleep,
101 ITIMER_DESC *pitdReport);
102static BOOL DoInsertion(GREP *grep,
103 ITIMER_DESC *pitdSleep,
104 ITIMER_DESC *pitdReport);
105static BOOL InsertDupe(GREP *grep, CHAR *dir, FILEFINDBUF4L *pffb);
106static VOID FillDupes(GREP *grep,
107 ITIMER_DESC *pitdSleep,
108 ITIMER_DESC *pitdReport);
109
110static VOID FreeDupes(GREP *grep);
111
112#define GREPCHARS "*?[] \\"
113
114#define isleap(year) ((((year%4)==0) && ((year%100)!=0)) || \
115 ((year%400)==0))
116
117// Data definitions
118#pragma data_seg(DATA2)
119static PSZ pszSrcFile = __FILE__;
120static INT monthdays[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
121
122#pragma data_seg(GLOBAL1)
123HWND hwndStatus;
124
125
126ULONG SecsSince1980(FDATE *date, FTIME *time)
127{
128 ULONG total = 0;
129 UINT x;
130
131 for (x = 1980; x < date->year + 1980; x++) {
132 if (isleap(x))
133 total += (366 * (24 * 60 * 60));
134 else
135 total += (365 * (24 * 60 * 60));
136 }
137 for (x = 1; x < date->month; x++) {
138 if (x == 2 && isleap(date->year + 1980))
139 total += (29 * (24 * 60 * 60));
140 else
141 total += ((long)monthdays[x - 1] * (24 * 60 * 60));
142 }
143 total += (((long)date->day - 1) * (24 * 60 * 60));
144 total += ((long)time->hours * (60 * 60));
145 total += ((long)time->minutes * 60);
146 total += ((long)time->twosecs * 2);
147 return total;
148}
149
150/**
151 * this function originally from C_ECHO's Snippets -- modified
152 * brute force methodology
153 */
154
155static BOOL m_match(CHAR *string, CHAR *pattern, BOOL absolute, BOOL ignore,
156 LONG len)
157{
158 // return TRUE if pattern found in string
159 register CHAR *tn = pattern;
160 register LONG len2 = 0;
161 LONG lastlen = 0;
162 CHAR lo, hi;
163
164 if (len && string && pattern) {
165 if (absolute) // no pattern matching
166 return (findstring(pattern, strlen(pattern), string, len,
167 (ignore == FALSE)) != NULL);
168
169 while (*tn && len2 < len) {
170 switch (*tn) {
171 case ' ':
172 while (*tn == ' ')
173 tn++;
174 while (len2 < len && isspace(string[len2]))
175 len2++;
176 break;
177
178 case '*':
179 while (*tn == '*' || *tn == '?')
180 tn++;
181 if (!*tn)
182 return TRUE;
183 if (ignore) {
184 while (len2 < len && string[len2] != *tn)
185 len2++;
186 }
187 else {
188 while (len2 < len && toupper(string[len2] != *tn))
189 len2++;
190 }
191 break;
192
193 case '[':
194 tn++;
195 if (!*tn)
196 return FALSE;
197 lo = *tn;
198 tn++;
199 if (*tn != '-')
200 return FALSE;
201 tn++;
202 if (!*tn)
203 return FALSE;
204 hi = *tn;
205 tn++;
206 if (*tn != ']')
207 return FALSE;
208 tn++;
209 if (ignore) {
210 if ((toupper(string[len2]) >= toupper(lo)) &&
211 (toupper(string[len2]) <= toupper(hi)))
212 len2++;
213 else {
214 tn = pattern;
215 len2 = lastlen = lastlen + 1;
216 }
217 }
218 else {
219 if ((string[len2] >= lo) && (string[len2] <= hi))
220 len2++;
221 else {
222 tn = pattern;
223 len2 = lastlen = lastlen + 1;
224 }
225 }
226 break;
227
228 case '?':
229 tn++;
230 len2++;
231 break;
232
233 case '\\':
234 tn++;
235 if (!*tn)
236 return FALSE;
237 // else intentional fallthru
238 default:
239 if (ignore) {
240 if (toupper(*tn) == toupper(string[len2])) {
241 tn++;
242 len2++;
243 }
244 else {
245 tn = pattern;
246 len2 = lastlen = lastlen + 1;
247 }
248 }
249 else {
250 if (*tn == string[len2]) {
251 tn++;
252 len2++;
253 }
254 else {
255 tn = pattern;
256 len2 = lastlen = lastlen + 1;
257 }
258 }
259 break;
260 }
261 }
262 while (*tn == '*')
263 tn++;
264
265 if (!*tn)
266 return TRUE;
267 }
268 return FALSE;
269}
270
271static BOOL match(CHAR *string, CHAR *patterns, BOOL absolute, BOOL ignore,
272 LONG len, ULONG numlines, CHAR *matched, BOOL matchall)
273{
274 BOOL ret = FALSE;
275 register CHAR *p;
276 register ULONG x = 0;
277
278 p = patterns;
279 while (!ret && *p) {
280 ret = m_match(string, p, absolute, ignore, len);
281 if (matchall && ret)
282 break;
283 if (matched && ret && x < numlines)
284 matched[x] = 1;
285 p += strlen(p); // check each pattern in 0-terminated list
286 p++;
287 x++;
288 }
289 return ret;
290}
291
292VOID GrepThread(VOID *arg)
293{
294 HAB ghab;
295 HMQ ghmq;
296 GREP grep;
297 UINT x;
298 UINT numFileMasks;
299 static CHAR *fileMasks[512]; // 06 Feb 08 SHL FIXME to not be static
300 CHAR *p, *pp, searchPath[CCHMAXPATH * 2];
301
302 ITIMER_DESC itdSleep = { 0 }; // 06 Feb 08 SHL
303 ITIMER_DESC itdReport = { 0 };
304
305 if (!arg) {
306 Runtime_Error(pszSrcFile, __LINE__, NULL);
307 return;
308 }
309
310# ifdef FORTIFY
311 Fortify_EnterScope();
312# endif
313 grep = *(GREP *)arg;
314 *grep.stopflag = 0; // reset thread-killing flag
315 DosError(FERR_DISABLEHARDERR);
316 priority_normal();
317
318 ghab = WinInitialize(0);
319 if (ghab) {
320 grep.ghab = ghab;
321 ghmq = WinCreateMsgQueue(ghab, 0);
322 if (ghmq) {
323 WinCancelShutdown(ghmq, TRUE);
324 IncrThreadUsage();
325 // hwndStatus does not exist for applet
326 WinSetWindowText(hwndStatus ? hwndStatus : grep.hwndCurFile,
327 (CHAR *) GetPString(grep.finddupes ? IDS_GREPDUPETEXT :
328 IDS_GREPSCANTEXT));
329
330 pp = grep.searchPattern;
331 while (*pp) {
332 if (!grep.absFlag) {
333 p = GREPCHARS; // see if any sense in pattern matching
334 while (*p) {
335 if (strchr(pp, *p))
336 break;
337 p++;
338 }
339 if (!*p) // nope, turn it off
340 grep.absFlag = TRUE;
341 }
342 pp = pp + strlen(pp) + 1;
343 }
344
345 grep.attrFile &= (~FILE_DIRECTORY);
346 grep.antiattr &= (~FILE_DIRECTORY);
347 if (grep.antiattr & FILE_READONLY)
348 grep.antiattr |= MUST_HAVE_READONLY;
349 if (grep.antiattr & FILE_HIDDEN)
350 grep.antiattr |= MUST_HAVE_HIDDEN;
351 if (grep.antiattr & FILE_SYSTEM)
352 grep.antiattr |= MUST_HAVE_SYSTEM;
353 if (grep.antiattr & FILE_ARCHIVED)
354 grep.antiattr |= MUST_HAVE_ARCHIVED;
355
356 grep.anyexcludes = FALSE;
357 numFileMasks = 0;
358 fileMasks[numFileMasks++] = strtok(grep.fileMasks, ";");
359
360 while ((fileMasks[numFileMasks] = strtok(NULL, ";")) != NULL && numFileMasks < 511) {
361 if (*fileMasks[numFileMasks] == '/')
362 grep.anyexcludes = TRUE;
363 numFileMasks++;
364 }
365
366 InitITimer(&itdSleep, 100); // Sleep every 100 mSec (was 500) GKY 8/11/13
367 InitITimer(&itdReport, 2000); // Report every 2 sec
368
369 // loop through search masks
370 for (x = 0; x < numFileMasks; x++) {
371
372 // Ignore exclude masks here
373 if (*fileMasks[x] == '/')
374 goto ExcludeSkip;
375
376 // Split directory pathname from mask
377 p = (char *)(fileMasks[x] + (strlen(fileMasks[x]) - 1));
378 while (*p != '\\' && *p != ':' && p != fileMasks[x])
379 --p;
380
381 if (p == fileMasks[x]) { // no path
382 strcpy(searchPath, grep.curdir);
383 strncpy(grep.fileMask, fileMasks[x], CCHMAXPATH);
384 grep.fileMask[CCHMAXPATH - 1] = 0;
385 }
386 else { // got to deal with a path
387 if (*p == ':') { // just a drive, start in root dir
388 *p = 0;
389 p++;
390 strncpy(searchPath, fileMasks[x], CCHMAXPATH - 2);
391 searchPath[CCHMAXPATH - 3] = 0;
392 strcat(searchPath, ":\\");
393 strcpy(grep.fileMask, p);
394 }
395 if (*p == '\\') {
396 // got a 'full' path
397 CHAR temp;
398
399 p++;
400 temp = *p; // Save for restore
401 *p = 0; // Chop after backslash
402 strncpy(searchPath, fileMasks[x], CCHMAXPATH);
403 searchPath[CCHMAXPATH - 1] = 0;
404 *p = temp;
405 strcpy(grep.fileMask, p);
406 }
407 if (!*grep.fileMask)
408 strcpy(grep.fileMask, "*");
409 }
410 if (*grep.stopflag)
411 break;
412 // do top level directory
413 DoMatchingFiles(&grep, searchPath, fileMasks, numFileMasks, &itdSleep, &itdReport);
414 // Recurse subdirectories if requested
415 if (grep.dirFlag)
416 DoAllSubdirs(&grep, searchPath, FALSE, fileMasks, numFileMasks, &itdSleep, &itdReport);
417
418 ExcludeSkip:
419 if (*grep.stopflag)
420 break;
421 if (WinIsWindow(grep.ghab, grep.hwndFiles))
422 DoInsertion(&grep, &itdSleep, &itdReport); // insert any remaining objects
423 } // for
424
425 if (WinIsWindow(grep.ghab, grep.hwndFiles))
426 DoInsertion(&grep, &itdSleep, &itdReport); // insert any remaining objects
427
428 if (WinIsWindow(grep.ghab, grep.hwndFiles) &&
429 grep.finddupes &&
430 !*grep.stopflag)
431 {
432 FillDupes(&grep, &itdSleep, &itdReport);
433 CollectorsortFlags = 0;
434 CollectorsortFlags |= SORT_FILENAME;
435 WinSendMsg(grep.hwndFiles, CM_SORTRECORD, MPFROMP(SortCollectorCnr),
436 MPFROMLONG(CollectorsortFlags));
437 SaySort(WinWindowFromID(WinQueryWindow(grep.hwndFiles, QW_PARENT),
438 DIR_SORT), CollectorsortFlags, FALSE);
439 }
440 if (!PostMsg(grep.hwndFiles, UM_CONTAINER_FILLED, MPVOID, MPVOID)) // tell window we're done
441 WinSendMsg(grep.hwndFiles, UM_CONTAINER_FILLED, MPVOID, MPVOID);
442 WinDestroyMsgQueue(ghmq);
443 }
444 DecrThreadUsage();
445 WinTerminate(ghab);
446 }
447 if (!ghab || !ghmq)
448 WinPostMsg(grep.hwndFiles, UM_CONTAINER_FILLED, MPVOID, MPVOID);
449 if (grep.dupehead)
450 FreeDupes(&grep);
451 if (grep.numlines && grep.matched) {
452 free(grep.matched);
453 }
454 // 07 Feb 08 SHL FIXME to free grep here when not static
455# ifdef FORTIFY
456 Fortify_LeaveScope();
457# endif
458 DosPostEventSem(CompactSem);
459}
460
461static BOOL IsExcluded(CHAR *name, CHAR **fileMasks, UINT numFileMasks)
462{
463 UINT x;
464 CHAR *n;
465
466 n = strrchr(name, '\\');
467 if (!n)
468 n = strrchr(name, ':');
469 if (n)
470 n++;
471 else
472 n = name;
473 for (x = 0; x < numFileMasks; x++) {
474 if (*fileMasks[x] == '/' &&
475 wildcard((strchr(fileMasks[x], '\\') ||
476 strchr(fileMasks[x], ':')) ? name : n, fileMasks[x] + 1, FALSE))
477 return TRUE;
478 }
479 return FALSE;
480}
481
482/**
483 * Recurse though subdirectories selecting files
484 */
485
486static VOID DoAllSubdirs(GREP *grep,
487 CHAR *searchPath,
488 BOOL recursing,
489 CHAR **fileMasks,
490 UINT numFileMasks,
491 ITIMER_DESC *pitdSleep,
492 ITIMER_DESC *pitdReport)
493{
494 FILEFINDBUF4 ffb;
495 HDIR findHandle = HDIR_CREATE;
496 ULONG ulFindCnt = 1;
497 CHAR *p = NULL;
498
499 // Append wildcard mask to directory pathname
500 AddBackslashToPath(searchPath);
501 strcat(searchPath, "*");
502 DosError(FERR_DISABLEHARDERR);
503 // Find first directory
504 if (!DosFindFirst(searchPath,
505 &findHandle,
506 (MUST_HAVE_DIRECTORY | FILE_ARCHIVED | FILE_SYSTEM |
507 FILE_HIDDEN | FILE_READONLY),
508 &ffb,
509 sizeof(ffb),
510 &ulFindCnt,
511 FIL_QUERYEASIZE))
512 {
513 // Point p at appended wildcard pattern to speed up pathname build
514 p = strrchr(searchPath, '\\');
515 if (p)
516 p++;
517 else
518 p = searchPath;
519 do { // Process each directory that matches the mask
520 int skip;
521 if (*grep->stopflag)
522 break;
523 // 2014-02-08 SHL
524 // Skip . and ..
525 skip = ffb.achName[0] == '.' &&
526 (ffb.achName[1] == 0 ||
527 (ffb.achName[1] == '.' && ffb.achName[2] == 0));
528 if (!skip && grep->ignoreSVN) {
529 // Skip version control meta data directories
530 skip = stricmp(ffb.achName, ".svn") == 0 ||
531 stricmp(ffb.achName, ".git") == 0 ||
532 stricmp(ffb.achName, ".hg") == 0 ||
533 stricmp(ffb.achName, "CVS") == 0;
534 }
535 if (!skip) {
536 strcpy(p, ffb.achName); // Build full directory pathname
537 skip = grep->anyexcludes && IsExcluded(searchPath, fileMasks, numFileMasks);
538 }
539 if (!skip) {
540 // Directory is selected
541 // 07 Feb 08 SHL
542 if (IsITimerExpired(pitdReport)) {
543 if (!hwndStatus)
544 WinSetWindowText(grep->hwndCurFile, searchPath);
545 else if (WinQueryFocus(HWND_DESKTOP) == grep->hwndFiles) {
546 CHAR s[CCHMAXPATH + 64];
547 sprintf(s, "%s %s", GetPString(IDS_SCANNINGTEXT), searchPath);
548 WinSetWindowText(hwndStatus, s);
549 }
550 }
551 // Select files from directory
552 DoMatchingFiles(grep, searchPath, fileMasks, numFileMasks, pitdSleep, pitdReport);
553 // 07 Feb 08 SHL
554 if (IsITimerExpired(pitdReport)) {
555 priority_normal();
556 if (!hwndStatus)
557 WinSetWindowText(grep->hwndCurFile, searchPath);
558 else {
559 if (WinQueryFocus(HWND_DESKTOP) == grep->hwndFiles) {
560 CHAR s[CCHMAXPATH + 64];
561 sprintf(s, "%s %s", GetPString(IDS_SCANNINGTEXT), searchPath);
562 WinSetWindowText(hwndStatus, s);
563 }
564 };
565 }
566 // Recurse
567 DoAllSubdirs(grep, searchPath, TRUE, fileMasks, numFileMasks, pitdSleep, pitdReport);
568 } // if !skip
569 ulFindCnt = 1;
570 // Get next directory
571 } while (!DosFindNext(findHandle,
572 &ffb,
573 sizeof(ffb),
574 &ulFindCnt));
575 DosFindClose(findHandle);
576 } // if at least one directory
577 if (p) // Restore orginal directory pathname
578 *p = 0;
579}
580
581/**
582 * Select files matching wildcard masks in single directory
583 */
584
585static INT DoMatchingFiles(GREP *grep,
586 CHAR *path,
587 CHAR **fileMasks,
588 UINT numFileMasks,
589 ITIMER_DESC *pitdSleep,
590 ITIMER_DESC *pitdReport)
591{
592 PFILEFINDBUF4L pffbArray;
593 PFILEFINDBUF4L pffbFile;
594 ULONG x;
595 HDIR findHandle = HDIR_CREATE;
596 ULONG ulFindCnt;
597 CHAR szFindPath[CCHMAXPATH];
598 PSZ p;
599 APIRET rc;
600 ULONG ulBufBytes = FilesToGet * sizeof(FILEFINDBUF4L);
601 static BOOL fDone;
602
603 pffbArray = xmalloc(ulBufBytes, pszSrcFile, __LINE__);
604 if (!pffbArray)
605 return 0;
606
607 BldFullPathName(szFindPath, path, grep->fileMask);
608
609 MakeFullName(szFindPath);
610
611 // Point p at wildcard mask to speed up pathname build
612 p = strrchr(szFindPath, '\\');
613 if (p)
614 p++;
615 else
616 p = szFindPath;
617
618 // Step through matching files
619 DosError(FERR_DISABLEHARDERR);
620 ulFindCnt = FilesToGet;
621 rc = xDosFindFirst(szFindPath,
622 &findHandle,
623 FILE_NORMAL | grep->attrFile | grep->antiattr,
624 pffbArray,
625 ulBufBytes,
626 &ulFindCnt,
627 FIL_QUERYEASIZEL);
628 if (!rc) {
629 do {
630 // Process each file that matches the mask
631 pffbFile = pffbArray;
632 for (x = 0; x < ulFindCnt; x++) {
633 if (*grep->stopflag)
634 break;
635 // 2014-02-08 SHL FIXME to know if really need to skip . and .. here
636 // We should only be selecting files
637 if (*pffbFile->achName != '.' ||
638 (pffbFile->achName[1] && pffbFile->achName[1] != '.')) {
639 strcpy(p, pffbFile->achName); // build full file pathname
640 if (strlen(szFindPath) > CCHMAXPATH){
641 // Complain if pathnames exceeds max
642 DosFindClose(findHandle);
643 if (!fDone) {
644 fDone = TRUE;
645 saymsg(MB_OK | MB_ICONASTERISK,
646 HWND_DESKTOP,
647 GetPString(IDS_WARNINGTEXT),
648 GetPString(IDS_LENGTHEXCEEDSMAXPATHTEXT));
649 }
650 return 1;
651 }
652
653 // 07 Feb 08 SHL
654 if (IsITimerExpired(pitdReport)) {
655 if (!hwndStatus)
656 WinSetWindowText(grep->hwndCurFile, szFindPath);
657 else {
658 if (WinQueryFocus(HWND_DESKTOP) == grep->hwndFiles) {
659 CHAR s[CCHMAXPATH + 64];
660 sprintf(s, "%s %s", GetPString(IDS_SCANNINGTEXT), szFindPath);
661 WinSetWindowText(hwndStatus, s);
662 }
663 }
664 }
665
666 if (!grep->anyexcludes || !IsExcluded(szFindPath, fileMasks, numFileMasks)) {
667 // File selected
668 if (!grep->finddupes)
669 DoOneFile(grep, szFindPath, pffbFile, pitdSleep, pitdReport);
670 else if (!InsertDupe(grep, szFindPath, pffbFile)) {
671 DosFindClose(findHandle);
672 free(pffbArray);
673# ifdef FORTIFY
674 Fortify_LeaveScope();
675# endif
676 return 1;
677 }
678 }
679 }
680 if (!pffbFile->oNextEntryOffset)
681 break;
682 pffbFile = (PFILEFINDBUF4L)((PBYTE)pffbFile + pffbFile->oNextEntryOffset);
683 } // for
684 if (*grep->stopflag)
685 break;
686 IdleIfNeeded(pitdSleep, 30);
687 ulFindCnt = FilesToGet;
688 // Next file
689 rc = xDosFindNext(findHandle, pffbArray, ulBufBytes, &ulFindCnt, FIL_QUERYEASIZEL);
690 } while (!rc);
691
692 DosFindClose(findHandle);
693 } // if at least one file
694
695 if (rc && rc != ERROR_NO_MORE_FILES) {
696 if (rc == ERROR_FILENAME_EXCED_RANGE) {
697 CHAR FileSystem[CCHMAXPATH];
698
699 CheckDrive(toupper(*szFindPath), FileSystem, NULL);
700 if (strcmp(FileSystem, NTFS))
701 Dos_Error(MB_ENTER, rc, HWND_DESKTOP, pszSrcFile, __LINE__,
702 GetPString(IDS_CANTFINDDIRTEXT), szFindPath);
703 }
704 else
705 Dos_Error(MB_ENTER, rc, HWND_DESKTOP, pszSrcFile, __LINE__,
706 GetPString(IDS_CANTFINDDIRTEXT), szFindPath);
707 }
708
709 free(pffbArray);
710# ifdef FORTIFY
711 Fortify_LeaveScope();
712# endif
713 return 0;
714}
715
716static VOID freegreplist(GREP *grep)
717{
718 UINT x;
719
720 if (grep) {
721 if (grep->insertffb) {
722 for (x = 0; grep->insertffb[x]; x++) {
723 free(grep->insertffb[x]);
724 }
725 free(grep->insertffb);
726 }
727 if (grep->dir) {
728 for (x = 0; grep->dir[x]; x++) {
729 free(grep->dir[x]);
730 }
731 free(grep->dir);
732 }
733 grep->dir = NULL;
734 grep->insertffb = NULL;
735 grep->toinsert = 0L;
736 grep->insertedbytes = 0L;
737# ifdef FORTIFY
738 Fortify_LeaveScope();
739# endif
740 }
741}
742
743/**
744 * Insert one or more records into container
745 */
746
747static BOOL DoInsertion(GREP *grep,
748 ITIMER_DESC *pitdSleep,
749 ITIMER_DESC *pitdReport)
750{
751 RECORDINSERT ri;
752 DIRCNRDATA *dcd;
753 PCNRITEM pci, pciFirst;
754 UINT x;
755 ULONG ulRecsToInsert;
756
757 if (!grep || !grep->toinsert || !grep->insertffb || !grep->dir)
758 return FALSE;
759
760 pci = NULL;
761 dcd = INSTDATA(grep->hwndFiles);
762 for (x = 0; grep->insertffb[x]; x++) {
763 if (pci == NULL) {
764 ulRecsToInsert = grep->toinsert - x < USHRT_MAX ? grep->toinsert - x : USHRT_MAX;
765 pciFirst = WinSendMsg(grep->hwndFiles, CM_ALLOCRECORD,
766 MPFROMLONG(EXTRA_RECORD_BYTES),
767 MPFROMLONG(ulRecsToInsert));
768 if (!pciFirst) {
769 Win_Error(grep->hwndFiles, grep->hwndFiles, pszSrcFile, __LINE__,
770 PCSZ_CM_ALLOCRECORD);
771 freegreplist(grep);
772 return FALSE;
773 }
774 else {
775 pci = pciFirst;
776 if (grep->sayfiles) {
777 if (!hwndStatus)
778 WinSetWindowText(grep->hwndCurFile, (CHAR *) GetPString(IDS_GREPINSERTINGTEXT));
779 else {
780 if (WinQueryFocus(HWND_DESKTOP) == grep->hwndFiles)
781 WinSetWindowText(hwndStatus, (CHAR *) GetPString(IDS_GREPINSERTINGTEXT));
782 }
783 }
784 }
785 }
786 FillInRecordFromFFB(grep->hwndFiles,
787 pci, grep->dir[x], grep->insertffb[x], FALSE, dcd);
788 pci = (PCNRITEM) pci->rc.preccNextRecord;
789 if (pci == NULL && ulRecsToInsert) {
790 memset(&ri, 0, sizeof(RECORDINSERT));
791 ri.cb = sizeof(RECORDINSERT);
792 ri.pRecordOrder = (PRECORDCORE) CMA_END;
793 ri.pRecordParent = (PRECORDCORE) NULL;
794 ri.zOrder = (USHORT) CMA_TOP;
795 ri.cRecordsInsert = ulRecsToInsert;
796 ri.fInvalidateRecord = TRUE;
797 WinSendMsg(grep->hwndFiles,
798 CM_INSERTRECORD, MPFROMP(pciFirst), MPFROMP(&ri));
799 if (dcd) {
800 DosRequestMutexSem(hmtxFM2Globals, SEM_INDEFINITE_WAIT);
801 dcd->ullTotalBytes += grep->insertedbytes;
802 DosReleaseMutexSem(hmtxFM2Globals);
803 }
804 pciFirst = NULL;
805 }
806 SleepIfNeeded(pitdSleep, 1);
807 }//for
808 freegreplist(grep);
809 PostMsg(grep->hwndFiles, UM_RESCAN, MPVOID, MPVOID);
810 return TRUE;
811}
812
813/**
814 * Insert file ffb and directory name into lists
815 */
816
817static BOOL InsertGrepFile(GREP *grep,
818 CHAR *pszFileName,
819 PFILEFINDBUF4L pffb,
820 ITIMER_DESC *pitdSleep,
821 ITIMER_DESC *pitdReport)
822{
823 PSZ p;
824 CHAR szDirectory[CCHMAXPATH];
825
826 if (!WinIsWindow(grep->ghab, grep->hwndFiles)) {
827 // Window closed - clean up and go away
828 freegreplist(grep);
829 }
830 else {
831 grep->numfiles++;
832 strcpy(szDirectory, pszFileName);
833 p = strrchr(szDirectory, '\\');
834
835 if (p) {
836 // Got directory
837 if (p < szDirectory + 4)
838 p++; // Include root backslash
839 *p = 0;
840
841 if (!grep->insertffb) {
842 // Allocate 1 extra for end marker?
843 grep->insertffb = xmallocz(sizeof(PFILEFINDBUF4L) * (FilesToGet + 1),
844 pszSrcFile, __LINE__);
845 if (!grep->insertffb)
846 return FALSE;
847 grep->dir = xmallocz(sizeof(CHAR *) * (FilesToGet + 1),
848 pszSrcFile, __LINE__);
849 if (!grep->dir) {
850 free(grep->insertffb);
851# ifdef FORTIFY
852 Fortify_LeaveScope();
853# endif
854 return FALSE;
855 }
856 }
857
858 grep->insertffb[grep->toinsert] =
859 xmalloc(sizeof(FILEFINDBUF4L), pszSrcFile, __LINE__);
860 if (!grep->insertffb[grep->toinsert])
861 return FALSE;
862 memcpy(grep->insertffb[grep->toinsert], pffb, sizeof(FILEFINDBUF4L));
863
864 grep->dir[grep->toinsert] = xstrdup(szDirectory, pszSrcFile, __LINE__);
865 if (!grep->dir) {
866 free(grep->insertffb[grep->toinsert]);
867# ifdef FORTIFY
868 Fortify_LeaveScope();
869# endif
870 return FALSE;
871 }
872
873 grep->insertedbytes += pffb->cbFile + CBLIST_TO_EASIZE(pffb->cbList);
874 grep->toinsert++;
875 // 07 Oct 09 SHL honor sync updates
876 if (grep->toinsert == FilesToGet || fSyncUpdates)
877 return DoInsertion(grep, pitdSleep, pitdReport);
878 return TRUE;
879 }
880 }
881 return FALSE;
882}
883
884/**
885 * Check file matches search criteria
886 */
887
888static BOOL DoOneFile(GREP *grep,
889 CHAR *pszFileName,
890 FILEFINDBUF4L *pffb,
891 ITIMER_DESC *pitdSleep,
892 ITIMER_DESC *pitdReport)
893{
894 // process a single file
895 CHAR *input;
896 FILE *inputFile;
897 ULONG pos;
898 BOOL ret = FALSE, strmatch = FALSE;
899
900 grep->fileCount++;
901 if (grep->sayfiles) {
902 if (!hwndStatus)
903 WinSetWindowText(grep->hwndCurFile, pszFileName);
904 else {
905 if (WinQueryFocus(HWND_DESKTOP) == grep->hwndFiles)
906 WinSetWindowText(hwndStatus, pszFileName);
907 }
908 }
909
910 if (grep->greaterthan || grep->lessthan) {
911
912 BOOL keep = TRUE;
913 ULONG adjsize;
914
915 adjsize = pffb->cbFile + (grep->searchEAs ? CBLIST_TO_EASIZE(pffb->cbList) : 0);
916 if (grep->greaterthan) {
917 if (adjsize < grep->greaterthan)
918 keep = FALSE;
919 }
920 if (keep && grep->lessthan) {
921 if (adjsize > grep->lessthan)
922 keep = FALSE;
923 }
924 if (!keep)
925 return ret;
926 }
927
928 if (grep->newerthan || grep->olderthan) {
929
930 BOOL keep = TRUE;
931 ULONG numsecs;
932
933 numsecs = SecsSince1980(&pffb->fdateLastWrite, &pffb->ftimeLastWrite);
934 if (grep->newerthan) {
935 if (numsecs < grep->newerthan)
936 keep = FALSE;
937 }
938 if (keep && grep->olderthan) {
939 if (numsecs > grep->olderthan)
940 keep = FALSE;
941 }
942 if (!keep)
943 return ret;
944 }
945
946 if ((!grep->searchEAs && !grep->searchFiles) || !*grep->searchPattern) // just a find
947 return InsertGrepFile(grep, pszFileName, pffb, pitdSleep, pitdReport);
948
949 if (grep->searchEAs) {
950
951 HOLDFEA *head, *info;
952 USHORT type, len;
953 BOOL alltext;
954 CHAR *data, temp;
955
956 head = GetFileEAs(pszFileName, FALSE, TRUE);
957 if (head) {
958 info = head;
959 while (info && !strmatch) {
960 alltext = TRUE;
961 switch (*(USHORT *)info->value) {
962 case EAT_ASCII:
963 if (match(info->value + (sizeof(USHORT) * 2),
964 grep->searchPattern, grep->absFlag,
965 grep->caseFlag == FALSE,
966 info->cbValue - (sizeof(USHORT) * 2),
967 grep->numlines,
968 grep->matched,
969 !grep->findifany)) {
970 strmatch = TRUE;
971 }
972 break;
973 case EAT_MVST:
974 type = *(USHORT *)(info->value + (sizeof(USHORT) * 3));
975 if (type == EAT_ASCII) {
976 data = info->value + (sizeof(USHORT) * 4);
977 len = *(USHORT *) data;
978 data += sizeof(USHORT);
979 while ((data - info->value) + len <= info->cbValue) {
980 temp = *(data + len);
981 *(data + len) = 0;
982 if (match(data,
983 grep->searchPattern,
984 grep->absFlag,
985 (grep->caseFlag == FALSE),
986 len,
987 grep->numlines, grep->matched, !grep->findifany)) {
988 strmatch = TRUE;
989 break;
990 }
991 data += len;
992 if (data - info->value >= info->cbValue)
993 break;
994 *data = temp;
995 len = *(USHORT *) data;
996 data += sizeof(USHORT);
997 }
998 }
999 break;
1000 case EAT_MVMT:
1001 data = info->value + (sizeof(USHORT) * 3);
1002 type = *(USHORT *) data;
1003 data += sizeof(USHORT);
1004 len = *(USHORT *) data;
1005 data += sizeof(USHORT);
1006 while ((data - info->value) - len <= info->cbValue) {
1007 if (type != EAT_ASCII) {
1008 alltext = FALSE;
1009 break;
1010 }
1011 data += len;
1012 if (data - info->value >= info->cbValue)
1013 break;
1014 type = *(USHORT *) data;
1015 data += sizeof(USHORT);
1016 len = *(USHORT *) data;
1017 data += sizeof(USHORT);
1018 }
1019 if (alltext) {
1020 data = info->value + (sizeof(USHORT) * 3);
1021 type = *(USHORT *) data;
1022 data += sizeof(USHORT);
1023 len = *(USHORT *) data;
1024 data += sizeof(USHORT);
1025 while ((data - info->value) - len <= info->cbValue) {
1026 temp = *(data + len);
1027 *(data + len) = 0;
1028 if (match(data,
1029 grep->searchPattern,
1030 grep->absFlag,
1031 (grep->caseFlag == FALSE),
1032 len,
1033 grep->numlines, grep->matched, !grep->findifany)) {
1034 strmatch = TRUE;
1035 break;
1036 }
1037 data += len;
1038 *data = temp;
1039 if (data - info->value >= info->cbValue)
1040 break;
1041 type = *(USHORT *) data;
1042 data += sizeof(USHORT);
1043 len = *(USHORT *) data;
1044 data += sizeof(USHORT);
1045 }
1046 }
1047 break;
1048 default:
1049 break;
1050 }
1051 info = info->next;
1052 } // while
1053 Free_FEAList(head);
1054 }
1055 }
1056
1057 if (grep->searchFiles) {
1058 input = xmalloc(65537, pszSrcFile, __LINE__);
1059 if (input) {
1060 LONG len;
1061 CHAR *moderb = "rb";
1062
1063 inputFile = xfsopen(pszFileName, moderb, SH_DENYNO, pszSrcFile, __LINE__, TRUE);
1064 if (inputFile) {
1065 pos = ftell(inputFile);
1066 while (!feof(inputFile)) {
1067 if (pos)
1068 fseek(inputFile, pos - 1024, SEEK_SET);
1069 len = fread(input, 1, 65536, inputFile);
1070 if (len >= 0) {
1071 if (*grep->stopflag)
1072 break;
1073 if (match(input,
1074 grep->searchPattern,
1075 grep->absFlag,
1076 (grep->caseFlag == FALSE),
1077 len, grep->numlines, grep->matched, !grep->findifany)) {
1078 strmatch = TRUE;
1079 break;
1080 }
1081 }
1082 else
1083 break;
1084 }
1085 fclose(inputFile);
1086 }
1087 free(input);
1088# ifdef FORTIFY
1089 Fortify_LeaveScope();
1090# endif
1091 }
1092 } // if
1093
1094 if (strmatch)
1095 ret = InsertGrepFile(grep, pszFileName, pffb, pitdSleep, pitdReport);
1096 return ret;
1097}
1098
1099static LONG cr3tab[] = { // CRC polynomial 0xEDB88320
1100
1101 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
1102 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
1103 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
1104 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
1105 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
1106 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
1107 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
1108 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
1109 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
1110 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
1111 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
1112 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
1113 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
1114 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
1115 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
1116 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
1117 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
1118 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
1119 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
1120 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
1121 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
1122 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
1123 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
1124 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
1125 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
1126 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
1127 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
1128 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
1129 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
1130 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
1131 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
1132 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
1133 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
1134 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
1135 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
1136 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
1137 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
1138 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
1139 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
1140 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
1141 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
1142 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
1143 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
1144 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
1145 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
1146 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
1147 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
1148 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
1149 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
1150 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
1151 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
1152 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
1153 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
1154 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
1155 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
1156 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
1157 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
1158 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
1159 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
1160 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
1161 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
1162 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
1163 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
1164 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
1165};
1166
1167LONG CRCBlock(register CHAR *str, register INT blklen, register LONG crc)
1168{
1169 while (blklen--) {
1170 crc =
1171 cr3tab[((INT) crc ^ *str) & 0xff] ^ (((ULONG) crc >> 8) & 0x00FFFFFF);
1172 str++;
1173 }
1174 return crc;
1175}
1176
1177LONG CRCFile(CHAR *pszFileName, INT *error)
1178{
1179 LONG CRC = -1L, len;
1180 FILE *fp;
1181 CHAR *buffer;
1182 CHAR *moderb = "rb";
1183
1184 *error = 0;
1185 buffer = xmalloc(65535, pszSrcFile, __LINE__);
1186 if (!buffer)
1187 *error = -1;
1188 else {
1189 fp = xfsopen(pszFileName, moderb, SH_DENYNO, pszSrcFile, __LINE__, TRUE);
1190 if (!fp)
1191 *error = -2;
1192 else {
1193 while (!feof(fp)) {
1194 len = fread(buffer, 1, 65535, fp);
1195 if (len && len < 65536L)
1196 CRC = CRCBlock(buffer, len, CRC);
1197 else
1198 break;
1199 }
1200 fclose(fp);
1201 }
1202 free(buffer);
1203# ifdef FORTIFY
1204 Fortify_LeaveScope();
1205# endif
1206 }
1207 return CRC;
1208}
1209
1210static VOID FreeDupes(GREP *grep)
1211{
1212 DUPES *i, *next;
1213
1214 i = grep->dupehead;
1215 while (i) {
1216 next = i->next;
1217 if (i->name) {
1218 free(i->name);
1219 }
1220 free(i);
1221 i = next;
1222 }
1223 grep->dupehead = grep->dupelast = NULL;
1224 xfree(grep->dupenames, pszSrcFile, __LINE__);
1225 xfree(grep->dupesizes, pszSrcFile, __LINE__);
1226 grep->dupesizes = grep->dupenames = NULL;
1227# ifdef FORTIFY
1228 Fortify_LeaveScope();
1229# endif
1230}
1231
1232INT comparenamesq(const VOID *v1, const VOID *v2)
1233{
1234 DUPES *d1 = *(DUPES **) v1;
1235 DUPES *d2 = *(DUPES **) v2;
1236 CHAR *p1, *p2;
1237
1238 p1 = strrchr(d1->name, '\\');
1239 if (p1)
1240 p1++;
1241 else
1242 p1 = d1->name;
1243 p2 = strrchr(d2->name, '\\');
1244 if (p2)
1245 p2++;
1246 else
1247 p2 = d2->name;
1248 return stricmp(p1, p2);
1249}
1250
1251INT comparenamesqe(const VOID *v1, const VOID *v2)
1252{
1253 DUPES *d1 = *(DUPES **) v1;
1254 DUPES *d2 = *(DUPES **) v2;
1255 CHAR *p1, *p2, *p1e, *p2e, e1, e2;
1256 INT ret;
1257
1258 p1 = strrchr(d1->name, '\\');
1259 if (p1)
1260 p1++;
1261 else
1262 p1 = d1->name;
1263 p1e = strrchr(p1, '.');
1264 if (p1e) {
1265 e1 = *p1e;
1266 *p1e = 0;
1267 }
1268 p2 = strrchr(d2->name, '\\');
1269 if (p2)
1270 p2++;
1271 else
1272 p2 = d2->name;
1273 p2e = strrchr(p2, '.');
1274 if (p2e) {
1275 e2 = *p2e;
1276 *p2e = 0;
1277 }
1278 ret = stricmp(p1, p2);
1279 if (p1e)
1280 *p1e = e1;
1281 if (p2e)
1282 *p2e = e2;
1283 return ret;
1284}
1285
1286INT comparesizesq(const void *v1, const void *v2)
1287{
1288 DUPES *d1 = *(DUPES **) v1;
1289 DUPES *d2 = *(DUPES **) v2;
1290
1291 return (d1->size > d2->size) ? 1 : (d1->size == d2->size) ? 0 : -1;
1292}
1293
1294INT comparenamesb(const void *v1, const void *v2)
1295{
1296 DUPES *d1 = (DUPES *) v1;
1297 DUPES *d2 = *(DUPES **) v2;
1298 CHAR *p1, *p2;
1299
1300 p1 = strrchr(d1->name, '\\');
1301 if (p1)
1302 p1++;
1303 else
1304 p1 = d1->name;
1305 p2 = strrchr(d2->name, '\\');
1306 if (p2)
1307 p2++;
1308 else
1309 p2 = d2->name;
1310 return stricmp(p1, p2);
1311}
1312
1313INT comparenamesbe(const VOID *v1, const VOID *v2)
1314{
1315 DUPES *d1 = (DUPES *) v1;
1316 DUPES *d2 = *(DUPES **) v2;
1317 CHAR *p1, *p2, *p1e, *p2e, e1, e2;
1318 INT ret;
1319
1320 p1 = strrchr(d1->name, '\\');
1321 if (p1)
1322 p1++;
1323 else
1324 p1 = d1->name;
1325 p1e = strrchr(p1, '.');
1326 if (p1e) {
1327 e1 = *p1e;
1328 *p1e = 0;
1329 }
1330 p2 = strrchr(d2->name, '\\');
1331 if (p2)
1332 p2++;
1333 else
1334 p2 = d2->name;
1335 p2e = strrchr(p2, '.');
1336 if (p2e) {
1337 e2 = *p2e;
1338 *p2e = 0;
1339 }
1340 ret = stricmp(p1, p2);
1341 if (p1e)
1342 *p1e = e1;
1343 if (p2e)
1344 *p2e = e2;
1345 return ret;
1346}
1347
1348INT comparesizesb(const VOID *v1, const VOID *v2)
1349{
1350 DUPES *d1 = (DUPES *) v1;
1351 DUPES *d2 = *(DUPES **) v2;
1352
1353 return (d1->size > d2->size) ? 1 : (d1->size == d2->size) ? 0 : -1;
1354}
1355
1356static VOID FillDupes(GREP *grep,
1357 ITIMER_DESC *pitdSleep,
1358 ITIMER_DESC *pitdReport)
1359{
1360 DUPES *c, *i, **r;
1361 register CHAR *pc, *pi;
1362 CHAR **list = NULL;
1363 UINT numfiles = 0, numalloced = 0;
1364 INT error;
1365 ULONG x;
1366 ULONG y;
1367
1368 x = 0;
1369 for (i = grep->dupehead; i; i = i->next)
1370 x++; // Count
1371
1372 if (x) {
1373 if (!hwndStatus)
1374 WinSetWindowText(grep->hwndCurFile, (CHAR *) GetPString(IDS_GREPDUPESORTINGTEXT));
1375 else if (WinQueryFocus(HWND_DESKTOP) == grep->hwndFiles)
1376 WinSetWindowText(hwndStatus, (CHAR *) GetPString(IDS_GREPDUPESORTINGTEXT));
1377 grep->dupenames = xmalloc(sizeof(DUPES *) * (x + 1), pszSrcFile, __LINE__);
1378 if (!grep->nosizedupes)
1379 grep->dupesizes = xmalloc(sizeof(DUPES *) * (x + 1), pszSrcFile, __LINE__);
1380 if (grep->dupenames && (grep->nosizedupes || grep->dupesizes)) {
1381 y = 0;
1382 for (i = grep->dupehead; i; i = i->next) {
1383 grep->dupenames[y] = i;
1384 if (!grep->nosizedupes)
1385 grep->dupesizes[y] = i;
1386 y++;
1387 }
1388 grep->dupenames[y] = NULL; // Mark end
1389 if (!grep->nosizedupes)
1390 grep->dupesizes[y] = NULL;
1391
1392 InitITimer(pitdSleep, 0); // Reset rate estimator
1393 SleepIfNeeded(pitdSleep, 1);
1394 qsort(grep->dupenames,
1395 x,
1396 sizeof(DUPES *),
1397 grep->ignoreextdupes ? comparenamesqe : comparenamesq);
1398 SleepIfNeeded(pitdSleep, 1);
1399 if (!grep->nosizedupes) {
1400 qsort(grep->dupesizes, x, sizeof(DUPES *), comparesizesq);
1401 SleepIfNeeded(pitdSleep, 1);
1402 }
1403
1404 if (!hwndStatus)
1405 WinSetWindowText(grep->hwndCurFile, (CHAR *) GetPString(IDS_GREPDUPECOMPARINGTEXT));
1406 else if (WinQueryFocus(HWND_DESKTOP) == grep->hwndFiles)
1407 WinSetWindowText(hwndStatus, (CHAR *) GetPString(IDS_GREPDUPECOMPARINGTEXT));
1408
1409 InitITimer(pitdSleep, 0); // Reset rate estimator
1410 i = grep->dupehead;
1411 y = 0;
1412 while (i) {
1413 if (*grep->stopflag)
1414 break;
1415 SleepIfNeeded(pitdSleep, 1); // 07 Feb 08 SHL
1416 if (!(i->flags & GF_SKIPME)) {
1417 r = (DUPES **) bsearch(i, grep->dupenames, x, sizeof(DUPES *),
1418 ((grep->ignoreextdupes) ? comparenamesbe :
1419 comparenamesb));
1420 if (r) {
1421 while (r > grep->dupenames && ((grep->ignoreextdupes) ?
1422 !comparenamesqe((r - 1), &i) :
1423 !comparenamesq((r - 1), &i)))
1424 r--;
1425 while (*r && ((grep->ignoreextdupes) ?
1426 !comparenamesqe(r, &i) : !comparenamesq(r, &i))) {
1427 if (*r == i || ((*r)->flags & (GF_INSERTED | GF_SKIPME))) {
1428 r++;
1429 continue;
1430 }
1431 if (grep->CRCdupes) {
1432 if ((*r)->CRC == -1L) {
1433 (*r)->CRC = CRCFile((*r)->name, &error);
1434 if (error)
1435 (*r)->CRC = -1L;
1436 else if ((*r)->CRC == -1L)
1437 (*r)->CRC = 0L;
1438 }
1439 if (i->CRC == -1L) {
1440 i->CRC = CRCFile(i->name, &error);
1441 if (error)
1442 i->CRC = -1L;
1443 else if (i->CRC == -1L)
1444 i->CRC = 0L;
1445 }
1446 if (((*r)->size != i->size) || ((*r)->CRC != -1L &&
1447 i->CRC != -1L
1448 && (*r)->CRC != i->CRC)) {
1449 r++;
1450 continue;
1451 }
1452 }
1453 if (!AddToList((*r)->name, &list, &numfiles, &numalloced)) {
1454 (*r)->flags |= GF_INSERTED;
1455 if (grep->sayfiles) {
1456 if (!hwndStatus)
1457 WinSetWindowText(grep->hwndFiles, (*r)->name);
1458 else if (WinQueryFocus(HWND_DESKTOP) == grep->hwndFiles)
1459 WinSetWindowText(hwndStatus, (*r)->name);
1460 }
1461 if ((*r)->size == i->size &&
1462 (i->date.year == (*r)->date.year &&
1463 i->date.month == (*r)->date.month &&
1464 i->date.day == (*r)->date.day &&
1465 i->time.hours == (*r)->time.hours &&
1466 i->time.minutes == (*r)->time.minutes &&
1467 i->time.twosecs == (*r)->time.twosecs))
1468 (*r)->flags |= GF_SKIPME;
1469 }
1470 if (!(i->flags & (GF_INSERTED | GF_SKIPME))) {
1471 if (!AddToList(i->name, &list, &numfiles, &numalloced)) {
1472 i->flags |= GF_INSERTED;
1473 if ((*r)->flags & GF_SKIPME)
1474 i->flags |= GF_SKIPME;
1475 }
1476 }
1477 r++;
1478 }
1479 }
1480 if (!grep->nosizedupes) {
1481 r = (DUPES **) bsearch(i,
1482 grep->dupesizes,
1483 x, sizeof(DUPES *), comparesizesb);
1484 if (r) {
1485 while (r > grep->dupesizes && !comparesizesq((r - 1), &i))
1486 r--;
1487 while (*r && !comparesizesq(r, &i)) {
1488 if (*r == i || ((*r)->flags & (GF_INSERTED | GF_SKIPME)) ||
1489 (i->date.year != (*r)->date.year ||
1490 i->date.month != (*r)->date.month ||
1491 i->date.day != (*r)->date.day ||
1492 i->time.hours != (*r)->time.hours ||
1493 i->time.minutes != (*r)->time.minutes ||
1494 i->time.twosecs != (*r)->time.twosecs)) {
1495 r++;
1496 continue;
1497 }
1498 if (grep->CRCdupes) {
1499 if ((*r)->CRC == -1L) {
1500 (*r)->CRC = CRCFile((*r)->name, &error);
1501 if (error)
1502 (*r)->CRC = -1L;
1503 else if ((*r)->CRC == -1L)
1504 (*r)->CRC = 0L;
1505 }
1506 if (i->CRC == -1L) {
1507 i->CRC = CRCFile(i->name, &error);
1508 if (error)
1509 i->CRC = -1L;
1510 else if (i->CRC == -1L)
1511 i->CRC = 0L;
1512 }
1513 if ((*r)->CRC != -1L && i->CRC != -1L &&
1514 (*r)->CRC != i->CRC) {
1515 *r += 1;
1516 continue;
1517 }
1518 }
1519 if (!AddToList((*r)->name, &list, &numfiles, &numalloced)) {
1520 if (grep->sayfiles) {
1521 if (!hwndStatus)
1522 WinSetWindowText(grep->hwndCurFile, (*r)->name);
1523 else if (WinQueryFocus(HWND_DESKTOP) == grep->hwndFiles)
1524 WinSetWindowText(hwndStatus, (*r)->name);
1525 }
1526 (*r)->flags |= GF_INSERTED;
1527 if (((grep->ignoreextdupes) ?
1528 comparenamesqe(r, &i) : comparenamesq(r, &i)))
1529 (*r)->flags |= GF_SKIPME;
1530 }
1531 if (!(i->flags & (GF_INSERTED | GF_SKIPME))) {
1532 if (!AddToList(i->name, &list, &numfiles, &numalloced)) {
1533 i->flags |= GF_INSERTED;
1534 if ((*r)->flags & GF_SKIPME)
1535 i->flags |= GF_SKIPME;
1536 }
1537 }
1538 r++;
1539 }
1540 }
1541 }
1542 }
1543 i = i->next;
1544 y++;
1545 // 08 Feb 08 SHL
1546 if (IsITimerExpired(pitdReport)) {
1547 CHAR s[44];
1548 sprintf(s, GetPString(IDS_GREPDUPECHECKPROGTEXT), y, grep->numfiles);
1549 if (!hwndStatus)
1550 WinSetWindowText(grep->hwndCurFile, s);
1551 else {
1552 if (WinQueryFocus(HWND_DESKTOP) == grep->hwndFiles)
1553 WinSetWindowText(hwndStatus, s);
1554 }
1555 }
1556 } // while
1557 }
1558 else {
1559 // Insufficient memory - fall back to slow method - FIXME to saymsg?
1560 if (!fErrorBeepOff)
1561 DosBeep(50, 100);
1562 if (!hwndStatus)
1563 WinSetWindowText(grep->hwndCurFile, (CHAR *) GetPString(IDS_GREPDUPECOMPARINGTEXT));
1564 else if (WinQueryFocus(HWND_DESKTOP) == grep->hwndFiles)
1565 WinSetWindowText(hwndStatus, (CHAR *) GetPString(IDS_GREPDUPECOMPARINGTEXT));
1566 x = y = 0;
1567 xfree(grep->dupenames, pszSrcFile, __LINE__);
1568 grep->dupenames = NULL;
1569 xfree(grep->dupesizes, pszSrcFile, __LINE__);
1570 grep->dupesizes = NULL;
1571# ifdef FORTIFY
1572 Fortify_LeaveScope();
1573# endif
1574
1575 InitITimer(pitdSleep, 0); // Reset rate estimator
1576 i = grep->dupehead;
1577 while (i) {
1578 if (*grep->stopflag)
1579 break;
1580 SleepIfNeeded(pitdSleep, 1);
1581 if (!(i->flags & GF_SKIPME)) {
1582 if (IsITimerExpired(pitdReport)) {
1583 CHAR s[44];
1584
1585 sprintf(s, GetPString(IDS_GREPDUPECHECKPROGTEXT), y, grep->numfiles);
1586 if (!hwndStatus)
1587 WinSetWindowText(grep->hwndCurFile, s);
1588 else if (WinQueryFocus(HWND_DESKTOP) == grep->hwndFiles)
1589 WinSetWindowText(hwndStatus, s);
1590 }
1591 y++;
1592 pi = strrchr(i->name, '\\');
1593 if (pi)
1594 pi++;
1595 else
1596 pi = i->name;
1597 c = grep->dupehead;
1598 while (c) {
1599 if (*grep->stopflag)
1600 break;
1601 if (c != i && !(c->flags & (GF_INSERTED | GF_SKIPME))) {
1602 x++;
1603 pc = strrchr(c->name, '\\');
1604 if (pc)
1605 pc++;
1606 else
1607 pc = c->name;
1608 if ((!grep->nosizedupes && i->size == c->size && i->date.year == c->date.year && i->date.month == c->date.month && i->date.day == c->date.day && i->time.hours == c->time.hours && i->time.minutes == c->time.minutes && i->time.twosecs == c->time.twosecs) || !stricmp(pc, pi)) { // potential dupe
1609 if (grep->CRCdupes) {
1610 if (grep->CRCdupes) {
1611 if (c->CRC == -1L) {
1612 c->CRC = CRCFile(c->name, &error);
1613 if (error)
1614 c->CRC = -1L;
1615 else if (c->CRC == -1L)
1616 c->CRC = 0L;
1617 }
1618 if (i->CRC == -1L) {
1619 i->CRC = CRCFile(i->name, &error);
1620 if (error)
1621 i->CRC = -1L;
1622 else if (i->CRC == -1L)
1623 i->CRC = 0L;
1624 }
1625 if ((c->size != i->size) || (c->CRC != -1L &&
1626 i->CRC != -1L
1627 && c->CRC != i->CRC)) {
1628 c = c->next;
1629 continue;
1630 }
1631 }
1632 }
1633 if (AddToList(c->name, &list, &numfiles, &numalloced))
1634 goto BreakOut; // Failed
1635 if (!(i->flags & GF_INSERTED)) {
1636 if (AddToList(i->name, &list, &numfiles, &numalloced))
1637 goto BreakOut; // Failed
1638 }
1639 if (grep->sayfiles) {
1640 if (!hwndStatus)
1641 WinSetWindowText(grep->hwndCurFile, pc);
1642 else if (WinQueryFocus(HWND_DESKTOP) == grep->hwndFiles)
1643 WinSetWindowText(hwndStatus, pc);
1644 }
1645 c->flags |= GF_INSERTED;
1646 i->flags |= GF_INSERTED;
1647 if (!stricmp(pc, pi)) {
1648 c->flags |= GF_SKIPME;
1649 i->flags |= GF_SKIPME;
1650 }
1651 }
1652 }
1653 c = c->next;
1654 }
1655 }
1656 i = i->next;
1657 } // while
1658 }
1659 }
1660BreakOut:
1661 FreeDupes(grep);
1662 if (numfiles && list) {
1663 if (!PostMsg(grep->hwndFiles,
1664 WM_COMMAND,
1665 MPFROM2SHORT(IDM_COLLECTOR, 0),
1666 MPFROMP(list)))
1667 FreeList(list);
1668 }
1669 else
1670 DosPostEventSem(CompactSem);
1671}
1672
1673static BOOL InsertDupe(GREP *grep, CHAR *dir, FILEFINDBUF4L *pffb)
1674{
1675 DUPES *info;
1676
1677 if (*dir) {
1678 info = xmallocz(sizeof(DUPES), pszSrcFile, __LINE__);
1679 if (!info)
1680 return FALSE;
1681
1682 info->name = xstrdup(dir, pszSrcFile, __LINE__);
1683 if (!info->name) {
1684 free(info);
1685# ifdef FORTIFY
1686 Fortify_LeaveScope();
1687# endif
1688 return FALSE;
1689 }
1690
1691 info->size = pffb->cbFile;
1692 info->date = pffb->fdateLastWrite;
1693 info->time = pffb->ftimeLastWrite;
1694 info->CRC = -1L;
1695 grep->numfiles++;
1696 if (!grep->dupehead)
1697 grep->dupehead = info;
1698 if (grep->dupelast)
1699 grep->dupelast->next = info;
1700 grep->dupelast = info;
1701 info->next = NULL;
1702 }
1703 return TRUE;
1704}
1705
1706#pragma alloc_text(GREP,InsertGrepFile,DoOneFile,DoInsertion,freegreplist)
1707#pragma alloc_text(GREP,SecsSince1980,match,mmatch,GrepThread)
1708#pragma alloc_text(GREP,DoAllSubdirs,DoMatchingFiles,InsertDupes,FreeDupes)
1709
1710#pragma alloc_text(DUPES,InsertDupe,FillDupes,FreeDupes,CRCFile,CRCBlock)
1711#pragma alloc_text(DUPES,comparenamesq,comparenamesqe,comparenamesb)
1712#pragma alloc_text(DUPES,comparenamesbe,comparesizesq,comparesizesb)
Note: See TracBrowser for help on using the repository browser.