Annotation of mstools/samples/sdktools/windiff/windiff.c, revision 1.1

1.1     ! root        1: 
        !             2: /******************************************************************************\
        !             3: *       This is a part of the Microsoft Source Code Samples. 
        !             4: *       Copyright (C) 1993 Microsoft Corporation.
        !             5: *       All rights reserved. 
        !             6: *       This source code is only intended as a supplement to 
        !             7: *       Microsoft Development Tools and/or WinHelp documentation.
        !             8: *       See these sources for detailed information regarding the 
        !             9: *       Microsoft samples programs.
        !            10: \******************************************************************************/
        !            11: 
        !            12: /****************************** Module Header *******************************
        !            13: * Module Name: WINDIFF.C
        !            14: *
        !            15: * File and directory comparisions.
        !            16: *
        !            17: * Functions:
        !            18: *
        !            19: * windiff_UI()
        !            20: * WinMain()
        !            21: * windiff_usage()
        !            22: * Poll()
        !            23: * DoResize()
        !            24: * AboutBox()
        !            25: * DoPrint()
        !            26: * FindNextChange()
        !            27: * FindPrevChange()
        !            28: * WriteProfileInt()
        !            29: * ToOutline()
        !            30: * ToMoved()
        !            31: * do_editfile()
        !            32: * do_editthread()
        !            33: * SetStatus()
        !            34: * SetNames()
        !            35: * IsBusy()
        !            36: * BusyError()
        !            37: * StateToColour()
        !            38: * SetSelection()
        !            39: * do_gethdr()
        !            40: * do_getprops()
        !            41: * do_getdata()
        !            42: * SvrClose()
        !            43: * TableServer()
        !            44: * wd_dirdialog()
        !            45: * wd_copy()
        !            46: * InitApplication()
        !            47: * InitInstance()
        !            48: * CreateTools()
        !            49: * DeleteTools()
        !            50: * MainWndProc()
        !            51: * SetBusy()
        !            52: * SetNotBusy()
        !            53: * SetSelection()
        !            54: * SetButtonText()
        !            55: * ToExpand()
        !            56: * ParseArgs()
        !            57: * wd_initial()
        !            58: *
        !            59: * Comments:
        !            60: *
        !            61: * Compare two directories (including all files and subdirs). Look for names
        !            62: * that are present in both (report all that are not). For files that
        !            63: * are present in both, produce a line-by-line comparison of the differences
        !            64: * between the two files (if any).
        !            65: *
        !            66: * Overview of Windiff internals - the whole program.
        !            67: *
        !            68: * Windiff is built from several modules (a "module" has a .h file
        !            69: * which describes its interface and a .c file which implements it).
        !            70: * Apart from THIS comment which tries to give an overview of the whole
        !            71: * scheme of things, each module is as self-contained as possible.
        !            72: * This is enforced by the use of opaque data types.  Modules cannot
        !            73: * see each others' internal data structures.  Modules are abstract
        !            74: * data types.  The term "Module" (from Modula2) and "Class" (from C++)
        !            75: * are used synonymously.
        !            76: *
        !            77: *    Windiff  - main program - parse arguments, put up main window,
        !            78: *               handle input, calling other modules as needed
        !            79: *               invoke table class to create the main display and
        !            80: *               service callbacks from the table class.
        !            81: *               Contains global flags for options (e.g. ignore_blanks)
        !            82: *    list     - (in gutils) a generalised LIST of anything data type
        !            83: *               has full set of operations for insert, delete, join etc.
        !            84: *    line     - a LINE is a numbered line of text.  Information is kept to
        !            85: *               allow fast comparisons of LINEs.  A LINE can hold a
        !            86: *               link to another LINE.  The links are used to connect
        !            87: *               lines in one file to matching lines in the other file.
        !            88: *    file     - a FILEDATA represents a file as a file name in the form
        !            89: *               of a DIRITEM and a LIST of LINEs
        !            90: *    scandir  - a DIRITEM represents information about a file.  (for
        !            91: *               instance its name, whether it has a local copy).
        !            92: *    compitem - a COMPITEM is a pair of files together with information
        !            93: *               on how they compare in the form of a breakdown of the
        !            94: *               files into a LIST of matching or non-matching sections.
        !            95: *               Either file can be absent.  This module contains the
        !            96: *               file "contrast" algorithm used for the actual comparison
        !            97: *    tree       (in gutils) A binary tree.  Important because it is what
        !            98: *               gives the file comparison its speed as it makes it
        !            99: *               an "N log N" algorithm rather than "N squared"
        !           100: *    complist - a COMPLIST is the master data structure.  It has a DIRLIST
        !           101: *               of the left hand files, a DIRLIST of the right hand files
        !           102: *               and a LIST of COMPITEMs. The left and right hand DIRLISTs
        !           103: *               are working data used to produce the COMPLIST.  The LIST
        !           104: *               is displayed as the outline table.  Any given COMPITEM can
        !           105: *               be displayed as an expanded item.
        !           106: *    section  - a SECTION is a section of a file (first line, last line)
        !           107: *               and information as to what it matches in the other file.
        !           108: *    bar.c    - the picture down the left of the screen
        !           109: *               has a WNDPROC.  
        !           110: *    view     - Although the COMPLIST is the master state, it doesn't do
        !           111: *               all the work itself.  The data is actually displayed by
        !           112: *               the table class which is highly generalised.  View
        !           113: *               owns a COMPLIST (and therefore calls upon the functions
        !           114: *               in complist to fill it and interrogate it) and calls
        !           115: *               upon (and is called back by) the functions in table to
        !           116: *               actually display it.  Read about table in gutils.h
        !           117: *    table.c    (in gutils) a highly generalised system for displaying
        !           118: *               data in rows and columns.  The interface is in gutils.h.
        !           119: *    status.c   (in gutils) the status line at the top. See gutils.h
        !           120: *************************************************************************
        !           121: *
        !           122: * Overview of this file:
        !           123: *
        !           124: *   We create a table window (gutils.dll) to show the files and the
        !           125: *   results of their comparisons. We create a COMPLIST object representing
        !           126: *   a list of files and their differences, and a VIEW object to map between
        !           127: *   the rows of the table window and the COMPLIST.
        !           128: *
        !           129: *   This module is responsible for creating and managing the main window,
        !           130: *   placing the child windows (table, status window etc) within it, and
        !           131: *   handling all menu items. We maintain global option flags set by
        !           132: *   menu commands.
        !           133: *
        !           134: *   Creating a COMPLIST creates a list of unmatched files, and of matching
        !           135: *   files that are compared with each other (these are COMPITEMS).
        !           136: *   The VIEW provides a mapping between rows on the screen, and items in
        !           137: *   the COMPLIST.
        !           138: *
        !           139: *   This version tries to maintain a responsive user interface by
        !           140: *   creating worker threads to do long jobs.  This potentially creates
        !           141: *   conflicts between the threads as they will both want to update common
        !           142: *   variables (for instance the UI thread may be changing the options to
        !           143: *   exclude identical files while the worker thread is adding in the
        !           144: *   results of new comparisons).  Critical sections are used to manage
        !           145: *   the conflicts.
        !           146: *
        !           147: *   The Edit options invoke an editor on a separate thread.  This allows
        !           148: *   us to repaint our window and thereby allow the user to refer back to
        !           149: *   what he saw before invoking the editor.  When he's finished editing,
        !           150: *   we would of course like to refresh things and if this is still on the
        !           151: *   separate thread it might clash. We avoid this clash by POSTing ourselves
        !           152: *   a (WM_COMMAND, IDM_UPDATE) message.
        !           153: *
        !           154: ****************************************************************************/
        !           155: 
        !           156: #include <windows.h>
        !           157: #include <shellapi.h>
        !           158: #include <stdlib.h>
        !           159: #include <commdlg.h>
        !           160: #include <string.h>
        !           161: 
        !           162: #include "gutils.h"
        !           163: #include "table.h"
        !           164: #include "list.h"
        !           165: #include "scandir.h"            /* needed for file.h     */
        !           166: #include "file.h"               /* needed for compitem.h */
        !           167: #include "compitem.h"           /* needed for view.h     */
        !           168: #include "complist.h"
        !           169: #include "view.h"
        !           170: #include "state.h"
        !           171: #include "windiff.h"
        !           172: #include "wdiffrc.h"
        !           173: 
        !           174: 
        !           175: /*--constants and data types--------------------------------------------*/
        !           176: 
        !           177: int Version = 2;
        !           178: int SubVersion = 01;
        !           179: 
        !           180: /* When we print the current table, we pass this id as the table id
        !           181:  * When we are queried for the properties of this table, we know they
        !           182:  * want the printing properties for the current view. We use this to
        !           183:  * select different fonts and colours for the printer.
        !           184:  */
        !           185: #define TABID_PRINTER   1
        !           186: 
        !           187: 
        !           188: 
        !           189: /*
        !           190:  * structure containing args passed to worker thread in initial
        !           191:  * case (executing command line instructions). 
        !           192:  */
        !           193: typedef struct {
        !           194: 
        !           195:         LPSTR first;
        !           196:         LPSTR second;
        !           197:         LPSTR savelist;
        !           198:         UINT saveopts;
        !           199:         VIEW view;
        !           200:         BOOL fDeep;
        !           201: } THREADARGS, FAR * PTHREADARGS;
        !           202: 
        !           203: 
        !           204: /* Structure containing all the arguments we'd like to give to do_editfile
        !           205:    Need a structure because CreateThread only allows for one argument.
        !           206: */
        !           207: typedef struct {
        !           208:         VIEW view;
        !           209:         int option;
        !           210:         int selection;
        !           211: } EDITARGS, FAR * PEDITARGS;
        !           212: 
        !           213: /*---- colour scheme------------------------------- */
        !           214: 
        !           215: /* outline */
        !           216: DWORD rgb_outlinehi = RGB(255, 0, 0);   /* hilighted files in outline mode  */
        !           217: 
        !           218: /* expand view */
        !           219: DWORD rgb_leftfore =   RGB(  0,   0,   0);         /* foregrnd for left lines */
        !           220: DWORD rgb_leftback  =  RGB(255,   0,   0);         /* backgrnd for left lines */
        !           221: DWORD rgb_rightfore =  RGB(  0,   0,   0);         /* foregrnd for right lines*/
        !           222: DWORD rgb_rightback =  RGB(255, 255,   0);         /* backgrnd for right lines*/
        !           223: 
        !           224: /* moved lines */
        !           225: DWORD rgb_mleftfore =  RGB(  0,   0, 128);         /* foregrnd for moved-left */
        !           226: DWORD rgb_mleftback =  RGB(255,   0,   0);         /* backgrnd for moved-left */
        !           227: DWORD rgb_mrightfore = RGB(  0,   0, 255);         /* foregrnd for moved-right*/
        !           228: DWORD rgb_mrightback = RGB(255, 255,   0);         /* backgrnd for moved-right*/
        !           229: 
        !           230: /* bar window */
        !           231: DWORD rgb_barleft =    RGB(255,   0,   0);         /* bar sections in left only  */
        !           232: DWORD rgb_barright =   RGB(255, 255,   0);         /* bar sections in right only */
        !           233: DWORD rgb_barcurrent = RGB(  0,   0, 255);         /* current pos markers in bar */
        !           234: 
        !           235: 
        !           236: /* module static data -------------------------------------------------*/
        !           237: 
        !           238: 
        !           239: /* current value of window title */
        !           240: char AppTitle[256];
        !           241: 
        !           242: 
        !           243: HWND hwndClient;        /* main window */
        !           244: HWND hwndRCD;           /* table window */
        !           245: HWND hwndStatus;        /* status bar across top */
        !           246: HWND hwndBar;           /* graphic of sections as vertical bars */
        !           247: 
        !           248: HACCEL haccel;
        !           249: 
        !           250: /* The status bar told us it should be this high. Rest of client area
        !           251:  * goes to the hwndBar and hwndRCD.
        !           252:  */
        !           253: int status_height;
        !           254: 
        !           255: HINSTANCE hInst;   /* handle to current app instance */
        !           256: HMENU hMenu;    /* handle to menu for hwndClient */
        !           257: 
        !           258: int nMinMax = SW_SHOWNORMAL;         /* default state of window normal */
        !           259: 
        !           260: /* The message sent to us as a callback by the table window needs to be
        !           261:  * registered - table_msgcode is the result of the RegisterMessage call
        !           262:  */
        !           263: UINT table_msgcode;
        !           264: 
        !           265: /* True if we are currently doing some scan or comparison.
        !           266:  * Must get critical section before checking/changing this (call
        !           267:  * SetBusy.
        !           268:  */
        !           269: BOOL fBusy = FALSE;
        !           270: 
        !           271: int     selection       =       -1;     /* selected row in table*/
        !           272: 
        !           273: /* Options for DisplayMode field indicating what is currently shown.
        !           274:  * We use this to know whether or not to show the graphic bar window.
        !           275:  */
        !           276: #define MODE_NULL       0       /* nothing displayed */
        !           277: #define MODE_OUTLINE    1       /* a list of files displayed */
        !           278: #define MODE_EXPAND     2       /* view is expanded view of one file */
        !           279: 
        !           280: int DisplayMode = MODE_NULL;    /* indicates whether we are in expand mode */
        !           281: 
        !           282: VIEW current_view = NULL;
        !           283: 
        !           284: /* command line parameters */
        !           285: extern int __argc;
        !           286: extern char ** __argv;
        !           287: 
        !           288: BOOL bAbort = FALSE;    /* set to request abort of current operation */
        !           289: 
        !           290: char editor_cmdline[256] = "notepad %p";  /* editor cmdline */
        !           291:                           /* slick version is "s %p -#%l" */
        !           292: 
        !           293: /* app-wide global data --------------------------------------------- */
        !           294: 
        !           295: /* Handle returned from gmem_init - we use this for all memory allocations */
        !           296: HANDLE hHeap;
        !           297: 
        !           298: /* Current state of menu options */
        !           299: int line_numbers = IDM_LNRS;
        !           300: int expand_mode = IDM_BOTHFILES;
        !           301: int outline_include = INCLUDE_LEFTONLY|INCLUDE_RIGHTONLY|INCLUDE_SAME|INCLUDE_DIFFER;
        !           302: BOOL ignore_blanks = TRUE;
        !           303: BOOL picture_mode = TRUE;
        !           304: 
        !           305: /* function prototypes ---------------------------------------------*/
        !           306: 
        !           307: BOOL InitApplication(HINSTANCE hInstance);
        !           308: BOOL InitInstance(HINSTANCE hInstance, int nCmdShow);
        !           309: void CreateTools(void);
        !           310: void DeleteTools(void);
        !           311: long APIENTRY MainWndProc(HWND hWnd, UINT message, UINT wParam, LONG lParam);
        !           312: BOOL SetBusy(void);
        !           313: void SetNotBusy(void);
        !           314: void SetSelection(long rownr);
        !           315: void SetButtonText(LPSTR cmd);
        !           316: BOOL ToExpand(HWND hwnd);
        !           317: void ParseArgs(int argc, char ** argv);
        !           318: 
        !           319: 
        !           320: DWORD wd_initial(LPVOID arg);
        !           321: 
        !           322: static HANDLE ghThread = NULL;
        !           323: 
        !           324: static DWORD gdwMainThreadId;     /* threadid of main (user interface) thread
        !           325:                                      initialised in winmain(), thereafter constant.
        !           326:                                      See windiff_UI()
        !           327:                                   */
        !           328: 
        !           329: /***************************************************************************
        !           330:  * Function: windiff_UI
        !           331:  *
        !           332:  * Purpose:
        !           333:  *
        !           334:  * If you are about to put up a dialog box or in fact process input in any way
        !           335:  * on any thread other than the main thread - or if you MIGHT be on a thread other
        !           336:  * than the main thread, then you must call this function with TRUE before doing
        !           337:  * it and with FALSE immediately afterwards.  Otherwise you will get one of a
        !           338:  * number of flavours of not-very-responsiveness
        !           339:  */
        !           340: void windiff_UI(BOOL bAttach)
        !           341: {
        !           342:         DWORD dwThreadId = GetCurrentThreadId();
        !           343:         if (dwThreadId==gdwMainThreadId) return;
        !           344: 
        !           345:         if (bAttach) GetDesktopWindow();
        !           346:         AttachThreadInput(dwThreadId, gdwMainThreadId, bAttach);
        !           347: } /* windiff_UI */
        !           348: 
        !           349: /***************************************************************************
        !           350:  * Function: WinMain
        !           351:  *
        !           352:  * Purpose:
        !           353:  *
        !           354:  * Main entry point. Register window classes, create windows,
        !           355:  * parse command line arguments and then perform a message loop
        !           356:  */
        !           357: int WINAPI
        !           358: WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
        !           359: {
        !           360: 
        !           361:         MSG msg;
        !           362: 
        !           363:         gdwMainThreadId = GetCurrentThreadId();
        !           364: 
        !           365:         /* create any pens/brushes etc and read in profile defaults */
        !           366:         CreateTools();
        !           367: 
        !           368:         /* init window class unless other instances running */
        !           369:         if (!hPrevInstance)
        !           370:             if (!InitApplication(hInstance))
        !           371:                 return(FALSE);
        !           372: 
        !           373: 
        !           374:         /* init this instance - create all the windows */
        !           375:         if (!InitInstance(hInstance, nCmdShow))
        !           376:             return(FALSE);
        !           377: 
        !           378:         ParseArgs(__argc, __argv);
        !           379: 
        !           380: 
        !           381:         /* message loop */
        !           382:         while(GetMessage(&msg, NULL, 0, 0)) {
        !           383:                 if (!TranslateAccelerator(hwndClient, haccel, &msg)) {
        !           384:                     TranslateMessage(&msg);
        !           385:                     DispatchMessage(&msg);
        !           386:                 }
        !           387:         }
        !           388: 
        !           389:         return (msg.wParam);
        !           390: 
        !           391: }
        !           392: 
        !           393: /***************************************************************************
        !           394:  * Function: InitApplication
        !           395:  *
        !           396:  * Purpose:
        !           397:  *
        !           398:  * Register window class for the main window and the bar window.
        !           399:  */
        !           400: BOOL
        !           401: InitApplication(HINSTANCE hInstance)
        !           402: {
        !           403:         WNDCLASS    wc;
        !           404:         BOOL resp;
        !           405: 
        !           406: 
        !           407:         /* register the bar window class */
        !           408:         InitBarClass(hInstance);
        !           409: 
        !           410:         wc.style = 0;
        !           411:         wc.lpfnWndProc = MainWndProc;
        !           412:         wc.cbClsExtra = 0;
        !           413:         wc.cbWndExtra = 0;
        !           414:         wc.hInstance = hInstance;
        !           415:         wc.hIcon = LoadIcon(hInstance, "WinDiff");
        !           416:         wc.hCursor = LoadCursor(NULL, IDC_ARROW);
        !           417:         wc.hbrBackground = NULL;
        !           418:         wc.lpszClassName =  "WinDiffViewerClass";
        !           419:         wc.lpszMenuName = NULL;
        !           420: 
        !           421:         resp = RegisterClass(&wc);
        !           422: 
        !           423:         return(resp);
        !           424: }
        !           425: 
        !           426: /***************************************************************************
        !           427:  * Function: InitInstance
        !           428:  *
        !           429:  * Purpose:
        !           430:  *
        !           431:  * Create and show the windows
        !           432:  */
        !           433: BOOL
        !           434: InitInstance(HINSTANCE hInstance, int nCmdShow)
        !           435: {
        !           436:         RECT rect;
        !           437:         HANDLE hstatus;
        !           438:         int bar_width;
        !           439:         RECT childrc;
        !           440: 
        !           441:         hInst = hInstance;
        !           442: 
        !           443:         /* initialise a heap. we use this one heap throughout
        !           444:          * the app. for all memory requirements
        !           445:          */
        !           446:         hHeap = gmem_init();
        !           447:         /* initialise the list package */
        !           448:         List_Init();
        !           449: 
        !           450: 
        !           451:         hMenu = LoadMenu(hInstance, "WinDiffMenu");
        !           452:         haccel = LoadAccelerators(hInstance, "WinDiffAccel");
        !           453: 
        !           454:         /* create the main window */
        !           455:         hwndClient = CreateWindow("WinDiffViewerClass",
        !           456:                             "WinDiff",
        !           457:                             WS_OVERLAPPEDWINDOW,
        !           458:                             CW_USEDEFAULT,
        !           459:                             CW_USEDEFAULT,
        !           460:                             CW_USEDEFAULT,
        !           461:                             CW_USEDEFAULT,
        !           462:                             NULL,
        !           463:                             hMenu,
        !           464:                             hInstance,
        !           465:                             NULL
        !           466:                 );
        !           467: 
        !           468: 
        !           469: 
        !           470:         if (!hwndClient) {
        !           471:             return(FALSE);
        !           472:         }
        !           473: 
        !           474:         /* create 3 child windows, one status, one table and one bar
        !           475:          * Initially, the bar window is hidden and covered by the table.
        !           476:          */
        !           477: 
        !           478:         /* create a status bar window as
        !           479:          * a child of the main window.
        !           480:          */
        !           481: 
        !           482:         /* build a status struct for two labels and an abort button */
        !           483:         hstatus = StatusAlloc(3);
        !           484:         StatusAddItem(hstatus, 0, SF_STATIC, SF_LEFT|SF_VAR|SF_SZMIN, IDL_STATLAB, 14, NULL);
        !           485:         StatusAddItem(hstatus, 1, SF_BUTTON, SF_RIGHT|SF_RAISE, IDM_ABORT, 8,
        !           486:                 "Exit");
        !           487:         StatusAddItem(hstatus, 2, SF_STATIC, SF_LOWER|SF_LEFT|SF_VAR,
        !           488:                         IDL_NAMES, 60, NULL);
        !           489: 
        !           490:         /* ask the status bar how high it should be for the controls
        !           491:          * we have chosen, and save this value for re-sizing.
        !           492:          */
        !           493:         status_height = StatusHeight(hstatus);
        !           494: 
        !           495:         /* create a window of this height */
        !           496:         GetClientRect(hwndClient, &rect);
        !           497:         childrc = rect;
        !           498:         childrc.bottom = status_height;
        !           499:         hwndStatus = StatusCreate(hInst, hwndClient, IDC_STATUS, &childrc,
        !           500:                         hstatus);
        !           501: 
        !           502:         /* layout constants are stated as percentages of the window width */
        !           503:         bar_width = (rect.right - rect.left) * BAR_WIN_WIDTH / 100;
        !           504: 
        !           505:         /* create the table class covering all the remaining part of
        !           506:          * the main window
        !           507:          */
        !           508:         hwndRCD = CreateWindow(TableClassName,
        !           509:                         NULL,
        !           510:                         WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL,
        !           511:                         0,
        !           512:                         status_height,
        !           513:                         (int)(rect.right - rect.left),
        !           514:                         (int)(rect.bottom - status_height),
        !           515:                         hwndClient,
        !           516:                         (HANDLE) IDC_RCDISP1,
        !           517:                         hInst,
        !           518:                         NULL);
        !           519: 
        !           520:         /* create a bar window as a child of the main window.
        !           521:          * this window remains hidden until we switch into MODE_EXPAND
        !           522:          */
        !           523:         hwndBar = CreateWindow("BarClass",
        !           524:                         NULL,
        !           525:                         WS_CHILD | WS_VISIBLE,
        !           526:                         0,
        !           527:                         status_height,
        !           528:                         bar_width,
        !           529:                         (int)(rect.bottom - status_height),
        !           530:                         hwndClient,
        !           531:                         (HANDLE) IDC_BAR,
        !           532:                         hInst,
        !           533:                         NULL);
        !           534: 
        !           535:         /* nMinMax indicates whether we are to be minimised on startup,
        !           536:          * on command line parameters
        !           537:          */
        !           538:         ShowWindow(hwndBar, SW_HIDE);
        !           539: 
        !           540:         if (GetProfileInt(APPNAME, "OutlineSaved", 0))
        !           541:         {
        !           542:                 WINDOWPLACEMENT wp;
        !           543: 
        !           544:                 /* restore the previous expanded size and position */
        !           545:                 wp.flags                   = 0;
        !           546:                 wp.showCmd                 = GetProfileInt( APPNAME, "OutlineShowCmd",
        !           547:                                                             SW_SHOWNORMAL);
        !           548:                 wp.ptMaxPosition.x         = GetProfileInt( APPNAME, "OutlineMaxX",       0);
        !           549:                 wp.ptMaxPosition.y         = GetProfileInt( APPNAME, "OutlineMaxY",       0);
        !           550:                 wp.rcNormalPosition.left   = (int)GetProfileInt( APPNAME, "OutlineNormLeft",  (UINT)(-1));
        !           551:                 wp.rcNormalPosition.top    = (int)GetProfileInt( APPNAME, "OutlineNormTop",   (UINT)(-1));
        !           552:                 wp.rcNormalPosition.right  = (int)GetProfileInt( APPNAME, "OutlineNormRight", (UINT)(-1));
        !           553:                 wp.rcNormalPosition.bottom = (int)GetProfileInt( APPNAME, "OutlineNormBottom",(UINT)(-1));
        !           554:                 SetWindowPlacement(hwndClient,&wp);
        !           555:         }
        !           556:         else ShowWindow(hwndClient, nMinMax);
        !           557: 
        !           558:         UpdateWindow(hwndClient);
        !           559: 
        !           560: 
        !           561:         /* initialise busy flag and status line to show we are idle
        !           562:          * (ie not comparing or scanning)
        !           563:          */
        !           564:         SetNotBusy();
        !           565: 
        !           566:         return(TRUE);
        !           567: 
        !           568: } /* InitInstance */
        !           569: 
        !           570: /***************************************************************************
        !           571:  * Function: windiff_usage
        !           572:  *
        !           573:  * Purpose:
        !           574:  *
        !           575:  * Complain to command line users about poor syntax,
        !           576:  * will be replaced by proper help file.
        !           577:  */
        !           578: void
        !           579: windiff_usage(LPSTR msg)
        !           580: {
        !           581:         int retval;
        !           582:         if (msg==NULL)
        !           583:                 msg = "windiff {-L} path1 {path2} {-s{slrd} savefile}";
        !           584: 
        !           585:         retval = MessageBox(hwndClient,
        !           586:                 msg,
        !           587:                 "Windiff Usage", MB_ICONINFORMATION|MB_OKCANCEL);
        !           588:         if (retval == IDCANCEL) {
        !           589:                 exit(1);
        !           590:         }
        !           591: }
        !           592: 
        !           593: /***************************************************************************
        !           594:  * Function: ParseArgs
        !           595:  *
        !           596:  * Purpose:
        !           597:  *
        !           598:  * Parse command line arguments
        !           599:  *
        !           600:  * The user can give one or two paths. If only one, we assume the second
        !           601:  * is '.' for the current directory. If one of the two paths is a directory
        !           602:  * and the other a file, we compare a file of the same name in the two dirs.
        !           603:  *
        !           604:  * The command -s filename causes the outline list to be written to a file
        !           605:  * and then the program exits. -s{slrd} filename allows selection of which
        !           606:  * files are written out; by default, we assume -sld for files left and different.
        !           607:  *
        !           608:  * -T means tree.  Go deep.
        !           609:  *
        !           610:  * The default is Deep, -L overrides and implies shallow, -T overrides -L
        !           611:  */
        !           612: void
        !           613: ParseArgs(int argc, char ** argv)
        !           614: {
        !           615:         int i;
        !           616:         LPSTR chp;
        !           617:         PTHREADARGS ta;
        !           618:         DWORD threadid;
        !           619: 
        !           620:         /* thread args can't be on the stack since the stack will change
        !           621:          * before the thread completes execution
        !           622:          */
        !           623:         ta = (PTHREADARGS) gmem_get(hHeap, sizeof(THREADARGS));
        !           624:         ta->first = NULL;
        !           625:         ta->second = NULL;
        !           626:         ta->savelist = NULL;
        !           627:         ta->saveopts = 0;
        !           628:         ta->fDeep = FALSE;  /* No -T option seen yet */
        !           629: 
        !           630:         for (i = 1; i < argc; i++) {
        !           631: 
        !           632:                 /* is this an option ? */
        !           633:                 if ((argv[i][0] == '-') || (argv[i][0] == '/')) {
        !           634:                         switch(argv[i][1]) {
        !           635: 
        !           636:                         case 's':
        !           637:                         case 'S':
        !           638:                                 /* read letters for the save option: s,l,r,d */
        !           639:                                 for(chp = &argv[i][2]; *chp != '\0'; chp++) {
        !           640:                                         switch(*chp) {
        !           641:                                         case 's':
        !           642:                                         case 'S':
        !           643:                                                 ta->saveopts |= INCLUDE_SAME;
        !           644:                                                 break;
        !           645:                                         case 'l':
        !           646:                                         case 'L':
        !           647:                                                 ta->saveopts |= INCLUDE_DIFFER;
        !           648:                                                 break;
        !           649:                                         case 'r':
        !           650:                                         case 'R':
        !           651:                                                 ta->saveopts |= INCLUDE_LEFTONLY;
        !           652:                                                 break;
        !           653:                                         case 'd':
        !           654:                                         case 'D':
        !           655:                                                 ta->saveopts |= INCLUDE_RIGHTONLY;
        !           656:                                                 break;
        !           657:                                         default:
        !           658:                                                 windiff_usage(NULL);
        !           659:                                                 return;
        !           660:                                         }
        !           661:                                 }
        !           662: 
        !           663:                                 if (ta->saveopts == 0) {
        !           664:                                         /* default to left and differ */
        !           665:                                         ta->saveopts = (INCLUDE_LEFTONLY) | (INCLUDE_DIFFER);
        !           666:                                 }
        !           667:                                 ta->savelist = argv[++i];
        !           668:                                 break;
        !           669:                         case 't':
        !           670:                         case 'T':
        !           671:                                 ta->fDeep = TRUE;
        !           672:                                 break;
        !           673:                         default:
        !           674:                                 windiff_usage(NULL);
        !           675:                                 return;
        !           676:                         }
        !           677:                 } else {
        !           678:                         if (ta->first == NULL) {
        !           679:                                 ta->first = argv[i];
        !           680:                         } else {
        !           681:                                 ta->second = argv[i];
        !           682:                         }
        !           683:                 }
        !           684:         }
        !           685: 
        !           686:         /* set the correct depth */
        !           687:         if (ta->fDeep)
        !           688:                 ;                       /* explicitly set -- leave it alone */
        !           689:         else ta->fDeep = TRUE;          /* global default */
        !           690: 
        !           691:         /* any paths to scan ? */
        !           692:         if (ta->first == NULL) {
        !           693:                 return;
        !           694:         }
        !           695: 
        !           696:         if (ta->second == NULL) {
        !           697:                 ta->second = ".";
        !           698:         }
        !           699: 
        !           700:         SetBusy();
        !           701: 
        !           702:         /* minimise the window if -s flag given */
        !           703:         if (ta->savelist != NULL) {
        !           704:                 ShowWindow(hwndClient, SW_MINIMIZE);
        !           705:         }
        !           706: 
        !           707:         /* make an empty view */
        !           708:         current_view = view_new(hwndRCD);
        !           709:         DisplayMode = MODE_OUTLINE;
        !           710: 
        !           711:         ta->view = current_view;
        !           712: 
        !           713:         /* attempt to create a worker thread */
        !           714: 
        !           715:         ghThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)wd_initial, (LPVOID) ta,
        !           716:                         0, &threadid);
        !           717:         if (ghThread == NULL)
        !           718:         {
        !           719:                 wd_initial( (LPVOID) ta);
        !           720:         }
        !           721: } /* ParseArgs */
        !           722: 
        !           723: 
        !           724: /***************************************************************************
        !           725:  * Function: CreateTools
        !           726:  *
        !           727:  * Purpose:
        !           728:  *
        !           729:  * Create any pens/brushes, and read defaults
        !           730:  * from the profile file for menu settings etc.
        !           731:  */
        !           732: void
        !           733: CreateTools(void)
        !           734: {
        !           735: 
        !           736:         /* standard message that table class sends us for
        !           737:          * notifications and queries.
        !           738:          */
        !           739:         table_msgcode = RegisterWindowMessage(TableMessage);
        !           740: 
        !           741:         line_numbers = GetProfileInt(APPNAME, "LineNumbers", line_numbers);
        !           742:         outline_include = GetProfileInt(APPNAME, "FileInclude", outline_include);
        !           743:         ignore_blanks = GetProfileInt(APPNAME, "Blanks", ignore_blanks);
        !           744:         picture_mode = GetProfileInt(APPNAME, "Picture", picture_mode);
        !           745: 
        !           746:         GetProfileString(APPNAME, "Editor", editor_cmdline, (LPTSTR)editor_cmdline,
        !           747:                         sizeof(editor_cmdline));
        !           748:         InitializeCriticalSection(&CSWindiff);
        !           749: 
        !           750: }
        !           751: 
        !           752: /***************************************************************************
        !           753:  * Function: DeleteTools
        !           754:  *
        !           755:  * Purpose:
        !           756:  *
        !           757:  * Delete any pens or brushes that were created in CreateTools 
        !           758:  */
        !           759: void
        !           760: DeleteTools(void)
        !           761: {
        !           762: 
        !           763:         DeleteCriticalSection(&CSWindiff);
        !           764: 
        !           765: }
        !           766: 
        !           767: 
        !           768: /***************************************************************************
        !           769:  * Function:
        !           770:  *
        !           771:  * Purpose:
        !           772:  *
        !           773:  * Check whether we have had an abort request (IDM_ABORT), and
        !           774:  * return TRUE if abort requested, otherwise FALSE
        !           775:  */
        !           776: BOOL
        !           777: Poll(void)
        !           778: {
        !           779:     return(bAbort);
        !           780: }
        !           781: 
        !           782: 
        !           783: /***************************************************************************
        !           784:  * Function: DoResize
        !           785:  *
        !           786:  * Purpose:
        !           787:  *
        !           788:  * Position child windows on a resize of the main window
        !           789:  */
        !           790: void
        !           791: DoResize(HWND hWnd)
        !           792: {
        !           793:         RECT rc;
        !           794:         int bar_width;
        !           795: 
        !           796:         GetClientRect(hWnd, &rc);
        !           797:         MoveWindow(hwndStatus, 0, 0, rc.right - rc.left, status_height, TRUE);
        !           798: 
        !           799:         bar_width = (rc.right - rc.left) * BAR_WIN_WIDTH / 100;
        !           800: 
        !           801:         /* bar window is hidden unless in expand mode */
        !           802:         if ((DisplayMode == MODE_EXPAND) && (picture_mode)) {
        !           803:                 ShowWindow(hwndBar, SW_SHOW);
        !           804:                 MoveWindow(hwndBar, 0, status_height,
        !           805:                         bar_width, rc.bottom - status_height, TRUE);
        !           806:                 MoveWindow(hwndRCD, bar_width, status_height,
        !           807:                         (rc.right - rc.left) - bar_width,
        !           808:                         rc.bottom - status_height, TRUE);
        !           809:         } else {
        !           810:                 MoveWindow(hwndRCD, 0, status_height, (rc.right - rc.left),
        !           811:                         rc.bottom - status_height, TRUE);
        !           812:                 ShowWindow(hwndBar, SW_HIDE);
        !           813:         }
        !           814: 
        !           815: }
        !           816: /***************************************************************************
        !           817:  * Function: AboutBox
        !           818:  *
        !           819:  * Purpose:
        !           820:  *
        !           821:  * Standard processing for About box.
        !           822:  */
        !           823: int APIENTRY
        !           824: AboutBox(HWND hDlg, unsigned message, UINT wParam, LONG lParam)
        !           825: {
        !           826:         char ch[256];
        !           827: 
        !           828:         switch (message) {
        !           829: 
        !           830:         case WM_INITDIALOG:
        !           831:                 wsprintf((LPTSTR)ch, "%d.%02d", Version, SubVersion);
        !           832:                 SetDlgItemText(hDlg, IDD_VERSION, ch);
        !           833:                 return(TRUE);
        !           834: 
        !           835:         case WM_COMMAND:
        !           836:                 switch (GET_WM_COMMAND_ID(wParam, lParam)) {
        !           837:                 case IDOK:
        !           838:                         EndDialog(hDlg, 0);
        !           839:                         return(TRUE);
        !           840:                 }
        !           841:                 break;
        !           842:         }
        !           843:         return(FALSE);
        !           844: }
        !           845: 
        !           846: 
        !           847: /* -- menu commands ---------------------------------------------------*/
        !           848: 
        !           849: /***************************************************************************
        !           850:  * Function: DoPrint
        !           851:  *
        !           852:  * Purpose:
        !           853:  *
        !           854:  * Print the current view 
        !           855:  */
        !           856: void
        !           857: DoPrint(void)
        !           858: {
        !           859:         Title head, foot;
        !           860:         PrintContext context;
        !           861: 
        !           862:         /* print context contains the header and footer. Use the
        !           863:          * default margins and printer selection
        !           864:          */
        !           865: 
        !           866:         /* we set the table id to be TABID_PRINTER. When the table calls
        !           867:          * back to get text and properties, we use this to indicate
        !           868:          * that the table refered to is the 'current_view', but in print
        !           869:          * mode, and thus we will use different colours/fonts.
        !           870:          */
        !           871:         context.head = &head;
        !           872:         context.foot = &foot;
        !           873:         context.margin = NULL;
        !           874:         context.pd = NULL;
        !           875:         context.id = TABID_PRINTER;
        !           876: 
        !           877:         /* header is filenames or just WinDiff if no names known*/
        !           878:         if (strlen(AppTitle) > 0) {
        !           879:                 head.ptext = AppTitle;
        !           880:         } else {
        !           881:                 head.ptext = "WinDiff";
        !           882:         }
        !           883: 
        !           884:         /* header is centred, footer is right-aligned and
        !           885:          * consists of the page number
        !           886:          */
        !           887:         head.props.valid = P_ALIGN;
        !           888:         head.props.alignment = P_CENTRE;
        !           889:         foot.ptext = "Page # of $";
        !           890:         foot.props.valid = P_ALIGN;
        !           891:         foot.props.alignment = P_RIGHT;
        !           892: 
        !           893:         SendMessage(hwndRCD, TM_PRINT, 0, (DWORD) (LPSTR) &context);
        !           894: }
        !           895: 
        !           896: /***************************************************************************
        !           897:  * Function: FindNextChange
        !           898:  *
        !           899:  * Purpose:
        !           900:  *
        !           901:  * Find the next line in the current view that is
        !           902:  * not STATE_SAME. Start from the current selection, if valid, or
        !           903:  * from the top of the window if no selection.
        !           904:  *
        !           905:  */
        !           906: BOOL
        !           907: FindNextChange(void)
        !           908: {
        !           909:         long row;
        !           910: 
        !           911:         /* start from the selection or top of the window if no selection */
        !           912:         if (selection >= 0) {
        !           913:                 row = selection + 1;
        !           914:         } else {
        !           915:                 row = (int) SendMessage(hwndRCD, TM_TOPROW, FALSE, 0);
        !           916:         }
        !           917: 
        !           918: 
        !           919:         /* find the next 'interesting' line */
        !           920:         row = view_findchange(current_view, row, TRUE);
        !           921:         if (row >= 0) {
        !           922:                 SetSelection(row);
        !           923:                 return(TRUE);
        !           924:         } else {
        !           925:                 windiff_UI(TRUE);
        !           926:                 MessageBox(hwndClient, "No More Changes", "Windiff",
        !           927:                         MB_ICONINFORMATION|MB_OK);
        !           928:                 windiff_UI(FALSE);
        !           929: 
        !           930:                 return(FALSE);
        !           931:         }
        !           932: }
        !           933: 
        !           934: /***************************************************************************
        !           935:  * Function: FindPrevChange
        !           936:  *
        !           937:  * Purpose:
        !           938:  *
        !           939:  * Find the previous line in the current view that is not STATE_SAME
        !           940:  */
        !           941: BOOL
        !           942: FindPrevChange(void)
        !           943: {
        !           944:         long row;
        !           945: 
        !           946:         /* start from the selection or top of window if no selection */
        !           947:         if (selection >= 0) {
        !           948:                 row = selection - 1;
        !           949:         } else {
        !           950:                 row = (int) SendMessage(hwndRCD, TM_TOPROW, FALSE, 0);
        !           951:         }
        !           952: 
        !           953:         /* find the previous 'interesting' line */
        !           954:         row = view_findchange(current_view, row, FALSE);
        !           955:         if (row >= 0) {
        !           956:                 SetSelection(row);
        !           957:                 return(TRUE);
        !           958:         } else {
        !           959:                 windiff_UI(TRUE);
        !           960:                 MessageBox(hwndClient, "No Previous Changes", "Windiff",
        !           961:                         MB_ICONINFORMATION|MB_OK);
        !           962:                 windiff_UI(FALSE);
        !           963: 
        !           964:                 return(FALSE);
        !           965:         }
        !           966: 
        !           967: }
        !           968: /***************************************************************************
        !           969:  * Function: WriteProfileInt
        !           970:  *
        !           971:  */
        !           972:  
        !           973: BOOL WriteProfileInt(LPSTR AppName, LPSTR Key, int Int)
        !           974: {       char Str[40];
        !           975: 
        !           976:         wsprintf((LPTSTR)Str, "%d", Int);
        !           977:         return WriteProfileString(AppName, Key, Str);
        !           978: 
        !           979: } /* WriteProfileInt */
        !           980: 
        !           981: 
        !           982: /***************************************************************************
        !           983:  * Function: ToExpand
        !           984:  *
        !           985:  * Purpose:
        !           986:  *
        !           987:  * Switch to expand view of the selected line 
        !           988:  */
        !           989: BOOL
        !           990: ToExpand(HWND hwnd)
        !           991: {
        !           992:         if (selection < 0) {
        !           993:                 return(FALSE);
        !           994:         }
        !           995: 
        !           996:         if (!view_isexpanded(current_view)) {
        !           997:                 /* save the current outline size and position */
        !           998:                 WINDOWPLACEMENT wp;
        !           999:                 if (GetWindowPlacement(hwndClient,&wp)) {
        !          1000:                         WriteProfileInt(APPNAME, "OutlineShowCmd", wp.showCmd);
        !          1001:                         WriteProfileInt(APPNAME, "OutlineMaxX", wp.ptMaxPosition.x);
        !          1002:                         WriteProfileInt(APPNAME, "OutlineMaxY", wp.ptMaxPosition.y);
        !          1003:                         WriteProfileInt(APPNAME, "OutlineNormLeft", wp.rcNormalPosition.left);
        !          1004:                         WriteProfileInt(APPNAME, "OutlineNormTop", wp.rcNormalPosition.top);
        !          1005:                         WriteProfileInt(APPNAME, "OutlineNormRight", wp.rcNormalPosition.right);
        !          1006:                         WriteProfileInt(APPNAME, "OutlineNormBottom", wp.rcNormalPosition.bottom);
        !          1007:                         WriteProfileInt(APPNAME, "OutlineSaved", 1);
        !          1008:                 }
        !          1009: 
        !          1010:                 /* restore the previous expanded size and position, if any */
        !          1011:                 if (GetProfileInt(APPNAME, "ExpandedSaved", 0)) {
        !          1012:                         wp.flags                   = 0;
        !          1013:                         wp.showCmd
        !          1014:                                 = GetProfileInt( APPNAME, "ExpandShowCmd"
        !          1015:                                                , SW_SHOWMAXIMIZED);
        !          1016:                         wp.ptMaxPosition.x
        !          1017:                                 = GetProfileInt( APPNAME, "ExpandMaxX", 0);
        !          1018:                         wp.ptMaxPosition.y
        !          1019:                                 = GetProfileInt( APPNAME, "ExpandMaxY", 0);
        !          1020:                         wp.rcNormalPosition.left
        !          1021:                                 = GetProfileInt( APPNAME, "ExpandNormLeft"
        !          1022:                                                , wp.rcNormalPosition.left);
        !          1023:                         wp.rcNormalPosition.top
        !          1024:                                 = GetProfileInt( APPNAME, "ExpandNormTop"
        !          1025:                                                , wp.rcNormalPosition.top);
        !          1026:                         wp.rcNormalPosition.right
        !          1027:                                 = GetProfileInt( APPNAME, "ExpandNormRight"
        !          1028:                                                , wp.rcNormalPosition.right);
        !          1029:                         wp.rcNormalPosition.bottom
        !          1030:                                 = GetProfileInt( APPNAME, "ExpandNormBottom"
        !          1031:                                                , wp.rcNormalPosition.bottom);
        !          1032:                         SetWindowPlacement(hwndClient,&wp);
        !          1033:                 }
        !          1034:                 else ShowWindow(hwndClient, SW_SHOWMAXIMIZED);
        !          1035:         }
        !          1036: 
        !          1037:         /*change the view mapping to expand mode */
        !          1038:         if (view_expand(current_view, selection)) {
        !          1039: 
        !          1040:                 /* ok - we now have an expanded view - change status
        !          1041:                  * to show this
        !          1042:                  */
        !          1043: 
        !          1044:                 DisplayMode = MODE_EXPAND;
        !          1045: 
        !          1046:                 /* resize to show the graphic bar picture */
        !          1047:                 DoResize(hwndClient);
        !          1048: 
        !          1049: 
        !          1050:                 /* change button,status text-if we are not still busy*/
        !          1051:                 if (!fBusy) {
        !          1052: 
        !          1053:                         /* the status field when we are expanded shows the
        !          1054:                          * tag field (normally the file name) for the
        !          1055:                          * item we are expanding
        !          1056:                          */
        !          1057:                         SetStatus(view_getcurrenttag(current_view) );
        !          1058:                         SetButtonText("Outline");
        !          1059:                 }
        !          1060: 
        !          1061:                 return(TRUE);
        !          1062:         }
        !          1063:         return(FALSE);
        !          1064: } /* ToExpand */
        !          1065: 
        !          1066: /***************************************************************************
        !          1067:  * Function: ToOutline
        !          1068:  *
        !          1069:  * Purpose:
        !          1070:  *
        !          1071:  * Switch back to outline view - showing just the list of file names.
        !          1072:  */
        !          1073: void
        !          1074: ToOutline(HWND hwnd)
        !          1075: {
        !          1076:         if (view_isexpanded(current_view)) {
        !          1077:                 /* save the current expanded size and position */
        !          1078:                 WINDOWPLACEMENT wp;
        !          1079:                 if (GetWindowPlacement(hwndClient,&wp)) {
        !          1080:                         WriteProfileInt(APPNAME, "ExpandShowCmd", wp.showCmd);
        !          1081:                         WriteProfileInt(APPNAME, "ExpandMaxX", wp.ptMaxPosition.x);
        !          1082:                         WriteProfileInt(APPNAME, "ExpandMaxY", wp.ptMaxPosition.y);
        !          1083:                         WriteProfileInt(APPNAME, "ExpandNormLeft", wp.rcNormalPosition.left);
        !          1084:                         WriteProfileInt(APPNAME, "ExpandNormTop", wp.rcNormalPosition.top);
        !          1085:                         WriteProfileInt(APPNAME, "ExpandNormRight", wp.rcNormalPosition.right);
        !          1086:                         WriteProfileInt(APPNAME, "ExpandNormBottom", wp.rcNormalPosition.bottom);
        !          1087:                         WriteProfileInt(APPNAME, "ExpandedSaved", 1);
        !          1088:                 }
        !          1089: 
        !          1090:                 /* restore the previous expanded size and position, if any */
        !          1091:                 if (GetProfileInt(APPNAME, "OutlineSaved", 0))  {
        !          1092:                         wp.flags = 0;
        !          1093:                         wp.showCmd
        !          1094:                                 = GetProfileInt( APPNAME, "OutlineShowCmd"
        !          1095:                                                , SW_SHOWNORMAL);
        !          1096:                         wp.ptMaxPosition.x
        !          1097:                                 = GetProfileInt( APPNAME, "OutlineMaxX", 0);
        !          1098:                         wp.ptMaxPosition.y
        !          1099:                                 = GetProfileInt( APPNAME, "OutlineMaxY", 0);
        !          1100:                         wp.rcNormalPosition.left
        !          1101:                                 = GetProfileInt( APPNAME, "OutlineNormLeft"
        !          1102:                                                , wp.rcNormalPosition.left);
        !          1103:                         wp.rcNormalPosition.top
        !          1104:                                 = GetProfileInt( APPNAME, "OutlineNormTop"
        !          1105:                                                , wp.rcNormalPosition.top);
        !          1106:                         wp.rcNormalPosition.right
        !          1107:                                 = GetProfileInt( APPNAME, "OutlineNormRight"
        !          1108:                                                , wp.rcNormalPosition.right);
        !          1109:                         wp.rcNormalPosition.bottom
        !          1110:                                 = GetProfileInt( APPNAME, "OutlineNormBottom"
        !          1111:                                                , wp.rcNormalPosition.bottom);
        !          1112:                         SetWindowPlacement(hwndClient,&wp);
        !          1113:                 }
        !          1114:                 ShowWindow(hwndClient, SW_SHOWNORMAL);
        !          1115:         }
        !          1116: 
        !          1117:         DisplayMode = MODE_OUTLINE;
        !          1118: 
        !          1119:         /* switch mapping back to outline view */
        !          1120:         view_outline(current_view);
        !          1121: 
        !          1122:         /* hide bar window and resize to cover */
        !          1123:         DoResize(hwndClient);
        !          1124: 
        !          1125: 
        !          1126:         /* change label on button */
        !          1127:         if (!fBusy) {
        !          1128:                 SetButtonText("Expand");
        !          1129:                 SetStatus(NULL);
        !          1130:         }
        !          1131: } /* ToOutline */
        !          1132: 
        !          1133: /***************************************************************************
        !          1134:  * Function: ToMoved
        !          1135:  *
        !          1136:  * Purpose:
        !          1137:  *
        !          1138:  * If the user clicks on a MOVED line in expand mode, we jump to the
        !          1139:  * other line. We return TRUE if this was possible,  or FALSE otherwise.
        !          1140:  */
        !          1141: BOOL
        !          1142: ToMoved(HWND hwnd)
        !          1143: {
        !          1144:         BOOL bIsLeft;
        !          1145:         int linenr, state;
        !          1146:         long i, total;
        !          1147: 
        !          1148:         if (DisplayMode != MODE_EXPAND) {
        !          1149:                 return(FALSE);
        !          1150:         }
        !          1151:         if (selection < 0) {
        !          1152:                 return(FALSE);
        !          1153:         }
        !          1154: 
        !          1155:         state = view_getstate(current_view, selection);
        !          1156:         if (state == STATE_MOVEDLEFT) {
        !          1157:                 bIsLeft = TRUE;
        !          1158:                 /* get the linenr of the other copy */
        !          1159:                 linenr = abs(view_getlinenr_right(current_view, selection));
        !          1160:         } else if (state == STATE_MOVEDRIGHT) {
        !          1161:                 bIsLeft = FALSE;
        !          1162:                 /* get the linenr of the other copy */
        !          1163:                 linenr = abs(view_getlinenr_left(current_view, selection));
        !          1164:         } else {
        !          1165:                 /* not a moved line - so we can't find another copy */
        !          1166:                 return(FALSE);
        !          1167:         }
        !          1168: 
        !          1169:         /* search the view for this line nr */
        !          1170:         total = view_getrowcount(current_view);
        !          1171:         for (i = 0; i < total; i++) {
        !          1172:                 if (bIsLeft) {
        !          1173:                         if (linenr == view_getlinenr_right(current_view, i)) {
        !          1174:                                 /* found it */
        !          1175:                                 SetSelection(i);
        !          1176:                                 return(TRUE);
        !          1177:                         }
        !          1178:                 } else {
        !          1179:                         if (linenr == view_getlinenr_left(current_view, i)) {
        !          1180:                                 SetSelection(i);
        !          1181:                                 return(TRUE);
        !          1182:                         }
        !          1183:                 }
        !          1184:         }
        !          1185:         return(FALSE);
        !          1186: }
        !          1187: 
        !          1188: /***************************************************************************
        !          1189:  * Function: do_editfile
        !          1190:  *
        !          1191:  * Purpose:
        !          1192:  *
        !          1193:  * Launch an editor on the current file (the file we are expanding, or
        !          1194:  * in outline mode the selected row. Option allows selection of the
        !          1195:  * left file, the right file or the composite view of this item.
        !          1196:  * pe points to a packet of parameters that must be freed before returning.
        !          1197:  * The return value is meaningless (just to conform to CreateThread).
        !          1198:  */
        !          1199: LONG
        !          1200: do_editfile(PEDITARGS pe)
        !          1201: {
        !          1202:         VIEW view = pe->view;
        !          1203:         int option = pe->option;
        !          1204:         int selection = pe->selection;
        !          1205: 
        !          1206:         COMPITEM item;
        !          1207:         LPSTR fname;
        !          1208:         char cmdline[256];
        !          1209:         int currentline;
        !          1210:         char * pOut = cmdline;
        !          1211:         char * pIn = editor_cmdline;
        !          1212: 
        !          1213:         STARTUPINFO si;
        !          1214:         PROCESS_INFORMATION pi;
        !          1215: 
        !          1216:         item = view_getitem(view, selection);
        !          1217:         if (item == NULL) {
        !          1218:                 return -1;
        !          1219:         }
        !          1220: 
        !          1221:         fname = compitem_getfilename(item, option);
        !          1222: 
        !          1223:         if ( 0 == fname )
        !          1224:         {
        !          1225:             windiff_UI(TRUE);
        !          1226:             MessageBox(hwndClient, "File does not exist.",
        !          1227:                        "Windiff", MB_ICONSTOP|MB_OK);
        !          1228:             windiff_UI(FALSE);
        !          1229:             goto error;
        !          1230:         }
        !          1231: 
        !          1232:        switch ( option )
        !          1233:         {
        !          1234:         case CI_LEFT:
        !          1235:             currentline = view_getlinenr_left( view,
        !          1236:                                                selection > 0 ? selection : 1);
        !          1237:             break;
        !          1238: 
        !          1239:         case CI_RIGHT:
        !          1240:             currentline = view_getlinenr_right( view,
        !          1241:                                                 selection > 0 ? selection : 1);
        !          1242:             break;
        !          1243: 
        !          1244:         default:
        !          1245:             currentline = 1;
        !          1246:             break;
        !          1247:         }
        !          1248: 
        !          1249:         while( *pIn )
        !          1250:         {
        !          1251:             switch( *pIn )
        !          1252:             {
        !          1253:             case '%':
        !          1254:                 pIn++;
        !          1255:                 switch ( *pIn )
        !          1256:                 {
        !          1257:                 case 'p':
        !          1258:                     lstrcpy( (LPTSTR)pOut, fname );
        !          1259:                     while ( *pOut )
        !          1260:                         pOut++;
        !          1261:                     break;
        !          1262: 
        !          1263:                 case 'l':
        !          1264:                     _ltoa( currentline, pOut, 10 );
        !          1265:                     while ( *pOut )
        !          1266:                         pOut++;
        !          1267:                     break;
        !          1268: 
        !          1269:                 default:
        !          1270:                     *pOut++ = *pIn;
        !          1271:                     break;
        !          1272:                 }
        !          1273:                 pIn++;
        !          1274:                 break;
        !          1275: 
        !          1276:             default:
        !          1277:                 *pOut++ = *pIn++;
        !          1278:                 break;
        !          1279:             }
        !          1280:         }
        !          1281: 
        !          1282: 
        !          1283:         /* Launch the process and waits for it to complete */
        !          1284: 
        !          1285:         si.cb = sizeof(STARTUPINFO);
        !          1286:         si.lpReserved = NULL;
        !          1287:         si.lpReserved2 = NULL;
        !          1288:         si.cbReserved2 = 0;
        !          1289:         si.lpTitle = (LPSTR)cmdline; 
        !          1290:         si.lpDesktop = (LPTSTR)NULL;
        !          1291:         si.dwFlags = STARTF_FORCEONFEEDBACK;
        !          1292: 
        !          1293: 
        !          1294:         if (!CreateProcess(NULL,
        !          1295:                         cmdline,
        !          1296:                         NULL,
        !          1297:                         NULL,
        !          1298:                         FALSE,
        !          1299:                         NORMAL_PRIORITY_CLASS,
        !          1300:                         NULL,
        !          1301:                         (LPTSTR)NULL,
        !          1302:                         &si,
        !          1303:                         &pi)) {
        !          1304:                 windiff_UI(TRUE);
        !          1305:                 MessageBox(hwndClient, "Failed to launch editor",
        !          1306:                         "Windiff", MB_ICONSTOP|MB_OK);
        !          1307:                 windiff_UI(FALSE);
        !          1308:                 goto error;
        !          1309:         }
        !          1310: 
        !          1311:         /* wait for completion. */
        !          1312:         WaitForSingleObject(pi.hProcess, INFINITE);
        !          1313: 
        !          1314:         /* close process and thread handles */
        !          1315:         CloseHandle(pi.hThread);
        !          1316:         CloseHandle(pi.hProcess);
        !          1317: 
        !          1318:         /* finished with the filename. deletes it if it was a temp. */
        !          1319:         compitem_freefilename(item, option, fname);
        !          1320: 
        !          1321:         /*
        !          1322:          * refresh cached view always .  A common trick is to edit the
        !          1323:          * composite file and then save it as a new left or right file.
        !          1324:          * Equally the user can edit the left and save as a new right.
        !          1325:          */
        !          1326: 
        !          1327:         /* We want to force both files to be re-read, but it's not a terribly
        !          1328:          * good idea to throw the lines away on this thread.  Someone might
        !          1329:          * be reading them on another thread!
        !          1330:          */
        !          1331:         /* file_discardlines(compitem_getleftfile(item)) */
        !          1332:         /* file_discardlines(compitem_getrightfile(item)) */
        !          1333: 
        !          1334:         /* force the compare to be re-done */
        !          1335:         PostMessage(hwndClient, WM_COMMAND, IDM_UPDATE, (LONG)item);
        !          1336: error:
        !          1337:         gmem_free(hHeap, (LPSTR) pe, sizeof(EDITARGS));
        !          1338: 
        !          1339:         return 0;
        !          1340: 
        !          1341: } /* do_editfile */
        !          1342: 
        !          1343: 
        !          1344: /***************************************************************************
        !          1345:  * Function: do_editthread
        !          1346:  *
        !          1347:  * Purpose:
        !          1348:  *
        !          1349:  * Launch an editor on a separate thread.  It will actually get a separate
        !          1350:  * process, but we want our own thread in this process.  This thread will
        !          1351:  * wait until it's finished and then order up a refresh of the UI.
        !          1352:  * Need to give it its parameters as a gmem allocated packet because
        !          1353:  * it IS on a separate thread.
        !          1354:  */
        !          1355: void do_editthread(VIEW view, int option)
        !          1356: {
        !          1357:         PEDITARGS pe;
        !          1358:         HANDLE thread;
        !          1359:         DWORD threadid;
        !          1360: 
        !          1361:         pe = (PEDITARGS) gmem_get(hHeap, sizeof(EDITARGS));
        !          1362:         pe->view = view;
        !          1363:         pe->option = option;
        !          1364:         pe->selection = selection;
        !          1365: 
        !          1366:         thread = CreateThread( NULL
        !          1367:                              , 0
        !          1368:                              , (LPTHREAD_START_ROUTINE)do_editfile
        !          1369:                              , (LPVOID) pe
        !          1370:                              , 0
        !          1371:                              , &threadid
        !          1372:                              );
        !          1373:         if (thread == NULL)
        !          1374:         {
        !          1375:                 /* The createthread failed, do without the extra thread - just
        !          1376:                  * call the function synchronously
        !          1377:                  */
        !          1378:                  do_editfile(pe);
        !          1379:         }
        !          1380:         else CloseHandle(thread);
        !          1381: } /* do_editthread */
        !          1382: 
        !          1383: 
        !          1384: /* status bar and busy flags --------------------------------------------*/
        !          1385: 
        !          1386: 
        !          1387: /***************************************************************************
        !          1388:  * Function: SetButtonText
        !          1389:  *
        !          1390:  * Purpose:
        !          1391:  *
        !          1392:  * Set the Text on the statusbar button to reflect the current state 
        !          1393:  */
        !          1394: void
        !          1395: SetButtonText(LPSTR cmd)
        !          1396: {
        !          1397:         SendMessage(hwndStatus, SM_SETTEXT, IDM_ABORT, (DWORD) cmd);
        !          1398: }
        !          1399: 
        !          1400: /***************************************************************************
        !          1401:  * Function: SetStatus
        !          1402:  *
        !          1403:  * Purpose:
        !          1404:  *
        !          1405:  * Set the status field (left-hand part) of the status bar. 
        !          1406:  */
        !          1407: void
        !          1408: SetStatus(LPSTR cmd)
        !          1409: {
        !          1410:         SendMessage(hwndStatus, SM_SETTEXT, IDL_STATLAB, (DWORD) cmd);
        !          1411: }
        !          1412: 
        !          1413: 
        !          1414: /***************************************************************************
        !          1415:  * Function: SetNames
        !          1416:  *
        !          1417:  * Purpose:
        !          1418:  *
        !          1419:  * Set the names field - the central box in the status bar 
        !          1420:  */
        !          1421: void
        !          1422: SetNames(LPSTR names)
        !          1423: {
        !          1424:         SendMessage(hwndStatus, SM_SETTEXT, IDL_NAMES, (DWORD) names);
        !          1425:         if (names == NULL) {
        !          1426:                 AppTitle[0] = '\0';
        !          1427:         } else {
        !          1428:                 strncpy(AppTitle, names, sizeof(AppTitle));
        !          1429:         }
        !          1430: }
        !          1431: 
        !          1432: /***************************************************************************
        !          1433:  * Function: SetBusy
        !          1434:  *
        !          1435:  * Purpose:
        !          1436:  *
        !          1437:  * If we are not already busy, set the busy flag.
        !          1438:  *
        !          1439:  * Enter critical section first.
        !          1440:  */
        !          1441: BOOL
        !          1442: SetBusy(void)
        !          1443: {
        !          1444:         HMENU hmenu;
        !          1445: 
        !          1446: 
        !          1447:         WDEnter();
        !          1448: 
        !          1449:         if (fBusy) {
        !          1450:                 WDLeave();
        !          1451:                 return(FALSE);
        !          1452:         }
        !          1453: 
        !          1454: 
        !          1455:         fBusy = TRUE;
        !          1456: 
        !          1457:         SetStatus("Comparing...");
        !          1458:         /* status also on window text, so that you can see even from
        !          1459:          * the icon when the scan has finished
        !          1460:          */
        !          1461:         SetWindowText(hwndClient, "WinDiff: scanning");
        !          1462: 
        !          1463:         /* disable appropriate parts of menu */
        !          1464:         hmenu = GetMenu(hwndClient);
        !          1465:         EnableMenuItem(hmenu, IDM_FILE,MF_DISABLED|MF_GRAYED|MF_BYCOMMAND);
        !          1466:         EnableMenuItem(hmenu, IDM_DIR,MF_DISABLED|MF_GRAYED|MF_BYCOMMAND);
        !          1467:         EnableMenuItem(hmenu, IDM_PRINT,MF_DISABLED|MF_GRAYED|MF_BYCOMMAND);
        !          1468: 
        !          1469:         /* enable abort only when busy */
        !          1470:         EnableMenuItem(hmenu, IDM_ABORT,MF_ENABLED|MF_BYCOMMAND);
        !          1471:         SetButtonText("Abort");  /* leave DisplayMode unchanged */
        !          1472: 
        !          1473:         WDLeave();
        !          1474:         return(TRUE);
        !          1475: } /* SetBusy */
        !          1476: /***************************************************************************
        !          1477:  * Function: SetNotBusy
        !          1478:  *
        !          1479:  * Purpose:
        !          1480:  *
        !          1481:  * This function can be called from the worker thread.
        !          1482:  * Thus we must not cause any SendMessage calls to windows
        !          1483:  * owned by the main thread while holding the CritSec or we
        !          1484:  * could cause deadlock.
        !          1485:  *
        !          1486:  * The critsec is only needed to protect the fBusy flag - so
        !          1487:  * clear the busy flag last, and only get the crit sec as needed.
        !          1488:  */
        !          1489: void
        !          1490: SetNotBusy(void)
        !          1491: {
        !          1492:         HMENU hmenu;
        !          1493: 
        !          1494:         /* reset button and status bar (clearing out busy flags) */
        !          1495:         if (current_view == NULL) {
        !          1496:                 SetButtonText("Exit");
        !          1497:                 SetStatus(NULL);
        !          1498:                 DisplayMode = MODE_NULL;
        !          1499:         } else if (view_isexpanded(current_view)) {
        !          1500:                 SetButtonText("Outline");
        !          1501:                 SetStatus(view_getcurrenttag(current_view) );
        !          1502:                 DisplayMode = MODE_EXPAND;
        !          1503:         } else {
        !          1504:                 SetButtonText("Expand");
        !          1505:                 SetStatus(NULL);
        !          1506:                 DisplayMode = MODE_OUTLINE;
        !          1507:         }
        !          1508: 
        !          1509:         SetWindowText(hwndClient, "WinDiff");
        !          1510: 
        !          1511:         /* re-enable appropriate parts of menu */
        !          1512:         hmenu = GetMenu(hwndClient);
        !          1513:         EnableMenuItem(hmenu, IDM_FILE,MF_ENABLED|MF_BYCOMMAND);
        !          1514:         EnableMenuItem(hmenu, IDM_DIR,MF_ENABLED|MF_BYCOMMAND);
        !          1515:         EnableMenuItem(hmenu, IDM_PRINT,MF_ENABLED|MF_BYCOMMAND);
        !          1516: 
        !          1517:         /* disable abort now no longer busy */
        !          1518:         EnableMenuItem(hmenu, IDM_ABORT,MF_DISABLED|MF_GRAYED|MF_BYCOMMAND);
        !          1519: 
        !          1520: 
        !          1521:         /* clear the busy flag, protected by critical section */
        !          1522:         WDEnter();
        !          1523: 
        !          1524:         fBusy = FALSE;
        !          1525:         bAbort = FALSE;
        !          1526: 
        !          1527:         if (ghThread!=NULL){
        !          1528:             CloseHandle(ghThread);
        !          1529:             ghThread = NULL;
        !          1530:         }
        !          1531:         WDLeave();
        !          1532: } /* SetNotBusy */
        !          1533: 
        !          1534: /***************************************************************************
        !          1535:  * Function: IsBusy
        !          1536:  *
        !          1537:  * Purpose:
        !          1538:  *
        !          1539:  * Checks whether or not crit sec is open
        !          1540:  */
        !          1541: BOOL
        !          1542: IsBusy()
        !          1543: {
        !          1544:         BOOL bOK;
        !          1545: 
        !          1546:         WDEnter();
        !          1547:         bOK = fBusy;
        !          1548:         WDLeave();
        !          1549:         return(bOK);
        !          1550: } /* IsBusy */
        !          1551: 
        !          1552: /***************************************************************************
        !          1553:  * Function: BusyError
        !          1554:  *
        !          1555:  * Purpose:
        !          1556:  *
        !          1557:  * Puts up message box that system is busy.
        !          1558:  */
        !          1559: void
        !          1560: BusyError(void)
        !          1561: {
        !          1562:         windiff_UI(TRUE);
        !          1563:         MessageBox(hwndClient,
        !          1564:                 "Please wait for current operation to finish",
        !          1565:                 "WinDiff", MB_OK|MB_ICONSTOP);
        !          1566:         windiff_UI(FALSE);
        !          1567: } /* BusyError */
        !          1568: 
        !          1569: /* --- colour scheme --------------------------------------------------- */
        !          1570: 
        !          1571: /***************************************************************************
        !          1572:  * Function: StateToColour
        !          1573:  *
        !          1574:  * Purpose:
        !          1575:  *
        !          1576:  * Map the state given into a foreground and a background colour
        !          1577:  * for states that are highlighted. Return P_FCOLOUR if the foreground
        !          1578:  * colour (put in *foreground) is to be used, return P_FCOLOUR|P_BCOLOUR if
        !          1579:  * both *foreground and *background are to be used, or 0 if the default
        !          1580:  * colours are to be used.
        !          1581:  */
        !          1582: UINT
        !          1583: StateToColour(int state, int col, DWORD FAR * foreground, DWORD FAR * background)
        !          1584: {
        !          1585: 
        !          1586: 
        !          1587:         switch (state) {
        !          1588: 
        !          1589:         case STATE_DIFFER:
        !          1590:                 /* files that differ are picked out in a foreground highlight,
        !          1591:                  * with the default background
        !          1592:                  */
        !          1593:                 *foreground = rgb_outlinehi;
        !          1594:                 return(P_FCOLOUR);
        !          1595: 
        !          1596:         case STATE_LEFTONLY:
        !          1597:                 /* lines only in the left file */
        !          1598:                 *foreground = rgb_leftfore;
        !          1599:                 *background = rgb_leftback;
        !          1600:                 return(P_FCOLOUR|P_BCOLOUR);
        !          1601: 
        !          1602:         case STATE_RIGHTONLY:
        !          1603:                 /* lines only in the right file */
        !          1604:                 *foreground = rgb_rightfore;
        !          1605:                 *background = rgb_rightback;
        !          1606:                 return(P_FCOLOUR|P_BCOLOUR);
        !          1607: 
        !          1608:         case STATE_MOVEDLEFT:
        !          1609:                 /* displaced lines in both files - left file version */
        !          1610:                 *foreground = rgb_mleftfore;
        !          1611:                 *background = rgb_mleftback;
        !          1612:                 return(P_FCOLOUR|P_BCOLOUR);
        !          1613: 
        !          1614:         case STATE_MOVEDRIGHT:
        !          1615:                 /* displaced lines in both files - right file version */
        !          1616:                 *foreground = rgb_mrightfore;
        !          1617:                 *background = rgb_mrightback;
        !          1618:                 return(P_FCOLOUR|P_BCOLOUR);
        !          1619: 
        !          1620:         default:
        !          1621: 
        !          1622:                 /* no highlighting - default colours */
        !          1623:                 return(0);
        !          1624:         }
        !          1625: 
        !          1626: }
        !          1627: 
        !          1628: /* table window communication routines ---------------------------------*/
        !          1629: 
        !          1630: /***************************************************************************
        !          1631:  * Function: SetSelection
        !          1632:  *
        !          1633:  * Purpose:
        !          1634:  *
        !          1635:  * Set a given row as the selected row in the table window 
        !          1636:  */
        !          1637: void
        !          1638: SetSelection(long rownr)
        !          1639: {
        !          1640:         TableSelection select;
        !          1641: 
        !          1642:         select.startrow = rownr;
        !          1643:         select.startcell = 0;
        !          1644:         select.nrows = 1;
        !          1645:         select.ncells = 1;
        !          1646:         SendMessage(hwndRCD, TM_SELECT, 0, (long) (LPSTR)&select);
        !          1647: }
        !          1648: 
        !          1649: 
        !          1650: /***************************************************************************
        !          1651:  * Function: do_gethdr
        !          1652:  *
        !          1653:  * Purpose:
        !          1654:  *
        !          1655:  * Handle table class call back to get nr of rows and columns,
        !          1656:  * and properties for the whole table.
        !          1657:  * The 'table id' is either TABID_PRINTER - meaning we are
        !          1658:  * printing the current_view, or it is the view to
        !          1659:  * use for row/column nr information
        !          1660:  */
        !          1661: long
        !          1662: do_gethdr(HWND hwnd, lpTableHdr phdr)
        !          1663: {
        !          1664:         VIEW view;
        !          1665:         BOOL bIsPrinter = FALSE;
        !          1666: 
        !          1667:         if (phdr->id == TABID_PRINTER) {
        !          1668:                 view = current_view;
        !          1669:                 bIsPrinter = TRUE;
        !          1670:         } else {
        !          1671:                 view = (VIEW) phdr->id;
        !          1672:         }
        !          1673:         if (view == NULL) {
        !          1674:                 return(FALSE);
        !          1675:         }
        !          1676: 
        !          1677:         phdr->nrows = view_getrowcount(view);
        !          1678: 
        !          1679:         /*  three columns: line nr, tag and rest of line */
        !          1680: 
        !          1681:         /*
        !          1682:          * if IDM_NONRS (no line numbers) is selected, suppress the
        !          1683:          * line-nr column entirely to save screen space
        !          1684:          */
        !          1685:         if (line_numbers == IDM_NONRS) {
        !          1686:                 phdr->ncols = 2;
        !          1687:                 phdr->fixedcols = 0;
        !          1688:         } else {
        !          1689:                 phdr->ncols = 3;
        !          1690:                 phdr->fixedcols = 1;
        !          1691:         }
        !          1692: 
        !          1693:         phdr->fixedrows = 0;
        !          1694:         phdr->fixedselectable = FALSE;
        !          1695:         phdr->hseparator = TRUE;
        !          1696:         phdr->vseparator = TRUE;
        !          1697: 
        !          1698:         phdr->selectmode = TM_ROW | TM_SINGLE;
        !          1699:         /*
        !          1700:          * find if we are in expand mode - ask for the item we are expanding.
        !          1701:          */
        !          1702:         if (view_isexpanded(view) == TRUE) {
        !          1703: 
        !          1704:                 /* use focus rect as selection mode in expand mode
        !          1705:                  * so as not to interfere with background colours.
        !          1706:                  */
        !          1707:                 phdr->selectmode |= TM_FOCUS;
        !          1708:         } else {
        !          1709:                 /* use default solid inversion when possible as it is clearer.*/
        !          1710:                 phdr->selectmode |= TM_SOLID;
        !          1711:         }
        !          1712: 
        !          1713:         /* please send TQ_SCROLL notifications when the table is scrolled */
        !          1714:         phdr->sendscroll = TRUE;
        !          1715:         phdr->props.valid = 0;
        !          1716: 
        !          1717:         return TRUE;
        !          1718: }
        !          1719: 
        !          1720: /***************************************************************************
        !          1721:  * Function: do_getprops
        !          1722:  *
        !          1723:  * Purpose:
        !          1724:  *
        !          1725:  * Respond to table callback asking for the size and properties
        !          1726:  * of each column. Table id is either TABID_PRINTER (meaning the
        !          1727:  * current_view, for printing) or it is the view to be used.
        !          1728:  */
        !          1729: long
        !          1730: do_getprops(HWND hwnd, lpColPropsList propslist)
        !          1731: {
        !          1732:         int i, cell;
        !          1733:         BOOL bIsPrinter = FALSE;
        !          1734:         VIEW view;
        !          1735: 
        !          1736:         if (propslist->id == TABID_PRINTER) {
        !          1737:                 view = current_view;
        !          1738:                 bIsPrinter = TRUE;
        !          1739:         } else {
        !          1740:                 view = (VIEW) propslist->id;
        !          1741:         }
        !          1742:         if (view == NULL) {
        !          1743:                 return(FALSE);
        !          1744:         }
        !          1745: 
        !          1746:         /* The table inteface is slightly confused here. we are not
        !          1747:          * guaranteed which columns we are being asked about, so instead
        !          1748:          * of just setting each column cols[0], cols[1] etc, we need
        !          1749:          * to loop through, looking at each column in the table and
        !          1750:          * seeing which it is.
        !          1751:          */
        !          1752:         for (i = 0; i < propslist->ncols; i++) {
        !          1753:                 cell = i + propslist->startcol;
        !          1754:                 propslist->plist[i].props.valid = 0;
        !          1755: 
        !          1756:                 /* for all column widths, add on 1 for the NULL char. */
        !          1757: 
        !          1758:                 /*
        !          1759:                  * skip the line nr column if IDM_NONRS
        !          1760:                  */
        !          1761:                 if (line_numbers == IDM_NONRS) {
        !          1762:                         cell++;
        !          1763:                 }
        !          1764: 
        !          1765:                 if (cell == 0) {
        !          1766:                         /* properties for line nr column */
        !          1767: 
        !          1768:                         propslist->plist[i].nchars = view_getwidth(view, 0)+1;
        !          1769:                         propslist->plist[i].props.valid |= P_ALIGN;
        !          1770:                         propslist->plist[i].props.alignment = P_CENTRE;
        !          1771:                 } else if (cell == 1) {
        !          1772: 
        !          1773:                         /* properties for tag field */
        !          1774:                         propslist->plist[i].nchars = view_getwidth(view, 1)+1;
        !          1775:                         propslist->plist[i].props.valid |= P_ALIGN;
        !          1776:                         propslist->plist[i].props.alignment = P_LEFT;
        !          1777:                 } else {
        !          1778:                         /* properties for main text column -
        !          1779:                          * use a fixed font unless printing (if
        !          1780:                          * printing, best to use the default font, because
        !          1781:                          * of resolution differences.
        !          1782:                          * add on 8 chars to the width to ensure that
        !          1783:                          * the width of lines beginning with tabs
        !          1784:                          * works out ok
        !          1785:                          */
        !          1786:                         propslist->plist[i].nchars = view_getwidth(view, 2)+1;
        !          1787:                         propslist->plist[i].props.valid |= P_ALIGN;
        !          1788:                         propslist->plist[i].props.alignment = P_LEFT;
        !          1789:                         if (!bIsPrinter) {
        !          1790:                                 propslist->plist[i].props.valid |= P_FONT;
        !          1791:                                 propslist->plist[i].props.hFont =
        !          1792:                                         GetStockObject(SYSTEM_FIXED_FONT);
        !          1793:                         }
        !          1794:                 }
        !          1795:         }
        !          1796:         return (TRUE);
        !          1797: }
        !          1798: 
        !          1799: /***************************************************************************
        !          1800:  * Function: do_getdata
        !          1801:  *
        !          1802:  * Purpose:
        !          1803:  *
        !          1804:  * Respond to a table callback asking for the contents of individual cells.
        !          1805:  * table id is either TABID_PRINTER, or it is a pointer to the view
        !          1806:  * to use for data. If going to the printer, don't set the
        !          1807:  * colours (stick to black and white).
        !          1808:  */
        !          1809: long
        !          1810: do_getdata(HWND hwnd, lpCellDataList cdlist)
        !          1811: {
        !          1812:         int start, endcell, col, i;
        !          1813:         lpCellData cd;
        !          1814:         VIEW view;
        !          1815:         LPSTR textp;
        !          1816:         BOOL bIsPrinter = FALSE;
        !          1817: 
        !          1818:         if (cdlist->id == TABID_PRINTER) {
        !          1819:                 view = current_view;
        !          1820:                 bIsPrinter = TRUE;
        !          1821:         } else {
        !          1822:                 view = (VIEW) cdlist->id;
        !          1823:         }
        !          1824: 
        !          1825:         start = cdlist->startcell;
        !          1826:         endcell = cdlist->ncells + start;
        !          1827:         if (cdlist->row >= view_getrowcount(view)) {
        !          1828:                 return(FALSE);
        !          1829:         }
        !          1830:         for (i = start; i < endcell; i++) {
        !          1831:                 cd = &cdlist->plist[i - start];
        !          1832: 
        !          1833: 
        !          1834:                 /* skip the line number column if IDM_NONRS */
        !          1835:                 if (line_numbers == IDM_NONRS) {
        !          1836:                         col = i+1;
        !          1837:                 } else {
        !          1838:                         col = i;
        !          1839:                 }
        !          1840: 
        !          1841:                 /* set colour of text to mark out
        !          1842:                  * lines that are changed, if not printer - for the
        !          1843:                  * printer everything should stay in the default colours
        !          1844:                  */
        !          1845: 
        !          1846:                 if (!bIsPrinter) {
        !          1847: 
        !          1848:                         /* convert the state of the requested row into a
        !          1849:                          * colour scheme. returns P_FCOLOUR and/or
        !          1850:                          * P_BCOLOUR if it sets either of the colours
        !          1851:                          */
        !          1852:                         cd->props.valid |=
        !          1853:                             StateToColour(view_getstate(view, cdlist->row), col,
        !          1854:                                         &cd->props.forecolour,
        !          1855:                                         &cd->props.backcolour);
        !          1856:                 }
        !          1857: 
        !          1858:                 textp = view_gettext(view, cdlist->row, col);
        !          1859:                 if (cd->nchars != 0) {
        !          1860:                         if (textp == NULL) {
        !          1861:                                 cd->ptext[0] = '\0';
        !          1862:                         } else {
        !          1863:                                 strncpy(cd->ptext, textp, cd->nchars -1);
        !          1864:                                 cd->ptext[cd->nchars - 1] = '\0';
        !          1865:                         }
        !          1866:                 }
        !          1867: 
        !          1868:         }
        !          1869:         return(TRUE);
        !          1870: }
        !          1871: 
        !          1872: /***************************************************************************
        !          1873:  * Function: SvrClose
        !          1874:  *
        !          1875:  * Purpose:
        !          1876:  *
        !          1877:  * Table window has finished with this view. It can be deleted.
        !          1878:  */
        !          1879: void
        !          1880: SvrClose(void)
        !          1881: {
        !          1882:         view_delete(current_view);
        !          1883:         current_view = NULL;
        !          1884: 
        !          1885:         /* hide picture - only visible when we are in MODE_EXPAND */
        !          1886:         DisplayMode = MODE_NULL;
        !          1887:         DoResize(hwndClient);
        !          1888: 
        !          1889:         /* if we already busy when closing this view (ie
        !          1890:          * we are in the process of starting a new scan,
        !          1891:          * then leave the status bar alone, otherwise
        !          1892:          * we should clean up the state of the status bar
        !          1893:          */
        !          1894:         if (!fBusy) {
        !          1895:                 SetButtonText("Exit");
        !          1896:                 SetNames(NULL);
        !          1897:                 SetStatus(NULL);
        !          1898: 
        !          1899:         }
        !          1900: 
        !          1901: } /* SvrClose */
        !          1902: 
        !          1903: 
        !          1904: /***************************************************************************
        !          1905:  * Function: TableServer
        !          1906:  *
        !          1907:  * Purpose:
        !          1908:  *
        !          1909:  * Handle callbacks and notifications from the table class 
        !          1910:  */
        !          1911: long
        !          1912: TableServer(HWND hwnd, UINT cmd, long lParam)
        !          1913: {
        !          1914:         lpTableHdr phdr;
        !          1915:         lpColPropsList proplist;
        !          1916:         lpCellDataList cdlist;
        !          1917:         lpTableSelection pselect;
        !          1918: 
        !          1919:         switch(cmd) {
        !          1920:         case TQ_GETSIZE:
        !          1921:                 /* get the nr of rows and cols in this table */
        !          1922:                 phdr = (lpTableHdr) lParam;
        !          1923:                 return(do_gethdr(hwnd, phdr));
        !          1924: 
        !          1925:         case TQ_GETCOLPROPS:
        !          1926:                 /* get the size and properties of each column */
        !          1927:                 proplist = (lpColPropsList) lParam;
        !          1928:                 return (do_getprops(hwnd, proplist));
        !          1929: 
        !          1930:         case TQ_GETDATA:
        !          1931:                 /* get the contents of individual cells */
        !          1932:                 cdlist = (lpCellDataList) lParam;
        !          1933:                 return (do_getdata(hwnd, cdlist));
        !          1934: 
        !          1935: 
        !          1936:         case TQ_SELECT:
        !          1937:                 /* selection has changed */
        !          1938:         case TQ_ENTER:
        !          1939:                 /* user has double-clicked or pressed enter */
        !          1940: 
        !          1941:                 pselect = (lpTableSelection) lParam;
        !          1942: 
        !          1943:                 /* store location for use in later search (IDM_FCHANGE) */
        !          1944:                 if (pselect->nrows < 1) {
        !          1945:                         selection = -1;
        !          1946:                 } else {
        !          1947:                         selection = (int) pselect->startrow;
        !          1948:                         if (cmd == TQ_ENTER) {
        !          1949:                                 /* try to expand this row */
        !          1950:                                 if (!ToExpand(hwnd)) {
        !          1951:                                         /* expand failed - maybe this
        !          1952:                                          * is a moved line- show the other
        !          1953:                                          * copy
        !          1954:                                          */
        !          1955:                                         ToMoved(hwnd);
        !          1956:                                 }
        !          1957: 
        !          1958:                         }
        !          1959:                 }
        !          1960:                 break;
        !          1961: 
        !          1962:         case TQ_CLOSE:
        !          1963:                 /* close this table - table class no longer needs data*/
        !          1964:                 SvrClose();
        !          1965:                 break;
        !          1966: 
        !          1967:         case TQ_SCROLL:
        !          1968:                 /* notification that the rows visible in the window
        !          1969:                  * have changed -change the current position lines in
        !          1970:                  * the graphic bar view (the sections picture)
        !          1971:                  */
        !          1972:                 if (picture_mode) {
        !          1973:                         BarDrawPosition(hwndBar, NULL, TRUE);
        !          1974:                 }
        !          1975:                 break;
        !          1976: 
        !          1977:         default:
        !          1978:                 return(FALSE);
        !          1979:         }
        !          1980:         return(TRUE);
        !          1981: }
        !          1982: 
        !          1983: 
        !          1984: /***************************************************************************
        !          1985:  * Function: wd_initial
        !          1986:  *
        !          1987:  * Purpose:
        !          1988:  *
        !          1989:  * Called on worker thread (not UI thread) to handle the work
        !          1990:  * requested on the command line. 
        !          1991:  * arg is a pointer to a THREADARGS block allocated from gmem_get(hHeap). This
        !          1992:  * needs to be freed before exiting.
        !          1993:  */
        !          1994: DWORD
        !          1995: wd_initial(LPVOID arg)
        !          1996: {
        !          1997:         PTHREADARGS pta = (PTHREADARGS) arg;
        !          1998:         COMPLIST cl;
        !          1999: 
        !          2000: 
        !          2001:         /* build a complist from these args,
        !          2002:          * and register with the view we have made
        !          2003:          */
        !          2004:         cl = complist_args(pta->first, pta->second, pta->view, pta->fDeep);
        !          2005: 
        !          2006:         if (cl == NULL) {
        !          2007:                 view_close(pta->view);
        !          2008:                 gmem_free(hHeap, (LPSTR) pta, sizeof(THREADARGS));
        !          2009:                 SetNotBusy();
        !          2010:                 return 0;
        !          2011:         }
        !          2012: 
        !          2013: 
        !          2014:         /* if savelist was selected, write out the list and exit */
        !          2015:         if(pta->savelist != NULL) {
        !          2016:                 complist_savelist(cl, pta->savelist, pta->saveopts);
        !          2017:                 gmem_free(hHeap, (LPSTR) pta, sizeof(THREADARGS));
        !          2018:                 SetNotBusy();
        !          2019:                 exit(0);
        !          2020:         }
        !          2021: 
        !          2022:         /* if there was only one file, expand it */
        !          2023:         if (view_getrowcount(pta->view) == 1) {
        !          2024:                 SetSelection(0);
        !          2025:                 ToExpand(hwndClient);
        !          2026:         }
        !          2027: 
        !          2028: 
        !          2029:         gmem_free(hHeap, (LPSTR) pta, sizeof(THREADARGS));
        !          2030:         SetNotBusy();
        !          2031:         return(0);
        !          2032: } /* wd_initial */
        !          2033: 
        !          2034: 
        !          2035: /***************************************************************************
        !          2036:  * Function: wd_dirdialog
        !          2037:  *
        !          2038:  * Purpose:
        !          2039:  *
        !          2040:  * Called on worker thread (not UI thread) to handle a Dir request
        !          2041:  */
        !          2042: DWORD
        !          2043: wd_dirdialog(LPVOID arg)
        !          2044: {
        !          2045: 
        !          2046:         VIEW view = (VIEW) arg;
        !          2047: 
        !          2048:         /* make a COMPLIST using the directory dialog,
        !          2049:          * and notify the view
        !          2050:          */
        !          2051:         if (complist_dirdialog(view) == NULL) {
        !          2052:                 view_close(view);
        !          2053:         }
        !          2054: 
        !          2055:         /* all done! */
        !          2056:         SetNotBusy();
        !          2057:         return(0);
        !          2058: }
        !          2059: 
        !          2060: 
        !          2061: /***************************************************************************
        !          2062:  * Function: wd_copy
        !          2063:  *
        !          2064:  * Purpose:
        !          2065:  *
        !          2066:  * Called on worker thread to do a copy-files operation
        !          2067:  */
        !          2068: DWORD
        !          2069: wd_copy(LPVOID arg)
        !          2070: {
        !          2071: 
        !          2072:         VIEW view = (VIEW) arg;
        !          2073: 
        !          2074:         complist_copyfiles(view_getcomplist(view), NULL, 0);
        !          2075: 
        !          2076:         SetNotBusy();
        !          2077: 
        !          2078:         return(0);
        !          2079: }
        !          2080: 
        !          2081: 
        !          2082: /***************************************************************************
        !          2083:  * Function: MainWndProc
        !          2084:  *
        !          2085:  * Purpose:
        !          2086:  *
        !          2087:  * Window processing for main window
        !          2088:  */
        !          2089: long APIENTRY
        !          2090: MainWndProc(HWND hWnd, UINT message, UINT wParam, LONG lParam)
        !          2091: {
        !          2092:         char str[32];
        !          2093:         long ret;
        !          2094:         DWORD threadid;
        !          2095: 
        !          2096:         switch(message) {
        !          2097: 
        !          2098: 
        !          2099:         case WM_CREATE:
        !          2100: 
        !          2101:                 /* initialise menu options to default/saved
        !          2102:                  * option settings
        !          2103:                  */
        !          2104: 
        !          2105:                 CheckMenuItem(hMenu, IDM_INCSAME,
        !          2106:                       (outline_include & INCLUDE_SAME) ?
        !          2107:                                 MF_CHECKED:MF_UNCHECKED);
        !          2108: 
        !          2109:                 CheckMenuItem(hMenu, IDM_INCLEFT,
        !          2110:                       (outline_include & INCLUDE_LEFTONLY) ?
        !          2111:                                 MF_CHECKED:MF_UNCHECKED);
        !          2112: 
        !          2113:                 CheckMenuItem(hMenu, IDM_INCRIGHT,
        !          2114:                       (outline_include & INCLUDE_RIGHTONLY) ?
        !          2115:                                 MF_CHECKED:MF_UNCHECKED);
        !          2116:                 CheckMenuItem(hMenu, IDM_INCDIFFER,
        !          2117:                       (outline_include & INCLUDE_DIFFER) ?
        !          2118:                                 MF_CHECKED:MF_UNCHECKED);
        !          2119: 
        !          2120:                 CheckMenuItem(hMenu, line_numbers, MF_CHECKED);
        !          2121:                 CheckMenuItem(hMenu, expand_mode, MF_CHECKED);
        !          2122: 
        !          2123:                 CheckMenuItem(hMenu, IDM_IGNBLANKS,
        !          2124:                         ignore_blanks ? MF_CHECKED : MF_UNCHECKED);
        !          2125:                 CheckMenuItem(hMenu, IDM_PICTURE,
        !          2126:                         picture_mode ? MF_CHECKED : MF_UNCHECKED);
        !          2127: 
        !          2128:                 /* nothing currently displayed */
        !          2129:                 DisplayMode = MODE_NULL;
        !          2130: 
        !          2131:                 break;
        !          2132: 
        !          2133: 
        !          2134:         case WM_COMMAND:
        !          2135:                 switch (GET_WM_COMMAND_ID(wParam, lParam)) {
        !          2136:                 case IDM_EXIT:
        !          2137:                         if (ghThread!=NULL) {
        !          2138:                                 extern CRITICAL_SECTION CSView;
        !          2139:                                 /* Stop any other thread from allocating things that we
        !          2140:                                    want to free!  See the threads DOGMA at the top
        !          2141:                                    of this file.
        !          2142:                                 */
        !          2143: 
        !          2144:                                 /* Because the thread that we are about to kill might be in
        !          2145:                                    a critical section, we first grab them both.  It is
        !          2146:                                    essential that anyone else who ever does this, does
        !          2147:                                    so in the same order!
        !          2148:                                 */
        !          2149:                                 WDEnter();
        !          2150:                                 EnterCriticalSection(&CSView);
        !          2151:                                 TerminateThread(ghThread, 31);
        !          2152:                                 CloseHandle(ghThread);
        !          2153:                                 ghThread = NULL;
        !          2154:                                 LeaveCriticalSection(&CSView);
        !          2155:                                 WDLeave();
        !          2156:                         }
        !          2157:                         if (!view_isexpanded(current_view)) {
        !          2158:                                 /* save the current outline size and position */
        !          2159:                                 WINDOWPLACEMENT wp;
        !          2160:                                 if (GetWindowPlacement(hwndClient,&wp)) {
        !          2161:                                         WriteProfileInt(APPNAME, "OutlineShowCmd", wp.showCmd);
        !          2162:                                         WriteProfileInt(APPNAME, "OutlineMaxX", wp.ptMaxPosition.x);
        !          2163:                                         WriteProfileInt(APPNAME, "OutlineMaxY", wp.ptMaxPosition.y);
        !          2164:                                         WriteProfileInt(APPNAME, "OutlineNormLeft", wp.rcNormalPosition.left);
        !          2165:                                         WriteProfileInt(APPNAME, "OutlineNormTop", wp.rcNormalPosition.top);
        !          2166:                                         WriteProfileInt(APPNAME, "OutlineNormRight", wp.rcNormalPosition.right);
        !          2167:                                         WriteProfileInt(APPNAME, "OutlineNormBottom", wp.rcNormalPosition.bottom);
        !          2168:                                         WriteProfileInt(APPNAME, "OutlineSaved", 1);
        !          2169:                                 }
        !          2170:                         } else {
        !          2171:                                 /* save the current expanded size and position */
        !          2172:                                 WINDOWPLACEMENT wp;
        !          2173:                                 if (GetWindowPlacement(hwndClient,&wp)) {
        !          2174:                                         WriteProfileInt(APPNAME, "ExpandShowCmd", wp.showCmd);
        !          2175:                                         WriteProfileInt(APPNAME, "ExpandMaxX", wp.ptMaxPosition.x);
        !          2176:                                         WriteProfileInt(APPNAME, "ExpandMaxY", wp.ptMaxPosition.y);
        !          2177:                                         WriteProfileInt(APPNAME, "ExpandNormLeft", wp.rcNormalPosition.left);
        !          2178:                                         WriteProfileInt(APPNAME, "ExpandNormTop", wp.rcNormalPosition.top);
        !          2179:                                         WriteProfileInt(APPNAME, "ExpandNormRight", wp.rcNormalPosition.right);
        !          2180:                                         WriteProfileInt(APPNAME, "ExpandNormBottom", wp.rcNormalPosition.bottom);
        !          2181:                                         WriteProfileInt(APPNAME, "ExpandedSaved", 1);
        !          2182:                                 }
        !          2183:                         }
        !          2184:                         DestroyWindow(hWnd);
        !          2185:                         break;
        !          2186: 
        !          2187:                 case IDM_ABORT:
        !          2188:                         /* abort menu item, or status bar button.
        !          2189:                          * the status bar button text gives the appropriate
        !          2190:                          * action depending on our state - abort, outline
        !          2191:                          * or expand. But the command sent is always
        !          2192:                          * IDM_ABORT. Thus we need to check the state
        !          2193:                          * to see what to do. If we are busy, set the abort
        !          2194:                          * flag. If there is nothing to view,
        !          2195:                          * exit, otherwise switch outline<->expand
        !          2196:                          */
        !          2197:                         if (IsBusy()) {
        !          2198:                                 bAbort = TRUE;
        !          2199:                                 SetStatus("Abort Pending");
        !          2200: 
        !          2201:                         } else if (DisplayMode == MODE_NULL) {
        !          2202:                                 DestroyWindow(hWnd);
        !          2203:                         } else if (DisplayMode == MODE_EXPAND) {
        !          2204:                                 ToOutline(hWnd);
        !          2205:                         } else {
        !          2206:                                 ToExpand(hWnd);
        !          2207:                         }
        !          2208:                         break;
        !          2209: 
        !          2210:                 case IDM_FILE:
        !          2211:                         /* select two files and compare them */
        !          2212:                         if (SetBusy()) {
        !          2213: 
        !          2214:                                /* close the current view */
        !          2215:                                 view_close(current_view);
        !          2216: 
        !          2217:                                 /* make a new empty view */
        !          2218:                                 current_view = view_new(hwndRCD);
        !          2219: 
        !          2220:                                 /* make a COMPLIST using the files dialog,
        !          2221:                                  * and notify the view
        !          2222:                                  */
        !          2223:                                 if (complist_filedialog(current_view) == NULL) {
        !          2224:                                         view_close(current_view);
        !          2225:                                 }
        !          2226: 
        !          2227:                                 /* all done! */
        !          2228:                                 SetNotBusy();
        !          2229:                         } else {
        !          2230:                                 BusyError();
        !          2231:                         }
        !          2232:                         break;
        !          2233: 
        !          2234:                 case IDM_DIR:
        !          2235: 
        !          2236:                         /* read two directory names, scan them and
        !          2237:                          * compare all the files and subdirs.
        !          2238:                          */
        !          2239:                         if (SetBusy()) {
        !          2240: 
        !          2241:                                 /* close the current view */
        !          2242:                                 view_close(current_view);
        !          2243: 
        !          2244:                                 /* make a new empty view */
        !          2245:                                 current_view = view_new(hwndRCD);
        !          2246: 
        !          2247:                                 ghThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)wd_dirdialog,
        !          2248:                                         (LPVOID) current_view, 0, &threadid);
        !          2249: 
        !          2250:                                 if (ghThread == NULL)
        !          2251:                                 {
        !          2252:                                         wd_dirdialog( (LPVOID) current_view);
        !          2253:                                 }
        !          2254: 
        !          2255:                         } else {
        !          2256:                                 BusyError();
        !          2257:                         }
        !          2258:                         break;
        !          2259: 
        !          2260:                 case IDM_CLOSE:
        !          2261:                         /* close the output list -
        !          2262:                          * discard all results so far
        !          2263:                          */
        !          2264:                         if (!IsBusy()) {
        !          2265:                                 view_close(current_view);
        !          2266:                         }
        !          2267:                         break;
        !          2268: 
        !          2269:                 case IDM_PRINT:
        !          2270:                         /* print the current view -
        !          2271:                          * either the outline list of filenames,
        !          2272:                          * or the currently expanded file.
        !          2273:                          */
        !          2274:                         if (!IsBusy()) {
        !          2275:                                 DoPrint();
        !          2276:                         } else {
        !          2277:                                 BusyError();
        !          2278:                         }
        !          2279:                         break;
        !          2280: 
        !          2281:                 case IDM_TIME:
        !          2282:                         /* show time it took */
        !          2283:                         {       char msg[50];
        !          2284:                                 DWORD tim;
        !          2285:                                 if (IsBusy()) {
        !          2286:                                          BusyError();
        !          2287:                                 }
        !          2288:                                 else{
        !          2289:                                         tim = complist_querytime();
        !          2290:                                         wsprintf((LPTSTR)msg, "%d.%03d seconds", tim/1000, tim%1000);
        !          2291:                                 }
        !          2292:                         }
        !          2293:                         break;
        !          2294: 
        !          2295:                 case IDM_SAVELIST:
        !          2296:                         /* allow user to save list of same/different files
        !          2297:                          * to a text file. dialog box to give filename
        !          2298:                          * and select which types of file to include
        !          2299:                          */
        !          2300:                         complist_savelist(view_getcomplist(current_view), NULL, 0);
        !          2301:                         break;
        !          2302: 
        !          2303:                 case IDM_COPYFILES:
        !          2304:                         /*
        !          2305:                          * copy files that are same/different to a new
        !          2306:                          * root directory. dialog box allows user
        !          2307:                          * to select new root and inclusion options
        !          2308:                          */
        !          2309:                         if (current_view == NULL) {
        !          2310:                                 MessageBox(hWnd,
        !          2311:                                     "Please create a diff list first",
        !          2312:                                     "WinDiff", MB_OK|MB_ICONSTOP);
        !          2313:                                 break;
        !          2314:                         }
        !          2315: 
        !          2316:                         if (SetBusy()) {
        !          2317:                                 ghThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)wd_copy,
        !          2318:                                         (LPVOID) current_view, 0, &threadid);
        !          2319:                                 if (ghThread == NULL)
        !          2320:                                 {
        !          2321:                                         wd_copy( (LPVOID) current_view);
        !          2322:                                 }
        !          2323: 
        !          2324:                         } else {
        !          2325:                                 BusyError();
        !          2326:                         }
        !          2327: 
        !          2328:                         break;
        !          2329: 
        !          2330:                 case IDM_ABOUT:
        !          2331: 
        !          2332:                         DialogBox( hInst, "About", hWnd, (DLGPROC)AboutBox);
        !          2333:                         break;
        !          2334: 
        !          2335:                 /* launch an editor on the current item - left, right or
        !          2336:                  * composite view
        !          2337:                  */
        !          2338:                 case IDM_EDITLEFT:
        !          2339:                         do_editthread(current_view, CI_LEFT);
        !          2340:                         break;
        !          2341: 
        !          2342:                 case IDM_EDITRIGHT:
        !          2343:                         do_editthread(current_view, CI_RIGHT);
        !          2344:                         break;
        !          2345: 
        !          2346:                 case IDM_EDITCOMP:
        !          2347:                         do_editthread(current_view, CI_COMP);
        !          2348:                         break;
        !          2349: 
        !          2350:                 /* allow customisation of the editor command line */
        !          2351:                 case IDM_SETEDIT:
        !          2352:                         if (StringInput(editor_cmdline, sizeof(editor_cmdline),
        !          2353:                                         "Please enter the editor command line",
        !          2354:                                         "Windiff", editor_cmdline))  {
        !          2355:                                 WriteProfileString(APPNAME, "Editor",
        !          2356:                                         (LPCSTR)editor_cmdline);
        !          2357:                         }
        !          2358:                         break;
        !          2359: 
        !          2360: 
        !          2361:                 case IDM_LNRS:
        !          2362:                 case IDM_RNRS:
        !          2363:                 case IDM_NONRS:
        !          2364: 
        !          2365:                         /* option selects whether the line nrs displayed
        !          2366:                          * in expand mode are the line nrs in the left
        !          2367:                          * file, the right file or none
        !          2368:                          */
        !          2369: 
        !          2370:                         CheckMenuItem(GetMenu(hWnd),
        !          2371:                                 line_numbers, MF_UNCHECKED);
        !          2372:                         line_numbers = GET_WM_COMMAND_ID(wParam, lParam);
        !          2373:                         CheckMenuItem(GetMenu(hWnd), line_numbers, MF_CHECKED);
        !          2374:                         wsprintf((LPTSTR)str, "%d", line_numbers);
        !          2375:                         WriteProfileString(APPNAME, "LineNumbers", str);
        !          2376: 
        !          2377:                         /* change the display to show the line nr style
        !          2378:                          * chosen
        !          2379:                          */
        !          2380: 
        !          2381:                         view_changeviewoptions(current_view);
        !          2382: 
        !          2383: 
        !          2384:                         break;
        !          2385: 
        !          2386:                 /*
        !          2387:                  * options selecting which files to include in the
        !          2388:                  * outline listing, based on their state
        !          2389:                  */
        !          2390:                 case IDM_INCLEFT:
        !          2391: 
        !          2392: 
        !          2393:                         /* toggle flag in outline_include options */
        !          2394:                         outline_include ^= INCLUDE_LEFTONLY;
        !          2395: 
        !          2396:                         /* check/uncheck as necessary */
        !          2397:                         CheckMenuItem(hMenu, IDM_INCLEFT,
        !          2398:                               (outline_include & INCLUDE_LEFTONLY) ?
        !          2399:                                         MF_CHECKED:MF_UNCHECKED);
        !          2400: 
        !          2401:                         wsprintf((LPTSTR)str, "%d", outline_include);
        !          2402:                         WriteProfileString(APPNAME, "FileInclude", str);
        !          2403:                         view_changeviewoptions(current_view);
        !          2404: 
        !          2405: 
        !          2406:                         break;
        !          2407: 
        !          2408:                 case IDM_INCRIGHT:
        !          2409: 
        !          2410: 
        !          2411:                         outline_include ^= INCLUDE_RIGHTONLY;
        !          2412: 
        !          2413:                         CheckMenuItem(hMenu, IDM_INCRIGHT,
        !          2414:                               (outline_include & INCLUDE_RIGHTONLY) ?
        !          2415:                                         MF_CHECKED:MF_UNCHECKED);
        !          2416:                         wsprintf((LPTSTR)str, "%d", outline_include);
        !          2417:                         WriteProfileString(APPNAME, "FileInclude", str);
        !          2418:                         view_changeviewoptions(current_view);
        !          2419: 
        !          2420:                         break;
        !          2421: 
        !          2422:                 case IDM_INCSAME:
        !          2423: 
        !          2424: 
        !          2425:                         outline_include ^= INCLUDE_SAME;
        !          2426: 
        !          2427:                         CheckMenuItem(hMenu, IDM_INCSAME,
        !          2428:                               (outline_include & INCLUDE_SAME) ?
        !          2429:                                         MF_CHECKED:MF_UNCHECKED);
        !          2430:                         wsprintf((LPTSTR)str, "%d", outline_include);
        !          2431:                         WriteProfileString(APPNAME, "FileInclude", str);
        !          2432:                         view_changeviewoptions(current_view);
        !          2433: 
        !          2434: 
        !          2435:                         break;
        !          2436: 
        !          2437: 
        !          2438:                 case IDM_INCDIFFER:
        !          2439: 
        !          2440: 
        !          2441: 
        !          2442:                         outline_include ^= INCLUDE_DIFFER;
        !          2443: 
        !          2444:                         CheckMenuItem(hMenu, IDM_INCDIFFER,
        !          2445:                               (outline_include & INCLUDE_DIFFER) ?
        !          2446:                                         MF_CHECKED:MF_UNCHECKED);
        !          2447: 
        !          2448:                         wsprintf((LPTSTR)str, "%d", outline_include);
        !          2449:                         WriteProfileString(APPNAME, "FileInclude", str);
        !          2450:                         view_changeviewoptions(current_view);
        !          2451: 
        !          2452: 
        !          2453:                         break;
        !          2454: 
        !          2455:                 case IDM_UPDATE:
        !          2456:                         /* update the display.  Options or files may have changed */
        !          2457:                         /* discard lines  (thereby forcing re-read).
        !          2458:                          */
        !          2459:                         file_discardlines(compitem_getleftfile( (COMPITEM)lParam) );
        !          2460:                         file_discardlines(compitem_getrightfile( (COMPITEM)lParam) );
        !          2461: 
        !          2462:                         view_changediffoptions(current_view);
        !          2463: 
        !          2464:                         /* force repaint of bar window */
        !          2465:                         InvalidateRect(hwndBar, NULL, TRUE);
        !          2466:                         break;
        !          2467: 
        !          2468: 
        !          2469: 
        !          2470:                 case IDM_LONLY:
        !          2471:                 case IDM_RONLY:
        !          2472:                 case IDM_BOTHFILES:
        !          2473:                         /* option selects whether the expanded file
        !          2474:                          * show is the combined file, or just one
        !          2475:                          * or other of the input files.
        !          2476:                          *
        !          2477:                          * if we are not in expand mode, this also
        !          2478:                          * causes us to expand the selection
        !          2479:                          */
        !          2480: 
        !          2481: 
        !          2482:                         CheckMenuItem(GetMenu(hWnd), expand_mode, MF_UNCHECKED);
        !          2483:                         expand_mode = GET_WM_COMMAND_ID(wParam, lParam);
        !          2484:                         CheckMenuItem(GetMenu(hWnd), expand_mode, MF_CHECKED);
        !          2485: 
        !          2486:                         /* change the current view to show only the lines
        !          2487:                          * of the selected type.
        !          2488:                          */
        !          2489:                         if (DisplayMode == MODE_OUTLINE) {
        !          2490:                                 ToExpand(hWnd);
        !          2491:                         } else {
        !          2492:                                 view_changeviewoptions(current_view);
        !          2493:                         }
        !          2494: 
        !          2495: 
        !          2496:                         break;
        !          2497: 
        !          2498: 
        !          2499:                 case IDM_IGNBLANKS:
        !          2500: 
        !          2501:                         /* if selected, ignore all spaces and tabs on
        !          2502:                          * comparison - expand view only: outline view
        !          2503:                          * will still show that 'text files differ'
        !          2504:                          */
        !          2505: 
        !          2506:                         ignore_blanks = !ignore_blanks;
        !          2507:                         CheckMenuItem(hMenu, IDM_IGNBLANKS,
        !          2508:                                 ignore_blanks? MF_CHECKED:MF_UNCHECKED);
        !          2509:                         wsprintf((LPTSTR)str, "%d", ignore_blanks);
        !          2510:                         WriteProfileString(APPNAME, "Blanks", str);
        !          2511: 
        !          2512:                         /* invalidate all diffs since we have
        !          2513:                          * changed diff options, and re-do and display the
        !          2514:                          * current diff if we are in expand mode.
        !          2515:                          */
        !          2516:                         view_changediffoptions(current_view);
        !          2517: 
        !          2518:                         /* force repaint of bar window */
        !          2519:                         InvalidateRect(hwndBar, NULL, TRUE);
        !          2520: 
        !          2521:                         break;
        !          2522: 
        !          2523:                 case IDM_PICTURE:
        !          2524:                         /* do we show the bar picture in expand mode ? */
        !          2525:                         picture_mode = !picture_mode;
        !          2526:                         CheckMenuItem(hMenu, IDM_PICTURE,
        !          2527:                                 picture_mode? MF_CHECKED:MF_UNCHECKED);
        !          2528:                         wsprintf((LPTSTR)str, "%d", picture_mode);
        !          2529:                         WriteProfileString(APPNAME, "Picture", str);
        !          2530:                         DoResize(hWnd);
        !          2531:                         break;
        !          2532: 
        !          2533: 
        !          2534:                 case IDM_EXPAND:
        !          2535: 
        !          2536:                         /* show the expanded view of the
        !          2537:                          * selected file
        !          2538:                          */
        !          2539:                         if (current_view != NULL) {
        !          2540:                                 ToExpand(hWnd);
        !          2541:                         }
        !          2542: 
        !          2543:                         break;
        !          2544: 
        !          2545:                 case IDM_OUTLINE:
        !          2546:                         /* return to the outline view (list of filenames) */
        !          2547:                         ToOutline(hWnd);
        !          2548: 
        !          2549:                         break;
        !          2550: 
        !          2551:                 case IDM_FCHANGE:
        !          2552:                         /* find the next line in the current view
        !          2553:                          * that is not the same in both files -
        !          2554:                          * in outline view, finds the next filename that
        !          2555:                          * is not identical
        !          2556:                          */
        !          2557:                         FindNextChange();
        !          2558: 
        !          2559:                         break;
        !          2560: 
        !          2561:                 case IDM_FPCHANGE:
        !          2562:                         /* same as IDM_FCHANGE, but going backwards from
        !          2563:                          * current position
        !          2564:                          */
        !          2565:                         FindPrevChange();
        !          2566: 
        !          2567:                         break;
        !          2568:                 }
        !          2569:                 break;
        !          2570: 
        !          2571:         case WM_SIZE:
        !          2572:                 DoResize(hWnd);
        !          2573:                 break;
        !          2574: 
        !          2575:         case WM_SETFOCUS:
        !          2576:                 /* set the focus on the table class so it can process
        !          2577:                  * page-up /pagedown keys etc.
        !          2578:                  */
        !          2579:                 SetFocus(hwndRCD);
        !          2580:                 break;
        !          2581: 
        !          2582:         case WM_KEYDOWN:
        !          2583:                 /* although the table window has the focus, he passes
        !          2584:                  * back to us any keys he doesn't understand
        !          2585:                  * We handle escape here to mean 'return to outline view'
        !          2586:                  */
        !          2587:                 if (wParam == VK_ESCAPE) {
        !          2588:                         ToOutline(hWnd);
        !          2589:                 }
        !          2590:                 break;
        !          2591: 
        !          2592:         case WM_CLOSE:
        !          2593:                 /* don't allow close when busy - process this message in
        !          2594:                  * order to ensure this
        !          2595:                  */
        !          2596:                 if (IsBusy()) {
        !          2597:                         return(TRUE);
        !          2598:                 } else {
        !          2599:                         return(DefWindowProc(hWnd, message, wParam, lParam));
        !          2600:                 }
        !          2601:                 break;
        !          2602: 
        !          2603:         case WM_DESTROY:
        !          2604: 
        !          2605:                 DeleteTools();
        !          2606:                 PostQuitMessage(0);
        !          2607:                 break;
        !          2608: 
        !          2609:         case TM_CURRENTVIEW:
        !          2610:                 /* allow other people such as the bar window to query the
        !          2611:                  * current view
        !          2612:                  */
        !          2613:                 return((DWORD) current_view);
        !          2614: 
        !          2615:         default:
        !          2616:                 /* handle registered table messages */
        !          2617:                 if (message == table_msgcode) {
        !          2618:                         ret = TableServer(hWnd, wParam, lParam);
        !          2619:                         return(ret);
        !          2620:                 }
        !          2621:                 return(DefWindowProc(hWnd, message, wParam, lParam));
        !          2622:         }
        !          2623:         return(0);
        !          2624: }
        !          2625: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.