/* * 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 #include #include #include #include #include
#include
#include "DtWidgetI.h" #include /* _XmStringSourceGetString */ #define X_INCLUDE_STRING_H #define XOS_USE_XT_LOCKING #include 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); }