cdesktopenv/cde/lib/DtWidget/SearchCalls.c

1383 lines
37 KiB
C

/*
* CDE - Common Desktop Environment
*
* Copyright (c) 1993-2012, The Open Group. All rights reserved.
*
* These libraries and programs are free software; you can
* redistribute them and/or modify them under the terms of the GNU
* Lesser General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* These libraries and programs are distributed in the hope that
* they will be useful, but WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with these libraries and programs; if not, write
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
* Floor, Boston, MA 02110-1301 USA
*/
/* $XConsortium: SearchCalls.c /main/13 1996/11/21 20:00:02 drk $ */
/**********************************<+>*************************************
***************************************************************************
**
** File: SearchCalls.c
**
** Project: DtEditor widget for editing services
**
** Description: Spell and Find functions
** -----------
**
*******************************************************************
*
* (c) Copyright 1996 Digital Equipment Corporation.
* (c) Copyright 1993, 1994, 1996 Hewlett-Packard Company.
* (c) Copyright 1993, 1994, 1996 International Business Machines Corp.
* (c) Copyright 1993, 1994, 1996 Sun Microsystems, Inc.
* (c) Copyright 1996 Novell, Inc.
* (c) Copyright 1996 FUJITSU LIMITED.
* (c) Copyright 1996 Hitachi.
* (c) Copyright 1993, 1994 Unix System Labs, Inc., a subsidiary of Novell, Inc.
*
********************************************************************/
#include "EditorP.h"
#include <Xm/TextF.h>
#include <Xm/MessageB.h>
#include <Xm/List.h>
#include <ctype.h>
#include <limits.h>
#include <Dt/DtMsgsP.h>
#include <Dt/HourGlass.h>
#include "DtWidgetI.h"
#include <Xm/XmPrivate.h> /* _XmStringSourceGetString */
#define X_INCLUDE_STRING_H
#define XOS_USE_XT_LOCKING
#include <X11/Xos_r.h>
extern XtPointer
_XmStringUngenerate(XmString string,
XmStringTag tag,
XmTextType tag_type,
XmTextType output_type);
static Boolean DoReplace(
DtEditorWidget pPriv,
char *replace_string,
Time time);
static int SearchForString(
DtEditorWidget pPriv,
XmTextPosition startLocation,
char *searchString);
static Boolean DoSearch(
DtEditorWidget pPriv,
char *search_string,
Time time);
static Boolean IsValidFilter(
DtEditorWidget pPriv);
static Boolean IsInGroup(
gid_t gid);
static Boolean IsExecutable(
struct stat statbuf);
static void DestroyThisWidgetCB(
Widget w,
XtPointer client,
XtPointer call);
DtEditorErrorCode
DtEditorInvokeSpellDialog(
Widget widget)
{
DtEditorWidget pPriv = (DtEditorWidget) widget;
char fileName[L_tmpnam], com[L_tmpnam + 7], *string, newline[1];
char *line;
FILE *fp; /* pipe to read words from */
int len = 0; /* length of line read in */
int maxLen = 0; /* max length of the line buffer */
XmString word; /* processed word ready to add to list */
DtEditorErrorCode error = DtEDITOR_NO_TMP_FILE;
_DtWidgetToAppContext(widget);
_DtAppLock(app);
newline[0]='\n';
if (!IsValidFilter(pPriv)) {
error = DtEDITOR_SPELL_FILTER_FAILED;
}
else {
_DtTurnOnHourGlass(M_topLevelShell(pPriv));
/*
* Write out to a tmp file, getting the name back
*/
(void)tmpnam(fileName);
if((fp = fopen(fileName, "w")) != (FILE *)NULL)
{
/*
* Temporary file created sucessfully so write out contents of
* widget in preparation of feeding it to the 'spell' filter.
*/
string = (char *)XmTextGetString(M_text(pPriv));
fwrite(string, sizeof(char), strlen(string), fp);
XtFree(string);
/*
* Tack on a final newline (\n) cuz spell(1) does not spell-check
* lines which do not terminate with a newline.
*/
fwrite(newline, sizeof(char), 1, fp);
fclose(fp);
/* start spell command */
sprintf(com, "%s %s", M_spellFilter(pPriv), fileName);
fp = popen(com, "r");
if ( fp == (FILE *)NULL )
error = DtEDITOR_SPELL_FILTER_FAILED;
else {
error = DtEDITOR_NO_ERRORS;
/*
* The filter was started successfully.
* Initialize the Spell dialog and get ready to receive
* the list of misspelled words.
*/
_DtEditorSearch(pPriv, True, True);
_DtTurnOnHourGlass(M_search_dialog(pPriv));
/* needed for bug in list */
XmListSetPos(M_search_spellList(pPriv), 1);
XmListDeleteAllItems(M_search_spellList(pPriv));
/*
* malloc the buffer
*/
maxLen = 50;
line = (char *) XtMalloc (sizeof(char) * (maxLen + 1));
len = 0;
/*
* Now, get each word and hand it to the list
*/
while(fgets(&line[len], maxLen - len, fp))
{
len += strlen(&line[len]);
if (len > 0)
{
if (line[len - 1] == '\n')
{
line[len - 1] = '\0';
word = XmStringCreateLocalized(line);
XmListAddItemUnselected(M_search_spellList(pPriv), word, 0);
XmStringFree(word);
len = 0;
}
else
{
maxLen += 50;
line = (char *) XtRealloc (line, sizeof(char) * (maxLen + 1));
}
}
}
/* clean up and display the results */
XtFree(line);
pclose(fp);
_DtEditorSearch(pPriv, True, False);
_DtTurnOffHourGlass(M_search_dialog(pPriv));
} /* end start the spell filter */
unlink(fileName);
} /* end create temporary file */
_DtTurnOffHourGlass(M_topLevelShell(pPriv));
}
if (error != DtEDITOR_NO_ERRORS) {
XmString title, msg1, msg2, msg3;
Arg al[10];
Cardinal ac;
char *buf;
Widget dialog;
buf = XtMalloc((strlen(BAD_FILTER2) +
strlen(M_spellFilter(pPriv)) + 1) *
sizeof(char));
sprintf(buf, BAD_FILTER2, M_spellFilter(pPriv));
msg1 = XmStringGenerate(BAD_FILTER,
XmFONTLIST_DEFAULT_TAG,
XmCHARSET_TEXT, NULL);
msg2 = XmStringSeparatorCreate();
msg3= XmStringConcatAndFree(msg1, msg2);
msg1 = XmStringGenerate(buf,
XmFONTLIST_DEFAULT_TAG,
XmCHARSET_TEXT, NULL);
msg2 = XmStringConcatAndFree(msg3, msg1);
XtFree(buf);
title = XmStringCreateLocalized(ERROR_TITLE);
ac = 0;
XtSetArg(al[ac], XmNdialogTitle, title); ac++;
XtSetArg(al[ac], XmNdialogType, XmDIALOG_ERROR); ac++;
XtSetArg(al[ac], XmNmessageString, msg2); ac++;
dialog = XmCreateMessageDialog((Widget)pPriv,
"Spell Error", al, ac
);
XtUnmanageChild(XmMessageBoxGetChild(dialog,
XmDIALOG_HELP_BUTTON));
XtUnmanageChild(XmMessageBoxGetChild(dialog,
XmDIALOG_CANCEL_BUTTON));
XtAddCallback(dialog, XmNokCallback, DestroyThisWidgetCB, NULL);
XtVaSetValues(XtParent(dialog),
XmNdeleteResponse, XmDESTROY,
NULL);
XtManageChild(dialog);
XmStringFree(msg2);
XmStringFree(title);
}
_DtAppUnlock(app);
return( error );
} /* end DtEditorInvokeSpellDialog */
static void DestroyThisWidgetCB (
Widget w,
XtPointer client,
XtPointer call)
{
XtDestroyWidget(w);
}
/* ARGSUSED */
Boolean
DtEditorFind(
Widget widget,
char *find)
{
DtEditorWidget editor = (DtEditorWidget) widget;
Boolean foundIt = True;
_DtWidgetToAppContext(widget);
_DtAppLock(app);
/*
* If we were passed a string to find, then use it. Otherwise,
* use the last find string entered in the Find/Change dialog.
*/
if ( find != (char *)NULL )
foundIt = DoSearch(editor, find, CurrentTime);
else
{
/*
* If there is no value from the dialog, then post the Find/Change
* dialog to get one.
*/
if (!M_search_string(editor))
_DtEditorSearch(editor, False, False);
else
foundIt = DoSearch(editor, M_search_string(editor), CurrentTime);
}
_DtAppUnlock(app);
return( foundIt );
} /* DtEditorFind */
/* Count the number of characters represented in the char* str.
* By definition, if MB_CUR_MAX == 1 then numBytes == number of characters.
* Otherwise, use mblen to calculate.
*/
int
_DtEditor_CountCharacters(
char *str,
int numBytes)
{
char *bptr;
int count = 0;
int char_size = 0;
int mbCurMax = MB_CUR_MAX; /* invoke the macro just once */
if (mbCurMax <= 1)
return (numBytes < 0)? 0 : numBytes;
if (numBytes <=0 || str == NULL || *str == '\0')
return 0;
for(bptr = str; numBytes > 0; count++, bptr+= char_size)
{
char_size = mblen(bptr, mbCurMax);
if (char_size <= 0)
break; /* error */
numBytes -= char_size;
}
return count;
}
/*
* SearchForString takes an Editor widget, a position at which
* to begin its search, and the string for which it is to search.
* It searches first from startLocation to the end of the file, and
* then if necessary from the start of the file to startLocation.
* It returns an integer indicating the location of the string, or
* -1 if the string is not found.
*/
static int
SearchForString(
DtEditorWidget pPriv,
XmTextPosition startLocation,
char *searchString)
{
XmTextPosition pos, searchAnchor, topAnchor, cursorLocation,
lastPosition = XmTextGetLastPosition(M_text(pPriv));
topAnchor = 0;
searchAnchor = cursorLocation = startLocation;
while((Boolean)XmTextFindString(M_text(pPriv), searchAnchor,
searchString, XmTEXT_FORWARD,
&pos) ||
((Boolean)XmTextFindString(M_text(pPriv), topAnchor,
searchString, XmTEXT_FORWARD, &pos) &&
pos < cursorLocation))
{
char *word, leadingChar, trailingChar;
XmTextPosition endPos;
int length;
/*
* Do some extra work for the Spell case, so we find only "words"
* and not strings.
* Get the word with the leading & trailing characters.
* It's a word if it's bounded by:
* a. 16-bit characters
* b. Spaces
* c. Punctuation
*/
/*
* Variables:
*
* 0 (constant) - first character position in the document.
* lastPosition - last character position in the document.
*
* pos - Position in the document of the first character
* of the word. Does not include leading character.
* endPos - Position in the document of the last character
* of the word + 1. Points to the trailing character,
* if any.
*
* word - The string we have matched. Includes the leading
* & trailing characters, if any.
* word[0] - Leading character, if any, otherwise first
* character of the matched string.
* word[length] - Trailing character, if any, otherwise last
* character of the matched string.
*
*/
endPos = pos + 1 + _DtEditor_CountCharacters(searchString,
strlen(searchString));
if(pos < cursorLocation)
topAnchor = pos + 1;
else
searchAnchor = pos + 1;
/*
* If the first character of the word is the first character in
* the document there is no leading character. Likewise, if the
* last character of the word is the last character in the document
* there is no trailing character.
*/
if( pos > 0 ) {
/*
* There is a leading character.
*/
if (endPos <= lastPosition) {
/*
* There is a trailing character.
*/
word = (char *)_XmStringSourceGetString(
(XmTextWidget) M_text(pPriv),
pos - 1, endPos, False);
length = strlen(word) - 1;
trailingChar = word[length];
}
else {
/*
* There is no trailing character.
*/
word = (char *)_XmStringSourceGetString(
(XmTextWidget) M_text(pPriv),
pos - 1, lastPosition, False);
length = strlen(word);
trailingChar = ' ';
}
leadingChar = word[0];
}
else {
/*
* There is no leading character.
*/
if (endPos <= lastPosition) {
/*
* There is a trailing character.
*/
word = (char *)_XmStringSourceGetString(
(XmTextWidget) M_text(pPriv),
0, endPos, False);
length = strlen(word) - 1;
trailingChar = word[length];
}
else {
/*
* There is no trailing character.
*/
word = (char *)_XmStringSourceGetString(
(XmTextWidget) M_text(pPriv),
0, lastPosition, False);
length = strlen(word);
trailingChar = ' ';
}
leadingChar = ' ';
}
if ((M_search_dialogMode(pPriv) != SPELL) ||
(
((mblen(word, MB_CUR_MAX) > 1) ||
( isascii(leadingChar) &&
(isspace(leadingChar) || ispunct(leadingChar))
)
) &&
((mblen(word+length-1, MB_CUR_MAX) > 1) ||
( isascii(trailingChar) &&
(isspace(trailingChar) || ispunct(trailingChar))
)
)
)
)
{
/*
* Either we are not in Spell mode or we have a word
* so return
*/
if (word != (char *)NULL)
XtFree(word);
return (int)pos;
}
XtFree(word);
}
return -1;
}
static Boolean
DoSearch(
DtEditorWidget widget,
char *search_string,
Time time)
{
int stringPosition;
Boolean foundIt = False;
stringPosition = SearchForString(widget,
XmTextGetInsertionPosition(M_text(widget)),
search_string);
if(stringPosition == -1) {
/*
* If the string was not found unselect everything
*/
XmTextClearSelection(M_text(widget), time);
}
else {
/*
* The string was found so highlight the word and scroll the window
* if it is not visible.
*/
XmTextPosition pos = (XmTextPosition) stringPosition;
XmTextWidget tw = (XmTextWidget)M_text(widget);
foundIt = True;
XmTextSetInsertionPosition(M_text(widget), pos);
XmTextSetSelection( M_text(widget), pos,
pos+_DtEditor_CountCharacters(search_string, strlen(search_string)),
XtLastTimestampProcessed(XtDisplay(M_text(widget))) );
/*
* Scroll the widget, if necessary
*/
if (pos < tw->text.top_character || pos >= tw->text.bottom_position)
{
Arg al[5];
int ac;
Dimension height;
short rows;
Position x, y;
ac = 0;
XtSetArg(al[ac], XmNheight, &height); ac++;
XtSetArg(al[ac], XmNrows, &rows); ac++;
XtGetValues(M_text(widget), al, ac);
if(XmTextPosToXY(M_text(widget), pos, &x, &y) == True)
{
int offset = (int)((y - height/2) * rows) / (int)height;
XmTextScroll(M_text(widget), offset);
}
}
}
return ( foundIt );
} /* end DoSearch */
/*
* DtEditorInvokeFindChangeDialog posts the "Find/Change" dialog.
*/
void
DtEditorInvokeFindChangeDialog(
Widget widget)
{
DtEditorWidget pPriv = (DtEditorWidget) widget;
_DtWidgetToAppContext(widget);
_DtAppLock(app);
_DtEditorSearch(pPriv, False, False);
_DtAppUnlock(app);
}
/*
* DoReplace checks that there is a non-null selection, and
* if so, replaces the selection with the replace_string argument.
*/
static Boolean
DoReplace(
DtEditorWidget pPriv,
char *replace_string,
Time time)
{
XmTextPosition first, last;
Boolean replaced = False;
/*
* Only do a replace if we have a non-null selection.
* We could check that the selection == the Find string, but
* this allows a little more flexibility for the user.
*/
if (XmTextGetSelectionPosition(M_text(pPriv), &first, &last) &&
first != last)
{
XmTextReplace(M_text(pPriv), first, last, replace_string);
XmTextSetSelection(M_text(pPriv), first,
first +
_DtEditor_CountCharacters(replace_string, strlen(replace_string)),
time);
replaced = True;
}
return( replaced );
}
/*
* ReplaceAll replaces all occurrences of search_string with
* replacement_string in widget.
*/
static Boolean
ReplaceAll(
DtEditorWidget widget,
char *search_string,
char *replace_string )
{
int replacementLength, searchLength, lastOccurrence, thisOccurrence;
Boolean replaceOK = False;
/*
* Make sure there is a string to find. Null replacement strings
* are OK.
*/
if( search_string && *search_string )
{
/*
* How long is the string we are searching for?
*/
searchLength = _DtEditor_CountCharacters( search_string,
strlen(search_string) );
/*
* How long is the replacement string?
*/
replacementLength = _DtEditor_CountCharacters( replace_string,
strlen(replace_string) );
/*
* Start at the beginning and search for the string
*/
lastOccurrence = -1;
while( ((thisOccurrence = SearchForString(widget,
(lastOccurrence > 0)? (XmTextPosition)lastOccurrence : 0,
search_string)
) != -1 ) &&
thisOccurrence >= lastOccurrence )
{
XmTextReplace( M_text(widget), (XmTextPosition)thisOccurrence,
(XmTextPosition) (thisOccurrence + searchLength),
replace_string );
lastOccurrence = thisOccurrence + replacementLength;
} /* end while */
if (lastOccurrence != -1)
replaceOK = True;
}
return( replaceOK );
} /* end ReplaceAll */
/*
* DtEditorChange replaces either the current selection, the next occurrence
* of a string, or all occurrences of the string with a replacement string.
* If no find or change to strings are passed in, DtEditorFindChange uses
* the last find and change to strings from the Find/Change dialog.
*/
Boolean
DtEditorChange(
Widget widget,
DtEditorChangeValues *findChangeStrings,
unsigned int instanceToChange)
{
Boolean returnVal = False;
DtEditorWidget editor = (DtEditorWidget) widget;
_DtWidgetToAppContext(widget);
_DtAppLock(app);
switch( instanceToChange )
{
case DtEDITOR_NEXT_OCCURRENCE:
{
/*
* Find the next occurrence and replace it (by treating it as
* a current selection).
*/
/*
* If we were passed a Find string use it. Otherwise, tell
* DtEditorFind to use the last search string value
* (M_search_string).
*/
if ( findChangeStrings != (DtEditorChangeValues *) NULL )
returnVal = DtEditorFind( widget, findChangeStrings->find );
else
returnVal = DtEditorFind( widget, (char *)NULL );
if ( returnVal == False)
break;
}
case DtEDITOR_CURRENT_SELECTION:
{
/*
* Replace whatever is selected.
*/
/*
* If we were passed a Change To string use it. Otherwise,
* use the last replace string value.
*/
if ( findChangeStrings != (DtEditorChangeValues *) NULL )
returnVal = DoReplace( editor, findChangeStrings->changeTo,
CurrentTime );
else
returnVal= DoReplace(editor,M_replace_string(editor),CurrentTime);
break;
}
case DtEDITOR_ALL_OCCURRENCES:
{
_DtTurnOnHourGlass( M_topLevelShell(editor) );
if ( findChangeStrings != (DtEditorChangeValues *) NULL )
returnVal = ReplaceAll( editor, findChangeStrings->find,
findChangeStrings->changeTo );
else
returnVal = ReplaceAll( editor, M_search_string(editor),
M_replace_string(editor) );
_DtTurnOffHourGlass( M_topLevelShell( editor ) );
break;
} /* replace all occurrences */
default :
{
}
} /* end switch */
_DtAppUnlock(app);
return( returnVal );
} /* end DtEditorChange */
/* ARGSUSED */
void
_DtEditorSearchMapCB(
Widget w,
caddr_t client_data,
caddr_t call_data )
{
int ac;
Arg al[4];
Widget parent;
Position newX, newY, pY, pX;
Dimension pHeight, myHeight, pWidth, myWidth;
DtEditorWidget pPriv = (DtEditorWidget) client_data;
parent = M_topLevelShell(pPriv);
pX = XtX(parent);
pY = XtY(parent);
pHeight = XtHeight(parent);
pWidth = XtWidth(parent);
myHeight = XtHeight(w);
myWidth = XtWidth(w);
if ((newY = pY - (int)myHeight + 5) < 0)
newY = pY + pHeight;
newX = pX + pWidth/2 - ((int)myWidth)/2;
ac = 0;
XtSetArg(al[ac], XmNx, newX); ac++;
XtSetArg(al[ac], XmNy, newY); ac++;
XtSetValues(w,al,ac);
}
/*
*
* _DtEditorDialogSearchCB is called whenever the Find button is pressed
* in the Find/Change dialog. If the dialog is displayed in Find/Change
* mode, it updates the contents of M_search_string() with the contents
* of the "Find" text field, and then invokes DtEditorFind(). If the
* find is successful, the Change button is enabled, otherwise the
* "String not found" dialog is displayed.
*
* When the dialog is in Spell mode, the selected misspelled word is merely
* passed to DtEditorFind(). The Change (and Change All) buttons are left
* insentive until the user types something into the Change To field
* (too many users were replacing misspelled words with blanks).
*
*/
/* ARGSUSED */
void
_DtEditorDialogSearchCB(
Widget w,
caddr_t client_data,
caddr_t call_data )
{
DtEditorWidget pPriv = (DtEditorWidget) client_data;
/*
* Is the dialog in Find/Change or Spell mode?
*/
if (M_search_dialogMode(pPriv) == REPLACE) {
/*
* Find/Change mode
* Free the existing search string and get the new one.
*/
XtFree(M_search_string(pPriv));
M_search_string(pPriv) = XmTextFieldGetString( M_findText(pPriv) );
/*
* Find the string
*/
if( DtEditorFind((Widget)pPriv, M_search_string(pPriv)) ) {
/*
* If the string was found then enable the Change button.
* It will be disabled when it is pressed or a new Find string is
* entered.
*/
_DtEditorSetReplaceSensitivity( pPriv, True );
}
else {
/*
* Post a dialog informing the user the string was not found.
*/
char *tempStr = (char *)XtMalloc(strlen(NO_FIND) +
strlen(M_search_string(pPriv)) + 1);
sprintf(tempStr, NO_FIND, M_search_string(pPriv));
_DtEditorWarning(pPriv, tempStr, XmDIALOG_INFORMATION);
XtFree(tempStr);
}
}
else {
/*
* Spell mode.
*/
char *pString;
M_misspelled_found(pPriv) = DtEditorFind((Widget)pPriv,
M_misspelled_string(pPriv) );
/*
* If the word was found & there is a Change To string then enable
* the Change button. If there is no Change To string, Change will
* be enabled when a string is entered if M_misspelled_found is True
* (see _DtEditorReplaceTextChangedCB)
*
* Change All is enabled in _DtEditorReplaceTextChangedCB()
* (ie. anytime there is a Change To string). It is not
* dependent upon a sucessful Find because it initiates its own
* find.
*/
if ( M_misspelled_found(pPriv) == True ) {
/*
* Is there a Change To string?
*/
pString = XmTextFieldGetString(M_replaceText(pPriv));
if( pString != (char *)NULL && *pString != (char)'\0' )
_DtEditorSetReplaceSensitivity( pPriv, True );
XtFree(pString);
}
else {
/*
* Post a dialog informing the user the string was not found.
*/
char *tempStr = (char *)XtMalloc(strlen(NO_FIND) +
strlen(M_misspelled_string(pPriv)) + 1);
sprintf(tempStr, NO_FIND, M_misspelled_string(pPriv));
_DtEditorWarning(pPriv, tempStr, XmDIALOG_INFORMATION);
XtFree(tempStr);
}
}
} /* end _DtEditorDialogSearchCB */
/*
* _DtEditorDialogReplaceCB is called whenever the Change button is pressed
* in the Find/Change dialog. If the dialog is displayed in Find/Change
* mode, it updates the contents of M_replace_string() with the contents
* of the "Change To" text field, and then invokes DtEditorChange().
*
* When the dialog is in Spell mode, the contents of the "Change To" text
* field is passed to DtEditorChange() without updating M_replace_string().
*
* In both cases, the Change button is disabled after the change is
* complete.
*/
/* ARGSUSED */
void
_DtEditorDialogReplaceCB(
Widget w,
caddr_t client_data,
caddr_t call_data )
{
DtEditorWidget pPriv = (DtEditorWidget) client_data;
/*
* Is the dialog in Find/Change or Spell mode?
*/
if (M_search_dialogMode(pPriv) == REPLACE) {
/*
* Find/Change mode
* Free the existing Change To string and get the new one.
*/
XtFree(M_replace_string(pPriv));
M_replace_string(pPriv) = XmTextFieldGetString(M_replaceText(pPriv));
DtEditorChange( (Widget)pPriv, (DtEditorChangeValues *)NULL,
DtEDITOR_CURRENT_SELECTION );
}
else {
/*
* Spell mode.
*/
DtEditorChangeValues newWord;
newWord.changeTo = XmTextFieldGetString(M_replaceText(pPriv));
if (newWord.changeTo != (char *)NULL) {
/* This field ignored when changing the current selection */
newWord.find = (char *)NULL;
DtEditorChange( (Widget)pPriv, &newWord, DtEDITOR_CURRENT_SELECTION );
XtFree(newWord.changeTo);
}
}
/*
* Disable the Change button. In Find/Change mode, it will be enabled
* when the Find button is pressed and the Find text is successfully
* found. In Spell mode, there must also be a value in the Change To
* field.
*/
_DtEditorSetReplaceSensitivity(pPriv, False );
/*
* Want the traversal to be on the Find button, so that the user
* can initiate another search.
*/
XmProcessTraversal(M_search_findBtn(pPriv), XmTRAVERSE_CURRENT);
}
/*
* _DtEditorDialogReplaceAllCB is attached to the "Change All" button
* in the Find/Change dialog. It replaces all occurrences of the "Find"
* string with the "Change To" string.
*/
/* ARGSUSED */
void
_DtEditorDialogReplaceAllCB(
Widget w,
caddr_t client_data,
caddr_t call_data )
{
DtEditorWidget pPriv = (DtEditorWidget) client_data;
/*
* Is the dialog in Find/Change or Spell mode?
*/
if (M_search_dialogMode(pPriv) == REPLACE) {
/*
* Find/Change mode
* Free any existing search string before getting the current one.
*/
XtFree(M_search_string(pPriv));
M_search_string(pPriv) = XmTextFieldGetString(M_findText(pPriv));
/*
* Free the existing Change To string and get the new one.
*/
XtFree(M_replace_string(pPriv));
M_replace_string(pPriv) = XmTextFieldGetString(M_replaceText(pPriv));
/*
* Make the change with the current values (set above).
*/
if( !DtEditorChange((Widget)pPriv, (DtEditorChangeValues *)NULL,
DtEDITOR_ALL_OCCURRENCES) ) {
/*
* If the replace failed, post a dialog informing the user
* the string was not found.
*/
char *tempStr = (char *)XtMalloc(strlen(NO_FIND) +
strlen(M_search_string(pPriv)) + 1);
sprintf(tempStr, NO_FIND, M_search_string(pPriv));
_DtEditorWarning(pPriv, tempStr, XmDIALOG_INFORMATION);
XtFree(tempStr);
}
}
else {
/*
* Spell mode.
*/
DtEditorChangeValues changeValues;
changeValues.find = M_misspelled_string(pPriv);
changeValues.changeTo = XmTextFieldGetString(M_replaceText(pPriv));
DtEditorChange((Widget)pPriv, &changeValues, DtEDITOR_ALL_OCCURRENCES);
XtFree( changeValues.changeTo );
}
/*
* Disable the Change button. It will be enabled when the Find
* button is pressed and the Find text is successfully found.
* In Spell mode, there must also be a value in the Change To field.
*/
_DtEditorSetReplaceSensitivity(pPriv, False );
} /* _DtEditorDialogReplaceAllCB */
/* ARGSUSED */
void
_DtEditorDialogFindCancelCB(
Widget w,
caddr_t client_data,
caddr_t call_data )
{
DtEditorWidget pPriv = (DtEditorWidget)client_data;
XtUnmanageChild(M_search_dialog(pPriv));
}
/*
* _DtEditorMisspelledSelectCB is called when a new word has been selected
* from the list of misspelled words.
*/
/* ARGSUSED */
void
_DtEditorMisspelledSelectCB(
Widget w,
caddr_t client_data,
caddr_t call_data )
{
XmListCallbackStruct *cb = (XmListCallbackStruct *)call_data;
DtEditorWidget editor = (DtEditorWidget)client_data;
/*
* Get the selected word for use when the Find or Replace All button
* is pressed.
*/
XtFree(M_misspelled_string(editor));
M_misspelled_string(editor) =
_XmStringUngenerate(cb->item, NULL, XmCHARSET_TEXT, XmCHARSET_TEXT);
/*
* Mark that it has not been found
*/
M_misspelled_found(editor) = False;
/*
* Enable the Find button
*/
_DtEditorSetFindSensitivity(editor, True );
/*
* Clear the "Change To" text field.
*/
XmTextFieldSetString(M_replaceText(editor), (char *)NULL);
} /* end _DtEditorMisspelledSelectCB */
/*
* _DtEditorMisspelledDblClickCB is called when a word has been double-
* clicked from the list of misspelled words. First, the word will become
* the new misspelled string and, then, a find will be initiated for it.
*/
/* ARGSUSED */
void
_DtEditorMisspelledDblClickCB(
Widget w,
caddr_t client_data,
caddr_t call_data )
{
_DtEditorMisspelledSelectCB(w, client_data, call_data );
_DtEditorDialogSearchCB(w, client_data, call_data );
} /* end _DtEditorMisspelledDblClickCB */
/*
* The following functions effectively track whether the user has
* entered or changed the "Find" text. This information is used to make
* the "Find" and "Change All" buttons sensitive/desensitive. The
* "Find" button must be pressed and the Find text found before the
* "Change" button is sensitive. These functions also set the default
* button to either the "Find" or "Close" button.
*/
void
_DtEditorSetFindSensitivity(
DtEditorWidget widget,
Boolean sensitivity)
{
XtSetSensitive(M_search_findBtn(widget), sensitivity);
}
void
_DtEditorSetReplaceSensitivity(
DtEditorWidget editor,
Boolean sensitivity)
{
/*
* Cannot enable Change button if widget is read only
*/
if ( M_editable(editor) || !sensitivity )
XtSetSensitive(M_search_replaceBtn(editor), sensitivity);
}
void
_DtEditorSetReplaceAllSensitivity(
DtEditorWidget editor,
Boolean sensitivity)
{
/*
* Cannot enable Change All button if widget is read only
*/
if ( M_editable(editor) || !sensitivity )
XtSetSensitive(M_search_replaceAllBtn(editor), sensitivity);
}
/* ARGSUSED */
void
_DtEditorFindTextChangedCB(
Widget w,
caddr_t client_data,
caddr_t call_data )
{
Arg al[10]; /* arg list */
Widget defaultButton;
char *pString;
DtEditorWidget editor = (DtEditorWidget)client_data;
/*
* Is there a Find string?
*/
pString = XmTextFieldGetString(M_findText(editor));
/*
* Only enable the Find & Change All buttons if there is a
* string to search for (i.e. a Find string).
*/
if(pString == (char *)NULL || *pString == (char)'\0') {
_DtEditorSetFindSensitivity(editor, False );
_DtEditorSetReplaceAllSensitivity(editor, False );
/*
* Make the Close button the default
*/
defaultButton = M_search_closeBtn(editor);
}
else {
_DtEditorSetFindSensitivity( editor, True );
_DtEditorSetReplaceAllSensitivity(editor, True );
/*
* Make the Find button the default
*/
defaultButton = M_search_findBtn(editor);
}
XtFree(pString);
/*
* Set the default button
*/
XtSetArg(al[0], XmNdefaultButton, defaultButton);
XtSetValues(M_search_dialog(editor), al, 1);
/*
* Disable the Change button. It will be enabled when the Find
* button is pressed and the Find text is successfully found.
*/
_DtEditorSetReplaceSensitivity(editor, False );
} /* end _DtEditorFindTextChangedCB */
/*
* The following functions effectively track whether the user has
* entered or changed the Change To text. This information is used
* in the Spell dialog to make the Change and Change All buttons
* sensitive/desensitive so users cannot replace a misspelled word with
* a null string.
*/
/* ARGSUSED */
void
_DtEditorReplaceTextChangedCB(
Widget w,
caddr_t client_data,
caddr_t call_data )
{
char *pString;
DtEditorWidget editor = (DtEditorWidget)client_data;
/*
* Ignore this callback if it is not being called from the Spell
* dialog.
*/
if( M_search_dialogMode(editor) == SPELL ) {
/*
* Is there a Change To string?
*/
pString = XmTextFieldGetString(M_replaceText(editor));
/*
* Disable the Change & Change All buttons if there is
* no Change To string.
*/
if( pString == (char *)NULL || *pString == (char)'\0' ) {
_DtEditorSetReplaceSensitivity(editor, False );
_DtEditorSetReplaceAllSensitivity(editor, False );
}
else {
/*
* If there is a Change To string enable the Change
* All button, but only enable the Change button if.
* the Find button has been pressed & the misspelled
* word found (see _DtEditorDialogSearchCB()
*/
_DtEditorSetReplaceAllSensitivity(editor, True );
if ( M_misspelled_found(editor) )
_DtEditorSetReplaceSensitivity(editor, True );
XtFree(pString);
}
}
} /* end _DtEditorReplaceTextChangedCB */
/***
IsInGroup -
Check to see if the process is in the group, gid.
***/
static Boolean IsInGroup(gid_t gid)
{
gid_t grps[NGROUPS_MAX];
int i;
int num_grps;
num_grps = getgroups(NGROUPS_MAX, grps);
if (num_grps == -1)
return(False);
for (i=0; i < num_grps; i++) {
if (gid == grps[i])
return(True);
}
return(False);
}
/***
IsExecutable -
Check to see if the process can execute the filter.
****/
static Boolean IsExecutable(struct stat statbuf)
{
Boolean ingroup = IsInGroup(statbuf.st_gid);
if (geteuid() == 0) { /** if root **/
/** if any execute bit is set, root can execute **/
if ((statbuf.st_mode & S_IXUSR)
|| (statbuf.st_mode & S_IXGRP)
|| (statbuf.st_mode & S_IXOTH))
{
return (True);
}
else {
return (False);
}
}
/*
* if this process is the user and the user
* does have execute permission, then the
* filter will run, so return false
*/
if ((statbuf.st_uid == geteuid())
&& (statbuf.st_mode & S_IXUSR))
{
return(True);
}
/*
* if this process is in the group for the
* filter and group execute is set (and the
* process isn't the user, then return true
*/
if (ingroup
&& (statbuf.st_mode & S_IXGRP)
&& (statbuf.st_uid != geteuid()))
{
return(True);
}
/*
* if this process is not in the group or the user
* for the filter and other execute is set, then
* return true
*/
if ((statbuf.st_mode & S_IXOTH)
&& (statbuf.st_uid != geteuid())
&& !ingroup)
{
return(True);
}
return(False);
}
/*****
IsValidFilter -
This function checks to makes sure that this filter
can be found, i.e. is in the current path and istalled.
*****/
static Boolean IsValidFilter(DtEditorWidget pPriv)
{
char *pathstr;
char *pathtmp;
char *pathtok;
char *tmp;
struct stat statbuf;
_Xstrtokparams strtok_buf;
/** check to see if a full path to the filter is given **/
if (*M_spellFilter(pPriv) == '/') {
if (stat(M_spellFilter(pPriv), &statbuf) != -1)
return(IsExecutable(statbuf));
else
return(False);
}
/*
* get the PATH from the environment and check to see if
* the filter is in the path
*/
pathstr = getenv("PATH");
if (pathstr == NULL)
return(FALSE);
pathtmp = XtNewString(pathstr);
pathtok = _XStrtok(pathtmp, ":", strtok_buf);
while (pathtok != NULL) {
tmp = (char*)XtMalloc((strlen(pathtok)
+ strlen(M_spellFilter(pPriv))
+ 2) * sizeof(char));
strcpy(tmp, pathtok);
strcat(tmp, "/");
strcat(tmp, M_spellFilter(pPriv));
if (stat(tmp, &statbuf) != -1) {
XtFree(pathtmp);
XtFree(tmp);
return(IsExecutable(statbuf));
}
XtFree(tmp);
pathtok = _XStrtok(NULL,":", strtok_buf);
}
XtFree(pathtmp);
return(False);
}