📄 windiff.c
字号:
/****************************** Module Header *******************************
* Module Name: WINDIFF.C
*
* File and directory comparisions.
*
* Functions:
*
* windiff_UI()
* WinMain()
* windiff_usage()
* Poll()
* DoResize()
* AboutBox()
* DoPrint()
* FindNextChange()
* FindPrevChange()
* WriteProfileInt()
* ToOutline()
* ToMoved()
* do_editfile()
* do_editthread()
* SetStatus()
* SetNames()
* IsBusy()
* BusyError()
* StateToColour()
* SetSelection()
* do_gethdr()
* do_getprops()
* do_getdata()
* SvrClose()
* TableServer()
* wd_dirdialog()
* wd_copy()
* InitApplication()
* InitInstance()
* CreateTools()
* DeleteTools()
* MainWndProc()
* SetBusy()
* SetNotBusy()
* SetSelection()
* SetButtonText()
* ToExpand()
* ParseArgs()
* wd_initial()
*
* Comments:
*
* Compare two directories (including all files and subdirs). Look for names
* that are present in both (report all that are not). For files that
* are present in both, produce a line-by-line comparison of the differences
* between the two files (if any).
*
* Overview of Windiff internals - the whole program.
*
* Windiff is built from several modules (a "module" has a .h file
* which describes its interface and a .c file which implements it).
* Apart from THIS comment which tries to give an overview of the whole
* scheme of things, each module is as self-contained as possible.
* This is enforced by the use of opaque data types. Modules cannot
* see each others' internal data structures. Modules are abstract
* data types. The term "Module" (from Modula2) and "Class" (from C++)
* are used synonymously.
*
* Windiff - main program - parse arguments, put up main window,
* handle input, calling other modules as needed
* invoke table class to create the main display and
* service callbacks from the table class.
* Contains global flags for options (e.g. ignore_blanks)
* list - (in gutils) a generalised LIST of anything data type
* has full set of operations for insert, delete, join etc.
* line - a LINE is a numbered line of text. Information is kept to
* allow fast comparisons of LINEs. A LINE can hold a
* link to another LINE. The links are used to connect
* lines in one file to matching lines in the other file.
* file - a FILEDATA represents a file as a file name in the form
* of a DIRITEM and a LIST of LINEs
* scandir - a DIRITEM represents information about a file. (for
* instance its name, whether it has a local copy).
* compitem - a COMPITEM is a pair of files together with information
* on how they compare in the form of a breakdown of the
* files into a LIST of matching or non-matching sections.
* Either file can be absent. This module contains the
* file "contrast" algorithm used for the actual comparison
* tree (in gutils) A binary tree. Important because it is what
* gives the file comparison its speed as it makes it
* an "N log N" algorithm rather than "N squared"
* complist - a COMPLIST is the master data structure. It has a DIRLIST
* of the left hand files, a DIRLIST of the right hand files
* and a LIST of COMPITEMs. The left and right hand DIRLISTs
* are working data used to produce the COMPLIST. The LIST
* is displayed as the outline table. Any given COMPITEM can
* be displayed as an expanded item.
* section - a SECTION is a section of a file (first line, last line)
* and information as to what it matches in the other file.
* bar.c - the picture down the left of the screen
* has a WNDPROC.
* view - Although the COMPLIST is the master state, it doesn't do
* all the work itself. The data is actually displayed by
* the table class which is highly generalised. View
* owns a COMPLIST (and therefore calls upon the functions
* in complist to fill it and interrogate it) and calls
* upon (and is called back by) the functions in table to
* actually display it. Read about table in gutils.h
* table.c (in gutils) a highly generalised system for displaying
* data in rows and columns. The interface is in gutils.h.
* status.c (in gutils) the status line at the top. See gutils.h
*************************************************************************
*
* Overview of this file:
*
* We create a table window (gutils.dll) to show the files and the
* results of their comparisons. We create a COMPLIST object representing
* a list of files and their differences, and a VIEW object to map between
* the rows of the table window and the COMPLIST.
*
* This module is responsible for creating and managing the main window,
* placing the child windows (table, status window etc) within it, and
* handling all menu items. We maintain global option flags set by
* menu commands.
*
* Creating a COMPLIST creates a list of unmatched files, and of matching
* files that are compared with each other (these are COMPITEMS).
* The VIEW provides a mapping between rows on the screen, and items in
* the COMPLIST.
*
* This version tries to maintain a responsive user interface by
* creating worker threads to do long jobs. This potentially creates
* conflicts between the threads as they will both want to update common
* variables (for instance the UI thread may be changing the options to
* exclude identical files while the worker thread is adding in the
* results of new comparisons). Critical sections are used to manage
* the conflicts.
*
* The Edit options invoke an editor on a separate thread. This allows
* us to repaint our window and thereby allow the user to refer back to
* what he saw before invoking the editor. When he's finished editing,
* we would of course like to refresh things and if this is still on the
* separate thread it might clash. We avoid this clash by POSTing ourselves
* a (WM_COMMAND, IDM_UPDATE) message.
*
****************************************************************************/
#include <windows.h>
#include <shellapi.h>
#include <stdlib.h>
#include <commdlg.h>
#include <string.h>
#include "gutils.h"
#include "table.h"
#include "list.h"
#include "scandir.h" /* needed for file.h */
#include "file.h" /* needed for compitem.h */
#include "compitem.h" /* needed for view.h */
#include "complist.h"
#include "view.h"
#include "state.h"
#include "windiff.h"
#include "wdiffrc.h"
/*--constants and data types--------------------------------------------*/
int Version = 2;
int SubVersion = 01;
/* When we print the current table, we pass this id as the table id
* When we are queried for the properties of this table, we know they
* want the printing properties for the current view. We use this to
* select different fonts and colours for the printer.
*/
#define TABID_PRINTER 1
/*
* structure containing args passed to worker thread in initial
* case (executing command line instructions).
*/
typedef struct {
LPSTR first;
LPSTR second;
LPSTR savelist;
UINT saveopts;
VIEW view;
BOOL fDeep;
} THREADARGS, FAR * PTHREADARGS;
/* Structure containing all the arguments we'd like to give to do_editfile
Need a structure because CreateThread only allows for one argument.
*/
typedef struct {
VIEW view;
int option;
int selection;
} EDITARGS, FAR * PEDITARGS;
/*---- colour scheme------------------------------- */
/* outline */
DWORD rgb_outlinehi = RGB(255, 0, 0); /* hilighted files in outline mode */
/* expand view */
DWORD rgb_leftfore = RGB( 0, 0, 0); /* foregrnd for left lines */
DWORD rgb_leftback = RGB(255, 0, 0); /* backgrnd for left lines */
DWORD rgb_rightfore = RGB( 0, 0, 0); /* foregrnd for right lines*/
DWORD rgb_rightback = RGB(255, 255, 0); /* backgrnd for right lines*/
/* moved lines */
DWORD rgb_mleftfore = RGB( 0, 0, 128); /* foregrnd for moved-left */
DWORD rgb_mleftback = RGB(255, 0, 0); /* backgrnd for moved-left */
DWORD rgb_mrightfore = RGB( 0, 0, 255); /* foregrnd for moved-right*/
DWORD rgb_mrightback = RGB(255, 255, 0); /* backgrnd for moved-right*/
/* bar window */
DWORD rgb_barleft = RGB(255, 0, 0); /* bar sections in left only */
DWORD rgb_barright = RGB(255, 255, 0); /* bar sections in right only */
DWORD rgb_barcurrent = RGB( 0, 0, 255); /* current pos markers in bar */
/* module static data -------------------------------------------------*/
/* current value of window title */
char AppTitle[256];
HWND hwndClient; /* main window */
HWND hwndRCD; /* table window */
HWND hwndStatus; /* status bar across top */
HWND hwndBar; /* graphic of sections as vertical bars */
HACCEL haccel;
/* The status bar told us it should be this high. Rest of client area
* goes to the hwndBar and hwndRCD.
*/
int status_height;
HINSTANCE hInst; /* handle to current app instance */
HMENU hMenu; /* handle to menu for hwndClient */
int nMinMax = SW_SHOWNORMAL; /* default state of window normal */
/* The message sent to us as a callback by the table window needs to be
* registered - table_msgcode is the result of the RegisterMessage call
*/
UINT table_msgcode;
/* True if we are currently doing some scan or comparison.
* Must get critical section before checking/changing this (call
* SetBusy.
*/
BOOL fBusy = FALSE;
int selection = -1; /* selected row in table*/
/* Options for DisplayMode field indicating what is currently shown.
* We use this to know whether or not to show the graphic bar window.
*/
#define MODE_NULL 0 /* nothing displayed */
#define MODE_OUTLINE 1 /* a list of files displayed */
#define MODE_EXPAND 2 /* view is expanded view of one file */
int DisplayMode = MODE_NULL; /* indicates whether we are in expand mode */
VIEW current_view = NULL;
/* command line parameters */
extern int __argc;
extern char ** __argv;
BOOL bAbort = FALSE; /* set to request abort of current operation */
char editor_cmdline[256] = "notepad %p"; /* editor cmdline */
/* slick version is "s %p -#%l" */
/* app-wide global data --------------------------------------------- */
/* Handle returned from gmem_init - we use this for all memory allocations */
HANDLE hHeap;
/* Current state of menu options */
int line_numbers = IDM_LNRS;
int expand_mode = IDM_BOTHFILES;
int outline_include = INCLUDE_LEFTONLY|INCLUDE_RIGHTONLY|INCLUDE_SAME|INCLUDE_DIFFER;
BOOL ignore_blanks = TRUE;
BOOL picture_mode = TRUE;
/* function prototypes ---------------------------------------------*/
BOOL InitApplication(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow);
void CreateTools(void);
void DeleteTools(void);
long APIENTRY MainWndProc(HWND hWnd, UINT message, UINT wParam, LONG lParam);
BOOL SetBusy(void);
void SetNotBusy(void);
void SetSelection(long rownr);
void SetButtonText(LPSTR cmd);
BOOL ToExpand(HWND hwnd);
void ParseArgs(int argc, char ** argv);
DWORD wd_initial(LPVOID arg);
static HANDLE ghThread = NULL;
static DWORD gdwMainThreadId; /* threadid of main (user interface) thread
initialised in winmain(), thereafter constant.
See windiff_UI()
*/
/***************************************************************************
* Function: windiff_UI
*
* Purpose:
*
* If you are about to put up a dialog box or in fact process input in any way
* on any thread other than the main thread - or if you MIGHT be on a thread other
* than the main thread, then you must call this function with TRUE before doing
* it and with FALSE immediately afterwards. Otherwise you will get one of a
* number of flavours of not-very-responsiveness
*/
void windiff_UI(BOOL bAttach)
{
DWORD dwThreadId = GetCurrentThreadId();
if (dwThreadId==gdwMainThreadId) return;
if (bAttach) GetDesktopWindow();
AttachThreadInput(dwThreadId, gdwMainThreadId, bAttach);
} /* windiff_UI */
/***************************************************************************
* Function: WinMain
*
* Purpose:
*
* Main entry point. Register window classes, create windows,
* parse command line arguments and then perform a message loop
*/
int WINAPI
WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
MSG msg;
gdwMainThreadId = GetCurrentThreadId();
/* create any pens/brushes etc and read in profile defaults */
CreateTools();
/* init window class unless other instances running */
if (!hPrevInstance)
if (!InitApplication(hInstance))
return(FALSE);
/* init this instance - create all the windows */
if (!InitInstance(hInstance, nCmdShow))
return(FALSE);
ParseArgs(__argc, __argv);
/* message loop */
while(GetMessage(&msg, NULL, 0, 0)) {
if (!TranslateAccelerator(hwndClient, haccel, &msg)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (msg.wParam);
}
/***************************************************************************
* Function: InitApplication
*
* Purpose:
*
* Register window class for the main window and the bar window.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -