Annotation of mstools/samples/sdktools/windiff/windiff.c, revision 1.1.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.