1
0
Files
irix-657m-src/eoe/cmd/xdiff/xdMain.c
2022-09-29 17:59:04 +03:00

980 lines
35 KiB
C

/****************************************************************************/
/* xdMain.c */
/****************************************************************************/
/*
* Produce a graphical difference of two files.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Copyright (c) 1994 Rudy Wortel. All rights reserved.
*/
/*
* $Source: /proj/irix6.5.7m/isms/eoe/cmd/xdiff/RCS/xdMain.c,v $
* $Revision: 1.3 $
* $Author: olson $
* $Date: 1995/03/18 01:53:32 $
*/
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <xdDiff.h>
#include <xdGUI.h>
#include <xdProto.h>
static XtResource appResources[] = {
{ "stdinName", "StdinName", XtRString, sizeof (String),
XtOffsetOf( ApplicationData, stdinName ),
XtRString, (XtPointer) "<stdin>" },
{ "tabWidth", "TabWidth", XtRInt, sizeof (int),
XtOffsetOf( ApplicationData, tabWidth ),
XtRImmediate, (XtPointer) 8 },
{ "confirmWrite", "ConfirmWrite", XtRBoolean, sizeof (Boolean),
XtOffsetOf( ApplicationData, confirmWrite ),
XtRImmediate, (XtPointer) True },
};
static XrmOptionDescRec appOptions[] = {
{ "-", NULL, XrmoptionSkipNArgs, 0 },
{ "-w", NULL, XrmoptionSkipNArgs, 0 },
{ "-b", NULL, XrmoptionSkipNArgs, 0 },
{ "-i", NULL, XrmoptionSkipNArgs, 0 },
{ "-D", NULL, XrmoptionSkipNArgs, 0 },
{ "-N", "*stdinName", XrmoptionSepArg, NULL },
{ "-tabs", "*tabWidth", XrmoptionSepArg, NULL },
};
static char *xdAttributes[] = {
"Common",
"Only",
"Absent",
"Changed",
"Selected",
"Deleted"
};
xdMenuButton xdFileButtons[] = {
{ "saveLeft", saveAsLeftCallback },
{ "saveRight", saveAsRightCallback },
{ "saveAs", saveAsCallback },
{ NULL, NULL },
{ "exit", exitCallback },
};
xdMenuButton xdEditButtons[] = {
{ "search", searchCallback },
{ "searchNext", searchNextCallback },
{ "searchPrevious", searchPreviousCallback },
{ NULL, NULL },
{ "scrollDown", scrollDownCallback },
{ "scrollUp", scrollUpCallback },
{ "cursorDown", cursorDownCallback },
{ "cursorUp", cursorUpCallback },
{ "cursorTop", cursorTopCallback },
{ "cursorBottom", cursorBottomCallback },
#ifdef __RedoDiff__
{ NULL, NULL },
{ "redoDiff", redoDiffCallback },
#endif /* __RedoDiff__ */
};
xdMenuButton xdGlobalButtons[] = {
{ "selectGlobalLeft", selectGlobalLeftCallback },
{ "selectGlobalRight", selectGlobalRightCallback },
{ "selectGlobalNeither", selectGlobalNeitherCallback },
{ "unselectGlobal", unselectGlobalCallback },
{ NULL, NULL },
{ "tabs4", tabsAt4Callback },
{ "tabs8", tabsAt8Callback },
{ NULL, NULL },
{ "lineNumbers", lineNumbersCallback },
};
xdMenuButton xdRegionButtons[] = {
{ "selectRegionLeft", selectRegionLeftCallback },
{ "selectRegionRight", selectRegionRightCallback },
{ "selectRegionNeither", selectRegionNeitherCallback },
{ "unselectRegion", unselectRegionCallback },
{ NULL, NULL },
{ "splitRight", splitRightCallback },
{ "splitLeft", splitLeftCallback },
};
xdMenuButton xdLineButtons[] = {
{ "selectLineLeft", selectLineLeftCallback },
{ "selectLineRight", selectLineRightCallback },
{ "selectLineNeither", selectLineNeitherCallback },
{ "unselectLine", unselectLineCallback },
};
xdMenuButton xdHelpButtons[] = {
{ "onContext", helpOnContextCallback },
{ NULL, NULL },
{ "aboutXdiff", aboutXdiffCallback },
};
xdMenuButton xdPopupButtons[] = {
{ "nextDifference", nextDifferenceCallback },
{ "previousDifference", previousDifferenceCallback },
{ "nextUnselected", nextUnselectedCallback },
{ "previousUnselected", previousUnselectedCallback },
};
xdPullDown xdMainMenuBar[] = {
{ "fileMenu", xdFileButtons, XtNumber( xdFileButtons ) },
{ "editMenu", xdEditButtons, XtNumber( xdEditButtons ) },
{ "globalMenu", xdGlobalButtons, XtNumber( xdGlobalButtons ) },
{ "regionMenu", xdRegionButtons, XtNumber( xdRegionButtons ) },
{ "lineMenu", xdLineButtons, XtNumber( xdLineButtons ) },
{ "helpMenu", xdHelpButtons, XtNumber( xdHelpButtons ) },
};
xdPullDown xdPopupMenu[] = {
{ "popupMenu", xdPopupButtons, XtNumber( xdPopupButtons ) },
};
/****************************************************************************/
void attachScrollBarCallbacks (
/*
* Attach all the required callbacks to the given scroll bar.
*/
Widget sb, /*< Scroll Bar Widget. */
XtCallbackProc callback, /*< Callback procedure. */
XtPointer data /*< User data. */
)
{ /**************************************************************************/
XtAddCallback( sb, XmNtoTopCallback, callback, data );
XtAddCallback( sb, XmNtoBottomCallback, callback, data );
XtAddCallback( sb, XmNdragCallback, callback, data );
XtAddCallback( sb, XmNincrementCallback, callback, data );
XtAddCallback( sb, XmNdecrementCallback, callback, data );
XtAddCallback( sb, XmNpageIncrementCallback, callback, data );
XtAddCallback( sb, XmNpageDecrementCallback, callback, data );
}
/****************************************************************************/
void createMainForm (
/*
* Create a XmForm to contain the application widget heirarchy listed below.
*
* mainForm{ viewFrame, textForm }
* viewFrame{ viewArea }
* textForm{ messageLine, spacer, verticalScroll,
* leftScroll, rightScroll, leftFrame, rightFrame }
* rightFrame{ rightWindow }
* rightWindow{ rightPopup }
* leftFrame{ rightWindow }
* leftWindow{ leftPopup }
*/
ApplicationData *appData /*< All application Data. */
)
{ /**************************************************************************/
Widget frame; /* frame widget for the drawing areas. */
Widget spacer; /* spacer for centrering the scroll bar. */
Widget popUp; /* a popup for the text areas. */
appData->mainForm =
XmCreateForm( appData->mainWindow, "mainForm", NULL, 0 );
XtVaSetValues( appData->mainForm,
XmNfractionBase, 100,
XmNrubberPositioning, True,
0 );
XtAddEventHandler( appData->mainForm, StructureNotifyMask, False,
(XtEventHandler) resizeEventHandler, appData );
frame = XmCreateFrame( appData->mainForm, "viewFrame", NULL, 0 );
XtVaSetValues( frame,
XmNrightAttachment, XmATTACH_FORM,
XmNtopAttachment, XmATTACH_FORM,
XmNbottomAttachment, XmATTACH_FORM,
XmNfractionBase, 100,
XmNrubberPositioning, True,
0 );
appData->viewArea = XmCreateDrawingArea( frame, "viewWindow", NULL, 0 );
XtVaSetValues( appData->viewArea,
XmNwidth, 60,
XmNrightAttachment, XmATTACH_FORM,
XmNtopAttachment, XmATTACH_FORM,
XmNbottomAttachment, XmATTACH_FORM,
XmNuserData, appData,
0 );
XtManageChild( appData->viewArea );
XtAddCallback( appData->viewArea,
XmNexposeCallback, viewAreaExposeCallback, appData );
XtAddCallback( appData->viewArea,
XmNinputCallback, viewAreaInputCallback, appData );
XtAddCallback( appData->viewArea,
XmNhelpCallback, helpCallback, "viewWindow" );
XtManageChild( frame );
appData->textForm = XmCreateForm( appData->mainForm, "textForm", NULL, 0 );
XtVaSetValues( appData->textForm,
XmNrubberPositioning, True,
XmNfractionBase, 100,
XmNleftAttachment, XmATTACH_FORM,
XmNrightAttachment, XmATTACH_WIDGET,
XmNrightWidget, frame,
XmNtopAttachment, XmATTACH_FORM,
XmNbottomAttachment, XmATTACH_FORM,
0 );
appData->messageLine =
XmCreateLabel( appData->textForm, "messageLine", NULL, 0 );
XtVaSetValues( appData->messageLine,
XmNlabelString, XmStringCreate( " ",
XmSTRING_DEFAULT_CHARSET ),
XmNalignment, XmALIGNMENT_BEGINNING,
XmNleftAttachment, XmATTACH_FORM,
XmNrightAttachment, XmATTACH_FORM,
XmNtopAttachment, XmATTACH_FORM,
XmNuserData, appData,
0 );
XtManageChild( appData->messageLine );
XtAddCallback( appData->messageLine,
XmNhelpCallback, helpCallback, "messageLine" );
spacer = XmCreateLabelGadget( appData->textForm, " ", NULL, 0 );
XtVaSetValues( spacer,
XmNrightAttachment, XmATTACH_POSITION,
XmNrightPosition, 50,
XmNwidth, 10,
XmNheight, 20,
XmNbottomAttachment, XmATTACH_FORM,
XmNsensitive, False,
0 );
XtManageChild( spacer );
appData->vertScroll =
XmCreateScrollBar( appData->textForm, "verticalScroll", NULL, 0 );
XtVaSetValues( appData->vertScroll,
XmNorientation, XmVERTICAL,
XmNwidth, 20,
XmNvalue, 1,
XmNsliderSize, 1,
XmNminimum, 1,
XmNmaximum, (appData->diffs.lines == 0) ?
2 : appData->diffs.lines + 1,
XmNresizeHeight, True,
XmNresizeWidth, True,
XmNleftAttachment, XmATTACH_OPPOSITE_WIDGET,
XmNleftWidget, spacer,
XmNtopAttachment, XmATTACH_WIDGET,
XmNtopWidget, appData->messageLine,
XmNbottomAttachment, XmATTACH_WIDGET,
XmNbottomWidget, spacer,
XmNuserData, appData,
0 );
XtManageChild( appData->vertScroll );
attachScrollBarCallbacks( appData->vertScroll,
scrollVerticalCallback, appData );
XtAddCallback( appData->vertScroll,
XmNhelpCallback, helpCallback, "verticalScroll" );
appData->leftScroll =
XmCreateScrollBar( appData->textForm, "leftScroll", NULL, 0 );
XtVaSetValues( appData->leftScroll,
XmNorientation, XmHORIZONTAL,
XmNheight, 20,
XmNleftAttachment, XmATTACH_FORM,
XmNrightAttachment, XmATTACH_WIDGET,
XmNrightWidget, appData->vertScroll,
XmNbottomAttachment, XmATTACH_FORM,
XmNuserData, appData,
0 );
XtManageChild( appData->leftScroll );
attachScrollBarCallbacks( appData->leftScroll,
scrollLeftCallback, appData );
XtAddCallback( appData->leftScroll,
XmNhelpCallback, helpCallback, "horizontalScroll" );
frame = XmCreateFrame( appData->textForm, "leftFrame", NULL, 0 );
XtVaSetValues( frame,
XmNleftAttachment, XmATTACH_FORM,
XmNrightAttachment, XmATTACH_WIDGET,
XmNrightWidget, appData->vertScroll,
XmNtopAttachment, XmATTACH_WIDGET,
XmNtopWidget, appData->messageLine,
XmNbottomAttachment, XmATTACH_WIDGET,
XmNbottomWidget, appData->leftScroll,
0 );
XtManageChild( frame );
appData->leftWindow = XmCreateDrawingArea( frame, "leftWindow", NULL, 0 );
XtVaSetValues( appData->leftWindow,
XmNuserData, appData,
0 );
XtManageChild( appData->leftWindow );
XtAddCallback( appData->leftWindow,
XmNexposeCallback, leftWindowExposeCallback, appData );
XtAddCallback( appData->leftWindow,
XmNinputCallback, leftWindowInputCallback, appData );
XtAddCallback( appData->leftWindow,
XmNhelpCallback, helpCallback, "textWindow" );
popUp = XmCreatePopupMenu( appData->leftWindow, "leftPopup", NULL, 0 );
createPullDown( appData, popUp, xdPopupMenu );
XtAddEventHandler( appData->leftWindow,
ButtonPressMask, False, postDrawingAreaMenu, popUp );
appData->rightScroll =
XmCreateScrollBar( appData->textForm, "rightScroll", NULL, 0 );
XtVaSetValues( appData->rightScroll,
XmNorientation, XmHORIZONTAL,
XmNheight, 20,
XmNrightAttachment, XmATTACH_FORM,
XmNleftAttachment, XmATTACH_WIDGET,
XmNleftWidget, appData->vertScroll,
XmNbottomAttachment, XmATTACH_FORM,
XmNuserData, appData,
0 );
XtManageChild( appData->rightScroll );
attachScrollBarCallbacks( appData->rightScroll,
scrollRightCallback, appData );
XtAddCallback( appData->rightScroll,
XmNhelpCallback, helpCallback, "horizontalScroll" );
frame = XmCreateFrame( appData->textForm, "rightFrame", NULL, 0 );
XtVaSetValues( frame,
XmNrightAttachment, XmATTACH_FORM,
XmNleftAttachment, XmATTACH_WIDGET,
XmNleftWidget, appData->vertScroll,
XmNtopAttachment, XmATTACH_WIDGET,
XmNtopWidget, appData->messageLine,
XmNbottomAttachment, XmATTACH_WIDGET,
XmNbottomWidget, appData->rightScroll,
0 );
XtManageChild( frame );
appData->rightWindow = XmCreateDrawingArea( frame, "rightWindow", NULL, 0 );
XtVaSetValues( appData->rightWindow,
XmNuserData, appData,
0 );
XtManageChild( appData->rightWindow );
XtAddCallback( appData->rightWindow,
XmNexposeCallback, rightWindowExposeCallback, appData );
XtAddCallback( appData->rightWindow,
XmNinputCallback, rightWindowInputCallback, appData );
XtAddCallback( appData->rightWindow,
XmNhelpCallback, helpCallback, "textWindow" );
popUp = XmCreatePopupMenu( appData->rightWindow, "rightPopup", NULL, 0 );
createPullDown( appData, popUp, xdPopupMenu );
XtAddEventHandler( appData->rightWindow,
ButtonPressMask, False, postDrawingAreaMenu, popUp );
XtManageChild( appData->textForm );
XtManageChild( appData->mainForm );
}
/****************************************************************************/
void createPullDown (
/*
* Create all the buttons for a PullDown menu Pane.
*/
ApplicationData *appData, /*< All application Data. */
Widget parent, /*< Parent XmPullDownMenu widget. */
xdPullDown *pullDown /*< This list of buttons in the pulldown. */
)
{ /**************************************************************************/
Widget widget;
String accelerator;
XmString acceleratorText;
XmString string;
xdMenuButton *menuButton;
Arg argv[ 10 ];
int argc;
int button;
for( button = 0; button < pullDown->n; ++button ){
menuButton = &pullDown->buttons[ button ];
if( menuButton->name == NULL ){
widget = XmCreateSeparator( parent, "-", NULL, 0 );
}else{
XtSetArg( argv[ 0 ], XmNuserData, appData );
argc = 1;
widget = XmCreatePushButton( parent, menuButton->name, argv, argc );
if( menuButton->inputCallback != NULL ){
XtAddCallback( widget, XmNactivateCallback,
menuButton->inputCallback, appData );
}
accelerator = NULL;
acceleratorText = NULL;
XtVaGetValues( widget,
XmNaccelerator, &accelerator,
XmNacceleratorText, &acceleratorText,
0 );
if( accelerator != NULL && acceleratorText == NULL ){
string = XmStringCreate(
accelerator, XmSTRING_DEFAULT_CHARSET );
XtVaSetValues( widget,
XmNacceleratorText, string,
XmNuserData, appData,
0 );
XmStringFree( string );
}
if( !strcmp( menuButton->name, "saveRight" ) ){
if( !(appData->diffs.flags & XD_RIGHT_WRITABLE) ){
XtVaSetValues( widget,
XmNsensitive, False,
0 );
}
}else if( !strcmp( menuButton->name, "saveLeft" ) ){
if( !(appData->diffs.flags & XD_LEFT_WRITABLE) ){
XtVaSetValues( widget,
XmNsensitive, False,
0 );
}
}
}
XtManageChild( widget );
}
}
/****************************************************************************/
void createMenuBar (
/*
* Encapsulation of the creation the Menu Bar and all of its pulldowns.
*/
ApplicationData *appData, /*< All application Data. */
Widget parent, /*< Parent widget for the menu bar. */
xdPullDown pulldowns[], /*< What do you want to put in it. */
int nPulldowns /*< How many are there. */
)
{ /**************************************************************************/
Widget menuBar;
Widget pullDown;
Widget cascadeButton;
xdPullDown *menuItem;
Arg argv[ 10 ];
int menu;
XtSetArg( argv[ 0 ], XmNuserData, appData );
menuBar = XmCreateMenuBar( parent, "menuBar", argv, 1 );
for( menu = 0; menu < nPulldowns; ++menu ){
menuItem = &pulldowns[ menu ];
pullDown = XmCreatePulldownMenu( menuBar, menuItem->name, NULL, 0 );
createPullDown( appData, pullDown, menuItem );
XtSetArg( argv[ 0 ], XmNsubMenuId, pullDown );
XtSetArg( argv[ 1 ], XmNuserData, appData );
cascadeButton = XmCreateCascadeButton(
menuBar, menuItem->name, argv, 2 );
XtAddCallback( cascadeButton,
XmNhelpCallback, helpCallback, menuItem->name );
/* Menu specfic things */
if( strcmp( menuItem->name, "helpMenu" ) == 0 ){
XtVaSetValues( menuBar,
XmNmenuHelpWidget, cascadeButton,
0 );
}
XtManageChild( cascadeButton );
}
XtAddCallback( menuBar, XmNhelpCallback, helpCallback, "menuBar" );
XtManageChild( menuBar );
}
/****************************************************************************/
void createTransients (
/*
* Create and attach the transient shells.
*/
ApplicationData *appData /*< All application Data. */
)
{ /**************************************************************************/
Widget button;
/* Create the File lister and it's popup shell */
appData->selectorShell = XtCreatePopupShell( "fileLister",
transientShellWidgetClass, appData->mainWindow, NULL, 0 );
XtVaSetValues( appData->selectorShell,
XmNallowShellResize,True,
XmNdeleteResponse, XmUNMAP,
0 );
appData->fileSelector = XmCreateFileSelectionBox(
appData->selectorShell, "fileLister", NULL, 0 );
XtManageChild( appData->fileSelector );
XtAddCallback( appData->fileSelector,
XmNokCallback, listerOkCallback, appData );
XtAddCallback( appData->fileSelector,
XmNcancelCallback, listerCancelCallback, appData );
button = XmFileSelectionBoxGetChild(
appData->fileSelector, XmDIALOG_HELP_BUTTON );
XtUnmanageChild( button );
/* Simple confirm shell */
appData->confirmShell = XtCreatePopupShell( "confirmWindow",
transientShellWidgetClass, appData->mainWindow, NULL, 0 );
XtVaSetValues( appData->confirmShell,
XmNdeleteResponse, XmDO_NOTHING,
XmNallowShellResize,True,
0 );
appData->messageBox = XmCreateMessageBox(
appData->confirmShell, "messageBox", NULL, 0 );
XtVaSetValues( appData->messageBox,
XmNresizable, True,
XmNdialogType, XmDIALOG_QUESTION,
0 );
XtManageChild( appData->messageBox );
XtAddCallback( appData->messageBox,
XmNokCallback, confirmCallback, appData );
XtAddCallback( appData->messageBox,
XmNcancelCallback, confirmCallback, appData );
/* Defer the creation of the search Shell. */
appData->searchShell = NULL;
}
/****************************************************************************/
void createApplicationWidgets (
/*
* Create the top level application Widgets.
*/
ApplicationData *appData /*< All application Data. */
)
{ /**************************************************************************/
appData->mainWindow =
XmCreateMainWindow( appData->appShell, "mainWindow", NULL, 0 );
createMenuBar( appData,
appData->mainWindow, xdMainMenuBar, XtNumber( xdMainMenuBar ) );
createMainForm( appData );
createTransients( appData );
XtManageChild( appData->mainWindow );
}
/****************************************************************************/
void xdLoadAttributes (
/*
* Load the fonts and colours for the various states and calculate
* the maximum bounds of the characters. If the resources are not specified
* use the common font.
*/
ApplicationData *appData /*< All application Data. */
)
{ /**************************************************************************/
Display *display;
char *appClass;
XFontStruct *font;
Colormap colourMap;
XColor rgb;
Pixel foregroundColour;
Pixel backgroundColour;
char resourceName[ 100 ];
char *resourceValue;
int i;
appData->maxBounds.width = -1;
appData->maxBounds.ascent = -1;
appData->maxBounds.descent = -1;
appData->screen = DefaultScreen( appData->display );
appData->gc = XCreateGC( appData->display,
RootWindow( appData->display, appData->screen ), 0, 0 );
display = XtDisplay( appData->appShell );
appClass = appData->appClass;
colourMap = DefaultColormap( appData->display, appData->screen );
/* find out the fonts and colours for all the display states. */
for( i = 0; i < XtNumber( xdAttributes ); ++i ){
foregroundColour = 0;
sprintf( resourceName, "fgc%s", xdAttributes[ i ] );
resourceValue = xdGetDefault( display, appClass, resourceName );
if( XParseColor( display, colourMap, resourceValue, &rgb ) ){
if( XAllocColor( display, colourMap, &rgb ) ){
foregroundColour = rgb.pixel;
}else{
fprintf( stderr, "Can't allocate colour for %s\n",
resourceName );
}
}else{
fprintf( stderr, "Can't get default for %s\n", resourceName );
}
backgroundColour = 0;
sprintf( resourceName, "bgc%s", xdAttributes[ i ] );
resourceValue = xdGetDefault( display, appClass, resourceName );
if( XParseColor( display, colourMap, resourceValue, &rgb ) ){
if( XAllocColor( display, colourMap, &rgb ) ){
backgroundColour = rgb.pixel;
}else{
fprintf( stderr, "Can't allocate colour for %s\n",
resourceName );
}
}else{
fprintf( stderr, "Can't get default for %s\n", resourceName );
}
sprintf( resourceName, "font%s", xdAttributes[ i ] );
resourceValue = xdGetDefault( display, appClass, resourceName );
font = XLoadQueryFont( display, resourceValue );
if( font != NULL ){
if( font->max_bounds.width > appData->maxBounds.width ){
appData->maxBounds.width = font->max_bounds.width;
}
if( font->max_bounds.ascent > appData->maxBounds.ascent ){
appData->maxBounds.ascent = font->max_bounds.ascent;
}
if( font->max_bounds.descent > appData->maxBounds.descent ){
appData->maxBounds.descent = font->max_bounds.descent;
}
}else{
font = appData->attributes[ 0 ].font;
}
appData->attributes[ i ].foregroundColour = foregroundColour;
appData->attributes[ i ].backgroundColour = backgroundColour;
appData->attributes[ i ].font = font;
}
appData->cursorColour = -1;
resourceValue = xdGetDefault( display, appClass, "cursorColour" );
if( XParseColor( display, colourMap, resourceValue, &rgb ) ){
if( XAllocColor( display, colourMap, &rgb ) ){
appData->cursorColour = rgb.pixel;
}
}
appData->matchColour = appData->cursorColour;
resourceValue = xdGetDefault( display, appClass, "matchColour" );
if( XParseColor( display, colourMap, resourceValue, &rgb ) ){
if( XAllocColor( display, colourMap, &rgb ) ){
appData->matchColour = rgb.pixel;
}
}
}
/****************************************************************************/
void xdUseage (
/*
* Print the useage string for xdiff.
*/
char *program /*< Name of the executable from argv[ 0 ]. */
)
{ /**************************************************************************/
fprintf( stderr, "Usage: %s [-Dwbi] [-N name] path1 path2\n", program );
}
/****************************************************************************/
Boolean xdBuildFileNames (
/*
* Given two paths build the two file names. NULL means <stdin>.
*/
ApplicationData *appData /*| All application Data. */
)
{ /**************************************************************************/
char fileName[ 1000 ];
struct stat statbuf[ 2 ];
char *slash;
int path;
int stdinPaths;
int dirPaths;
int filePaths;
int status;
status = True;
stdinPaths = 0;
dirPaths = 0;
filePaths = 0;
/* make sure paths exist */
for( path = 0; path < 2; ++path ){
if( appData->pathNames[ path ] == NULL ){
++stdinPaths;
}else{
if( stat( appData->pathNames[ path ], &statbuf[ path ] ) == -1 ){
fprintf( stderr, "%s: Can't open '%s'\n",
appData->appInstance, appData->pathNames[ path ] );
status = False;
}else{
switch( statbuf[ path ].st_mode & S_IFMT ){
case S_IFDIR:
++dirPaths;
break;
case S_IFREG:
++filePaths;
break;
default:
fprintf( stderr, "%s: '%s' has illegal file type\n",
appData->appInstance, appData->pathNames[ path ] );
status = False;
break;
}
}
}
}
if( status == True ){
if( stdinPaths > 1 ){
fprintf( stderr, "%s: Only one path may be <stdin>\n",
appData->appInstance );
status = False;
}else if( dirPaths > 1 ){
fprintf( stderr, "%s: Only one path may be a directory\n",
appData->appInstance );
status = False;
}else if( filePaths == 0 ){
fprintf( stderr, "%s: One path must be a regular file\n",
appData->appInstance );
status = False;
}else{
/* We must have a valid pair of path names by now. */
if( appData->pathNames[ 0 ] == NULL ){
appData->diffs.lfile = NULL;
}else if( (statbuf[ 0 ].st_mode & S_IFMT) == S_IFDIR ){
if( (slash = strrchr( appData->pathNames[ 1 ], '/' )) == NULL ){
sprintf( fileName, "%s/%s",
appData->pathNames[ 0 ], appData->pathNames[ 1 ] );
}else{
sprintf( fileName, "%s%s", appData->pathNames[ 0 ], slash );
}
appData->diffs.lfile = strdup( fileName );
}else{
appData->diffs.lfile = strdup( appData->pathNames[ 0 ] );
}
if( appData->diffs.lfile == NULL ||
access( appData->diffs.lfile, 2 ) == 0 ){
appData->diffs.flags |= XD_LEFT_WRITABLE;
}else{
appData->diffs.flags &= ~XD_LEFT_WRITABLE;
}
if( appData->pathNames[ 1 ] == NULL ){
appData->diffs.rfile = NULL;
}else if( (statbuf[ 1 ].st_mode & S_IFMT) == S_IFDIR ){
if( (slash = strrchr( appData->pathNames[ 0 ], '/' )) == NULL ){
sprintf( fileName, "%s/%s",
appData->pathNames[ 1 ], appData->pathNames[ 0 ] );
}else{
sprintf( fileName, "%s%s", appData->pathNames[ 1 ], slash );
}
appData->diffs.rfile = strdup( fileName );
}else{
appData->diffs.rfile = strdup( appData->pathNames[ 1 ] );
}
if( appData->diffs.rfile == NULL ||
access( appData->diffs.rfile, 2 ) == 0 ){
appData->diffs.flags |= XD_RIGHT_WRITABLE;
}else{
appData->diffs.flags &= ~XD_RIGHT_WRITABLE;
}
}
}
return status;
}
/****************************************************************************/
Boolean xdParseArgs (
/*
* Parse the remaining arguments after X11 is done with them.
*/
ApplicationData *appData, /*| All application Data. */
int argc, /*< Argument count. */
char *argv[] /*< Argument vector. */
)
{ /**************************************************************************/
int arg;
int path;
char *opt;
path = 0;
for( arg = 1; arg < argc; ++arg ){
opt = argv[ arg ];
if( *opt == '-' ){
if( *++opt == '\0' ){
/* Simple '-' as an argument means use stdin for the file. */
if( path < 2 ){
appData->pathNames[ path ] = NULL;
++path;
}
}else{
for( ; *opt != '\0'; ++opt ){
switch( *opt ){
case 'w':
appData->diffs.flags |= XD_IGN_TRAILING;
break;
case 'b':
appData->diffs.flags |= XD_IGN_WHITESPACE;
break;
case 'i':
appData->diffs.flags |= XD_IGN_CASE;
break;
case 'D':
appData->diffs.flags |= XD_EXIT_NODIFF;
break;
default:
fprintf( stderr, "%s: Unknown option '%c'\n",
appData->appInstance, *opt );
break;
}
}
}
}else{
/* Treat it as a path name */
if( path < 2 ){
appData->pathNames[ path ] = argv[ arg ];
++path;
}
}
}
return (path == 2);
}
/****************************************************************************/
int main (
/*
* Standard main function.
*/
int argc, /*< Standard main line arguments. */
char *argv[],
char *envp[]
)
{ /**************************************************************************/
ApplicationData appData; /* All application data. */
char windowTitle[ 1000 ]; /* Title for window title bar. */
int differences; /* How many differences are there. */
memset( &appData, 0, sizeof appData );
if( (appData.appInstance = strrchr( argv[ 0 ], '/' )) == NULL ){
appData.appInstance = argv[ 0 ];
}else{
++appData.appInstance;
}
appData.appClass = "Xdiff";
XtToolkitInitialize();
appData.appContext = XtCreateApplicationContext();
appData.display = XtOpenDisplay( appData.appContext,
NULL, appData.appInstance, appData.appClass,
appOptions, XtNumber( appOptions ), &argc, argv );
if( appData.display == NULL ){
fprintf( stderr, "%s: Can't open display\n", appData.appInstance );
exit( -1 );
}
appData.appShell = XtAppCreateShell( appData.appInstance,
appData.appClass, applicationShellWidgetClass, appData.display,
NULL, 0 );
XtGetApplicationResources( appData.appShell, &appData,
appResources, XtNumber( appResources ), NULL, 0 );
xdLoadAttributes( &appData );
if( xdParseArgs( &appData, argc, argv ) == False ||
xdBuildFileNames( &appData ) == False ){
xdUseage( appData.appInstance );
exit( -1 );
}
if( (differences = xdBuildDiffs( &appData.diffs )) == -1 ){
exit( -1 );
}
if( !(appData.diffs.flags & XD_EXIT_NODIFF) || differences > 0 ){
appData.lineNumbers = False;
sprintf( windowTitle, "%.200s <-> %.200s",
(appData.diffs.lfile == NULL) ?
appData.stdinName : appData.diffs.lfile,
(appData.diffs.rfile == NULL) ?
appData.stdinName : appData.diffs.rfile );
XtVaSetValues( appData.appShell, XmNtitle, windowTitle, 0 );
createApplicationWidgets( &appData );
XtRealizeWidget( appData.appShell );
XtAppMainLoop( appData.appContext );
}
exit( 0 );
}