source: trunk/dll/comp.c@ 1891

Last change on this file since 1891 was 1891, checked in by Steven Levine, 6 years ago

Rework FreeCnrItem to ensure all CNRITEMs deleted.
Use WinSendMsg CMA_NEXT.
Was using preccNextRecord which is not recommended because control does
not maintain linkage after inserts and deletes.
Note: arccnrs.c still needs to be reworked to use common functions from filldir.c.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 103.5 KB
Line 
1
2/***********************************************************************
3
4 $Id: comp.c 1891 2020-01-31 02:47:37Z stevenhl $
5
6 Compare directories
7
8 Copyright (c) 1993-2002 M. Kimes
9 Copyright (c) 2003-2020 Steven H. Levine
10
11 16 Oct 02 MK Baseline
12 04 Nov 03 SHL Force window refresh after subdir toggle
13 01 Aug 04 SHL Rework lstrip/rstrip usage
14 24 May 05 SHL Rework Win_Error usage
15 24 May 05 SHL Rework for CNRITEM.szSubject
16 25 May 05 SHL Rework with ULONGLONG
17 06 Jun 05 SHL Drop unused
18 12 Jul 06 SHL Renames and comments
19 13 Jul 06 SHL Use Runtime_Error
20 26 Jul 06 SHL Drop unreachable CN_... code
21 29 Jul 06 SHL Use xfgets_bstripcr
22 15 Aug 06 SHL Turn off hide not selected on dir change
23 19 Oct 06 SHL Correct . and .. detect
24 03 Nov 06 SHL Count thread usage
25 22 Mar 07 GKY Use QWL_USER
26 29 Jul 07 SHL Use Win_Error to report container errors
27 01 Aug 07 SHL Rework to sync with CNRITEM mods
28 01 Aug 07 SHL Rework to remove vast amount of duplicate code
29 03 Aug 07 GKY Enlarged and made setable everywhere Findbuf (speed file loading)
30 06 Aug 07 SHL Move BldFullPathName here to be near primary caller
31 07 Aug 07 SHL COMP_COLLECT: Avoid collecting empty entries when nothing selected
32 06 Aug 07 GKY Reduce DosSleep times (ticket 148)
33 13 Aug 07 SHL Sync code with other FilesToGet usage
34 13 Aug 07 SHL Move #pragma alloc_text to end for OpenWatcom compat
35 20 Aug 07 SHL Correct remaining pcil/pcir typos (we hope)
36 20 Aug 07 SHL Revert to DosSleep(0)
37 20 Aug 07 SHL Use GetMSecTimer for timing
38 20 Aug 07 SHL A few more speed up tweaks. Some experimental timing code
39 26 Aug 07 GKY DosSleep(1) in loops changed to (0)
40 27 Sep 07 SHL Correct ULONGLONG size formatting
41 30 Dec 07 GKY Use TestCDates for compare by file date/time
42 04 Jan 08 SHL Avoid traps if CM_ALLOCRECORD returns less that requested
43 05 Jan 08 SHL Use WM_TIMER for progress messaging
44 05 Jan 08 SHL Use ITIMER_DESC for hogging control
45 12 Jan 08 SHL Correct select count display regression
46 12 Jan 08 SHL Localize SpecialSelect here and rename
47 12 Jan 08 SHL Use SleepIfNeeded
48 12 Jan 08 SHL Reduce/eliminate more DosSleep calls
49 16 Jan 08 SHL Update total/select counts with WM_TIMER only
50 17 Jan 08 SHL Change hide not selected button to 3 state
51 18 Jan 08 SHL Honor filters in actions
52 20 Jan 08 GKY Compare dialog now saves and restores size and position
53 29 Feb 08 GKY Use xfree where appropriate
54 29 Feb 08 GKY Refactor global command line variables to notebook.h
55 16 Mar 08 GKY Prevent trap caused by files that exceed maxpath length
56 11 Jul 08 JBS Ticket 230: Simplified code and eliminated some local variables by incorporating
57 all the details view settings (both the global variables and those in the
58 DIRCNRDATA struct) into a new struct: DETAILS_SETTINGS.
59 08 Sep 08 SHL Avoid aliased pszLongName pointer in ActionCnrThread IDM_MOVE
60 10 Dec 08 SHL Integrate exception handler support
61 25 Dec 08 GKY Add code to allow write verify to be turned off on a per drive basis.
62 11 Jan 09 GKY Replace font names in the string file with global set at compile in init.c
63 07 Feb 09 GKY Add *DateFormat functions to format dates based on locale
64 08 Mar 09 GKY Renamed commafmt.h i18nutil.h
65 08 Mar 09 GKY Removed variable aurguments from docopyf and unlinkf (not used)
66 08 Mar 09 GKY Additional strings move to PCSZs in init.c & String Table
67 15 Mar 09 GKY Use WriteDetailsSwitchs to save detail switch changes to the ini file.
68 28 Jun 09 GKY Added AddBackslashToPath() to remove repeatative code.
69 13 Jul 09 SHL Sync with renames
70 26 Sep 09 SHL Don't hide if nothing selected
71 27 Sep 09 SHL Support AND'ed selections
72 27 Sep 09 SHL Rework CompSelect for size and speed
73 27 Sep 09 SHL Allow fast cancel
74 27 Sep 09 SHL Drop unused reset logic
75 17 JAN 10 GKY Changes to get working with Watcom 1.9 Beta (1/16/10). Mostly cast CHAR CONSTANT * as CHAR *.
76 23 Oct 10 GKY Add ForwardslashToBackslash function to streamline code
77 29 May 11 SHL Rework >65K records logic - prior fix was not quite right
78 12 Jun 11 GKY Added SleepIfNeeded in the container fill loop
79 02 Jan 12 GKY Added pszFmtFileSize to container info to fix loss of file sizes on move and copy.
80 12 Aug 12 GKY Add ability to change and save PresParam
81 12 Aug 12 GKY Fix loading of a list file in the right compare container
82 12 Aug 12 GKY Allow for selection of include subdirectories or a list file on initial startup of compare dirs
83 05 Jan 13 GKY Fix snapshot file to actually load and save (with/without subdirectories) properly.
84 05 Jan 13 GKY Toggle of include subdirectories leaves snapshot file loaded.
85 05 Jan 13 GKY Added an indicator (textbox) that a list (snapshot) file is loaded.
86 06 Jan 13 GKY Added optional confirmation dialogs for delete move and copy to compare dir Ticket 277
87 06 Jan 13 GKY Added EA compare option to compare dir Ticket 80
88 06 Mar 13 SHL ActionCnrThread: need to strdup pszFmtFileSize to avoid aliased pointers
89 09 Mar 13 SHL SetButtonEnables: correct enable support for newish buttons
90 10 Mar 13 GKY Improvrd readonly check on delete to allow cancel and don't ask again options
91 Added saymsg2 for this purpose
92 10 Mar 13 GKY Fixes to snapshot file.
93 14 Jun 15 GKY Changes to prvenet access violations when cmp is freed
94 28 Jan 20 SHL ActionCnrThread: report CM_INVALIDATERECORD failures
95
96***********************************************************************/
97
98#include <stdlib.h>
99#include <string.h>
100#include <share.h>
101#include <io.h>
102#include <ctype.h>
103#include <limits.h> // USHRT_MAX
104
105#define INCL_DOS
106#define INCL_WIN
107#define INCL_DOSERRORS
108#define INCL_GPI
109#define INCL_LONGLONG
110
111#include "fm3dll.h"
112#include "fm3dll2.h" // #define's for UM_*, control id's, etc.
113#include "mainwnd2.h" // Data declaration(s)
114#include "inis.h" // Data declaration(s)
115#include "init.h" // Data declaration(s)
116#include "newview.h" // Data declarations
117#include "fm3dlg.h"
118#include "fm3str.h"
119#include "pathutil.h" // BldFullPathName
120#include "filldir.h" // EmptyCnr...
121#include "makelist.h" // AddToFileList...
122#include "errutil.h" // Dos_Error...
123#include "strutil.h" // GetPString
124#include "tmrsvcs.h" // IsITimerExpired
125#include "comp.h"
126#include "misc.h" // AddToListboxBottom, AdjustCnrColRO, AdjustCnrColVis,
127 // AdjustCnrColsForPref, CurrentRecord,
128 // AdjustDetailsSwitches, LoadDetailsSwitches, SetCnrCols
129 // SetDetailsSwitches
130#include "select.h" // Deselect, Deselect, InvertAll
131#include "mkdir.h" // MassMkdir
132#include "valid.h" // TestCDates
133#include "walkem.h" // WalkTwoCmpDlgProc
134#include "common.h" // DecrThreadUsage, IncrThreadUsage
135#include "defview.h" // DefaultViewKeys
136#include "draglist.h" // DoFileDrag
137#include "systemf.h" // ExecOnList
138#include "filter.h" // Filter
139#include "mainwnd.h" // GetNextWindowPos
140#include "shadow.h" // OpenObject
141#include "chklist.h" // PopupMenu
142#include "presparm.h" // SetPresParams
143#include "collect.h" // StartCollector
144#include "subj.h" // Subject
145#include "copyf.h" // docopyf
146#include "getnames.h" // export_filename
147#include "wrappers.h" // xDosFindNext
148#include "notebook.h" // External compare/dircompare
149#include "i18nutil.h" // CommaFmtULL
150#include "fortify.h" // 06 May 08 SHL added
151#include "excputil.h" // xbeginthread
152#include "info.h" // driveflags
153#include "worker.h" // MOVEIT
154#include "rename.h" // RenameProc
155
156typedef struct
157{
158 CHAR filename[CCHMAXPATH];
159 CHAR dirname[CCHMAXPATH];
160 BOOL recurse;
161}
162SNAPSTUFF;
163
164// Data definitions
165static PSZ pszSrcFile = __FILE__;
166
167#pragma data_seg(GLOBAL1)
168BOOL fSelectedAlways;
169
170/**
171 * Write directory tree to snapshot file; recurse if requested
172 */
173
174static VOID SnapShot(char *path, FILE *fp, BOOL recurse)
175{
176 PFILEFINDBUF4L pffb;
177 char *mask, *enddir;
178 HDIR hdir = HDIR_CREATE;
179 ULONG ulFindCnt;
180 // CHAR szDate[DATE_BUF_BYTES];
181
182 // 13 Aug 07 SHL FIXME to use FileToGet
183 pffb = xmalloc(sizeof(FILEFINDBUF4L), pszSrcFile, __LINE__);
184 if (pffb) {
185 mask = xmalloc(CCHMAXPATH, pszSrcFile, __LINE__);
186 if (mask) {
187 BldFullPathName(mask, path, "*");
188 enddir = strrchr(mask, '\\');
189 enddir++;
190 ulFindCnt = 1;
191 // 13 Aug 07 SHL FIXME to report errors
192 if (!xDosFindFirst(mask,
193 &hdir,
194 FILE_NORMAL | FILE_DIRECTORY |
195 FILE_ARCHIVED | FILE_READONLY | FILE_HIDDEN |
196 FILE_SYSTEM,
197 pffb, sizeof(FILEFINDBUF4L), &ulFindCnt, FIL_QUERYEASIZEL)) {
198 do {
199 strcpy(enddir, pffb->achName);
200 if (!(pffb->attrFile & FILE_DIRECTORY)) {
201 // FDateFormat(szDate, pffb->fdateLastWrite);
202 fprintf(fp,
203 "\"%s\",%u,%llu,%lu/%lu/%lu,%02u:%02u:%02u,%lu,%lu,N\n",
204 mask,
205 enddir - mask,
206 pffb->cbFile,
207 pffb->fdateLastWrite.year + 1980,
208 pffb->fdateLastWrite.month,
209 pffb->fdateLastWrite.day,
210 pffb->ftimeLastWrite.hours,
211 pffb->ftimeLastWrite.minutes,
212 pffb->ftimeLastWrite.twosecs,
213 pffb->attrFile,
214 pffb->cbList > 4 ? pffb->cbList / 2 : 0);
215 }
216 // Skip . and ..
217 else if (recurse &&
218 (pffb->achName[0] != '.' ||
219 (pffb->achName[1] &&
220 (pffb->achName[1] != '.' || pffb->achName[2])))) {
221 SnapShot(mask, fp, recurse);
222 }
223 ulFindCnt = 1;
224 } while (!xDosFindNext(hdir, pffb, sizeof(FILEFINDBUF4L), &ulFindCnt, FIL_QUERYEASIZEL));
225 DosFindClose(hdir);
226 }
227 free(mask);
228 }
229 free(pffb);
230 }
231}
232
233/**
234 * Write snapshot file thread
235 * Write directory tree to snapshot file
236 */
237
238static VOID StartSnapThread(VOID *pargs)
239{
240 SNAPSTUFF *sf = (SNAPSTUFF *)pargs;
241 FILE *fp;
242 CHAR *modew = "w";
243
244 if (sf) {
245 if (*sf->dirname && *sf->filename) {
246 priority_normal();
247 ForwardslashToBackslash(sf->dirname);
248 AddBackslashToPath(sf->dirname);
249 fp = xfopen(sf->filename, modew, pszSrcFile, __LINE__, FALSE);
250 if (fp) {
251 fprintf(fp, "\"%s\"\n", sf->dirname);
252 SnapShot(sf->dirname, fp, sf->recurse);
253 fclose(fp);
254 }
255 }
256 free(sf);
257 }
258}
259
260/**
261 * Compare files thread
262 * Scan files and update container select flags
263 */
264
265static VOID CompareFilesThread(VOID *args)
266{
267 FCOMPARE fc;
268 HAB hab2;
269 HMQ hmq2;
270 FILE *fp1, *fp2;
271 ULONG len1, len2;
272 ULONG offset = 0;
273 LONG numread1, numread2;
274 CHAR s[1024], ss[1024], *p1, *p2;
275 CHAR *moderb = "rb";
276
277 if (args) {
278 fc = *(FCOMPARE *)args;
279 hab2 = WinInitialize(0);
280 if (hab2) {
281# ifdef FORTIFY
282 Fortify_EnterScope();
283# endif
284 hmq2 = WinCreateMsgQueue(hab2, 0);
285 if (hmq2) {
286 WinCancelShutdown(hmq2, TRUE);
287 IncrThreadUsage();
288 if (!IsFile(fc.file1) || IsRoot(fc.file1)) {
289 p1 = strrchr(fc.file2, '\\');
290 if (p1) {
291 if (fc.file1[strlen(fc.file1) - 1] == '\\')
292 p1++;
293 strcat(fc.file1, p1);
294 }
295 }
296 else if (!IsFile(fc.file2) || IsRoot(fc.file2)) {
297 p1 = strrchr(fc.file1, '\\');
298 if (p1) {
299 if (fc.file2[strlen(fc.file2) - 1] == '\\')
300 p1++;
301 strcat(fc.file2, p1);
302 }
303 }
304 sprintf(s, GetPString(IDS_COMPCOMPARETEXT), fc.file1);
305 AddToListboxBottom(fc.hwndList, s);
306 sprintf(s, GetPString(IDS_COMPTOTEXT), fc.file2);
307 AddToListboxBottom(fc.hwndList, s);
308 fp1 = xfsopen(fc.file1, moderb, SH_DENYNO, pszSrcFile, __LINE__, TRUE);
309 if (!fp1) {
310 sprintf(s, GetPString(IDS_COMPCANTOPENTEXT), fc.file1);
311 AddToListboxBottom(fc.hwndList, s);
312 WinSetWindowText(fc.hwndHelp, (CHAR *) GetPString(IDS_ERRORTEXT));
313 }
314 else {
315 fp2 = xfsopen(fc.file2, moderb, SH_DENYNO, pszSrcFile, __LINE__, TRUE);
316 if (!fp2) {
317 sprintf(s, GetPString(IDS_COMPCANTOPENTEXT), fc.file2);
318 AddToListboxBottom(fc.hwndList, s);
319 WinSetWindowText(fc.hwndHelp, (CHAR *) GetPString(IDS_ERRORTEXT));
320 }
321 else {
322 len1 = filelength(fileno(fp1));
323 len2 = filelength(fileno(fp2));
324 if (len1 != len2) {
325 strcpy(s, GetPString(IDS_COMPDIFSIZESTEXT));
326 AddToListboxBottom(fc.hwndList, s);
327 sprintf(s, GetPString(IDS_COMPVSBYTESTEXT), len1, len2);
328 AddToListboxBottom(fc.hwndList, s);
329 WinSetWindowText(fc.hwndHelp,
330 (CHAR *) GetPString(IDS_COMPDONTMATCHTEXT));
331 }
332 else {
333 WinSetWindowText(fc.hwndHelp,
334 (CHAR *) GetPString(IDS_COMPCOMPARINGTEXT));
335 while (WinIsWindow(hab2, fc.hwndList)) {
336 numread1 = fread(s, 1, 1024, fp1);
337 numread2 = fread(ss, 1, 1024, fp2);
338 if (numread1 != numread2 || feof(fp1) != feof(fp2)) {
339 sprintf(s, GetPString(IDS_COMPREADERRORTEXT),
340 offset, offset);
341 AddToListboxBottom(fc.hwndList, s);
342 WinSetWindowText(fc.hwndHelp, (CHAR *) GetPString(IDS_ERRORTEXT));
343 break;
344 }
345 else if (!numread1 && feof(fp1) && feof(fp2)) {
346 AddToListboxBottom(fc.hwndList,
347 GetPString(IDS_COMPFILESMATCHTEXT));
348 if (!stricmp(fc.file1, fc.file2))
349 AddToListboxBottom(fc.hwndList,
350 GetPString(IDS_COMPWONDERWHYTEXT));
351 WinSetWindowText(fc.hwndHelp,
352 (CHAR *) GetPString(IDS_COMPCOMPLETETEXT));
353 break;
354 }
355 else if (numread1 <= 0 || numread2 <= 0) {
356 if (offset == len1)
357 break;
358 else {
359 sprintf(s, GetPString(IDS_COMPMATCHREADERRORTEXT),
360 offset, offset);
361 WinSetWindowText(fc.hwndHelp,
362 (CHAR *) GetPString(IDS_COMPODDERRORTEXT));
363 AddToListboxBottom(fc.hwndList, s);
364 break;
365 }
366 }
367 else if (memcmp(s, ss, numread1)) {
368 p1 = s;
369 p2 = ss;
370 while (p1 < s + numread1) {
371 if (*p1 != *p2) {
372 sprintf(s, GetPString(IDS_COMPMISMATCHERRORTEXT),
373 offset + (p1 - s), offset + (p1 - s));
374 AddToListboxBottom(fc.hwndList, s);
375 WinSetWindowText(fc.hwndHelp,
376 (CHAR *) GetPString(IDS_COMPDONTMATCHTEXT));
377 break;
378 }
379 p1++;
380 p2++;
381 }
382 break;
383 }
384 offset += numread1;
385 }
386 }
387 fclose(fp2);
388 }
389 fclose(fp1);
390 }
391 DecrThreadUsage();
392 WinDestroyMsgQueue(hmq2);
393 }
394 WinTerminate(hab2);
395# ifdef FORTIFY
396 Fortify_LeaveScope();
397# endif
398 }
399 }
400}
401
402/**
403 * Select directories to compare dialog procedure
404 */
405
406MRESULT EXPENTRY CFileDlgProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
407{
408 FCOMPARE *fc;
409
410 switch (msg) {
411 case WM_INITDLG:
412 if (!mp2)
413 WinDismissDlg(hwnd, 0);
414 else {
415 WinSetWindowPtr(hwnd, QWL_USER, mp2);
416 fc = (FCOMPARE *)mp2;
417 fc->hwndReport = hwnd;
418 fc->hwndList = WinWindowFromID(hwnd, FCMP_LISTBOX);
419 fc->hwndHelp = WinWindowFromID(hwnd, FCMP_HELP);
420 if (!*fc->file1 || !fc->file2) {
421 WinDismissDlg(hwnd, 0);
422 break;
423 }
424 MakeFullName(fc->file1);
425 MakeFullName(fc->file2);
426 if (!stricmp(fc->file1, fc->file2)) {
427 saymsg(MB_CANCEL, hwnd,
428 GetPString(IDS_COMPSILLYALERTTEXT),
429 GetPString(IDS_COMPTOITSELFTEXT));
430 WinDismissDlg(hwnd, 0);
431 break;
432 }
433 if (xbeginthread(CompareFilesThread,
434 65536,
435 fc,
436 pszSrcFile,
437 __LINE__) == -1)
438 {
439 WinDismissDlg(hwnd, 0);
440 }
441 }
442 break;
443
444 case WM_ADJUSTWINDOWPOS:
445 PostMsg(hwnd, UM_SETDIR, MPVOID, MPVOID);
446 break;
447
448 case UM_SETDIR:
449 PaintRecessedWindow(WinWindowFromID(hwnd, FCMP_HELP),
450 (HPS)0, FALSE, TRUE);
451 return 0;
452
453 case WM_COMMAND:
454 switch (SHORT1FROMMP(mp1)) {
455 case DID_OK:
456 WinDismissDlg(hwnd, 0);
457 break;
458 case DID_CANCEL:
459 WinDismissDlg(hwnd, 1);
460 break;
461 }
462 return 0;
463
464 case WM_DESTROY:
465 DosSleep(50); // Let others die first
466 break;
467 }
468 return WinDefDlgProc(hwnd, msg, mp1, mp2);
469}
470int ConfirmAction(HWND hwnd, CHAR *OldName, CHAR *NewName);
471
472/**
473 * ConfirmAction provides an optional confirmation dialog
474 * for move and copy operations.
475 */
476int ConfirmAction(HWND hwnd, CHAR *OldName, CHAR *NewName)
477{
478 MOVEIT mv;
479 int rc;
480
481 memset(&mv, 0, sizeof(MOVEIT));
482 mv.rename = FALSE;
483 mv.source = OldName;
484 mv.compare = TRUE;
485 strcpy(mv.target, NewName);
486 rc = WinDlgBox(HWND_DESKTOP,
487 hwnd,
488 RenameProc,
489 FM3ModHandle, REN_FRAME, (PVOID) & mv);
490 if (!rc)
491 return 1;
492
493 DosSleep(1);
494 if (mv.skip || !*mv.target)
495 return 1;
496 if (mv.dontask)
497 return 2;
498 return 0;
499}
500
501/**
502 * Action Thread
503 * Do requested action on container contents
504 */
505static VOID ActionCnrThread(VOID *args)
506{
507 COMPARE *cmp = (COMPARE *)args;
508 HAB hab;
509 HMQ hmq;
510 HWND hwndCnrS, hwndCnrD;
511 PCNRITEM pciS, pciD, pciNextS, pciNextD;
512 CHAR szNewName[CCHMAXPATH], szDirName[CCHMAXPATH], *p;
513 APIRET rc;
514 ITIMER_DESC itdSleep = { 0 };
515 BOOL fConfirmAction = FALSE;
516 BOOL dontask = FALSE;
517 BOOL enddelete = FALSE;
518
519 if (!cmp) {
520 Runtime_Error(pszSrcFile, __LINE__, NULL);
521 return;
522 }
523
524 DosError(FERR_DISABLEHARDERR);
525
526 hab = WinInitialize(0);
527 if (hab) {
528# ifdef FORTIFY
529 Fortify_EnterScope();
530# endif
531 hmq = WinCreateMsgQueue(hab, 0);
532 if (hmq) {
533 WinCancelShutdown(hmq, TRUE);
534 IncrThreadUsage();
535 priority_normal();
536 switch (cmp->action) {
537 case COMP_DELETELEFT:
538 hwndCnrS = WinWindowFromID(cmp->hwnd, COMP_LEFTDIR);
539 hwndCnrD = WinWindowFromID(cmp->hwnd, COMP_RIGHTDIR);
540 cmp->action = IDM_DELETE;
541 break;
542 case COMP_DELETERIGHT:
543 hwndCnrS = WinWindowFromID(cmp->hwnd, COMP_RIGHTDIR);
544 hwndCnrD = WinWindowFromID(cmp->hwnd, COMP_LEFTDIR);
545 cmp->action = IDM_DELETE;
546 break;
547 case COMP_MOVELEFT:
548 cmp->action = IDM_MOVE;
549 hwndCnrS = WinWindowFromID(cmp->hwnd, COMP_LEFTDIR);
550 hwndCnrD = WinWindowFromID(cmp->hwnd, COMP_RIGHTDIR);
551 break;
552 case COMP_MOVERIGHT:
553 cmp->action = IDM_MOVE;
554 hwndCnrS = WinWindowFromID(cmp->hwnd, COMP_RIGHTDIR);
555 hwndCnrD = WinWindowFromID(cmp->hwnd, COMP_LEFTDIR);
556 break;
557 case COMP_COPYLEFT:
558 cmp->action = IDM_COPY;
559 hwndCnrS = WinWindowFromID(cmp->hwnd, COMP_LEFTDIR);
560 hwndCnrD = WinWindowFromID(cmp->hwnd, COMP_RIGHTDIR);
561 break;
562 case COMP_COPYRIGHT:
563 cmp->action = IDM_COPY;
564 hwndCnrS = WinWindowFromID(cmp->hwnd, COMP_RIGHTDIR);
565 hwndCnrD = WinWindowFromID(cmp->hwnd, COMP_LEFTDIR);
566 break;
567 default:
568 Runtime_Error(pszSrcFile, __LINE__, "bad case %u", cmp->action);
569 goto Abort;
570 }
571
572 pciS = WinSendMsg(hwndCnrS, CM_QUERYRECORD, MPVOID,
573 MPFROM2SHORT(CMA_FIRST, CMA_ITEMORDER));
574 pciD = WinSendMsg(hwndCnrD, CM_QUERYRECORD, MPVOID,
575 MPFROM2SHORT(CMA_FIRST, CMA_ITEMORDER));
576 fConfirmAction = WinQueryButtonCheckstate(cmp->hwnd, COMP_CONFIRMACTION);
577 InitITimer(&itdSleep, 500); // Sleep every 500 mSec
578
579 while (pciS && (INT)pciS != -1 && pciD && (INT)pciD != -1) {
580
581 if (cmp->cmp->stop)
582 break; // 27 Sep 09 SHL
583
584 pciNextS = WinSendMsg(hwndCnrS, CM_QUERYRECORD, MPFROMP(pciS),
585 MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER));
586 pciNextD = WinSendMsg(hwndCnrD, CM_QUERYRECORD, MPFROMP(pciD),
587 MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER));
588
589 // Process file if selected and not filtered
590 if (*pciS->pszFileName &&
591 pciS->rc.flRecordAttr & CRA_SELECTED &&
592 ~pciS->rc.flRecordAttr & CRA_FILTERED)
593 {
594 // Source name not blank
595 switch (cmp->action) {
596 case IDM_DELETE:
597
598 if (fConfirmAction && !dontask) {
599 rc = saymsg2(NULL, 0, cmp->hwnd, GetPString(IDS_CONFIRMDELETE), GetPString(IDS_DOYOUWISHTODELETE),
600 pciS->pszFileName);
601 if (rc == 3 || rc == 4) {
602 if (rc == 4)
603 enddelete = TRUE;
604 break;
605 }
606 else if (rc == 2)
607 dontask = TRUE;
608 }
609
610 if (!unlinkf(pciS->pszFileName)) {
611 WinSendMsg(hwndCnrS, CM_SETRECORDEMPHASIS, MPFROMP(pciS),
612 MPFROM2SHORT(FALSE, CRA_SELECTED));
613
614 if (!*pciD->pszFileName) {
615 // Other side is blank - remove from both sides
616
617# ifdef PMPRINTF
618 PmPrintf_Report(pszSrcFile, __LINE__, "ActionCnrThread RemoveCnrItems pciS %p", pciS);
619# endif
620
621 RemoveCnrItems(hwndCnrS, pciS, 1, CMA_FREE | CMA_INVALIDATE);
622 if (pciD->rc.flRecordAttr & CRA_SELECTED)
623 WinSendMsg(hwndCnrD, CM_SETRECORDEMPHASIS, MPFROMP(pciD),
624 MPFROM2SHORT(FALSE, CRA_SELECTED));
625
626# ifdef PMPRINTF
627 PmPrintf_Report(pszSrcFile, __LINE__, "ActionCnrThread RemoveCnrItems pciD %p", pciD);
628# endif
629
630 RemoveCnrItems(hwndCnrD, pciD, 1, CMA_FREE | CMA_INVALIDATE);
631 }
632 else {
633 // Other side is not blank - blank just this side
634
635# ifdef PMPRINTF
636 PmPrintf_Report(pszSrcFile, __LINE__, "ActionCnrThread FreeCnrItemData pciS %p", pciS);
637# endif
638
639 FreeCnrItemData(pciS);
640 // 29 Aug 08 SHL Point pci fields at NullStr to sync with FreeCnrItemData mods
641 pciS->pszFileName = NullStr;
642 pciS->pszDisplayName = pciS->pszFileName;
643 pciS->rc.pszIcon = pciS->pszFileName;
644 pciS->flags = 0; // Just on one side
645 if (!WinSendMsg(hwndCnrS, CM_INVALIDATERECORD, MPFROMP(&pciS),
646 MPFROM2SHORT(1, CMA_ERASE | CMA_TEXTCHANGED))) {
647 Win_Error(hwndCnrS, cmp->hwnd, pszSrcFile, __LINE__, "CM_INVALIDATERECORD");
648 }
649
650 pciD->flags = 0; // Just on one side
651 if (pciD->pszSubject != NullStr) {
652 xfree(pciD->pszSubject, pszSrcFile, __LINE__);
653 pciD->pszSubject = NullStr;
654 }
655 }
656
657 if (hwndCnrS == WinWindowFromID(cmp->hwnd, COMP_LEFTDIR))
658 cmp->cmp->totalleft--;
659 else
660 cmp->cmp->totalright--;
661 }
662 break; // IDM_DELETE
663
664 case IDM_MOVE:
665 {
666 BOOL fResetVerify = FALSE;
667
668 if (hwndCnrS == WinWindowFromID(cmp->hwnd, COMP_RIGHTDIR))
669 BldFullPathName(szNewName, cmp->leftdir, pciS->pszDisplayName);
670 else
671 BldFullPathName(szNewName, cmp->rightdir, pciS->pszDisplayName);
672 // Make directory if required
673 strcpy(szDirName, szNewName);
674 p = strrchr(szDirName, '\\');
675 if (fVerify && (driveflags[toupper(*szNewName) - 'A'] & DRIVE_WRITEVERIFYOFF ||
676 driveflags[toupper(*pciS->pszFileName) - 'A'] & DRIVE_WRITEVERIFYOFF)) {
677 DosSetVerify(FALSE);
678 fResetVerify = TRUE;
679 }
680 if (p) {
681 if (p > szDirName + 2)
682 p++;
683 *p = 0;
684 if (IsFile(szDirName) == -1)
685 MassMkdir(hwndMain, szDirName);
686 }
687 if (fConfirmAction && pciS->flags & CNRITEM_EXISTS && !dontask) {
688 rc = ConfirmAction(cmp->hwnd, pciS->pszFileName, szNewName);
689 if (rc == 1)
690 break;
691 else if (rc == 2)
692 dontask = TRUE;
693 }
694 rc = docopyf(MOVE, pciS->pszFileName, szNewName);
695 if (fResetVerify) {
696 DosSetVerify(fVerify);
697 fResetVerify = FALSE;
698 }
699 if (!rc && stricmp(pciS->pszFileName, szNewName)) {
700 WinSendMsg(hwndCnrS, CM_SETRECORDEMPHASIS, MPFROMP(pciS),
701 MPFROM2SHORT(FALSE, CRA_SELECTED));
702 if (pciD->rc.flRecordAttr & CRA_SELECTED)
703 WinSendMsg(hwndCnrD, CM_SETRECORDEMPHASIS, MPFROMP(pciD),
704 MPFROM2SHORT(FALSE, CRA_SELECTED));
705 FreeCnrItemData(pciD);
706 pciD->pszFileName = xstrdup(szNewName, pszSrcFile, __LINE__);
707 if (hwndCnrS == WinWindowFromID(cmp->hwnd, COMP_RIGHTDIR)) {
708 pciD->pszDisplayName = pciD->pszFileName + strlen(cmp->leftdir);
709 if (cmp->leftdir[strlen(cmp->leftdir) - 1] != '\\')
710 pciD->pszDisplayName++;
711 }
712 else {
713 pciD->pszDisplayName = pciD->pszFileName + strlen(cmp->rightdir);
714 if (cmp->rightdir[strlen(cmp->rightdir) - 1] != '\\')
715 pciD->pszDisplayName++;
716 }
717 pciD->pszLongName = pciS->pszLongName;
718 pciS->pszLongName = NullStr; // 07 Sep 08 SHL avoid aliased pointer
719 if (pciD->pszSubject != NullStr) {
720 xfree(pciD->pszSubject, pszSrcFile, __LINE__);
721 pciD->pszSubject = NullStr;
722 }
723 pciD->attrFile = pciS->attrFile;
724 pciD->pszDispAttr = pciS->pszDispAttr;
725 pciD->flags = 0; // Just on one side
726 pciD->date = pciS->date;
727 pciD->time = pciS->time;
728 pciD->ladate = pciS->ladate;
729 pciD->latime = pciS->latime;
730 pciD->crdate = pciS->crdate;
731 pciD->crtime = pciS->crtime;
732 // 2013-03-06 SHL
733 if (pciS->pszFmtFileSize == NullStr)
734 pciD->pszFmtFileSize = pciS->pszFmtFileSize;
735 else
736 pciD->pszFmtFileSize = strdup(pciS->pszFmtFileSize);
737 pciD->cbFile = pciS->cbFile;
738 pciD->easize = pciS->easize;
739
740 if (pciS->pszFileName != NullStr) {
741 xfree(pciS->pszFileName, pszSrcFile, __LINE__);
742 pciS->pszFileName = NullStr;
743 pciS->pszDisplayName = pciS->pszFileName;
744 pciS->rc.pszIcon = pciS->pszFileName;
745 }
746 if (pciS->pszSubject != NullStr) {
747 xfree(pciS->pszSubject, pszSrcFile, __LINE__);
748 pciS->pszSubject = NullStr;
749 }
750 pciS->flags = 0; // Just on one side
751
752 if (!WinSendMsg(hwndCnrS, CM_INVALIDATERECORD, MPFROMP(&pciS),
753 MPFROM2SHORT(1, CMA_ERASE | CMA_TEXTCHANGED))) {
754 Win_Error(hwndCnrS, cmp->hwnd, pszSrcFile, __LINE__, "CM_INVALIDATERECORD");
755 }
756
757 if (!WinSendMsg(hwndCnrD, CM_INVALIDATERECORD, MPFROMP(&pciD),
758 MPFROM2SHORT(1, CMA_ERASE | CMA_TEXTCHANGED))) {
759 Win_Error(hwndCnrD, cmp->hwnd, pszSrcFile, __LINE__, "CM_INVALIDATERECORD");
760 }
761
762 if (hwndCnrS == WinWindowFromID(cmp->hwnd, COMP_LEFTDIR))
763 cmp->cmp->totalleft--;
764 else
765 cmp->cmp->totalright--;
766 }
767 else if (rc) {
768 rc = Dos_Error(MB_ENTERCANCEL,
769 rc,
770 HWND_DESKTOP,
771 pszSrcFile,
772 __LINE__,
773 GetPString(IDS_COMPMOVEFAILEDTEXT),
774 pciS->pszFileName, szNewName);
775 if (rc == MBID_CANCEL) // Cause loop to break
776 pciNextS = NULL;
777 }
778 break;
779 }
780
781 case IDM_COPY:
782 {
783 BOOL fResetVerify = FALSE;
784
785 if (hwndCnrS == WinWindowFromID(cmp->hwnd, COMP_RIGHTDIR))
786 BldFullPathName(szNewName, cmp->leftdir, pciS->pszDisplayName);
787 else
788 BldFullPathName(szNewName, cmp->rightdir, pciS->pszDisplayName);
789 // Make directory if required
790 strcpy(szDirName, szNewName);
791 p = strrchr(szDirName, '\\');
792 if (fVerify && (driveflags[toupper(*szNewName) - 'A'] & DRIVE_WRITEVERIFYOFF ||
793 driveflags[toupper(*pciS->pszFileName) - 'A'] & DRIVE_WRITEVERIFYOFF)) {
794 DosSetVerify(FALSE);
795 fResetVerify = TRUE;
796 }
797 if (p) {
798 if (p > szDirName + 2)
799 p++;
800 *p = 0;
801 if (IsFile(szDirName) == -1)
802 MassMkdir(hwndMain, szDirName);
803 }
804 if (fConfirmAction && pciS->flags & CNRITEM_EXISTS && !dontask) {
805 rc = ConfirmAction(cmp->hwnd, pciS->pszFileName, szNewName);
806 if (rc == 1)
807 break;
808 else if (rc == 2)
809 dontask = TRUE;
810 }
811 rc = docopyf(COPY, pciS->pszFileName, szNewName);
812 if (fResetVerify) {
813 DosSetVerify(fVerify);
814 fResetVerify = FALSE;
815 }
816 if (rc) {
817 rc = Dos_Error(MB_ENTERCANCEL,
818 rc,
819 HWND_DESKTOP,
820 pszSrcFile,
821 __LINE__,
822 GetPString(IDS_COMPCOPYFAILEDTEXT),
823 pciS->pszFileName, szNewName);
824 if (rc == MBID_CANCEL)
825 pciNextS = NULL; // Cause loop to break
826 }
827 else {
828 WinSendMsg(hwndCnrS, CM_SETRECORDEMPHASIS, MPFROMP(pciS),
829 MPFROM2SHORT(FALSE, CRA_SELECTED));
830 if (pciD->rc.flRecordAttr & CRA_SELECTED)
831 WinSendMsg(hwndCnrD, CM_SETRECORDEMPHASIS, MPFROMP(pciD),
832 MPFROM2SHORT(FALSE, CRA_SELECTED));
833 if (~pciD->flags & CNRITEM_EXISTS) {
834 if (hwndCnrD == WinWindowFromID(cmp->hwnd, COMP_LEFTDIR))
835 cmp->cmp->totalleft++;
836 else
837 cmp->cmp->totalright++;
838 }
839 FreeCnrItemData(pciD);
840 pciD->pszFileName = xstrdup(szNewName, pszSrcFile, __LINE__);
841 if (hwndCnrS == WinWindowFromID(cmp->hwnd, COMP_RIGHTDIR)) {
842 pciD->pszDisplayName = pciD->pszFileName + strlen(cmp->leftdir);
843 if (cmp->leftdir[strlen(cmp->leftdir) - 1] != '\\')
844 pciD->pszDisplayName++;
845 }
846 else {
847 pciD->pszDisplayName = pciD->pszFileName + strlen(cmp->rightdir);
848 if (cmp->rightdir[strlen(cmp->rightdir) - 1] != '\\')
849 pciD->pszDisplayName++;
850 }
851 pciD->attrFile = pciS->attrFile;
852 pciD->pszDispAttr = pciS->pszDispAttr;
853 pciD->flags = CNRITEM_EXISTS; // Now on both sides
854 pciD->date = pciS->date;
855 pciD->time = pciS->time;
856 pciD->ladate = pciS->ladate;
857 pciD->latime = pciS->latime;
858 pciD->crdate = pciS->crdate;
859 pciD->crtime = pciS->crtime;
860 // 2013-03-06 SHL
861 if (pciS->pszFmtFileSize == NullStr)
862 pciD->pszFmtFileSize = pciS->pszFmtFileSize;
863 else
864 pciD->pszFmtFileSize = strdup(pciS->pszFmtFileSize);
865 pciD->cbFile = pciS->cbFile;
866 pciD->easize = pciS->easize;
867
868 // Forget status until we regenerate it
869 if (pciS->pszSubject != NullStr) {
870 xfree(pciS->pszSubject, pszSrcFile, __LINE__);
871 pciS->pszSubject = NullStr;
872 }
873 pciS->flags = CNRITEM_EXISTS; // Now on both sides
874
875 WinSendMsg(hwndCnrS, CM_INVALIDATERECORD, MPFROMP(&pciS),
876 MPFROM2SHORT(1, CMA_ERASE | CMA_TEXTCHANGED));
877 WinSendMsg(hwndCnrD, CM_INVALIDATERECORD, MPFROMP(&pciD),
878 MPFROM2SHORT(1, CMA_ERASE | CMA_TEXTCHANGED));
879 }
880 break;
881 }
882
883 default:
884 break;
885 } // switch
886
887 } // if have name
888 if (enddelete)
889 break;
890 pciS = pciNextS;
891 pciD = pciNextD;
892
893 SleepIfNeeded(&itdSleep, 0);
894 } // while
895
896 WinPostMsg(cmp->hwnd, WM_TIMER, MPFROMLONG(ID_COMP_TIMER), 0); // Force update
897 Abort:
898 WinDestroyMsgQueue(hmq);
899 }
900 PostMsg(cmp->hwnd, UM_CONTAINER_FILLED, MPFROMLONG(1), MPVOID);
901 DecrThreadUsage();
902 free(cmp);
903 WinTerminate(hab);
904# ifdef FORTIFY
905 Fortify_LeaveScope();
906# endif
907 }
908 else
909 xfree(cmp, pszSrcFile, __LINE__);
910}
911
912static VOID CompSelect(HWND hwndCnrS, HWND hwndCnrD, HWND hwnd, INT action, USHORT shiftstate, BOOL *stop);
913
914/**
915 * Update container selection flags thread
916 */
917
918static VOID SelectCnrsThread(VOID *args)
919{
920 COMPARE *cmp = (COMPARE *)args;
921 HAB hab;
922 HMQ hmq;
923
924 if (!cmp) {
925 Runtime_Error(pszSrcFile, __LINE__, NULL);
926 return;
927 }
928
929 DosError(FERR_DISABLEHARDERR);
930
931 hab = WinInitialize(0);
932 if (hab) {
933# ifdef FORTIFY
934 Fortify_EnterScope();
935# endif
936 hmq = WinCreateMsgQueue(hab, 0);
937 if (hmq) {
938 WinCancelShutdown(hmq, TRUE);
939 IncrThreadUsage();
940 priority_normal();
941 switch (cmp->action) {
942 case IDM_INVERT:
943 InvertAll(WinWindowFromID(cmp->hwnd, COMP_LEFTDIR));
944 InvertAll(WinWindowFromID(cmp->hwnd, COMP_RIGHTDIR));
945 break;
946
947 case IDM_DESELECTALL:
948 Deselect(WinWindowFromID(cmp->hwnd, COMP_LEFTDIR));
949 Deselect(WinWindowFromID(cmp->hwnd, COMP_RIGHTDIR));
950 break;
951
952 default:
953 CompSelect(WinWindowFromID(cmp->hwnd, COMP_LEFTDIR),
954 WinWindowFromID(cmp->hwnd, COMP_RIGHTDIR),
955 cmp->hwnd,
956 cmp->action,
957 cmp->shiftstate,
958 &cmp->cmp->stop);
959 break;
960 }
961 if (!PostMsg(cmp->hwnd, UM_CONTAINER_FILLED, MPFROMLONG(1L), MPVOID))
962 WinSendMsg(cmp->hwnd, UM_CONTAINER_FILLED, MPFROMLONG(1L), MPVOID);
963 WinDestroyMsgQueue(hmq);
964 }
965 DecrThreadUsage();
966 free(cmp);
967 WinTerminate(hab);
968# ifdef FORTIFY
969 Fortify_LeaveScope();
970# endif
971 }
972 else {
973 DosRequestMutexSem(hmtxFiltering, SEM_INDEFINITE_WAIT);
974 free(cmp);
975 cmp = NULL;
976 DosReleaseMutexSem(hmtxFiltering);
977 }
978}
979
980/**
981 * Set item selections for CompSelect
982 */
983
984static VOID CompSelectSetSelects(PCNRITEM pciS, PCNRITEM pciD, BOOL matchS, BOOL matchD, BOOL wantAnd);
985
986static VOID CompSelectSetSelects(PCNRITEM pciS, PCNRITEM pciD, BOOL matchS, BOOL matchD, BOOL wantAnd)
987{
988 ULONG oldSel;
989 ULONG newSel;
990
991 oldSel = pciS->rc.flRecordAttr & CRA_SELECTED;
992 newSel = matchS ? (wantAnd ? oldSel : CRA_SELECTED) : (wantAnd ? 0 : oldSel);
993 if ((pciS->rc.flRecordAttr & CRA_SELECTED) != newSel)
994 WinSendMsg(pciS->hwndCnr, CM_SETRECORDEMPHASIS, MPFROMP(pciS),
995 MPFROM2SHORT(newSel ? TRUE : FALSE, CRA_SELECTED));
996
997 oldSel = pciD->rc.flRecordAttr & CRA_SELECTED;
998 newSel = matchD ? (wantAnd ? oldSel : CRA_SELECTED) : (wantAnd ? 0 : oldSel);
999 if ((pciD->rc.flRecordAttr & CRA_SELECTED) != newSel) {
1000 WinSendMsg(pciD->hwndCnr, CM_SETRECORDEMPHASIS, MPFROMP(pciD),
1001 MPFROM2SHORT(newSel ? TRUE : FALSE, CRA_SELECTED));
1002 }
1003}
1004
1005/**
1006 * Clear item selections for CompSelect
1007 */
1008
1009static BOOL CompSelectClearSelects(PCNRITEM pciS, PCNRITEM pciD, BOOL matchS, BOOL matchD);
1010
1011static BOOL CompSelectClearSelects(PCNRITEM pciS, PCNRITEM pciD, BOOL matchS, BOOL matchD)
1012{
1013 BOOL changed;
1014
1015 if ((pciS->rc.flRecordAttr & CRA_SELECTED) && matchS) {
1016 WinSendMsg(pciS->hwndCnr, CM_SETRECORDEMPHASIS, MPFROMP(pciS),
1017 MPFROM2SHORT(FALSE, CRA_SELECTED));
1018 changed = TRUE;
1019 }
1020 else
1021 changed = FALSE;
1022
1023 if ((pciD->rc.flRecordAttr & CRA_SELECTED) && matchD) {
1024 WinSendMsg(pciD->hwndCnr, CM_SETRECORDEMPHASIS, MPFROMP(pciD),
1025 MPFROM2SHORT(FALSE, CRA_SELECTED));
1026 changed = TRUE;
1027 }
1028
1029 return changed;
1030}
1031
1032/**
1033 * Do select actions for compare directories containers
1034 * @param action is select mode
1035 */
1036
1037static VOID CompSelect(HWND hwndCnrS, HWND hwndCnrD, HWND hwnd, INT action, USHORT shiftstate, BOOL *stop)
1038{
1039 PCNRITEM pciS;
1040 PCNRITEM pciD;
1041 PCNRITEM *pciSa = NULL;
1042 PCNRITEM *pciDa = NULL;
1043 CNRINFO cnri;
1044 BOOL slow = FALSE;
1045 UINT x;
1046 UINT numD;
1047 UINT numS;
1048 ITIMER_DESC itdSleep = { 0 };
1049 BOOL fUpdateHideButton = FALSE;
1050 BOOL wantAnd = (shiftstate & (KC_SHIFT | KC_ALT | KC_CTRL)) == KC_CTRL;
1051 BOOL matched;
1052
1053 if (!hwndCnrS || !hwndCnrD) {
1054 Runtime_Error(pszSrcFile, __LINE__, "hwndCnrS %p hwndCnrD %p", hwndCnrS, hwndCnrD);
1055 return;
1056 }
1057
1058 memset(&cnri, 0, sizeof(CNRINFO));
1059 cnri.cb = sizeof(CNRINFO);
1060 WinSendMsg(hwndCnrD, CM_QUERYCNRINFO, MPFROMP(&cnri),
1061 MPFROMLONG(sizeof(CNRINFO)));
1062 numD = cnri.cRecords;
1063 memset(&cnri, 0, sizeof(CNRINFO));
1064 cnri.cb = sizeof(CNRINFO);
1065 WinSendMsg(hwndCnrS, CM_QUERYCNRINFO, MPFROMP(&cnri),
1066 MPFROMLONG(sizeof(CNRINFO)));
1067 numS = cnri.cRecords;
1068 if (!numD || numS != numD) {
1069 Runtime_Error(pszSrcFile, __LINE__, "numD %u != numS %u", numD, numS);
1070 return;
1071 }
1072
1073 pciDa = xmalloc(sizeof(PCNRITEM) * numD, pszSrcFile, __LINE__);
1074 if (!pciDa)
1075 return;
1076
1077 pciSa = xmalloc(sizeof(PCNRITEM) * numS, pszSrcFile, __LINE__);
1078 if (!pciSa) {
1079 free(pciDa);
1080 return;
1081 }
1082
1083 InitITimer(&itdSleep, 500); // Sleep every 500 mSec
1084
1085Restart:
1086
1087 memset(pciDa, 0, sizeof(PCNRITEM) * numD);
1088 memset(pciSa, 0, sizeof(PCNRITEM) * numS);
1089
1090 pciD = (PCNRITEM)WinSendMsg(hwndCnrD, CM_QUERYRECORD, MPVOID,
1091 MPFROM2SHORT(CMA_FIRST, CMA_ITEMORDER));
1092 x = 0;
1093 while (pciD && (INT)pciD != -1 && x < numD) {
1094 pciDa[x] = pciD;
1095 x++;
1096 if (!slow)
1097 pciD = (PCNRITEM) pciD->rc.preccNextRecord;
1098 else
1099 pciD = (PCNRITEM) WinSendMsg(hwndCnrD, CM_QUERYRECORD, MPFROMP(pciD),
1100 MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER));
1101 SleepIfNeeded(&itdSleep, 0);
1102 } // while
1103
1104 if (numD != x) {
1105 // Something out of sync - FIXME to document why slow logic needed
1106 if (!slow) {
1107 slow = TRUE;
1108 goto Restart;
1109 }
1110 free(pciDa);
1111 free(pciSa);
1112 Runtime_Error(pszSrcFile, __LINE__, "numD %u != x %lu", numD, x);
1113 return;
1114 }
1115
1116 pciS = (PCNRITEM) WinSendMsg(hwndCnrS, CM_QUERYRECORD, MPVOID,
1117 MPFROM2SHORT(CMA_FIRST, CMA_ITEMORDER));
1118 x = 0;
1119 while (pciS && (INT)pciS != -1 && x < numS) {
1120 pciSa[x] = pciS;
1121 x++;
1122 if (!slow)
1123 pciS = (PCNRITEM) pciS->rc.preccNextRecord;
1124 else
1125 pciS = (PCNRITEM) WinSendMsg(hwndCnrS, CM_QUERYRECORD, MPFROMP(pciS),
1126 MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER));
1127 SleepIfNeeded(&itdSleep, 0);
1128 } // while
1129
1130 if (numS != x) {
1131 if (!slow) {
1132 slow = TRUE;
1133 goto Restart;
1134 }
1135 free(pciSa);
1136 free(pciDa);
1137 Runtime_Error(pszSrcFile, __LINE__, "numS (%lu) != x (%lu)", numS, x);
1138 return;
1139 }
1140
1141 switch (action) {
1142 case IDM_SELECTIDENTICAL:
1143 // Same Date/size including EAs
1144 for (x = 0; x < numS; x++) {
1145 pciS = pciSa[x];
1146 if (~pciS->rc.flRecordAttr & CRA_FILTERED) {
1147 matched = pciS->flags & CNRITEM_EXISTS &&
1148 ~pciS->flags & CNRITEM_SMALLER &&
1149 ~pciS->flags & CNRITEM_LARGER &&
1150 ~pciS->flags & CNRITEM_NEWER &&
1151 ~pciS->flags & CNRITEM_OLDER &&
1152 ~pciS->flags & CNRITEM_EASDIFFER;
1153 CompSelectSetSelects(pciS, pciDa[x], matched, matched, wantAnd);
1154 }
1155 SleepIfNeeded(&itdSleep, 0);
1156 } // for
1157 break;
1158
1159 case IDM_SELECTSAME:
1160 // Same Size including EAs
1161 for (x = 0; x < numS; x++) {
1162 pciS = pciSa[x];
1163 if (~pciS->rc.flRecordAttr & CRA_FILTERED) {
1164 matched = pciS->flags & CNRITEM_EXISTS &&
1165 ~pciS->flags & CNRITEM_SMALLER &&
1166 ~pciS->flags & CNRITEM_LARGER &&
1167 ~pciS->flags & CNRITEM_EASDIFFER;
1168 CompSelectSetSelects(pciS, pciDa[x], matched, matched, wantAnd);
1169 }
1170 SleepIfNeeded(&itdSleep, 0);
1171 } // for
1172 break;
1173
1174 case IDM_SELECTSAMECONTENT:
1175 for (x = 0; x < numS && !*stop; x++) {
1176
1177 pciS = pciSa[x];
1178 if (~pciS->rc.flRecordAttr & CRA_FILTERED) {
1179 matched = FALSE;
1180 pciD = pciDa[x];
1181 if (pciS->flags & CNRITEM_EXISTS) {
1182 FILE *fp1 = NULL;
1183 FILE *fp2 = NULL;
1184 UINT errLineNo = 0;
1185 UINT compErrno = 0;
1186 CHAR buf1[1024];
1187 CHAR buf2[1024];
1188 HAB hab = WinQueryAnchorBlock(hwndCnrS);
1189 CHAR *moderb = "rb";
1190
1191 if (!*pciS->pszFileName ||
1192 !*pciD->pszFileName) {
1193 Runtime_Error(pszSrcFile, __LINE__,
1194 "CNRITEM_EXISTS set with null file name for index %u", x);
1195 break;
1196 }
1197
1198 fp1 = xfsopen(pciS->pszFileName, moderb, SH_DENYNO, pszSrcFile, __LINE__, TRUE);
1199 if (!fp1) {
1200 errLineNo = __LINE__;
1201 compErrno = errno;
1202 }
1203 else {
1204 fp2 = xfsopen(pciD->pszFileName, moderb, SH_DENYNO, pszSrcFile, __LINE__, TRUE);
1205 if (!fp2) {
1206 errLineNo = __LINE__;
1207 compErrno = errno;
1208 }
1209 else {
1210 size_t len1 = filelength(fileno(fp1));
1211 size_t len2 = filelength(fileno(fp2));
1212 if (len1 == len2) {
1213 setbuf(fp1, NULL);
1214 setbuf(fp2, NULL);
1215 while (WinIsWindow(hab, hwndCnrS)) {
1216 size_t numread1 = fread(buf1, 1, 1024, fp1);
1217 size_t numread2 = fread(buf2, 1, 1024, fp2);
1218
1219 if (!numread1 || !numread2 || numread1 != numread2) {
1220 if (ferror(fp1) || ferror(fp2)) {
1221 errLineNo = __LINE__;
1222 compErrno = errno;
1223 }
1224 else if (feof(fp1) && feof(fp2))
1225 matched = TRUE;
1226 break;
1227 }
1228 else if (memcmp(buf1, buf2, numread1))
1229 break;
1230 } // while
1231 } // same len
1232 } // if open ok
1233 } // if open ok
1234 if (fp1)
1235 fclose(fp1);
1236 if (fp2)
1237 fclose(fp2);
1238
1239 if (errLineNo) {
1240 Runtime_Error(pszSrcFile, errLineNo,
1241 "error %d while comparing", compErrno);
1242 }
1243 } // if exists
1244 CompSelectSetSelects(pciS, pciD, matched, matched, wantAnd);
1245 } // if not filtered
1246 SleepIfNeeded(&itdSleep, 0);
1247 } // for
1248 break;
1249
1250 case IDM_SELECTBOTH:
1251 for (x = 0; x < numS; x++) {
1252 pciS = pciSa[x];
1253 if (~pciS->rc.flRecordAttr & CRA_FILTERED) {
1254 pciD = pciDa[x];
1255 matched = pciS->flags & CNRITEM_EXISTS;
1256 CompSelectSetSelects(pciS, pciD, matched, matched, wantAnd);
1257 }
1258 SleepIfNeeded(&itdSleep, 0);
1259 } // for
1260 break;
1261
1262 case IDM_SELECTONE:
1263 for (x = 0; x < numS; x++) {
1264 pciS = pciSa[x];
1265 if (~pciS->rc.flRecordAttr & CRA_FILTERED) {
1266 pciD = pciDa[x];
1267 CompSelectSetSelects(pciS,
1268 pciD,
1269 ~pciS->flags & CNRITEM_EXISTS && *pciS->pszFileName,
1270 ~pciD->flags & CNRITEM_EXISTS && *pciD->pszFileName,
1271 wantAnd);
1272 }
1273 SleepIfNeeded(&itdSleep, 0);
1274 } // for
1275 break;
1276
1277 case IDM_SELECTBIGGER:
1278 for (x = 0; x < numS; x++) {
1279 pciS = pciSa[x];
1280 if (~pciS->rc.flRecordAttr & CRA_FILTERED) {
1281 pciD = pciDa[x];
1282 CompSelectSetSelects(pciS,
1283 pciD,
1284 pciS->flags & CNRITEM_LARGER,
1285 pciD->flags & CNRITEM_LARGER,
1286 wantAnd);
1287 }
1288 SleepIfNeeded(&itdSleep, 0);
1289 } // for
1290 break;
1291
1292 case IDM_SELECTSMALLER:
1293 for (x = 0; x < numS; x++) {
1294 pciS = pciSa[x];
1295 if (~pciS->rc.flRecordAttr & CRA_FILTERED) {
1296 pciD = pciDa[x];
1297 CompSelectSetSelects(pciS,
1298 pciD,
1299 pciS->flags & CNRITEM_SMALLER,
1300 pciD->flags & CNRITEM_SMALLER,
1301 wantAnd);
1302 }
1303 SleepIfNeeded(&itdSleep, 0);
1304 } // for
1305 break;
1306
1307 case IDM_SELECTNEWER:
1308 for (x = 0; x < numS; x++) {
1309 pciS = pciSa[x];
1310 if (~pciS->rc.flRecordAttr & CRA_FILTERED) {
1311 pciD = pciDa[x];
1312 CompSelectSetSelects(pciS,
1313 pciD,
1314 pciS->flags & CNRITEM_NEWER,
1315 pciD->flags & CNRITEM_NEWER,
1316 wantAnd);
1317 }
1318 SleepIfNeeded(&itdSleep, 0);
1319 } // for
1320 break;
1321
1322 case IDM_SELECTOLDER:
1323 for (x = 0; x < numS; x++) {
1324 pciS = pciSa[x];
1325 if (~pciS->rc.flRecordAttr & CRA_FILTERED) {
1326 pciD = pciDa[x];
1327 CompSelectSetSelects(pciS,
1328 pciD,
1329 pciS->flags & CNRITEM_OLDER,
1330 pciD->flags & CNRITEM_OLDER,
1331 wantAnd);
1332 }
1333 SleepIfNeeded(&itdSleep, 0);
1334 } // for
1335 break;
1336
1337 case IDM_SELECTEAS:
1338 for (x = 0; x < numS; x++) {
1339 pciS = pciSa[x];
1340 if (~pciS->rc.flRecordAttr & CRA_FILTERED) {
1341 pciD = pciDa[x];
1342 CompSelectSetSelects(pciS,
1343 pciD,
1344 pciS->flags & CNRITEM_EASDIFFER,
1345 pciD->flags & CNRITEM_EASDIFFER,
1346 wantAnd);
1347 }
1348 SleepIfNeeded(&itdSleep, 0);
1349 } // for
1350 break;
1351
1352 case IDM_DESELECTBOTH:
1353 for (x = 0; x < numS; x++) {
1354 pciS = pciSa[x];
1355 if (~pciS->rc.flRecordAttr & CRA_FILTERED) {
1356 matched = pciS->flags & CNRITEM_EXISTS;
1357 if (CompSelectClearSelects(pciS, pciDa[x], matched, matched))
1358 fUpdateHideButton = TRUE;
1359 }
1360 SleepIfNeeded(&itdSleep, 0);
1361 } // for
1362 break;
1363
1364 case IDM_DESELECTONE:
1365 for (x = 0; x < numS; x++) {
1366 pciS = pciSa[x];
1367 if (~pciS->rc.flRecordAttr & CRA_FILTERED) {
1368 pciD = pciDa[x];
1369 if (CompSelectClearSelects(pciS,
1370 pciD,
1371 ~pciS->flags & CNRITEM_EXISTS && *pciS->pszFileName,
1372 ~pciD->flags & CNRITEM_EXISTS && *pciD->pszFileName)) {
1373 fUpdateHideButton = TRUE;
1374 }
1375 }
1376 SleepIfNeeded(&itdSleep, 0);
1377 } // for
1378 break;
1379
1380 case IDM_DESELECTBIGGER:
1381 for (x = 0; x < numS; x++) {
1382 pciS = pciSa[x];
1383 if (~pciS->rc.flRecordAttr & CRA_FILTERED) {
1384 pciD = pciDa[x];
1385 if (CompSelectClearSelects(pciS,
1386 pciD,
1387 pciS->flags & CNRITEM_LARGER,
1388 pciD->flags & CNRITEM_LARGER)) {
1389 fUpdateHideButton = TRUE;
1390 }
1391 }
1392 SleepIfNeeded(&itdSleep, 0);
1393 } // for
1394 break;
1395
1396 case IDM_DESELECTSMALLER:
1397 for (x = 0; x < numS; x++) {
1398 pciS = pciSa[x];
1399 if (~pciS->rc.flRecordAttr & CRA_FILTERED) {
1400 pciD = pciDa[x];
1401 if (CompSelectClearSelects(pciS,
1402 pciD,
1403 pciS->flags & CNRITEM_SMALLER,
1404 pciD->flags & CNRITEM_SMALLER)) {
1405 fUpdateHideButton = TRUE;
1406 }
1407 }
1408 SleepIfNeeded(&itdSleep, 0);
1409 } // for
1410 break;
1411
1412 case IDM_DESELECTNEWER:
1413 for (x = 0; x < numS; x++) {
1414 pciS = pciSa[x];
1415 if (~pciS->rc.flRecordAttr & CRA_FILTERED) {
1416 pciD = pciDa[x];
1417 if (CompSelectClearSelects(pciS,
1418 pciD,
1419 pciS->flags & CNRITEM_NEWER,
1420 pciD->flags & CNRITEM_NEWER)) {
1421 fUpdateHideButton = TRUE;
1422 }
1423 }
1424 SleepIfNeeded(&itdSleep, 0);
1425 } // for
1426 break;
1427
1428 case IDM_DESELECTOLDER:
1429 for (x = 0; x < numS; x++) {
1430 pciS = pciSa[x];
1431 if (~pciS->rc.flRecordAttr & CRA_FILTERED) {
1432 pciD = pciDa[x];
1433 if (CompSelectClearSelects(pciS,
1434 pciD,
1435 pciS->flags & CNRITEM_OLDER,
1436 pciD->flags & CNRITEM_OLDER)) {
1437 fUpdateHideButton = TRUE;
1438 }
1439 }
1440 SleepIfNeeded(&itdSleep, 0);
1441 } // for
1442 break;
1443
1444 case IDM_DESELECTEAS:
1445 for (x = 0; x < numS; x++) {
1446 pciS = pciSa[x];
1447 if (~pciS->rc.flRecordAttr & CRA_FILTERED) {
1448 pciD = pciDa[x];
1449 if (CompSelectClearSelects(pciS,
1450 pciD,
1451 pciS->flags & CNRITEM_EASDIFFER,
1452 pciD->flags & CNRITEM_EASDIFFER)) {
1453 fUpdateHideButton = TRUE;
1454 }
1455 }
1456 SleepIfNeeded(&itdSleep, 0);
1457 } // for
1458 break;
1459
1460 default:
1461 break;
1462 } // switch action
1463
1464 free(pciSa);
1465 free(pciDa);
1466
1467 if (fUpdateHideButton) {
1468 if (WinQueryButtonCheckstate(hwnd,COMP_HIDENOTSELECTED) == 1)
1469 WinCheckButton(hwnd, COMP_HIDENOTSELECTED, 2);
1470 }
1471
1472 WinPostMsg(hwnd, WM_TIMER, MPFROMLONG(ID_COMP_TIMER), 0); // Force update
1473 DosPostEventSem(CompactSem);
1474}
1475
1476/**
1477 * Build FILELIST given pathname
1478 */
1479
1480static VOID FillDirList(CHAR *str, UINT skiplen, BOOL recurse,
1481 FILELIST ***list, UINT *pnumfiles, UINT *pnumalloc)
1482{
1483 CHAR *enddir;
1484 ULONG x;
1485 CHAR *maskstr;
1486 PFILEFINDBUF4L pffbArray;
1487 PFILEFINDBUF4L pffbFile;
1488 HDIR hDir;
1489 ULONG ulFindCnt;
1490 ULONG ulBufBytes = sizeof(FILEFINDBUF4L) * FilesToGet;
1491 APIRET rc;
1492 static BOOL fDone;
1493 ITIMER_DESC itdSleep = { 0 }; // 30 May 11 GKY
1494
1495 if (!str || !*str) {
1496 Runtime_Error(pszSrcFile, __LINE__, NULL);
1497 return;
1498 }
1499
1500 maskstr = xmalloc(CCHMAXPATH + 100, pszSrcFile, __LINE__);
1501 if (!maskstr)
1502 return;
1503 pffbArray = xmalloc(ulBufBytes, pszSrcFile, __LINE__);
1504 if (!pffbArray) {
1505 free(maskstr);
1506 return;
1507 }
1508 x = strlen(str);
1509 memcpy(maskstr, str, x + 1);
1510 enddir = maskstr + x;
1511 if (*(enddir - 1) != '\\') {
1512 *enddir = '\\';
1513 enddir++;
1514 *enddir = 0;
1515 }
1516 *enddir = '*';
1517 *(enddir + 1) = 0;
1518 hDir = HDIR_CREATE;
1519 DosError(FERR_DISABLEHARDERR);
1520 ulFindCnt = FilesToGet;
1521 rc = xDosFindFirst(maskstr, &hDir,
1522 FILE_NORMAL | FILE_READONLY | FILE_ARCHIVED |
1523 FILE_SYSTEM | FILE_HIDDEN |
1524 (recurse ? FILE_DIRECTORY : 0),
1525 pffbArray, ulBufBytes, &ulFindCnt, FIL_QUERYEASIZEL);
1526 if (!rc) {
1527 InitITimer(&itdSleep, 500);
1528 do {
1529 pffbFile = pffbArray;
1530 for (x = 0; x < ulFindCnt; x++) {
1531 if (pffbFile->attrFile & FILE_DIRECTORY) {
1532 // Skip . and ..
1533 if (recurse &&
1534 (pffbFile->achName[0] != '.' ||
1535 (pffbFile->achName[1] &&
1536 (pffbFile->achName[1] != '.' || pffbFile->achName[2])))) {
1537 if (fForceUpper)
1538 strupr(pffbFile->achName);
1539 else if (fForceLower)
1540 strlwr(pffbFile->achName);
1541 memcpy(enddir, pffbFile->achName, pffbFile->cchName + 1);
1542 FillDirList(maskstr, skiplen, recurse, list, pnumfiles, pnumalloc);
1543 }
1544 }
1545 else {
1546 if (fForceUpper)
1547 strupr(pffbFile->achName);
1548 else if (fForceLower)
1549 strlwr(pffbFile->achName);
1550 memcpy(enddir, pffbFile->achName, pffbFile->cchName + 1);
1551 if (strlen(maskstr) > CCHMAXPATH) {
1552 // Complain if pathnames exceeds max
1553 DosFindClose(hDir);
1554 free(pffbArray);
1555 free(maskstr);
1556 if (!fDone) {
1557 fDone = TRUE;
1558 saymsg(MB_OK | MB_ICONASTERISK,
1559 HWND_DESKTOP,
1560 GetPString(IDS_WARNINGTEXT),
1561 GetPString(IDS_LENGTHEXCEEDSMAXPATHTEXT));
1562 }
1563 return;
1564 }
1565 if (AddToFileList(maskstr + skiplen,
1566 pffbFile, list, pnumfiles, pnumalloc)) {
1567 goto Abort;
1568 }
1569 }
1570 pffbFile = (PFILEFINDBUF4L)((PBYTE)pffbFile + pffbFile->oNextEntryOffset);
1571 } // for
1572 DosError(FERR_DISABLEHARDERR);
1573 ulFindCnt = FilesToGet;
1574 rc = xDosFindNext(hDir, pffbArray, ulBufBytes, &ulFindCnt, FIL_QUERYEASIZEL);
1575 SleepIfNeeded(&itdSleep, 1);
1576 } while (!rc);
1577
1578Abort:
1579
1580 DosFindClose(hDir);
1581 DosSleep(0);
1582 }
1583
1584 if (rc && rc != ERROR_NO_MORE_FILES) {
1585 Dos_Error(MB_ENTER, rc, HWND_DESKTOP, pszSrcFile, __LINE__,
1586 GetPString(IDS_CANTFINDDIRTEXT), maskstr);
1587 }
1588
1589 xfree(maskstr, pszSrcFile, __LINE__);
1590 xfree(pffbArray, pszSrcFile, __LINE__);
1591}
1592
1593#define GetHwndLeft(h) (WinWindowFromID(h,COMP_LEFTDIR))
1594#define GetHwndRight(h) (WinWindowFromID(h,COMP_RIGHTDIR))
1595
1596/**
1597 * Compare names for qsort
1598 */
1599
1600static int CompNames(const void *n1, const void *n2)
1601{
1602 FILELIST *fl1 = *(FILELIST **)n1;
1603 FILELIST *fl2 = *(FILELIST **)n2;
1604
1605 return stricmp(fl1->fname, fl2->fname);
1606}
1607
1608/**
1609 * Fill left and right containers
1610 */
1611
1612static VOID FillCnrsThread(VOID *args)
1613{
1614 COMPARE *cmp = (COMPARE *)args;
1615 HAB hab;
1616 HMQ hmq;
1617 BOOL notified = FALSE;
1618 ITIMER_DESC itdSleep = { 0 };
1619
1620 CHAR szBuf[CCHMAXPATH];
1621 CNRINFO cnri;
1622
1623# ifdef FORTIFY
1624 // 10 May 08 SHL FIXME to suppress W111
1625 Fortify_EnterScope();
1626# endif
1627
1628 if (!cmp) {
1629 Runtime_Error(pszSrcFile, __LINE__, NULL);
1630# ifdef FORTIFY
1631 // 10 May 08 SHL FIXME to suppress W111
1632 Fortify_LeaveScope();
1633# endif
1634 return; // 10 Dec 08 SHL was _endthread
1635 }
1636
1637 DosError(FERR_DISABLEHARDERR);
1638
1639 InitITimer(&itdSleep, 500); // Sleep every 500 mSec
1640
1641 hab = WinInitialize(0);
1642 if (!hab)
1643 Win_Error(NULLHANDLE, NULLHANDLE, pszSrcFile, __LINE__, "WinInitialize");
1644 else {
1645 hmq = WinCreateMsgQueue(hab, 0);
1646 if (!hmq)
1647 Win_Error(NULLHANDLE, NULLHANDLE, pszSrcFile, __LINE__,
1648 "WinCreateMsgQueue");
1649 else {
1650 INT x;
1651 UINT l;
1652 UINT r;
1653 FILELIST **filesl = NULL;
1654 FILELIST **filesr = NULL;
1655 UINT numallocl = 0;
1656 UINT numallocr = 0;
1657 UINT lenl; // Directory prefix length
1658 UINT lenr;
1659 ULONG ulRecsNeeded;
1660 CHAR *pch;
1661 HWND hwndLeft;
1662 HWND hwndRight;
1663
1664 WinCancelShutdown(hmq, TRUE);
1665 IncrThreadUsage();
1666
1667 hwndLeft = GetHwndLeft(cmp->hwnd);
1668 hwndRight = GetHwndRight(cmp->hwnd);
1669 lenl = strlen(cmp->leftdir);
1670 if (cmp->leftdir[strlen(cmp->leftdir) - 1] != '\\')
1671 lenl++;
1672 lenr = strlen(cmp->rightdir);
1673 if (cmp->rightdir[strlen(cmp->rightdir) - 1] != '\\')
1674 lenr++;
1675 priority_normal();
1676 // Clear containers in case restarting
1677 RemoveCnrItems(hwndRight, NULL, 0, CMA_FREE | CMA_INVALIDATE);
1678 RemoveCnrItems(hwndLeft, NULL, 0, CMA_FREE | CMA_INVALIDATE);
1679 cmp->cmp->totalleft = 0;
1680 cmp->cmp->totalright = 0;
1681
1682 // Build list of all files in left directory
1683 if (fForceLower)
1684 strlwr(cmp->leftdir);
1685 else if (fForceUpper)
1686 strupr(cmp->leftdir);
1687 FillDirList(cmp->leftdir, lenl, cmp->includesubdirs,
1688 &filesl, &cmp->cmp->totalleft, &numallocl);
1689 if (filesl)
1690 qsort(filesl, cmp->cmp->totalleft, sizeof(CHAR *), CompNames);
1691 // Build list of all files in right directory
1692 if (!*cmp->rightlist) {
1693 if (fForceLower)
1694 strlwr(cmp->rightdir);
1695 else if (fForceUpper)
1696 strupr(cmp->rightdir);
1697 FillDirList(cmp->rightdir, lenr, cmp->includesubdirs,
1698 &filesr, &cmp->cmp->totalright, &numallocr);
1699 }
1700 else {
1701 // Use snapshot file
1702 FILE *fp;
1703 FILEFINDBUF4L fb4;
1704 CHAR str[CCHMAXPATH * 2], *p;
1705 CHAR *moder = "r";
1706 BOOL fFixedSnap = TRUE;
1707
1708 memset(&fb4, 0, sizeof(fb4));
1709 fp = xfopen(cmp->rightlist, moder, pszSrcFile, __LINE__, FALSE);
1710 if (fp) {
1711 while (!feof(fp)) {
1712 // First get name of directory
1713 if (!xfgets_bstripcr(str, sizeof(str), fp, pszSrcFile, __LINE__))
1714 break; // EOF
1715 p = str;
1716 if (*p == '\"') {
1717 // Quoted
1718 p++;
1719 if (*p && *p != '\"') {
1720 p = strchr(p, '\"');
1721 if (p) {
1722 *p = 0;
1723 if (*(str + 1)) {
1724 strcpy(cmp->rightdir, str + 1);
1725 if (fForceUpper)
1726 strupr(cmp->rightdir);
1727 else if (fForceLower)
1728 strlwr(cmp->rightdir);
1729 p = cmp->rightdir + (strlen(cmp->rightdir) - 1);
1730 if (p - cmp->rightdir > 3 && *p == '\\')
1731 *p = 0; // Chop trailing slash
1732 break;
1733 }
1734 }
1735 }
1736 }
1737 } // while !EOF
1738
1739 memset(&cnri, 0, sizeof(cnri));
1740 cnri.cb = sizeof(cnri);
1741 WinSetDlgItemText(cmp->hwnd, COMP_LISTLOADED, "List File Loaded");
1742 cnri.pszCnrTitle = cmp->rightdir;
1743 if (!WinSendMsg(hwndRight, CM_SETCNRINFO,
1744 MPFROMP(&cnri), MPFROMLONG(CMA_CNRTITLE))) {
1745 Win_Error(hwndRight, cmp->hwnd, pszSrcFile, __LINE__, "CM_SETCNRINFO");
1746 WinSetDlgItemText(cmp->hwnd, COMP_LISTLOADED, "");
1747 }
1748
1749 if (*cmp->rightdir) {
1750 lenr = strlen(cmp->rightdir);
1751 if (cmp->rightdir[strlen(cmp->rightdir) - 1] != '\\')
1752 lenr++;
1753 while (!feof(fp)) {
1754 if (!xfgets_bstripcr
1755 (str, sizeof(str), fp, pszSrcFile, __LINE__)) {
1756 break;
1757 }
1758 p = str;
1759 if (*p == '\"') {
1760 p++;
1761 if (*p && *p != '\"') {
1762 p = strchr(p, '\"');
1763 if (p) {
1764 *p = 0;
1765 p++;
1766 if (*p == ',') {
1767 p++;
1768 if (!cmp->includesubdirs && atol(p) > lenr)
1769 continue;
1770 p = strchr(p, ',');
1771 if (p) {
1772 p++;
1773 if (((strchr(p, '/') ? strchr(p, '/') : strchr(p, DateSeparator[0])) - strchr(p, ',')) > 5) {
1774 CHAR szTemp[30];
1775 CHAR *q;
1776 int i;
1777
1778 memset(szTemp, 0, sizeof(szTemp));
1779 i = (strchr(p, '/') ? strchr(p, '/') : strchr(p, DateSeparator[0])) - 3 - p;
1780 strncpy(&szTemp, p, i);
1781 for (q = szTemp; q = strchr(szTemp, ',');) {
1782 strcpy(q, q + 1);
1783 }
1784 fb4.cbFile = atoll(szTemp);
1785 fFixedSnap = FALSE;
1786
1787 }
1788 else
1789 fb4.cbFile = atoll(p);
1790 if (!strchr(p, '/'))
1791 fFixedSnap = FALSE;
1792 p = (strchr(p, '/') ? strchr(p, '/') : strchr(p, DateSeparator[0])) - 6;
1793 p = strchr(p, ',');
1794 if (p) {
1795 p++;
1796 if (ulDateFmt == 2 || ulDateFmt == 3 || fFixedSnap)
1797 fb4.fdateLastWrite.year = atol(p) - 1980;
1798 else if (ulDateFmt == 1)
1799 fb4.fdateLastWrite.day = atol(p);
1800 else
1801 fb4.fdateLastWrite.month = atol(p);
1802 p = strchr(p, '/') ? strchr(p, '/') : strchr(p, DateSeparator[0]);
1803 if (p) {
1804 p++;
1805 if (ulDateFmt == 2 || ulDateFmt == 1 || fFixedSnap)
1806 fb4.fdateLastWrite.month = atol(p);
1807 else
1808 fb4.fdateLastWrite.day = atol(p);
1809 p = strchr(p, '/') ? strchr(p, '/') : strchr(p, DateSeparator[0]);
1810 if (p) {
1811 p++;
1812 if (ulDateFmt == 2 || fFixedSnap)
1813 fb4.fdateLastWrite.day = atol(p);
1814 else if (ulDateFmt == 3)
1815 fb4.fdateLastWrite.month = atol(p);
1816 else
1817 fb4.fdateLastWrite.year = atol(p) - 1980;
1818 p = strchr(p, ',');
1819 if (p) {
1820 p++;
1821 fb4.ftimeLastWrite.hours = atol(p);
1822 p = strchr(p, ':') ? strchr(p, ':') : strchr(p, TimeSeparator[0]);
1823 if (p) {
1824 p++;
1825 fb4.ftimeLastWrite.minutes = atol(p);
1826 p = strchr(p, ':') ? strchr(p, ':') : strchr(p, TimeSeparator[0]);
1827 if (p) {
1828 p++;
1829 fb4.ftimeLastWrite.twosecs = atol(p);
1830 p = strchr(p, ',');
1831 if (p) {
1832 p++;
1833 fb4.attrFile = atol(p);
1834 p = strchr(p, ',');
1835 if (p) {
1836 p++;
1837 fb4.cbList = atol(p) * 2;
1838 if (fForceUpper)
1839 strupr(str + 1);
1840 else if (fForceLower)
1841 strlwr(str + 1);
1842 if (AddToFileList((str + 1) + lenr,
1843 &fb4,
1844 &filesr,
1845 &cmp->cmp->totalright,
1846 &numallocr))
1847 break;
1848 }
1849 }
1850 }
1851 }
1852 }
1853 }
1854 }
1855 }
1856 }
1857 }
1858 }
1859 }
1860 }
1861 } // while
1862 } // if have rightdir
1863 fclose(fp);
1864 if (!filesr)
1865 saymsg(MB_OK | MB_ICONASTERISK, HWND_DESKTOP,
1866 GetPString(IDS_WARNINGTEXT),
1867 GetPString(IDS_SNAPSHOTFILEBADFORMAT));
1868 }
1869 else
1870 saymsg(MB_OK | MB_ICONASTERISK, HWND_DESKTOP,
1871 GetPString(IDS_WARNINGTEXT),
1872 GetPString(IDS_SNAPSHOTFILELOADFAILED), cmp->rightlist);
1873 } // if snapshot file
1874
1875 if (filesr)
1876 qsort(filesr, cmp->cmp->totalright, sizeof(CHAR *), CompNames);
1877
1878 // We now have two lists of files, both sorted.
1879 // Count total number of container entries required on each side
1880 l = 0;
1881 r = 0;
1882 ulRecsNeeded = 0;
1883 while ((filesl && filesl[l]) || (filesr && filesr[r])) {
1884
1885 if (cmp->stop)
1886 break; // Cancel requested
1887
1888 if (filesl && filesl[l]) {
1889 if (filesr && filesr[r])
1890 x = stricmp(filesl[l]->fname, filesr[r]->fname);
1891 else
1892 x = -1; // Left side list longer
1893 }
1894 else
1895 x = +1; // Right side list longer
1896
1897 if (x <= 0)
1898 l++; // On left side
1899 if (x >= 0)
1900 r++; // On right side
1901
1902 ulRecsNeeded++; // Count how many entries req'd
1903
1904 } // while counting
1905
1906 if (cmp->stop)
1907 ulRecsNeeded = 0;
1908
1909 // Insert records into the containers
1910
1911 if (ulRecsNeeded) {
1912
1913 PCNRITEM pcilFirst;
1914 PCNRITEM pcirFirst;
1915 PCNRITEM pcil = NULL;
1916 PCNRITEM pcir = NULL;
1917 INT ret;
1918 ULONG ulRecsAllocated = 0;
1919 ULONG insertedl;
1920 ULONG insertedr;
1921
1922 l = 0;
1923 r = 0;
1924
1925 // Use send to get message on screen quickly
1926 WinSendMsg(cmp->hwnd, UM_CONTAINERHWND, MPVOID, MPVOID);
1927
1928 cmp->cmp->totalleft = 0;
1929 cmp->cmp->totalright = 0;
1930
1931 while ((filesl && filesl[l]) || (filesr && filesr[r])) {
1932
1933 ULONG ulRecsToInsert; // limited to USHRT_MAX
1934
1935 if (cmp->stop)
1936 break;
1937
1938 // Check alloc needed
1939 if (!pcil || !pcir) {
1940 if (pcil != pcir) {
1941 Runtime_Error(pszSrcFile, __LINE__, GetPString(IDS_LEFTRIGHTOUTOFSYNC));
1942 cmp->stop = TRUE;
1943 break;
1944 }
1945 ulRecsToInsert = ulRecsNeeded - ulRecsAllocated;
1946 if (ulRecsToInsert > USHRT_MAX)
1947 ulRecsToInsert = USHRT_MAX;
1948
1949 pcilFirst = WinSendMsg(hwndLeft,
1950 CM_ALLOCRECORD,
1951 MPFROMLONG(EXTRA_RECORD_BYTES),
1952 MPFROMLONG(ulRecsToInsert));
1953 if (!pcilFirst) {
1954 Win_Error(hwndLeft, cmp->hwnd, pszSrcFile, __LINE__, PCSZ_CM_ALLOCRECORD);
1955 cmp->stop = TRUE;
1956 break;
1957 }
1958 pcirFirst = WinSendMsg(hwndRight, CM_ALLOCRECORD,
1959 MPFROMLONG(EXTRA_RECORD_BYTES),
1960 MPFROMLONG(ulRecsToInsert));
1961 if (!pcirFirst) {
1962 Win_Error(hwndRight, cmp->hwnd, pszSrcFile, __LINE__, PCSZ_CM_ALLOCRECORD);
1963 FreeCnrItemList(hwndLeft, pcilFirst);
1964 pcilFirst = NULL;
1965 cmp->stop = TRUE;
1966 break;
1967 }
1968 pcil = pcilFirst;
1969 pcir = pcirFirst;
1970 insertedl = 0;
1971 insertedr = 0;
1972 ulRecsAllocated += ulRecsToInsert;
1973 } // if need alloc
1974
1975 pcir->hwndCnr = hwndRight;
1976 pcir->rc.hptrIcon = (HPOINTER)0;
1977 pcil->hwndCnr = hwndLeft;
1978 pcil->rc.hptrIcon = (HPOINTER)0;
1979
1980 if (filesl && filesl[l]) {
1981 if (filesr && filesr[r])
1982 x = stricmp(filesl[l]->fname, filesr[r]->fname);
1983 else
1984 x = -1; // Left side list longer
1985 }
1986 else
1987 x = +1; // Right side list longer
1988
1989 if (x <= 0) {
1990 // File appears on left side
1991 cmp->cmp->totalleft++;
1992 insertedl++;
1993 BldFullPathName(szBuf, cmp->leftdir, filesl[l]->fname);
1994 pcil->pszFileName = xstrdup(szBuf, pszSrcFile, __LINE__);
1995 pcil->pszDisplayName = pcil->pszFileName + lenl;
1996 pcil->attrFile = filesl[l]->attrFile;
1997 pcil->pszDispAttr = FileAttrToString(pcil->attrFile);
1998 pcil->cbFile = filesl[l]->cbFile;
1999 // 12 Jan 08 SHL FIXME to use cached size here too
2000 CommaFmtULL(szBuf, sizeof(szBuf), pcil->cbFile, ' ');
2001 pcil->pszFmtFileSize = xstrdup(szBuf, pszSrcFile, __LINE__);
2002 pcil->easize = filesl[l]->easize;
2003 pcil->date.day = filesl[l]->date.day;
2004 pcil->date.month = filesl[l]->date.month;
2005 pcil->date.year = filesl[l]->date.year + 1980;
2006 pcil->time.seconds = filesl[l]->time.twosecs * 2;
2007 pcil->time.minutes = filesl[l]->time.minutes;
2008 pcil->time.hours = filesl[l]->time.hours;
2009 pcil->ladate.day = filesl[l]->ladate.day;
2010 pcil->ladate.month = filesl[l]->ladate.month;
2011 pcil->ladate.year = filesl[l]->ladate.year + 1980;
2012 pcil->latime.seconds = filesl[l]->latime.twosecs * 2;
2013 pcil->latime.minutes = filesl[l]->latime.minutes;
2014 pcil->latime.hours = filesl[l]->latime.hours;
2015 pcil->crdate.day = filesl[l]->crdate.day;
2016 pcil->crdate.month = filesl[l]->crdate.month;
2017 pcil->crdate.year = filesl[l]->crdate.year + 1980;
2018 pcil->crtime.seconds = filesl[l]->crtime.twosecs * 2;
2019 pcil->crtime.minutes = filesl[l]->crtime.minutes;
2020 pcil->crtime.hours = filesl[l]->crtime.hours;
2021 DosRequestMutexSem(hmtxFiltering, SEM_INDEFINITE_WAIT);
2022 if (cmp && *cmp->dcd.mask.szMask) {
2023 if (!Filter((PMINIRECORDCORE)pcil, (PVOID)&cmp->dcd.mask)) {
2024 pcil->rc.flRecordAttr |= CRA_FILTERED;
2025 pcir->rc.flRecordAttr |= CRA_FILTERED;
2026 }
2027 }
2028 DosReleaseMutexSem(hmtxFiltering);
2029 } // if on left
2030
2031 if (x >= 0) {
2032 // File appears on right side
2033 cmp->cmp->totalright++;
2034 insertedr++;
2035 BldFullPathName(szBuf, cmp->rightdir, filesr[r]->fname);
2036 pcir->pszFileName = xstrdup(szBuf, pszSrcFile, __LINE__); // 31 Jul 07 SHL
2037 pcir->pszDisplayName = pcir->pszFileName + lenr;
2038 pcir->attrFile = filesr[r]->attrFile;
2039 pcir->pszDispAttr = FileAttrToString(pcir->attrFile);
2040 pcir->cbFile = filesr[r]->cbFile;
2041 // 12 Jan 08 SHL FIXME to used cached size here too
2042 CommaFmtULL(szBuf, sizeof(szBuf), pcir->cbFile, ' ');
2043 pcir->pszFmtFileSize = xstrdup(szBuf, pszSrcFile, __LINE__);
2044 pcir->easize = filesr[r]->easize;
2045 pcir->date.day = filesr[r]->date.day;
2046 pcir->date.month = filesr[r]->date.month;
2047 pcir->date.year = filesr[r]->date.year + 1980;
2048 pcir->time.seconds = filesr[r]->time.twosecs * 2;
2049 pcir->time.minutes = filesr[r]->time.minutes;
2050 pcir->time.hours = filesr[r]->time.hours;
2051 pcir->ladate.day = filesr[r]->ladate.day;
2052 pcir->ladate.month = filesr[r]->ladate.month;
2053 pcir->ladate.year = filesr[r]->ladate.year + 1980;
2054 pcir->latime.seconds = filesr[r]->latime.twosecs * 2;
2055 pcir->latime.minutes = filesr[r]->latime.minutes;
2056 pcir->latime.hours = filesr[r]->latime.hours;
2057 pcir->crdate.day = filesr[r]->crdate.day;
2058 pcir->crdate.month = filesr[r]->crdate.month;
2059 pcir->crdate.year = filesr[r]->crdate.year + 1980;
2060 pcir->crtime.seconds = filesr[r]->crtime.twosecs * 2;
2061 pcir->crtime.minutes = filesr[r]->crtime.minutes;
2062 pcir->crtime.hours = filesr[r]->crtime.hours;
2063 // Bypass check if already filtered on left side
2064 DosRequestMutexSem(hmtxFiltering, SEM_INDEFINITE_WAIT);
2065 if (cmp && ~pcir->rc.flRecordAttr & CRA_FILTERED &&
2066 *cmp->dcd.mask.szMask) {
2067 if (!Filter((PMINIRECORDCORE)pcir, (PVOID)&cmp->dcd.mask)) {
2068 pcil->rc.flRecordAttr |= CRA_FILTERED;
2069 pcir->rc.flRecordAttr |= CRA_FILTERED;
2070 }
2071 }
2072 DosReleaseMutexSem(hmtxFiltering);
2073 } // if on right
2074
2075 if (x == 0) {
2076 // File appears on both sides
2077 pcil->flags |= CNRITEM_EXISTS;
2078 pcir->flags |= CNRITEM_EXISTS;
2079 pch = szBuf;
2080 // Subject field holds status messages
2081 *pch = 0;
2082 if (pcil->cbFile > pcir->cbFile) {
2083 pcil->flags |= CNRITEM_LARGER;
2084 pcir->flags |= CNRITEM_SMALLER;
2085 strcpy(pch, GetPString(IDS_LARGERTEXT));
2086 pch += 6;
2087 }
2088 else if (pcil->cbFile < pcir->cbFile) {
2089 pcil->flags |= CNRITEM_SMALLER;
2090 pcir->flags |= CNRITEM_LARGER;
2091 strcpy(pch, GetPString(IDS_SMALLERTEXT));
2092 pch += 7;
2093 }
2094 if (pcil->easize != pcir->easize) {
2095 pcil->flags |= CNRITEM_EASDIFFER;
2096 pcir->flags |= CNRITEM_EASDIFFER;
2097 if (pch != szBuf) {
2098 strcpy(pch, ", ");
2099 pch += 2;
2100 }
2101 strcpy(pch, GetPString(IDS_EASDIFFERTEXT));
2102 pch += 10;
2103 }
2104 ret = TestCDates(&pcir->date, &pcir->time,
2105 &pcil->date, &pcil->time);
2106 if (ret == 1) {
2107 pcil->flags |= CNRITEM_NEWER;
2108 pcir->flags |= CNRITEM_OLDER;
2109 if (pch != szBuf) {
2110 strcpy(pch, ", ");
2111 pch += 2;
2112 }
2113 strcpy(pch, GetPString(IDS_NEWERTEXT));
2114 pch += 5;
2115 }
2116 else if (ret == -1) {
2117 pcil->flags |= CNRITEM_OLDER;
2118 pcir->flags |= CNRITEM_NEWER;
2119 if (pch != szBuf) {
2120 strcpy(pch, ", ");
2121 pch += 2;
2122 }
2123 strcpy(pch, GetPString(IDS_OLDERTEXT));
2124 pch += 5;
2125 }
2126 pcil->pszSubject = *szBuf ?
2127 xstrdup(szBuf, pszSrcFile, __LINE__) :
2128 NullStr;
2129
2130 } // if on both sides
2131
2132 if (x <= 0)
2133 free(filesl[l++]); // Done with item on left
2134
2135 if (x >= 0)
2136 free(filesr[r++]); // Done with item on right
2137
2138 // Ensure empty buffers point somewhere
2139 if (!pcil->pszFileName) {
2140 pcil->pszFileName = NullStr;
2141 pcil->pszDisplayName = pcil->pszFileName;
2142 }
2143
2144 if (!pcir->pszFileName) {
2145 pcir->pszFileName = NullStr;
2146 pcir->pszDisplayName = pcir->pszFileName;
2147 }
2148
2149 pcil->rc.pszIcon = pcil->pszDisplayName;
2150 pcir->rc.pszIcon = pcir->pszDisplayName;
2151
2152 pcil->pszLongName = NullStr;
2153 pcir->pszLongName = NullStr;
2154
2155 if (!pcil->pszSubject)
2156 if (!pcir->pszSubject)
2157 pcir->pszSubject = NullStr;
2158
2159 if (!pcil->pszDispAttr)
2160 pcil->pszDispAttr = NullStr;
2161 if (!pcir->pszDispAttr)
2162 pcir->pszDispAttr = NullStr;
2163
2164 // Avoid hogging systems
2165 SleepIfNeeded(&itdSleep, 0);
2166
2167 pcil = (PCNRITEM)pcil->rc.preccNextRecord;
2168 pcir = (PCNRITEM)pcir->rc.preccNextRecord;
2169
2170 if (pcil == NULL || pcir == NULL) {
2171 RECORDINSERT ri;
2172 if (pcil != pcir) {
2173 Runtime_Error(pszSrcFile, __LINE__, "pcil and pcir out of sync");
2174 cmp->stop = TRUE;
2175 break;
2176 }
2177 // Say inserting
2178 WinSendMsg(cmp->hwnd, UM_CONTAINERDIR, MPVOID, MPVOID);
2179
2180 // Insert left side
2181 memset(&ri, 0, sizeof(RECORDINSERT));
2182 ri.cb = sizeof(RECORDINSERT);
2183 ri.pRecordOrder = (PRECORDCORE)CMA_END;
2184 ri.pRecordParent = (PRECORDCORE)NULL;
2185 ri.zOrder = (ULONG)CMA_TOP;
2186 ri.cRecordsInsert = ulRecsToInsert;
2187 ri.fInvalidateRecord = FALSE;
2188
2189 if (!WinSendMsg(hwndLeft, CM_INSERTRECORD,
2190 MPFROMP(pcilFirst), MPFROMP(&ri))) {
2191 Win_Error(hwndLeft, cmp->hwnd, pszSrcFile, __LINE__, "CM_INSERTRECORD");
2192 FreeCnrItemList(hwndLeft, pcilFirst);
2193 cmp->cmp->totalleft -= insertedl;
2194 }
2195 pcilFirst = NULL;
2196
2197 // Insert right side
2198 memset(&ri, 0, sizeof(RECORDINSERT));
2199 ri.cb = sizeof(RECORDINSERT);
2200 ri.pRecordOrder = (PRECORDCORE)CMA_END;
2201 ri.pRecordParent = (PRECORDCORE)NULL;
2202 ri.zOrder = (ULONG)CMA_TOP;
2203 ri.cRecordsInsert = ulRecsToInsert;
2204 ri.fInvalidateRecord = FALSE;
2205
2206 if (!WinSendMsg(hwndRight, CM_INSERTRECORD,
2207 MPFROMP(pcirFirst), MPFROMP(&ri))) {
2208 Win_Error(hwndRight, cmp->hwnd, pszSrcFile, __LINE__, "CM_INSERTRECORD");
2209 // 2011-05-29 SHL FIXME?
2210 RemoveCnrItems(hwndLeft, NULL, 0, CMA_FREE | CMA_INVALIDATE);
2211 FreeCnrItemList(hwndRight, pcirFirst);
2212 cmp->cmp->totalright -= insertedr;
2213 }
2214 pcirFirst = NULL;
2215 } // if need insert
2216
2217 } // while filling left or right
2218
2219 // If stopped early clean up
2220
2221 if (cmp->stop) {
2222 // Free up container records that we did not insert in container
2223 if (pcilFirst)
2224 FreeCnrItemList(hwndLeft, pcilFirst);
2225
2226 // Free up items we did not insert in container
2227 if (filesl) {
2228 for(; filesl[l]; l++) {
2229 free(filesl[l]);
2230 }
2231 }
2232
2233 if (pcirFirst)
2234 FreeCnrItemList(hwndRight, pcirFirst);
2235
2236 if (filesr) {
2237 for (; filesr[r]; r++) {
2238 free(filesr[r]);
2239 }
2240 }
2241 } // if insufficient resources
2242
2243 xfree(filesl, pszSrcFile, __LINE__); // Free header - have already freed elements
2244 filesl = NULL;
2245 xfree(filesr, pszSrcFile, __LINE__);
2246 filesr = NULL;
2247
2248 } // if ulRecsNeeded
2249
2250 Deselect(hwndLeft);
2251 Deselect(hwndRight);
2252
2253 // Request window update
2254 if (!PostMsg(cmp->hwnd, UM_CONTAINER_FILLED, MPVOID, MPVOID))
2255 WinSendMsg(cmp->hwnd, UM_CONTAINER_FILLED, MPVOID, MPVOID);
2256 notified = TRUE;
2257
2258 if (filesl)
2259 FreeList((CHAR **)filesl); // Must have failed to create container
2260 if (filesr)
2261 FreeList((CHAR **)filesr);
2262
2263 WinDestroyMsgQueue(hmq);
2264 } // if have queue
2265 if (!notified)
2266 PostMsg(cmp->hwnd, UM_CONTAINER_FILLED, MPVOID, MPVOID);
2267 DecrThreadUsage();
2268 WinTerminate(hab);
2269 }
2270 DosRequestMutexSem(hmtxFiltering, SEM_INDEFINITE_WAIT);
2271 free(cmp);
2272 cmp = NULL;
2273 DosReleaseMutexSem(hmtxFiltering);
2274 DosPostEventSem(CompactSem);
2275
2276# ifdef FORTIFY
2277 Fortify_LeaveScope();
2278# endif
2279
2280}
2281
2282/**
2283 * Find matching item in other container
2284 * @return PCNRITEM or NULL
2285 */
2286
2287static PCNRITEM FindMatchingItem(PCNRITEM pciFindS, HWND hwndCnrS, HWND hwndCnrD);
2288
2289static PCNRITEM FindMatchingItem(PCNRITEM pciFindS, HWND hwndCnrS, HWND hwndCnrD)
2290{
2291
2292 PCNRITEM pciS;
2293 PCNRITEM pciD;
2294
2295 pciS = WinSendMsg(hwndCnrS, CM_QUERYRECORD, MPVOID,
2296 MPFROM2SHORT(CMA_FIRST, CMA_ITEMORDER));
2297 pciD = WinSendMsg(hwndCnrD, CM_QUERYRECORD, MPVOID,
2298 MPFROM2SHORT(CMA_FIRST, CMA_ITEMORDER));
2299 while (pciS && (INT)pciS != -1 && pciD && (INT)pciD != -1) {
2300
2301 if (pciS == pciFindS)
2302 break;
2303
2304 pciS = WinSendMsg(hwndCnrS, CM_QUERYRECORD, MPFROMP(pciS),
2305 MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER));
2306 pciD = WinSendMsg(hwndCnrD, CM_QUERYRECORD, MPFROMP(pciD),
2307 MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER));
2308 } // while
2309
2310 if (pciS != pciFindS)
2311 pciD = NULL;
2312
2313 return pciD;
2314}
2315
2316/**
2317 * Set button/window enables
2318 */
2319
2320static VOID SetButtonEnables(COMPARE* cmp, BOOL fEnable);
2321
2322static VOID SetButtonEnables(COMPARE* cmp, BOOL fEnable)
2323{
2324 HWND hwnd = cmp->hwnd;
2325 HWND hwndLeft = GetHwndLeft(hwnd);
2326 HWND hwndRight = GetHwndRight(hwnd);
2327
2328 if (!fEnable) {
2329 // Disable before
2330 WinEnableWindowUpdate(hwndLeft, fEnable);
2331 WinEnableWindowUpdate(hwndRight, fEnable);
2332 }
2333 WinEnableWindow(hwndLeft, fEnable);
2334 WinEnableWindow(hwndRight, fEnable);
2335 if (fEnable) {
2336 // Enable after
2337 WinEnableWindowUpdate(hwndLeft, fEnable);
2338 WinEnableWindowUpdate(hwndRight, fEnable);
2339 }
2340
2341 WinEnableWindow(WinWindowFromID(hwnd, DID_OK), fEnable);
2342 WinEnableWindow(WinWindowFromID(hwnd, COMP_COLLECT), fEnable);
2343 WinEnableWindow(WinWindowFromID(hwnd, IDM_SELECTBOTH), fEnable);
2344 WinEnableWindow(WinWindowFromID(hwnd, IDM_SELECTONE), fEnable);
2345 WinEnableWindow(WinWindowFromID(hwnd, IDM_SELECTNEWER), fEnable);
2346 WinEnableWindow(WinWindowFromID(hwnd, IDM_SELECTEAS), fEnable); // 2013-03-09 SHL
2347 WinEnableWindow(WinWindowFromID(hwnd, IDM_SELECTOLDER), fEnable);
2348 WinEnableWindow(WinWindowFromID(hwnd, IDM_SELECTBIGGER), fEnable);
2349 WinEnableWindow(WinWindowFromID(hwnd, IDM_SELECTSMALLER), fEnable);
2350 WinEnableWindow(WinWindowFromID(hwnd, IDM_DESELECTBOTH), fEnable);
2351 WinEnableWindow(WinWindowFromID(hwnd, IDM_DESELECTONE), fEnable);
2352 WinEnableWindow(WinWindowFromID(hwnd, IDM_DESELECTNEWER), fEnable);
2353 WinEnableWindow(WinWindowFromID(hwnd, IDM_DESELECTEAS), fEnable); // 2013-03-09 SHL
2354 WinEnableWindow(WinWindowFromID(hwnd, IDM_DESELECTOLDER), fEnable);
2355 WinEnableWindow(WinWindowFromID(hwnd, IDM_DESELECTBIGGER), fEnable);
2356 WinEnableWindow(WinWindowFromID(hwnd, IDM_DESELECTSMALLER), fEnable);
2357 WinEnableWindow(WinWindowFromID(hwnd, IDM_DESELECTALL), fEnable);
2358 WinEnableWindow(WinWindowFromID(hwnd, IDM_SELECTSAMECONTENT), fEnable);
2359 WinEnableWindow(WinWindowFromID(hwnd, IDM_SELECTIDENTICAL), fEnable);
2360 WinEnableWindow(WinWindowFromID(hwnd, IDM_SELECTSAME), fEnable);
2361 WinEnableWindow(WinWindowFromID(hwnd, IDM_INVERT), fEnable);
2362 WinEnableWindow(WinWindowFromID(hwnd, COMP_SETDIRS), fEnable);
2363 WinEnableWindow(WinWindowFromID(hwnd, COMP_DELETELEFT), fEnable);
2364 WinEnableWindow(WinWindowFromID(hwnd, COMP_FILTER), fEnable);
2365 if (!fEnable || !*cmp->rightlist) {
2366 WinEnableWindow(WinWindowFromID(hwnd, COMP_COPYLEFT), fEnable);
2367 WinEnableWindow(WinWindowFromID(hwnd, COMP_MOVELEFT), fEnable);
2368 WinEnableWindow(WinWindowFromID(hwnd, COMP_DELETERIGHT), fEnable);
2369 WinEnableWindow(WinWindowFromID(hwnd, COMP_COPYRIGHT), fEnable);
2370 WinEnableWindow(WinWindowFromID(hwnd, COMP_MOVERIGHT), fEnable);
2371 }
2372 WinEnableWindow(WinWindowFromID(hwnd, COMP_INCLUDESUBDIRS), fEnable);
2373 WinEnableWindow(WinWindowFromID(hwnd, COMP_HIDENOTSELECTED), fEnable);
2374 WinEnableWindow(WinWindowFromID(hwnd, COMP_CONFIRMACTION), fEnable); // 2013-03-09 SHL
2375}
2376
2377/**
2378 * Compare directories dialog procedure
2379 */
2380
2381MRESULT EXPENTRY CompareDlgProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
2382{
2383 COMPARE *cmp;
2384 BOOL temp;
2385 CHAR szPathName[CCHMAXPATH];
2386 CHAR s[81];
2387
2388 static HPOINTER hptr;
2389
2390 switch (msg) {
2391 case WM_INITDLG:
2392 cmp = (COMPARE *)mp2;
2393 if (!cmp) {
2394 Runtime_Error(pszSrcFile, __LINE__, NULL);
2395 WinDismissDlg(hwnd, 0);
2396 }
2397 else {
2398 if (!hptr)
2399 hptr = WinLoadPointer(HWND_DESKTOP, FM3ModHandle, COMPARE_ICON);
2400 WinDefDlgProc(hwnd, WM_SETICON, MPFROMLONG(hptr), MPVOID);
2401 cmp->hwnd = hwnd;
2402 WinSetWindowPtr(hwnd, QWL_USER, (PVOID)cmp);
2403 {
2404 SWP swp;
2405 ULONG size = sizeof(SWP);
2406
2407 PrfQueryProfileData(fmprof, FM3Str, "CompDir.Position", (PVOID) &swp, &size);
2408 swp.fl &= ~SWP_SIZE; // 04 Feb 09 SHL ignore saved size
2409 WinSetWindowPos(hwnd,
2410 HWND_TOP,
2411 swp.x,
2412 swp.y,
2413 swp.cx,
2414 swp.cy,
2415 swp.fl);
2416 }
2417 SetCnrCols(GetHwndLeft(hwnd), TRUE);
2418 SetCnrCols(GetHwndRight(hwnd), TRUE);
2419 if (cmp->listfile) {
2420 CHAR fullname[CCHMAXPATH];
2421
2422 strcpy(fullname, PCSZ_STARDOTPMD);
2423 if (insert_filename(HWND_DESKTOP, fullname, TRUE, FALSE) &&
2424 *fullname && !strchr(fullname, '*') && !strchr(fullname, '?'))
2425 strcpy(cmp->rightlist, fullname);
2426 }
2427 WinSendMsg(hwnd, UM_SETUP, MPVOID, MPVOID);
2428 WinSendMsg(hwnd, UM_SETDIR, MPVOID, MPVOID);
2429 PostMsg(hwnd, UM_STRETCH, MPVOID, MPVOID);
2430 {
2431 USHORT ids[] = {COMP_FRAME, COMP_LEFTDIR, COMP_RIGHTDIR, COMP_COLLECT,
2432 COMP_VIEW, COMP_NOTE, COMP_TOTALLEFT, COMP_SELLEFT, COMP_TOTALRIGHT,
2433 COMP_SELRIGHT, COMP_CNRMENU, COMP_DIRMENU, COMP_MENU,
2434 COMP_INCLUDESUBDIRS, COMP_SETDIRS, COMP_COPYLEFT, COMP_MOVELEFT,
2435 COMP_DELETELEFT, COMP_COPYRIGHT, COMP_MOVERIGHT, COMP_DELETERIGHT,
2436 COMP_TOTALLEFTHDR, COMP_SELLEFTHDR, COMP_TOTALRIGHTHDR,
2437 COMP_SELRIGHTHDR, COMP_FILTER, COMP_HIDENOTSELECTED, 0};
2438 UINT x;
2439 CHAR s[24];
2440
2441 for (x = 0; ids[x]; x++) {
2442 sprintf(s, "CompDir%i", ids[x]);
2443 RestorePresParams(WinWindowFromID(hwnd, ids[x]), s);
2444 }
2445 }
2446 WinStartTimer(WinQueryAnchorBlock(hwnd), hwnd, ID_COMP_TIMER, 500);
2447 }
2448 break;
2449
2450 case UM_STRETCH:
2451 {
2452 SWP swp, swpC;
2453 LONG titl, szbx, szby, sz;
2454 HWND hwndActive;
2455
2456 WinQueryWindowPos(hwnd, &swp);
2457 if (!(swp.fl & (SWP_HIDE | SWP_MINIMIZE))) {
2458 hwndActive = WinQueryFocus(HWND_DESKTOP);
2459 szbx = SysVal(SV_CXSIZEBORDER);
2460 szby = SysVal(SV_CYSIZEBORDER);
2461 titl = SysVal(SV_CYTITLEBAR);
2462 titl += 26;
2463 swp.cx -= (szbx * 2);
2464 sz = (swp.cx / 8);
2465 WinQueryWindowPos(WinWindowFromID(hwnd, COMP_LEFTDIR), &swpC);
2466 WinSetWindowPos(WinWindowFromID(hwnd, COMP_LEFTDIR), HWND_TOP,
2467 szbx + 6,
2468 swpC.y,
2469 (swp.cx / 2) - (szbx + 6),
2470 ((swp.cy - swpC.y) - titl) - szby,
2471 SWP_MOVE | SWP_SIZE);
2472 WinSetWindowPos(WinWindowFromID(hwnd, COMP_RIGHTDIR), HWND_TOP,
2473 (swp.cx / 2) + (szbx + 6),
2474 swpC.y,
2475 (swp.cx / 2) - (szbx + 6),
2476 ((swp.cy - swpC.y) - titl) - szby,
2477 SWP_MOVE | SWP_SIZE);
2478 WinSetWindowPos(WinWindowFromID(hwnd, COMP_TOTALLEFTHDR), HWND_TOP,
2479 szbx + 6,
2480 ((swp.cy - titl) - szby) + 4,
2481 sz - (szbx + 6), 20, SWP_MOVE | SWP_SIZE);
2482 WinSetWindowPos(WinWindowFromID(hwnd, COMP_TOTALLEFT), HWND_TOP,
2483 sz + (szbx + 6),
2484 ((swp.cy - titl) - szby) + 4,
2485 sz - (szbx + 6), 20, SWP_MOVE | SWP_SIZE);
2486 WinSetWindowPos(WinWindowFromID(hwnd, COMP_SELLEFTHDR), HWND_TOP,
2487 (sz * 2) + (szbx + 6),
2488 ((swp.cy - titl) - szby) + 4,
2489 sz - (szbx + 6), 20, SWP_MOVE | SWP_SIZE);
2490 WinSetWindowPos(WinWindowFromID(hwnd, COMP_SELLEFT), HWND_TOP,
2491 (sz * 3) + (szbx + 6),
2492 ((swp.cy - titl) - szby) + 4,
2493 sz - (szbx + 6), 20, SWP_MOVE | SWP_SIZE);
2494 WinSetWindowPos(WinWindowFromID(hwnd, COMP_TOTALRIGHTHDR), HWND_TOP,
2495 (sz * 4) + (szbx + 6),
2496 ((swp.cy - titl) - szby) + 4,
2497 sz - (szbx + 6), 20, SWP_MOVE | SWP_SIZE);
2498 WinSetWindowPos(WinWindowFromID(hwnd, COMP_TOTALRIGHT), HWND_TOP,
2499 (sz * 5) + (szbx + 6),
2500 ((swp.cy - titl) - szby) + 4,
2501 sz - (szbx + 6), 20, SWP_MOVE | SWP_SIZE);
2502 WinSetWindowPos(WinWindowFromID(hwnd, COMP_SELRIGHTHDR), HWND_TOP,
2503 (sz * 6) + (szbx + 6),
2504 ((swp.cy - titl) - szby) + 4,
2505 sz - (szbx + 6), 20, SWP_MOVE | SWP_SIZE);
2506 WinSetWindowPos(WinWindowFromID(hwnd, COMP_SELRIGHT), HWND_TOP,
2507 (sz * 7) + (szbx + 6),
2508 ((swp.cy - titl) - szby) + 4,
2509 sz - (szbx + 6), 20, SWP_MOVE | SWP_SIZE);
2510 PaintRecessedWindow(WinWindowFromID(hwnd, COMP_TOTALLEFT),
2511 (HPS)0, FALSE, FALSE);
2512 PaintRecessedWindow(WinWindowFromID(hwnd, COMP_SELLEFT),
2513 (HPS)0, FALSE, FALSE);
2514 PaintRecessedWindow(WinWindowFromID(hwnd, COMP_TOTALRIGHT),
2515 (HPS)0, FALSE, FALSE);
2516 PaintRecessedWindow(WinWindowFromID(hwnd, COMP_SELRIGHT),
2517 (HPS)0, FALSE, FALSE);
2518 PaintRecessedWindow(GetHwndLeft(hwnd), (HPS)0,
2519 (hwndActive == GetHwndLeft(hwnd)), TRUE);
2520 PaintRecessedWindow(GetHwndRight(hwnd), (HPS)0,
2521 (hwndActive == GetHwndRight(hwnd)), TRUE);
2522 }
2523 }
2524 return 0;
2525
2526 case WM_ADJUSTWINDOWPOS:
2527 PostMsg(hwnd, UM_STRETCH, MPVOID, MPVOID);
2528 break;
2529
2530 case UM_SETUP:
2531 {
2532 CNRINFO cnri;
2533 BOOL tempsubj;
2534
2535 cmp = INSTDATA(hwnd);
2536 if (!cmp)
2537 Runtime_Error(pszSrcFile, __LINE__, NULL);
2538 else {
2539 cmp->dcd.size = sizeof(DIRCNRDATA);
2540 cmp->dcd.type = DIR_FRAME;
2541 cmp->dcd.hwndFrame = hwnd;
2542 cmp->dcd.hwndClient = hwnd;
2543 cmp->dcd.mask.attrFile = (FILE_DIRECTORY | FILE_ARCHIVED |
2544 FILE_READONLY | FILE_SYSTEM | FILE_HIDDEN);
2545 LoadDetailsSwitches(PCSZ_DIRCMP, &cmp->dcd.ds, FALSE);
2546 cmp->dcd.ds.detailslongname = FALSE;
2547 cmp->dcd.ds.detailsicon = FALSE; // TRUE;
2548 }
2549 memset(&cnri, 0, sizeof(CNRINFO));
2550 cnri.cb = sizeof(CNRINFO);
2551 WinSendDlgItemMsg(hwnd, COMP_LEFTDIR, CM_QUERYCNRINFO,
2552 MPFROMP(&cnri), MPFROMLONG(sizeof(CNRINFO)));
2553 cnri.flWindowAttr |= (CA_OWNERDRAW | CV_MINI);
2554 cnri.xVertSplitbar = DIR_SPLITBAR_OFFSET - 68;
2555 WinSendDlgItemMsg(hwnd, COMP_LEFTDIR, CM_SETCNRINFO, MPFROMP(&cnri),
2556 MPFROMLONG(CMA_FLWINDOWATTR | CMA_XVERTSPLITBAR));
2557 memset(&cnri, 0, sizeof(CNRINFO));
2558 cnri.cb = sizeof(CNRINFO);
2559 WinSendDlgItemMsg(hwnd, COMP_RIGHTDIR, CM_QUERYCNRINFO,
2560 MPFROMP(&cnri), MPFROMLONG(sizeof(CNRINFO)));
2561 cnri.flWindowAttr |= (CA_OWNERDRAW | CV_MINI);
2562 cnri.xVertSplitbar = DIR_SPLITBAR_OFFSET - 54;
2563 WinSendDlgItemMsg(hwnd, COMP_RIGHTDIR, CM_SETCNRINFO, MPFROMP(&cnri),
2564 MPFROMLONG(CMA_FLWINDOWATTR | CMA_XVERTSPLITBAR));
2565 AdjustCnrColRO(GetHwndLeft(hwnd), GetPString(IDS_FILENAMECOLTEXT), TRUE, FALSE);
2566 AdjustCnrColRO(GetHwndLeft(hwnd), GetPString(IDS_LONGNAMECOLTEXT), TRUE, FALSE);
2567 AdjustCnrColRO(GetHwndRight(hwnd), GetPString(IDS_FILENAMECOLTEXT), TRUE, FALSE);
2568 AdjustCnrColRO(GetHwndRight(hwnd), GetPString(IDS_LONGNAMECOLTEXT), TRUE, FALSE);
2569 AdjustCnrColsForPref(GetHwndLeft(hwnd), cmp->leftdir, &cmp->dcd.ds, TRUE);
2570 tempsubj = cmp->dcd.ds.detailssubject;
2571 cmp->dcd.ds.detailssubject = FALSE;
2572 AdjustCnrColsForPref(GetHwndRight(hwnd), cmp->rightdir, &cmp->dcd.ds, TRUE);
2573 if (*cmp->rightlist) {
2574 AdjustCnrColVis(GetHwndRight(hwnd), GetPString(IDS_LADATECOLTEXT), FALSE,
2575 FALSE);
2576 AdjustCnrColVis(GetHwndRight(hwnd), GetPString(IDS_LATIMECOLTEXT), FALSE,
2577 FALSE);
2578 AdjustCnrColVis(GetHwndRight(hwnd), GetPString(IDS_CRDATECOLTEXT), FALSE,
2579 FALSE);
2580 AdjustCnrColVis(GetHwndRight(hwnd), GetPString(IDS_CRTIMECOLTEXT), FALSE,
2581 FALSE);
2582 }
2583 cmp->dcd.ds.detailssubject = tempsubj;
2584 }
2585 return 0;
2586
2587 case WM_DRAWITEM:
2588 if (mp2) {
2589 POWNERITEM pown = (POWNERITEM)mp2;
2590 PCNRDRAWITEMINFO pcown;
2591 PCNRITEM pci;
2592
2593 pcown = (PCNRDRAWITEMINFO)pown->hItem;
2594 if (pcown) {
2595 pci = (PCNRITEM)pcown->pRecord;
2596 // 01 Aug 07 SHL if field null or blank, we draw
2597 // FIXME to document why - probably to optimize and bypass draw?
2598 if (pci && (INT)pci != -1 && !*pci->pszFileName && pci->pszFileName != NullStr)
2599 return MRFROMLONG(TRUE);
2600 }
2601 }
2602 return 0;
2603
2604 case UM_CONTAINERHWND:
2605 // Building list
2606 WinSetDlgItemText(hwnd, COMP_NOTE, (CHAR *) GetPString(IDS_COMPHOLDBLDLISTTEXT));
2607 return 0;
2608
2609 case UM_CONTAINERDIR:
2610 // Filling container
2611 WinSetDlgItemText(hwnd, COMP_NOTE, (CHAR *) GetPString(IDS_COMPHOLDFILLCNRTEXT));
2612 return 0;
2613
2614 case WM_TIMER:
2615 // Show current totals
2616 cmp = INSTDATA(hwnd);
2617 if (!cmp) {
2618 Runtime_Error(pszSrcFile, __LINE__, "pCompare NULL");
2619 WinDismissDlg(hwnd, 0);
2620 }
2621 else {
2622 if (cmp->uOldTotalLeft != cmp->totalleft) {
2623 cmp->uOldTotalLeft = cmp->totalleft;
2624 sprintf(s, " %d", cmp->totalleft);
2625 WinSetDlgItemText(hwnd, COMP_TOTALLEFT, s);
2626 }
2627 if (cmp->uOldTotalRight != cmp->totalright) {
2628 cmp->uOldTotalRight = cmp->totalright;
2629 sprintf(s, " %d", cmp->totalright);
2630 WinSetDlgItemText(hwnd, COMP_TOTALRIGHT, s);
2631 }
2632 if (cmp->uOldSelLeft != cmp->selleft) {
2633 cmp->uOldSelLeft = cmp->selleft;
2634 sprintf(s, " %d", cmp->selleft);
2635 WinSetDlgItemText(hwnd, COMP_SELLEFT, s);
2636 }
2637 if (cmp->uOldSelRight != cmp->selright) {
2638 cmp->uOldSelRight = cmp->selright;
2639 sprintf(s, " %d", cmp->selright);
2640 WinSetDlgItemText(hwnd, COMP_SELRIGHT, s);
2641 }
2642 }
2643 break;
2644
2645 case UM_CONTAINER_FILLED:
2646 cmp = INSTDATA(hwnd);
2647 if (!cmp) {
2648 Runtime_Error(pszSrcFile, __LINE__, "pCompare NULL");
2649 WinDismissDlg(hwnd, 0);
2650 }
2651 else if (cmp->stop) {
2652 // Delayed cancel
2653 WinDismissDlg(hwnd, 1);
2654 }
2655 else {
2656 cmp->filling = FALSE;
2657 SetButtonEnables(cmp, TRUE);
2658 WinPostMsg(hwnd, WM_TIMER, MPFROMLONG(ID_COMP_TIMER), 0); // Force counts to update
2659 if (*cmp->dcd.mask.szMask) {
2660 sprintf(s, GetPString(IDS_COMPREADYFILTEREDTEXT), cmp->dcd.mask.szMask);
2661 WinSetDlgItemText(hwnd, COMP_NOTE, s);
2662 }
2663 else
2664 WinSetDlgItemText(hwnd, COMP_NOTE, (CHAR *) GetPString(IDS_COMPREADYTEXT));
2665 }
2666 break;
2667
2668 case WM_INITMENU:
2669 cmp = INSTDATA(hwnd);
2670 if (cmp) {
2671 switch (SHORT1FROMMP(mp1)) {
2672 case IDM_COMMANDSMENU:
2673 SetupCommandMenu(cmp->dcd.hwndLastMenu, hwnd);
2674 break;
2675 }
2676 }
2677 break;
2678
2679 case WM_MENUEND:
2680 cmp = INSTDATA(hwnd);
2681 if (cmp) {
2682 if ((HWND)mp2 == cmp->dcd.hwndLastMenu) {
2683 MarkAll(GetHwndLeft(hwnd), TRUE, FALSE, TRUE);
2684 MarkAll(GetHwndRight(hwnd), TRUE, FALSE, TRUE);
2685 WinDestroyWindow(cmp->dcd.hwndLastMenu);
2686 cmp->dcd.hwndLastMenu = (HWND)0;
2687 }
2688 }
2689 break;
2690
2691 case WM_CONTROL:
2692 switch (SHORT1FROMMP(mp1)) {
2693 case COMP_INCLUDESUBDIRS:
2694 switch (SHORT2FROMMP(mp1)) {
2695 case BN_CLICKED:
2696 cmp = INSTDATA(hwnd);
2697 PostMsg(hwnd, UM_SETUP, MPVOID, MPVOID);
2698 PostMsg(hwnd, UM_SETDIR, MPVOID, MPVOID);
2699 break;
2700 }
2701 break;
2702 case COMP_HIDENOTSELECTED:
2703 switch (SHORT2FROMMP(mp1)) {
2704 case BN_CLICKED:
2705 WinSendMsg(hwnd, UM_HIDENOTSELECTED, MPVOID, MPVOID);
2706 break;
2707 }
2708 break;
2709
2710 case COMP_LEFTDIR:
2711 case COMP_RIGHTDIR:
2712 switch (SHORT2FROMMP(mp1)) {
2713 case CN_KILLFOCUS:
2714 PaintRecessedWindow(WinWindowFromID(hwnd, SHORT1FROMMP(mp1)),
2715 (HPS)0, FALSE, TRUE);
2716 break;
2717
2718 case CN_SETFOCUS:
2719 PaintRecessedWindow(WinWindowFromID(hwnd, SHORT1FROMMP(mp1)),
2720 (HPS)0, TRUE, TRUE);
2721 break;
2722
2723 case CN_ENTER:
2724 if (mp2) {
2725
2726 PCNRITEM pci = (PCNRITEM)((PNOTIFYRECORDENTER)mp2)->pRecord;
2727 HWND hwndCnr = WinWindowFromID(hwnd, SHORT1FROMMP(mp1));
2728
2729 SetShiftState();
2730 if (pci) {
2731 if (pci->rc.flRecordAttr & CRA_INUSE || !pci || !*pci->pszFileName)
2732 break;
2733 WinSendMsg(hwndCnr, CM_SETRECORDEMPHASIS, MPFROMP(pci),
2734 MPFROM2SHORT(TRUE, CRA_INUSE));
2735 if (pci->attrFile & FILE_DIRECTORY) {
2736 if ((shiftstate & (KC_CTRL | KC_SHIFT)) == (KC_CTRL | KC_SHIFT))
2737 OpenObject(pci->pszFileName, Settings, hwnd);
2738 else
2739 OpenObject(pci->pszFileName, Default, hwnd);
2740 }
2741 else
2742 DefaultViewKeys(hwnd, hwnd, HWND_DESKTOP, NULL,
2743 pci->pszFileName);
2744 WinSendMsg(hwndCnr, CM_SETRECORDEMPHASIS,
2745 MPFROMP(pci),
2746 MPFROM2SHORT(FALSE,
2747 CRA_INUSE | (fUnHilite ? CRA_SELECTED : 0)));
2748 }
2749 }
2750 break;
2751
2752 case CN_CONTEXTMENU:
2753 cmp = INSTDATA(hwnd);
2754 if (cmp) {
2755 PCNRITEM pci = (PCNRITEM)mp2;
2756 USHORT id = COMP_CNRMENU; // Assume container menu
2757
2758 if (cmp->dcd.hwndLastMenu)
2759 WinDestroyWindow(cmp->dcd.hwndLastMenu);
2760 cmp->dcd.hwndLastMenu = (HWND)0;
2761 cmp->hwndCalling = WinWindowFromID(hwnd, SHORT1FROMMP(mp1));
2762 if (pci) {
2763 if (!pci || !*pci->pszFileName || *cmp->rightlist)
2764 break;
2765 id = COMP_MENU; // Want container item menu
2766 WinSendMsg(cmp->hwndCalling, CM_SETRECORDEMPHASIS,
2767 MPFROMP(pci), MPFROM2SHORT(TRUE, CRA_CURSORED));
2768 }
2769 cmp->dcd.hwndLastMenu = WinLoadMenu(HWND_DESKTOP, FM3ModHandle, id);
2770 if (cmp->dcd.hwndLastMenu) {
2771 switch (id) {
2772 case COMP_CNRMENU:
2773 if (SHORT1FROMMP(mp1) == COMP_RIGHTDIR)
2774 WinSendMsg(cmp->dcd.hwndLastMenu, MM_DELETEITEM,
2775 MPFROM2SHORT(IDM_SHOWSUBJECT, FALSE), MPVOID);
2776 SetDetailsSwitches(cmp->dcd.hwndLastMenu, &cmp->dcd.ds);
2777 if (SHORT1FROMMP(mp1) == COMP_LEFTDIR)
2778 WinSendMsg(cmp->dcd.hwndLastMenu, MM_DELETEITEM,
2779 MPFROM2SHORT(IDM_LOADLISTFILE, 0), MPVOID);
2780 else if (*cmp->rightlist)
2781 WinSendMsg(cmp->dcd.hwndLastMenu, MM_DELETEITEM,
2782 MPFROM2SHORT(IDM_SAVELISTFILE, 0), MPVOID);
2783 break;
2784 case COMP_MENU:
2785 // Can't compare what's not there
2786 if (~pci->flags & CNRITEM_EXISTS) {
2787 WinSendMsg(cmp->dcd.hwndLastMenu, MM_DELETEITEM,
2788 MPFROM2SHORT(IDM_COMPARE, 0), MPVOID);
2789 }
2790 break;
2791 } // switch
2792 PopupMenu(hwnd, hwnd, cmp->dcd.hwndLastMenu);
2793 }
2794 }
2795 break;
2796
2797 case CN_INITDRAG:
2798 cmp = INSTDATA(hwnd);
2799 if (*cmp->rightlist && SHORT1FROMMP(mp1) == COMP_RIGHTDIR)
2800 break;
2801 DoFileDrag(WinWindowFromID(hwnd, SHORT1FROMMP(mp1)),
2802 (HWND)0, mp2, NULL, NULL, TRUE);
2803 break;
2804
2805 case CN_BEGINEDIT:
2806 case CN_REALLOCPSZ:
2807 // FIXME to be gone - field edits not allowed?
2808 Runtime_Error(pszSrcFile, __LINE__,
2809 "CN_BEGINEDIT/CN_REALLOCPSZ unexpected");
2810 break;
2811
2812 case CN_EMPHASIS:
2813 {
2814 PNOTIFYRECORDEMPHASIS pnre = mp2;
2815 BOOL fSelected;
2816 if (pnre->fEmphasisMask & CRA_SELECTED) {
2817 // Select toggled
2818 PCNRITEM pci = (PCNRITEM)pnre->pRecord;
2819 if (pci) {
2820 if (!*pci->pszFileName) {
2821 // User clicked on empty slot - just clear
2822 if (pci->rc.flRecordAttr & CRA_SELECTED)
2823 WinSendDlgItemMsg(hwnd, SHORT1FROMMP(mp1),
2824 CM_SETRECORDEMPHASIS,
2825 MPFROMP(pci),
2826 MPFROM2SHORT(FALSE, CRA_SELECTED));
2827 }
2828 else {
2829 BOOL fUpdateHideButton = FALSE;
2830 cmp = INSTDATA(hwnd);
2831 if (SHORT1FROMMP(mp1) == COMP_LEFTDIR) {
2832 fSelected = pci->rc.flRecordAttr & CRA_SELECTED;
2833 cmp->selleft += fSelected ? 1 : -1;
2834 if (!fSelected)
2835 fUpdateHideButton = TRUE;
2836 }
2837 else if (SHORT1FROMMP(mp1) == COMP_RIGHTDIR) {
2838 fSelected = pci->rc.flRecordAttr & CRA_SELECTED;
2839 cmp->selright += fSelected ? 1 : -1;
2840 if (!fSelected)
2841 fUpdateHideButton = TRUE;
2842 }
2843 else {
2844 Runtime_Error(pszSrcFile, __LINE__,
2845 "mp1 %u unexpected", SHORT1FROMMP(mp1));
2846 }
2847 if (fUpdateHideButton) {
2848 ULONG state = WinQueryButtonCheckstate(hwnd,COMP_HIDENOTSELECTED);
2849 if (state == 1) {
2850 WinCheckButton(hwnd, COMP_HIDENOTSELECTED, 2);
2851 }
2852 }
2853 }
2854 }
2855 }
2856 }
2857 break;
2858
2859 case CN_SCROLL:
2860 cmp = INSTDATA(hwnd);
2861 if (!cmp->forcescroll) {
2862
2863 PNOTIFYSCROLL pns = mp2;
2864
2865 if (pns->fScroll & CMA_VERTICAL) {
2866 cmp->forcescroll = TRUE;
2867 // Scroll other window to match
2868 WinSendDlgItemMsg(hwnd,
2869 SHORT1FROMMP(mp1) == COMP_LEFTDIR ?
2870 COMP_RIGHTDIR : COMP_LEFTDIR,
2871 CM_SCROLLWINDOW,
2872 MPFROMSHORT(CMA_VERTICAL),
2873 MPFROMLONG(pns->lScrollInc));
2874 cmp->forcescroll = FALSE;
2875 }
2876 }
2877 break;
2878 } // switch COMP_LEFTDIR mp1
2879 break; // COMP_LEFTDIR / COMP_RIGHTDIR
2880 } // switch WM_CONTROL mp1
2881 return 0; // WM_CONTROL
2882
2883 case UM_SETDIR:
2884 cmp = INSTDATA(hwnd);
2885 if (cmp) {
2886 COMPARE *forthread;
2887 CNRINFO cnri;
2888 if (cmp->includesubdirs)
2889 WinCheckButton(hwnd, COMP_INCLUDESUBDIRS, TRUE);
2890 cmp->includesubdirs = WinQueryButtonCheckstate(hwnd,
2891 COMP_INCLUDESUBDIRS);
2892 memset(&cnri, 0, sizeof(CNRINFO));
2893 cnri.cb = sizeof(CNRINFO);
2894 cnri.pszCnrTitle = cmp->leftdir;
2895 cnri.flWindowAttr = CV_DETAIL | CV_MINI |
2896 CA_CONTAINERTITLE | CA_TITLESEPARATOR |
2897 CA_DETAILSVIEWTITLES | CA_OWNERDRAW;
2898 WinSendDlgItemMsg(hwnd, COMP_LEFTDIR, CM_SETCNRINFO, MPFROMP(&cnri),
2899 MPFROMLONG(CMA_CNRTITLE | CMA_FLWINDOWATTR));
2900 WinSetDlgItemText(hwnd, COMP_LISTLOADED, "");
2901 cnri.pszCnrTitle = cmp->rightdir;
2902 WinSendDlgItemMsg(hwnd, COMP_RIGHTDIR, CM_SETCNRINFO, MPFROMP(&cnri),
2903 MPFROMLONG(CMA_CNRTITLE | CMA_FLWINDOWATTR));
2904 WinCheckButton(hwnd, COMP_HIDENOTSELECTED, 0);
2905 cmp->filling = TRUE;
2906# ifdef FORTIFY
2907 Fortify_EnterScope();
2908# endif
2909 forthread = xmalloc(sizeof(COMPARE), pszSrcFile, __LINE__);
2910 if (!forthread)
2911 WinDismissDlg(hwnd, 0);
2912 else {
2913 *forthread = *cmp;
2914 forthread->cmp = cmp;
2915 if (xbeginthread(FillCnrsThread,
2916 122880,
2917 forthread,
2918 pszSrcFile,
2919 __LINE__) == -1)
2920 {
2921 WinDismissDlg(hwnd, 0);
2922 free(forthread);
2923# ifdef FORTIFY
2924 Fortify_LeaveScope();
2925# endif
2926 }
2927 else {
2928 WinSetDlgItemText(hwnd, COMP_NOTE,
2929 (CHAR *) GetPString(IDS_COMPHOLDREADDISKTEXT));
2930 SetButtonEnables(cmp, FALSE);
2931 cmp->includesubdirs = FALSE;
2932 cmp->selleft = 0;
2933 cmp->selright = 0;
2934 }
2935 }
2936 }
2937 return 0;
2938
2939 case UM_FILTER:
2940 cmp = INSTDATA(hwnd);
2941 if (cmp) {
2942 if (mp1)
2943 SetMask((CHAR *)mp1, &cmp->dcd.mask);
2944
2945 WinSetDlgItemText(hwnd, COMP_NOTE,
2946 (CHAR *) GetPString(IDS_COMPHOLDFILTERINGTEXT));
2947 priority_idle(); // Don't hog resources
2948 WinSendMsg(GetHwndLeft(hwnd), CM_FILTER, MPFROMP(Filter),
2949 MPFROMP(&cmp->dcd.mask));
2950 WinSendMsg(GetHwndRight(hwnd), CM_FILTER, MPFROMP(Filter),
2951 MPFROMP(&cmp->dcd.mask));
2952 priority_normal();
2953 if (*cmp->dcd.mask.szMask) {
2954 sprintf(s,
2955 GetPString(IDS_COMPREADYFILTEREDTEXT),
2956 cmp->dcd.mask.szMask);
2957 WinSetDlgItemText(hwnd, COMP_NOTE, s);
2958 }
2959 else
2960 WinSetDlgItemText(hwnd, COMP_NOTE, (CHAR *) GetPString(IDS_COMPREADYTEXT));
2961 }
2962 return 0;
2963
2964 case UM_HIDENOTSELECTED:
2965 cmp = INSTDATA(hwnd);
2966 if (cmp) {
2967 ULONG wasHidden = WinQueryButtonCheckstate(hwnd,
2968 COMP_HIDENOTSELECTED);
2969 ULONG nowHidden = wasHidden != 1 && (cmp->selleft || cmp->selright);
2970
2971 // cmp->dcd.suspendview = 1; // 12 Jan 08 SHL appears not to be used here
2972 // 26 Sep 09 SHL Unhide if nothing selected
2973 if (nowHidden) {
2974 // Hide items not selected on both sides
2975 BOOL needRefresh = FALSE;
2976 HWND hwndl = WinWindowFromID(cmp->hwnd, COMP_LEFTDIR);
2977 HWND hwndr = WinWindowFromID(cmp->hwnd, COMP_RIGHTDIR);
2978 PCNRITEM pcil = WinSendMsg(hwndl, CM_QUERYRECORD, MPVOID,
2979 MPFROM2SHORT(CMA_FIRST, CMA_ITEMORDER));
2980 PCNRITEM pcir = WinSendMsg(hwndr, CM_QUERYRECORD, MPVOID,
2981 MPFROM2SHORT(CMA_FIRST, CMA_ITEMORDER));
2982
2983 while (pcil && (INT)pcil != -1 && pcir && (INT)pcir != -1) {
2984 if (~pcil->rc.flRecordAttr & CRA_SELECTED &&
2985 ~pcir->rc.flRecordAttr & CRA_SELECTED) {
2986 if (~pcil->rc.flRecordAttr & CRA_FILTERED) {
2987 needRefresh = TRUE;
2988 pcil->rc.flRecordAttr |= CRA_FILTERED;
2989 }
2990 if (~pcir->rc.flRecordAttr & CRA_FILTERED) {
2991 pcir->rc.flRecordAttr |= CRA_FILTERED;
2992 needRefresh = TRUE;
2993 }
2994 }
2995 pcil = WinSendMsg(hwndl, CM_QUERYRECORD, MPFROMP(pcil),
2996 MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER));
2997 pcir = WinSendMsg(hwndr, CM_QUERYRECORD, MPFROMP(pcir),
2998 MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER));
2999 } // while
3000 if (needRefresh) {
3001 WinSendMsg(hwndl, CM_INVALIDATERECORD,
3002 MPVOID, MPFROM2SHORT(0, CMA_REPOSITION));
3003 WinSendMsg(hwndr, CM_INVALIDATERECORD,
3004 MPVOID, MPFROM2SHORT(0, CMA_REPOSITION));
3005 }
3006 }
3007 else {
3008 // Unhide
3009 WinSendMsg(GetHwndLeft(hwnd), CM_FILTER, MPFROMP(Filter),
3010 MPFROMP(&cmp->dcd.mask));
3011 WinSendMsg(GetHwndRight(hwnd), CM_FILTER, MPFROMP(Filter),
3012 MPFROMP(&cmp->dcd.mask));
3013 }
3014 if (*cmp->dcd.mask.szMask) {
3015 sprintf(s,
3016 GetPString(IDS_COMPREADYFILTEREDTEXT),
3017 cmp->dcd.mask.szMask);
3018 WinSetDlgItemText(hwnd, COMP_NOTE, s);
3019 }
3020 else
3021 WinSetDlgItemText(hwnd, COMP_NOTE, (CHAR *) GetPString(IDS_COMPREADYTEXT));
3022 WinCheckButton(hwnd, COMP_HIDENOTSELECTED, nowHidden);
3023 }
3024 return 0;
3025
3026 case WM_COMMAND:
3027 // 29 Apr 09 SHL FIXME to support more context menu items - IDM_VIEW, IDM_EDIT etc.
3028 switch (SHORT1FROMMP(mp1)) {
3029 case IDM_COMPARE:
3030 cmp = INSTDATA(hwnd);
3031 if (cmp) {
3032 PCNRITEM pci;
3033 pci = (PCNRITEM)WinSendMsg(cmp->hwndCalling,
3034 CM_QUERYRECORDEMPHASIS,
3035 MPFROMLONG(CMA_FIRST),
3036 MPFROMSHORT(CRA_CURSORED));
3037 if (pci && *pci->pszFileName) {
3038 if (cmp->hwndCalling == GetHwndLeft(hwnd))
3039 strcpy(szPathName, cmp->rightdir);
3040 else
3041 strcpy(szPathName, cmp->leftdir);
3042 AddBackslashToPath(szPathName);
3043 strcat(szPathName, pci->pszDisplayName);
3044 if (*compare) {
3045 CHAR *fakelist[3];
3046 fakelist[0] = pci->pszFileName;
3047 fakelist[1] = szPathName;
3048 fakelist[2] = NULL;
3049 ExecOnList(hwnd, compare, WINDOWED | SEPARATEKEEP,
3050 NULL, NULL, fakelist, NULL,
3051 pszSrcFile, __LINE__);
3052 }
3053 else {
3054 FCOMPARE fc;
3055 memset(&fc, 0, sizeof(fc));
3056 fc.size = sizeof(fc);
3057 fc.hwndParent = hwnd;
3058 strcpy(fc.file1, pci->pszFileName);
3059 strcpy(fc.file2, szPathName);
3060 WinDlgBox(HWND_DESKTOP, hwnd,
3061 CFileDlgProc, FM3ModHandle, FCMP_FRAME, (PVOID)&fc);
3062 }
3063 }
3064 }
3065 break;
3066
3067 case IDM_DELETE:
3068 cmp = INSTDATA(hwnd);
3069 if (!cmp)
3070 Runtime_Error(pszSrcFile, __LINE__, NULL);
3071 else {
3072 PCNRITEM pciS;
3073 PCNRITEM pciD;
3074 HWND hwndCnrS;
3075 HWND hwndCnrD;
3076 pciS = (PCNRITEM)WinSendMsg(cmp->hwndCalling,
3077 CM_QUERYRECORDEMPHASIS,
3078 MPFROMLONG(CMA_FIRST),
3079 MPFROMSHORT(CRA_CURSORED));
3080 if (!pciS)
3081 Runtime_Error(pszSrcFile, __LINE__, NULL);
3082 else {
3083 // Find matching record
3084 if (cmp->hwndCalling == GetHwndLeft(hwnd)) {
3085 hwndCnrS = GetHwndLeft(hwnd);
3086 hwndCnrD = GetHwndRight(hwnd);
3087 }
3088 else {
3089 hwndCnrS = GetHwndRight(hwnd);
3090 hwndCnrD = GetHwndLeft(hwnd);
3091 }
3092
3093 pciD = FindMatchingItem(pciS, hwndCnrS, hwndCnrD);
3094
3095 if (!pciD)
3096 Runtime_Error(pszSrcFile, __LINE__, NULL);
3097 else if (!pciS->pszFileName)
3098 Runtime_Error(pszSrcFile, __LINE__, NULL);
3099 else {
3100 if (!unlinkf(pciS->pszFileName)) {
3101 WinSendMsg(hwndCnrS, CM_SETRECORDEMPHASIS, MPFROMP(pciS),
3102 MPFROM2SHORT(FALSE, CRA_SELECTED));
3103
3104 if (!*pciD->pszFileName) {
3105 // Other side is blank - remove from both sides
3106 RemoveCnrItems(hwndCnrS, pciS, 1, CMA_FREE | CMA_INVALIDATE);
3107 if (pciD->rc.flRecordAttr & CRA_SELECTED)
3108 WinSendMsg(hwndCnrD, CM_SETRECORDEMPHASIS, MPFROMP(pciD),
3109 MPFROM2SHORT(FALSE, CRA_SELECTED));
3110 RemoveCnrItems(hwndCnrD, pciD, 1, CMA_FREE | CMA_INVALIDATE);
3111 }
3112 else {
3113 // Other side is not blank - just blank this side
3114 FreeCnrItemData(pciS);
3115 pciS->pszFileName = NullStr;
3116 pciS->pszDisplayName = pciS->pszFileName;
3117 pciS->rc.pszIcon = pciS->pszFileName;
3118 pciS->flags = 0; // Just on one side
3119 WinSendMsg(hwndCnrS, CM_INVALIDATERECORD, MPFROMP(&pciS),
3120 MPFROM2SHORT(1, CMA_ERASE | CMA_TEXTCHANGED));
3121 pciD->flags = 0; // Just on one side
3122 if (pciD->pszSubject != NullStr) {
3123 xfree(pciD->pszSubject, pszSrcFile, __LINE__);
3124 pciD->pszSubject = NullStr;
3125 }
3126 }
3127 if (hwndCnrS == GetHwndLeft(hwnd))
3128 cmp->totalleft--;
3129 else
3130 cmp->totalright--;
3131 // Force displayed counts to update
3132 WinPostMsg(hwnd, WM_TIMER, MPFROMLONG(ID_COMP_TIMER), 0);
3133 }
3134 }
3135 }
3136 }
3137 break; // IDM_DELETE
3138
3139 case COMP_FILTER:
3140 case IDM_FILTER:
3141 cmp = INSTDATA(hwnd);
3142 if (cmp) {
3143 BOOL empty = FALSE;
3144 PCNRITEM pci;
3145 CHAR *p;
3146 BOOL temp;
3147
3148 if (!*cmp->dcd.mask.szMask) {
3149 empty = TRUE;
3150 temp = fSelectedAlways;
3151 fSelectedAlways = TRUE;
3152 pci = (PCNRITEM)CurrentRecord(hwnd);
3153 fSelectedAlways = temp;
3154 // 01 Aug 07 SHL
3155 if (pci && ~pci->attrFile & FILE_DIRECTORY) {
3156 p = strrchr(pci->pszFileName, '\\');
3157 if (p) {
3158 p++;
3159 strcpy(cmp->dcd.mask.szMask, p);
3160 }
3161 }
3162 }
3163 cmp->dcd.mask.fNoAttribs = TRUE;
3164 cmp->dcd.mask.attrFile = ALLATTRS;
3165 cmp->dcd.mask.antiattr = 0;
3166 if (WinDlgBox(HWND_DESKTOP, hwnd, PickMaskDlgProc,
3167 FM3ModHandle, MSK_FRAME, MPFROMP(&cmp->dcd.mask))) {
3168 cmp->dcd.mask.attrFile = ALLATTRS;
3169 cmp->dcd.mask.antiattr = 0;
3170 WinSendMsg(hwnd, UM_FILTER, MPVOID, MPVOID);
3171 }
3172 else if (empty) {
3173 *cmp->dcd.mask.szMask = 0;
3174 cmp->dcd.mask.attrFile = ALLATTRS;
3175 cmp->dcd.mask.antiattr = 0;
3176 }
3177 }
3178 break;
3179
3180 case IDM_SHOWSUBJECT:
3181 case IDM_SHOWEAS:
3182 case IDM_SHOWSIZE:
3183 case IDM_SHOWLWDATE:
3184 case IDM_SHOWLWTIME:
3185 case IDM_SHOWLADATE:
3186 case IDM_SHOWLATIME:
3187 case IDM_SHOWCRDATE:
3188 case IDM_SHOWCRTIME:
3189 case IDM_SHOWATTR:
3190 cmp = INSTDATA(hwnd);
3191 if (cmp) {
3192 DIRCNRDATA dcd1;
3193 BOOL tempsubj;
3194
3195 dcd1 = cmp->dcd;
3196 AdjustDetailsSwitches(GetHwndLeft(hwnd),
3197 (HWND)0, SHORT1FROMMP(mp1),
3198 cmp->leftdir, PCSZ_DIRCMP, &cmp->dcd.ds, TRUE);
3199 tempsubj = cmp->dcd.ds.detailssubject;
3200 cmp->dcd = dcd1;
3201 cmp->dcd.ds.detailssubject = FALSE;
3202 AdjustDetailsSwitches(GetHwndRight(hwnd),
3203 cmp->dcd.hwndLastMenu, SHORT1FROMMP(mp1),
3204 cmp->rightdir, PCSZ_DIRCMP, &cmp->dcd.ds, TRUE);
3205 cmp->dcd.ds.detailssubject = tempsubj;
3206 WriteDetailsSwitches(PCSZ_DIRCMP, &cmp->dcd.ds, TRUE);
3207 }
3208 break;
3209
3210 case IDM_LOADLISTFILE:
3211 cmp = INSTDATA(hwnd);
3212 if (cmp) {
3213 CHAR fullname[CCHMAXPATH];
3214
3215 strcpy(fullname, PCSZ_STARDOTPMD);
3216 if (insert_filename(HWND_DESKTOP, fullname, TRUE, FALSE) &&
3217 *fullname && !strchr(fullname, '*') && !strchr(fullname, '?')) {
3218 strcpy(cmp->rightlist, fullname);
3219 PostMsg(hwnd, UM_SETUP, MPVOID, MPVOID);
3220 PostMsg(hwnd, UM_SETDIR, MPVOID, MPVOID);
3221 }
3222 }
3223 break;
3224
3225 case IDM_SAVELISTFILE:
3226 cmp = INSTDATA(hwnd);
3227 if (cmp) {
3228 SNAPSTUFF *sf;
3229 CHAR fullname[CCHMAXPATH];
3230
3231 strcpy(fullname, PCSZ_STARDOTPMD);
3232 if (export_filename(HWND_DESKTOP, fullname, 1) && *fullname &&
3233 !strchr(fullname, '*') && !strchr(fullname, '?')) {
3234 sf = xmallocz(sizeof(SNAPSTUFF), pszSrcFile, __LINE__);
3235 if (sf) {
3236 strcpy(sf->filename, fullname);
3237 if (GetHwndLeft(hwnd) == cmp->hwndCalling)
3238 strcpy(sf->dirname, cmp->leftdir);
3239 else
3240 strcpy(sf->dirname, cmp->rightdir);
3241 sf->recurse = WinQueryButtonCheckstate(hwnd, COMP_INCLUDESUBDIRS);
3242
3243 if (xbeginthread(StartSnapThread,
3244 65536,
3245 sf,
3246 pszSrcFile,
3247 __LINE__) == -1)
3248 {
3249 free(sf);
3250 }
3251 }
3252 }
3253 }
3254 break;
3255
3256 case COMP_SETDIRS:
3257 cmp = INSTDATA(hwnd);
3258 if (cmp) {
3259 WALK2 wa;
3260 memset(&wa, 0, sizeof(wa));
3261 wa.size = sizeof(wa);
3262 strcpy(wa.szCurrentPath1, cmp->leftdir);
3263 strcpy(wa.szCurrentPath2, cmp->rightdir);
3264 wa.includesubdirs = WinQueryButtonCheckstate(hwnd,
3265 COMP_INCLUDESUBDIRS);
3266 if (WinDlgBox(HWND_DESKTOP,
3267 hwnd,
3268 WalkTwoCmpDlgProc,
3269 FM3ModHandle,
3270 WALK2_FRAME,
3271 MPFROMP(&wa)) &&
3272 !IsFile(wa.szCurrentPath1) &&
3273 !IsFile(wa.szCurrentPath2)) {
3274 strcpy(cmp->leftdir, wa.szCurrentPath1);
3275 strcpy(cmp->rightdir, wa.szCurrentPath2);
3276 cmp->includesubdirs = wa.includesubdirs;
3277 if (!cmp->includesubdirs)
3278 WinCheckButton(hwnd, COMP_INCLUDESUBDIRS, FALSE);
3279 cmp->listfile = wa.listfile;
3280 if (cmp->listfile) {
3281 CHAR fullname[CCHMAXPATH];
3282
3283 strcpy(fullname, PCSZ_STARDOTPMD);
3284 if (insert_filename(HWND_DESKTOP, fullname, TRUE, FALSE) &&
3285 *fullname && !strchr(fullname, '*') && !strchr(fullname, '?'))
3286 strcpy(cmp->rightlist, fullname);
3287 }
3288 else
3289 *cmp->rightlist = 0;
3290 PostMsg(hwnd, UM_SETUP, MPVOID, MPVOID);
3291 PostMsg(hwnd, UM_SETDIR, MPVOID, MPVOID);
3292 }
3293 }
3294 break;
3295
3296 case COMP_COPYLEFT:
3297 case COMP_MOVELEFT:
3298 case COMP_COPYRIGHT:
3299 case COMP_MOVERIGHT:
3300 case COMP_DELETELEFT:
3301 case COMP_DELETERIGHT:
3302 cmp = INSTDATA(hwnd);
3303 if (cmp) {
3304 COMPARE *forthread;
3305
3306 cmp->filling = TRUE;
3307 forthread = xmalloc(sizeof(COMPARE), pszSrcFile, __LINE__);
3308 if (forthread) {
3309 *forthread = *cmp;
3310 forthread->cmp = cmp;
3311 forthread->action = SHORT1FROMMP(mp1);
3312 if (xbeginthread(ActionCnrThread,
3313 122880,
3314 forthread,
3315 pszSrcFile,
3316 __LINE__) == -1)
3317 {
3318 free(forthread);
3319 }
3320 else {
3321 WinEnableWindowUpdate(GetHwndLeft(hwnd), FALSE);
3322 WinEnableWindowUpdate(GetHwndRight(hwnd), FALSE);
3323 switch (SHORT1FROMMP(mp1)) {
3324 case COMP_DELETELEFT:
3325 case COMP_DELETERIGHT:
3326 WinSetDlgItemText(hwnd, COMP_NOTE,
3327 (CHAR *) GetPString(IDS_COMPHOLDDELETINGTEXT));
3328 break;
3329 case COMP_MOVELEFT:
3330 case COMP_MOVERIGHT:
3331 WinSetDlgItemText(hwnd, COMP_NOTE,
3332 (CHAR *) GetPString(IDS_COMPHOLDMOVINGTEXT));
3333 break;
3334 case COMP_COPYLEFT:
3335 case COMP_COPYRIGHT:
3336 WinSetDlgItemText(hwnd, COMP_NOTE,
3337 (CHAR *) GetPString(IDS_COMPHOLDCOPYINGTEXT));
3338 break;
3339 default:
3340 Runtime_Error(pszSrcFile, __LINE__, "mp1 %u unexpected", SHORT1FROMMP(mp1));
3341 }
3342 SetButtonEnables(cmp, FALSE);
3343 }
3344 }
3345 }
3346 break;
3347
3348 case DID_OK:
3349 {
3350 SWP swp;
3351 ULONG size = sizeof(SWP);
3352 USHORT ids[] = {COMP_FRAME, COMP_LEFTDIR, COMP_RIGHTDIR, COMP_COLLECT,
3353 COMP_VIEW, COMP_NOTE, COMP_TOTALLEFT, COMP_SELLEFT, COMP_TOTALRIGHT,
3354 COMP_SELRIGHT, COMP_CNRMENU, COMP_DIRMENU, COMP_MENU,
3355 COMP_INCLUDESUBDIRS, COMP_SETDIRS, COMP_COPYLEFT, COMP_MOVELEFT,
3356 COMP_DELETELEFT, COMP_COPYRIGHT, COMP_MOVERIGHT, COMP_DELETERIGHT,
3357 COMP_TOTALLEFTHDR, COMP_SELLEFTHDR, COMP_TOTALRIGHTHDR,
3358 COMP_SELRIGHTHDR, COMP_FILTER, COMP_HIDENOTSELECTED, 0};
3359 UINT x;
3360 CHAR s[24];
3361 WinQueryWindowPos(hwnd, &swp);
3362 PrfWriteProfileData(fmprof, FM3Str, "CompDir.Position", (PVOID) &swp,
3363 size);
3364 for (x = 0; ids[x]; x++) {
3365 sprintf(s, "CompDir%i", ids[x]);
3366 SavePresParams(WinWindowFromID(hwnd, ids[x]), s);
3367 }
3368 }
3369 WinDismissDlg(hwnd, 0);
3370 break;
3371 case DID_CANCEL:
3372 cmp = INSTDATA(hwnd);
3373 if (!cmp)
3374 Runtime_Error(pszSrcFile, __LINE__, NULL);
3375 else {
3376 cmp->stop = TRUE; // In case thread running
3377 if (cmp->filling)
3378 break; // UM_CONTAINER_FILLED will dismiss
3379 }
3380 {
3381 SWP swp;
3382 ULONG size = sizeof(SWP);
3383 WinQueryWindowPos(hwnd, &swp);
3384 PrfWriteProfileData(fmprof, FM3Str, "CompDir.Position", (PVOID) &swp,
3385 size);
3386 }
3387 WinDismissDlg(hwnd, 1);
3388 break;
3389
3390 case IDM_HELP:
3391 if (hwndHelp)
3392 WinSendMsg(hwndHelp, HM_DISPLAY_HELP,
3393 MPFROM2SHORT(HELP_COMPARE, 0), MPFROMSHORT(HM_RESOURCEID));
3394 break;
3395
3396 case IDM_DESELECTALL:
3397 case IDM_SELECTNEWER:
3398 case IDM_SELECTOLDER:
3399 case IDM_SELECTBIGGER:
3400 case IDM_SELECTSMALLER:
3401 case IDM_SELECTEAS:
3402 case IDM_DESELECTNEWER:
3403 case IDM_DESELECTOLDER:
3404 case IDM_DESELECTBIGGER:
3405 case IDM_DESELECTSMALLER:
3406 case IDM_DESELECTONE:
3407 case IDM_DESELECTBOTH:
3408 case IDM_DESELECTEAS:
3409 case IDM_SELECTBOTH:
3410 case IDM_SELECTONE:
3411 case IDM_SELECTSAMECONTENT:
3412 case IDM_SELECTIDENTICAL: // Name, size and time
3413 case IDM_SELECTSAME: // Name and size
3414 case IDM_INVERT:
3415 cmp = INSTDATA(hwnd);
3416 if (!cmp)
3417 Runtime_Error(pszSrcFile, __LINE__, NULL);
3418 else {
3419 COMPARE *forthread;
3420
3421 cmp->filling = TRUE;
3422 forthread = xmalloc(sizeof(COMPARE), pszSrcFile, __LINE__);
3423 if (forthread) {
3424 *forthread = *cmp;
3425 forthread->cmp = cmp;
3426 forthread->action = SHORT1FROMMP(mp1);
3427 SetShiftState();
3428 forthread->shiftstate = shiftstate; // For and'ed actions
3429
3430 if (xbeginthread(SelectCnrsThread,
3431 65536,
3432 forthread,
3433 pszSrcFile,
3434 __LINE__) == -1)
3435 {
3436 free(forthread);
3437 }
3438 else {
3439 WinEnableWindowUpdate(GetHwndLeft(hwnd), FALSE);
3440 WinEnableWindowUpdate(GetHwndRight(hwnd), FALSE);
3441 switch (SHORT1FROMMP(mp1)) {
3442 case IDM_DESELECTALL:
3443 case IDM_DESELECTNEWER:
3444 case IDM_DESELECTOLDER:
3445 case IDM_DESELECTBIGGER:
3446 case IDM_DESELECTSMALLER:
3447 case IDM_DESELECTONE:
3448 case IDM_DESELECTBOTH:
3449 WinSetDlgItemText(hwnd, COMP_NOTE,
3450 (CHAR *) GetPString(IDS_COMPHOLDDESELTEXT));
3451 break;
3452 case IDM_INVERT:
3453 WinSetDlgItemText(hwnd, COMP_NOTE,
3454 (CHAR *) GetPString(IDS_COMPHOLDINVERTTEXT));
3455 break;
3456 default:
3457 WinSetDlgItemText(hwnd, COMP_NOTE,
3458 (CHAR *) GetPString(IDS_COMPHOLDSELTEXT));
3459 break;
3460 }
3461 SetButtonEnables(cmp, FALSE);
3462 }
3463 }
3464 }
3465 break;
3466
3467 case COMP_COLLECT:
3468 cmp = INSTDATA(hwnd);
3469 if (!cmp)
3470 Runtime_Error(pszSrcFile, __LINE__, NULL);
3471 else {
3472 CHAR **listl;
3473 CHAR **listr = NULL;
3474 if (!Collector) {
3475 SWP swp;
3476 HWND hwndC;
3477 if (!fAutoTile &&
3478 !ParentIsDesktop(hwnd, cmp->hwndParent) &&
3479 !fExternalCollector &&
3480 !strcmp(realappname, FM3Str)) {
3481 GetNextWindowPos(cmp->hwndParent, &swp, NULL, NULL);
3482 }
3483 hwndC = StartCollector(fExternalCollector ||
3484 strcmp(realappname, FM3Str) ?
3485 HWND_DESKTOP :
3486 cmp->hwndParent,
3487 4);
3488 if (hwndC) {
3489 if (!fAutoTile &&
3490 !ParentIsDesktop(hwnd, cmp->hwndParent) &&
3491 !fExternalCollector &&
3492 !strcmp(realappname, FM3Str)) {
3493 WinSetWindowPos(hwndC, HWND_TOP,
3494 swp.x, swp.y, swp.cx, swp.cy,
3495 SWP_MOVE | SWP_SIZE | SWP_SHOW | SWP_ZORDER);
3496 }
3497 else if (!ParentIsDesktop(hwnd, cmp->hwndParent) &&
3498 fAutoTile &&
3499 !strcmp(realappname, FM3Str)) {
3500 TileChildren(cmp->hwndParent, TRUE);
3501 }
3502 DosSleep(1); // 12 Jan 08 SHL Let screen update
3503 PostMsg(hwnd, WM_COMMAND, MPFROM2SHORT(COMP_COLLECT, 0), MPVOID);
3504 break;
3505 }
3506 }
3507 else
3508 StartCollector(cmp->hwndParent, 4);
3509
3510 temp = fSelectedAlways;
3511 fSelectedAlways = TRUE;
3512 listl = BuildList(GetHwndLeft(hwnd));
3513 if (!*cmp->rightlist)
3514 listr = BuildList(GetHwndRight(hwnd));
3515 fSelectedAlways = temp;
3516
3517 if (listl || listr) {
3518 if (Collector) {
3519 // 07 Aug 07 SHL Avoid collected from empty list
3520 if (listl && listl[0] && *listl[0]) {
3521 if (PostMsg(Collector, WM_COMMAND,
3522 MPFROM2SHORT(IDM_COLLECTOR, 0), MPFROMP(listl)))
3523 listl = NULL; // Collector will free
3524 }
3525 if (listr && listr[0] && *listr[0]) {
3526 if (PostMsg(Collector, WM_COMMAND,
3527 MPFROM2SHORT(IDM_COLLECTOR, 0), MPFROMP(listr)))
3528 listr = NULL; // Collector will free
3529 }
3530 WinSetWindowPos(WinQueryWindow(WinQueryWindow(Collector,
3531 QW_PARENT),
3532 QW_PARENT),
3533 HWND_TOP, 0, 0, 0, 0,
3534 SWP_ACTIVATE);
3535 }
3536 FreeList(listl);
3537 FreeList(listr);
3538 }
3539 }
3540 break;
3541 } // switch mp1
3542 return 0;
3543
3544 case WM_CLOSE:
3545 cmp = INSTDATA(hwnd);
3546 if (!cmp)
3547 Runtime_Error(pszSrcFile, __LINE__, NULL);
3548 else {
3549 cmp->stop = TRUE; // In case thread running
3550 if (cmp->filling)
3551 break; // UM_CONTAINER_FILLED will dismiss
3552 }
3553 WinDismissDlg(hwnd, 0);
3554 return 0;
3555
3556 case WM_DESTROY:
3557 cmp = INSTDATA(hwnd);
3558 if (cmp) {
3559 // 17 Jan 08 SHL FIXME to know if stop really needed?
3560 WinStopTimer(WinQueryAnchorBlock(hwnd), hwnd, ID_COMP_TIMER);
3561 if (cmp->dcd.hwndLastMenu)
3562 WinDestroyWindow(cmp->dcd.hwndLastMenu);
3563 if (cmp->dcd.hwndObject) {
3564 WinSetWindowPtr(cmp->dcd.hwndObject, QWL_USER, (PVOID)NULL);
3565 if (!PostMsg(cmp->dcd.hwndObject, WM_CLOSE, MPVOID, MPVOID))
3566 WinSendMsg(cmp->dcd.hwndObject, WM_CLOSE, MPVOID, MPVOID);
3567 }
3568 DosRequestMutexSem(hmtxFiltering, SEM_INDEFINITE_WAIT);
3569 free(cmp);
3570 cmp = NULL;
3571 DosReleaseMutexSem(hmtxFiltering);
3572 }
3573
3574# ifdef PMPRINTF
3575 PmPrintf_Report(pszSrcFile, __LINE__, "CompareDlgProc EmptyCnr Left");
3576# endif
3577 EmptyCnr(GetHwndLeft(hwnd));
3578
3579# ifdef PMPRINTF
3580 PmPrintf_Report(pszSrcFile, __LINE__, "CompareDlgProc EmptyCnr Right");
3581# endif
3582 EmptyCnr(GetHwndRight(hwnd));
3583
3584 DosPostEventSem(CompactSem);
3585 break;
3586 }
3587 return WinDefDlgProc(hwnd, msg, mp1, mp2);
3588}
3589
3590#undef GetHwndLeft
3591#undef GetHwndRight
3592
3593#pragma alloc_text(COMPAREDIR,FillCnrsThread,FillDirList,CompNames,BldFullPathName)
3594#pragma alloc_text(COMPAREDIR1,CompareDlgProc)
3595#pragma alloc_text(COMPAREDIR2,SelectCnrsThread,ActionCnrThread)
3596#pragma alloc_text(COMPAREFILE,CFileDlgProc,CompareFilesThread)
3597#pragma alloc_text(SNAPSHOT,SnapShot,StartSnapThread)
3598#pragma alloc_text(COMPSELECT,CompSelect,CompSelectSetSelects,CompSelectClearSelects)
3599
Note: See TracBrowser for help on using the repository browser.