📄 complist.c
字号:
/****************************** Module Header *******************************
* Module Name: COMPLIST.C
*
* Supports a list of compitems, where each compitem represents
* a pair of matching files, or an unmatched file.
*
* Functions:
*
* complist_filedialog()
* complist_dirdialog()
* complist_args()
* complist_getitems()
* complist_delete()
* complist_savelist()
* complist_copyfiles()
* complist_dodlg_savelist()
* complist_dodlg_copyfiles()
* complist_match()
* complist_new()
* complist_dodlg_dir()
*
* Comments:
*
* We build lists of filenames from two pathnames (using the
* scandir module) and then traverse the two lists comparing names.
* Where the names match, we create a CompItem from the matching
* names. Where there is an unmatched name, we create a compitem for it.
*
* We may also be asked to create a complist for two individual files:
* here we create a single compitem for them as a matched pair even if
* the names don't match.
*
****************************************************************************/
#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include <dos.h>
#include <direct.h>
#include "gutils.h"
#include "state.h"
#include "windiff.h"
#include "wdiffrc.h"
#include "list.h"
#include "line.h"
#include "scandir.h"
#include "file.h"
#include "section.h"
#include "compitem.h"
#include "complist.h"
#include "view.h"
extern BOOL bAbort; /* defined in windiff.c Read only here */
/*
* The COMPLIST handle is typedef-ed to be a pointer to one
* of these struct complist
*/
struct complist {
DIRLIST left; /* left list of files */
DIRLIST right; /* right list of files */
LIST items; /* list of COMPITEMs */
};
/* ---- module-wide data -------------------------------------*/
/* data for communicating between the SaveList dlg and complist_savelist() */
char dlg_file[256]; /* filename to save to */
/* checkbox options */
BOOL dlg_identical, dlg_differ, dlg_left, dlg_right;
BOOL dlg_recursive = FALSE;
/* data for Directory and SaveList */
char dialog_leftname[256];
char dialog_rightname[256];
/*
* data used by dodlg_copyfiles
*/
UINT dlg_options;
char dlg_root[256];
/*------------------------timing for performance measurements-----------------*/
static DWORD TickCount; /* time operation started, then time taken*/
int FAR PASCAL complist_dodlg_savelist(HWND hDlg, UINT message,
UINT wParam, long lParam);
int FAR PASCAL complist_dodlg_copyfiles(HWND hDlg, UINT message,
UINT wParam, long lParam);
BOOL complist_match(COMPLIST cl, VIEW view, BOOL fDeep, BOOL fExact);
COMPLIST complist_new(void);
int FAR PASCAL complist_dodlg_dir(HWND hDlg, unsigned message,
WORD wParam, LONG lParam);
/***************************************************************************
* Function: complist_filedialog
*
* Purpose:
*
* Builds a complist by putting up two dialogs to allow the user to
* select two files. This will build a Complist with one CompItem (even
* if the names don't match).
*
***************************************************************************/
COMPLIST
complist_filedialog(VIEW view)
{
COMPLIST cl;
OFSTRUCT os1, os2;
char fname[256], FileExt[256], FileOpenSpec[256];
/* ask for the filenames */
lstrcpy(FileExt, ".c");
lstrcpy(FileOpenSpec, "*.*");
lstrcpy(fname,"");
if (!complist_open(LoadRcString(IDS_SELECT_FIRST_FILE), FileExt, FileOpenSpec,
&os1, fname) )
return(NULL);
lstrcpy(FileExt, ".c");
lstrcpy(FileOpenSpec, "*.*");
lstrcpy(fname,"");
if (!complist_open(LoadRcString(IDS_SELECT_SECOND_FILE), FileExt, FileOpenSpec,
&os2, fname) )
return(NULL);
/* alloc a new structure */
cl = complist_new();
cl->left = dir_buildlist(os1.szPathName, TRUE);
cl->right = dir_buildlist(os2.szPathName, TRUE);
/* register with the view (must be done after the list is non-null) */
view_setcomplist(view, cl);
complist_match(cl, view, FALSE, TRUE);
return(cl);
}/* complist_filedialog */
/***************************************************************************
* Function: complist_dirdialog
*
* Purpose:
*
* Builds a new complist by querying the user for two directory
* names and scanning those in parallel.
*
* Names that match in the same directory will be paired - unmatched
* names will go in a compitem on their own.
*
***************************************************************************/
COMPLIST
complist_dirdialog(VIEW view)
{
DLGPROC lpProc;
BOOL fOK;
/* put up a dialog for the two pathnames */
lpProc = (DLGPROC)MakeProcInstance((WNDPROC)complist_dodlg_dir, hInst);
windiff_UI(TRUE);
fOK = DialogBox(hInst, "Directory", hwndClient, lpProc);
windiff_UI(FALSE);
FreeProcInstance(lpProc);
if (!fOK) {
return(NULL);
}
return complist_args( dialog_leftname, dialog_rightname
, view, dlg_recursive);
} /* complist_dirdialog */
/***************************************************************************
* Function: complist_args
*
* Purpose:
*
* Given two pathname strings, scan the directories and traverse them
* in parallel comparing matching names.
*
***************************************************************************/
COMPLIST
complist_args(LPSTR p1, LPSTR p2, VIEW view, BOOL fDeep)
{
COMPLIST cl;
char msg[256];
/* alloc a new complist */
cl = complist_new();
cl->left = dir_buildlist(p1, TRUE);
/* check that we could find the paths, and report if not */
if (cl->left == NULL) {
wsprintf((LPTSTR)msg, LoadRcString(IDS_COULDNT_FIND), p1);
MessageBox(NULL, msg, NULL, MB_OK | MB_ICONSTOP);
return(NULL);
}
cl->right = dir_buildlist(p2, TRUE);
if (cl->right == NULL) {
wsprintf((LPTSTR)msg, LoadRcString(IDS_COULDNT_FIND), p2);
MessageBox(NULL, msg, NULL, MB_OK | MB_ICONSTOP);
return(NULL);
}
/* register with the view (must be done after building lists) */
view_setcomplist(view, cl);
complist_match(cl, view, fDeep, TRUE);
return(cl);
} /* complist_args */
/***************************************************************************
* Function: complist_getitems
*
* Purpose:
*
* Gets the handle to the list of COMPITEMs. The list continues to be
* owned by the COMPLIST, so don't delete except by calling complist_delete.
*
***************************************************************************/
LIST
complist_getitems(COMPLIST cl)
{
if (cl == NULL) {
return(NULL);
}
return(cl->items);
}
/***************************************************************************
* Function: complist_delete
*
* Purpose:
*
* Deletes a complist and all associated CompItems and DIRLISTs. Note this
* does not delete any VIEW - the VIEW owns the COMPLIST and not the other
* way around.
*
**************************************************************************/
void
complist_delete(COMPLIST cl)
{
COMPITEM item;
if (cl == NULL) {
return;
}
/* delete the two directory scan lists */
dir_delete(cl->left);
dir_delete(cl->right);
/* delete the compitems in the list */
List_TRAVERSE(cl->items, item) {
compitem_delete(item);
}
/* delete the list itself */
List_Destroy(&cl->items);
gmem_free(hHeap, (LPSTR) cl, sizeof(struct complist));
}
/***************************************************************************
* Function: complist_savelist
*
* Purpose:
*
* Writes out to a text file the list of compitems as relative filenames
* one per line.
*
* If savename is non-null, use this as the filename for output; otherwise,
* query the user via a dialog for the filename and include options.
*
**************************************************************************/
void
complist_savelist(COMPLIST cl, LPSTR savename, UINT options)
{
DLGPROC lpProc;
static BOOL done_init = FALSE;
BOOL bOK;
int fh, state;
OFSTRUCT os;
char msg[256];
HCURSOR hcurs;
COMPITEM ci;
LPSTR pstr, lhead, rhead;
int nFiles = 0;
if (!done_init) {
/* init the options once round - but keep the same options
* for the rest of the session.
*/
/* first init default options */
dlg_identical = FALSE;
dlg_differ = TRUE;
dlg_left = TRUE;
dlg_right = FALSE;
dlg_file[0] = '\0';
done_init = TRUE;
}
if (cl == NULL) {
return;
}
if (savename == NULL) {
/* store the left and right rootnames so that dodlg_savelist
* can display them in the dialog.
*/
pstr = dir_getroot_list(cl->left);
lstrcpy(dialog_leftname, pstr);
dir_freeroot_list(cl->left, pstr);
pstr = dir_getroot_list(cl->right);
lstrcpy(dialog_rightname, pstr);
dir_freeroot_list(cl->right, pstr);
lpProc = (DLGPROC)MakeProcInstance((WNDPROC)complist_dodlg_savelist, hInst);
windiff_UI(TRUE);
bOK = DialogBox(hInst, "SaveList", hwndClient, lpProc);
windiff_UI(FALSE);
FreeProcInstance(lpProc);
if (!bOK) {
/* user cancelled from dialog box */
return;
}
savename = dlg_file;
} else {
dlg_identical = (options & INCLUDE_SAME);
dlg_differ = (options & INCLUDE_DIFFER);
dlg_left = (options & INCLUDE_LEFTONLY);
dlg_right = (options & INCLUDE_RIGHTONLY);
}
/* try to open the file */
fh = OpenFile(savename, &os, OF_CREATE|OF_READWRITE|OF_SHARE_DENY_WRITE);
if (fh < 0) {
wsprintf((LPTSTR)msg, LoadRcString(IDS_CANT_OPEN), savename);
windiff_UI(TRUE);
MessageBox(NULL, msg, "Windiff", MB_ICONSTOP|MB_OK);
windiff_UI(FALSE);
return;
}
hcurs = SetCursor(LoadCursor(NULL, IDC_WAIT));
/* write out the header line */
lhead = dir_getroot_list(cl->left);
rhead = dir_getroot_list(cl->right);
{
TCHAR szBuf1[20],szBuf2[20],szBuf3[20],szBuf4[20];
lstrcpy(szBuf1,(LPSTR)(dlg_identical ? LoadRcString(IDS_IDENTICAL_COMMA) : ""));
lstrcpy(szBuf2,(LPSTR)(dlg_left ? LoadRcString(IDS_LEFT_ONLY_COMMA) : ""));
lstrcpy(szBuf3,(LPSTR)(dlg_right ? LoadRcString(IDS_RIGHT_ONLY_COMMA) : ""));
lstrcpy(szBuf4,(LPSTR)(dlg_differ ? LoadRcString(IDS_DIFFERING) : ""));
wsprintf(msg, LoadRcString(IDS_HEADER_LINE_STR),
lhead, rhead, szBuf1, szBuf2, szBuf3, szBuf4);
}
_lwrite(fh, msg, lstrlen(msg));
dir_freeroot_list(cl->left, lhead);
dir_freeroot_list(cl->right, rhead);
/* traverse the list of compitems looking for the
* ones we are supposed to include
*/
List_TRAVERSE(cl->items, ci) {
/* check if files of this type are to be listed */
state = compitem_getstate(ci);
if ((state == STATE_SAME) && (!dlg_identical)) {
continue;
} else if ((state == STATE_DIFFER) && (!dlg_differ)) {
continue;
} else if ((state == STATE_FILELEFTONLY) && (!dlg_left)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -