source: trunk/dll/comp.c

Last change on this file was 1900, checked in by Gregg Young, 15 months ago

Fix ticket #575 spurious display of 00/00/00 date 0 eas and 0 time in compare directories on files that don't exist in one of the directories

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