source: trunk/dll/comp.c@ 1836

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

Fix trap in collector if a pci-pszFileName = NullStr and fix heap corruption problem and its related traps. This code reverts John double free fix. Ticket [551][555]

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