2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 /* $XConsortium: SearchCalls.c /main/13 1996/11/21 20:00:02 drk $ */
24 /**********************************<+>*************************************
25 ***************************************************************************
27 ** File: SearchCalls.c
29 ** Project: DtEditor widget for editing services
31 ** Description: Spell and Find functions
34 *******************************************************************
36 * (c) Copyright 1996 Digital Equipment Corporation.
37 * (c) Copyright 1993, 1994, 1996 Hewlett-Packard Company.
38 * (c) Copyright 1993, 1994, 1996 International Business Machines Corp.
39 * (c) Copyright 1993, 1994, 1996 Sun Microsystems, Inc.
40 * (c) Copyright 1996 Novell, Inc.
41 * (c) Copyright 1996 FUJITSU LIMITED.
42 * (c) Copyright 1996 Hitachi.
43 * (c) Copyright 1993, 1994 Unix System Labs, Inc., a subsidiary of Novell, Inc.
45 ********************************************************************/
50 #include <Xm/MessageB.h>
54 #include <Dt/DtMsgsP.h>
55 #include <Dt/HourGlass.h>
56 #include "DtWidgetI.h"
58 #include <Xm/XmPrivate.h> /* _XmStringSourceGetString */
60 #define X_INCLUDE_STRING_H
61 #define XOS_USE_XT_LOCKING
62 #include <X11/Xos_r.h>
65 _XmStringUngenerate(XmString string,
68 XmTextType output_type);
70 static Boolean DoReplace(
74 static int SearchForString(
76 XmTextPosition startLocation,
78 static Boolean DoSearch(
82 static Boolean IsValidFilter(
83 DtEditorWidget pPriv);
84 static Boolean IsInGroup(
86 static Boolean IsExecutable(
88 static void DestroyThisWidgetCB(
95 DtEditorInvokeSpellDialog(
98 DtEditorWidget pPriv = (DtEditorWidget) widget;
99 char fileName[L_tmpnam], com[L_tmpnam + 7], *string, newline[1];
101 FILE *fp; /* pipe to read words from */
102 int len = 0; /* length of line read in */
103 int maxLen = 0; /* max length of the line buffer */
104 XmString word; /* processed word ready to add to list */
106 DtEditorErrorCode error = DtEDITOR_NO_TMP_FILE;
107 _DtWidgetToAppContext(widget);
112 if (!IsValidFilter(pPriv)) {
113 error = DtEDITOR_SPELL_FILTER_FAILED;
117 _DtTurnOnHourGlass(M_topLevelShell(pPriv));
120 * Write out to a tmp file, getting the name back
122 (void)tmpnam(fileName);
123 if((fp = fopen(fileName, "w")) != (FILE *)NULL)
126 * Temporary file created sucessfully so write out contents of
127 * widget in preparation of feeding it to the 'spell' filter.
129 string = (char *)XmTextGetString(M_text(pPriv));
130 fwrite(string, sizeof(char), strlen(string), fp);
133 * Tack on a final newline (\n) cuz spell(1) does not spell-check
134 * lines which do not terminate with a newline.
136 fwrite(newline, sizeof(char), 1, fp);
140 /* start spell command */
141 sprintf(com, "%s %s", M_spellFilter(pPriv), fileName);
142 fp = popen(com, "r");
144 if ( fp == (FILE *)NULL )
145 error = DtEDITOR_SPELL_FILTER_FAILED;
147 error = DtEDITOR_NO_ERRORS;
150 * The filter was started successfully.
151 * Initialize the Spell dialog and get ready to receive
152 * the list of mispelled words.
154 _DtEditorSearch(pPriv, True, True);
155 _DtTurnOnHourGlass(M_search_dialog(pPriv));
156 /* needed for bug in list */
157 XmListSetPos(M_search_spellList(pPriv), 1);
158 XmListDeleteAllItems(M_search_spellList(pPriv));
164 line = (char *) XtMalloc (sizeof(char) * (maxLen + 1));
168 * Now, get each word and hand it to the list
170 while(fgets(&line[len], maxLen - len, fp))
172 len += strlen(&line[len]);
175 if (line[len - 1] == '\n')
177 line[len - 1] = '\0';
178 word = XmStringCreateLocalized(line);
179 XmListAddItemUnselected(M_search_spellList(pPriv), word, 0);
186 line = (char *) XtRealloc (line, sizeof(char) * (maxLen + 1));
191 /* clean up and display the results */
194 _DtEditorSearch(pPriv, True, False);
195 _DtTurnOffHourGlass(M_search_dialog(pPriv));
196 } /* end start the spell filter */
199 } /* end create temporary file */
201 _DtTurnOffHourGlass(M_topLevelShell(pPriv));
204 if (error != DtEDITOR_NO_ERRORS) {
205 XmString title, msg1, msg2, msg3;
211 buf = XtMalloc((strlen(BAD_FILTER2) +
212 strlen(M_spellFilter(pPriv)) + 1) *
215 sprintf(buf, BAD_FILTER2, M_spellFilter(pPriv));
216 msg1 = XmStringGenerate(BAD_FILTER,
217 XmFONTLIST_DEFAULT_TAG,
218 XmCHARSET_TEXT, NULL);
220 msg2 = XmStringSeparatorCreate();
221 msg3= XmStringConcatAndFree(msg1, msg2);
222 msg1 = XmStringGenerate(buf,
223 XmFONTLIST_DEFAULT_TAG,
224 XmCHARSET_TEXT, NULL);
226 msg2 = XmStringConcatAndFree(msg3, msg1);
229 title = XmStringCreateLocalized(ERROR_TITLE);
232 XtSetArg(al[ac], XmNdialogTitle, title); ac++;
233 XtSetArg(al[ac], XmNdialogType, XmDIALOG_ERROR); ac++;
234 XtSetArg(al[ac], XmNmessageString, msg2); ac++;
235 dialog = XmCreateMessageDialog((Widget)pPriv,
236 "Spell Error", al, ac
239 XtUnmanageChild(XmMessageBoxGetChild(dialog,
240 XmDIALOG_HELP_BUTTON));
241 XtUnmanageChild(XmMessageBoxGetChild(dialog,
242 XmDIALOG_CANCEL_BUTTON));
243 XtAddCallback(dialog, XmNokCallback, DestroyThisWidgetCB, NULL);
244 XtVaSetValues(XtParent(dialog),
245 XmNdeleteResponse, XmDESTROY,
247 XtManageChild(dialog);
256 } /* end DtEditorInvokeSpellDialog */
258 static void DestroyThisWidgetCB (
272 DtEditorWidget editor = (DtEditorWidget) widget;
273 Boolean foundIt = True;
274 _DtWidgetToAppContext(widget);
278 * If we were passed a string to find, then use it. Otherwise,
279 * use the last find string entered in the Find/Change dialog.
281 if ( find != (char *)NULL )
282 foundIt = DoSearch(editor, find, CurrentTime);
286 * If there is no value from the dialog, then post the Find/Change
289 if (!M_search_string(editor))
290 _DtEditorSearch(editor, False, False);
292 foundIt = DoSearch(editor, M_search_string(editor), CurrentTime);
300 /* Count the number of characters represented in the char* str.
301 * By definition, if MB_CUR_MAX == 1 then numBytes == number of characters.
302 * Otherwise, use mblen to calculate.
305 _DtEditor_CountCharacters(
312 int mbCurMax = MB_CUR_MAX; /* invoke the macro just once */
315 return (numBytes < 0)? 0 : numBytes;
316 if (numBytes <=0 || str == NULL || *str == '\0')
319 for(bptr = str; numBytes > 0; count++, bptr+= char_size)
321 char_size = mblen(bptr, mbCurMax);
324 numBytes -= char_size;
330 * SearchForString takes an Editor widget, a position at which
331 * to begin its search, and the string for which it is to search.
332 * It searches first from startLocation to the end of the file, and
333 * then if necessary from the start of the file to startLocation.
334 * It returns an integer indicating the location of the string, or
335 * -1 if the string is not found.
339 DtEditorWidget pPriv,
340 XmTextPosition startLocation,
343 XmTextPosition pos, searchAnchor, topAnchor, cursorLocation,
344 lastPosition = XmTextGetLastPosition(M_text(pPriv));
347 searchAnchor = cursorLocation = startLocation;
349 while((Boolean)XmTextFindString(M_text(pPriv), searchAnchor,
350 searchString, XmTEXT_FORWARD,
352 ((Boolean)XmTextFindString(M_text(pPriv), topAnchor,
353 searchString, XmTEXT_FORWARD, &pos) &&
354 pos < cursorLocation))
356 char *word, leadingChar, trailingChar;
357 XmTextPosition endPos;
360 * Do some extra work for the Spell case, so we find only "words"
362 * Get the word with the leading & trailing characters.
363 * It's a word if it's bounded by:
364 * a. 16-bit characters
372 * 0 (constant) - first character position in the document.
373 * lastPosition - last character position in the document.
375 * pos - Position in the document of the first character
376 * of the word. Does not include leading character.
377 * endPos - Position in the document of the last character
378 * of the word + 1. Points to the trailing character,
381 * word - The string we have matched. Includes the leading
382 * & trailing characters, if any.
383 * word[0] - Leading character, if any, otherwise first
384 * character of the matched string.
385 * word[length] - Trailing character, if any, otherwise last
386 * character of the matched string.
390 endPos = pos + 1 + _DtEditor_CountCharacters(searchString,
391 strlen(searchString));
392 if(pos < cursorLocation)
395 searchAnchor = pos + 1;
398 * If the first character of the word is the first character in
399 * the document there is no leading character. Likewise, if the
400 * last character of the word is the last character in the document
401 * there is no trailing character.
405 * There is a leading character.
408 if (endPos <= lastPosition) {
410 * There is a trailing character.
412 word = (char *)_XmStringSourceGetString(
413 (XmTextWidget) M_text(pPriv),
414 pos - 1, endPos, False);
415 length = strlen(word) - 1;
416 trailingChar = word[length];
421 * There is no trailing character.
423 word = (char *)_XmStringSourceGetString(
424 (XmTextWidget) M_text(pPriv),
425 pos - 1, lastPosition, False);
426 length = strlen(word);
429 leadingChar = word[0];
434 * There is no leading character.
437 if (endPos <= lastPosition) {
439 * There is a trailing character.
441 word = (char *)_XmStringSourceGetString(
442 (XmTextWidget) M_text(pPriv),
444 length = strlen(word) - 1;
445 trailingChar = word[length];
449 * There is no trailing character.
451 word = (char *)_XmStringSourceGetString(
452 (XmTextWidget) M_text(pPriv),
453 0, lastPosition, False);
454 length = strlen(word);
460 if ((M_search_dialogMode(pPriv) != SPELL) ||
462 ((mblen(word, MB_CUR_MAX) > 1) ||
463 ( isascii(leadingChar) &&
464 (isspace(leadingChar) || ispunct(leadingChar))
467 ((mblen(word+length-1, MB_CUR_MAX) > 1) ||
468 ( isascii(trailingChar) &&
469 (isspace(trailingChar) || ispunct(trailingChar))
476 * Either we are not in Spell mode or we have a word
479 if (word != (char *)NULL)
493 DtEditorWidget widget,
498 Boolean foundIt = False;
500 stringPosition = SearchForString(widget,
501 XmTextGetInsertionPosition(M_text(widget)),
504 if(stringPosition == -1) {
506 * If the string was not found unselect everything
508 XmTextClearSelection(M_text(widget), time);
512 * The string was found so highlight the word and scroll the window
513 * if it is not visible.
515 XmTextPosition pos = (XmTextPosition) stringPosition;
516 XmTextWidget tw = (XmTextWidget)M_text(widget);
519 XmTextSetInsertionPosition(M_text(widget), pos);
520 XmTextSetSelection( M_text(widget), pos,
521 pos+_DtEditor_CountCharacters(search_string, strlen(search_string)),
522 XtLastTimestampProcessed(XtDisplay(M_text(widget))) );
525 * Scroll the widget, if necessary
527 if (pos < tw->text.top_character || pos >= tw->text.bottom_position)
536 XtSetArg(al[ac], XmNheight, &height); ac++;
537 XtSetArg(al[ac], XmNrows, &rows); ac++;
538 XtGetValues(M_text(widget), al, ac);
540 if(XmTextPosToXY(M_text(widget), pos, &x, &y) == True)
542 int offset = (int)((y - height/2) * rows) / (int)height;
543 XmTextScroll(M_text(widget), offset);
555 * DtEditorInvokeFindChangeDialog posts the "Find/Change" dialog.
558 DtEditorInvokeFindChangeDialog(
561 DtEditorWidget pPriv = (DtEditorWidget) widget;
562 _DtWidgetToAppContext(widget);
565 _DtEditorSearch(pPriv, False, False);
570 * DoReplace checks that there is a non-null selection, and
571 * if so, replaces the selection with the replace_string argument.
575 DtEditorWidget pPriv,
576 char *replace_string,
579 XmTextPosition first, last;
580 Boolean replaced = False;
583 * Only do a replace if we have a non-null selection.
584 * We could check that the selection == the Find string, but
585 * this allows a little more flexibility for the user.
587 if (XmTextGetSelectionPosition(M_text(pPriv), &first, &last) &&
590 XmTextReplace(M_text(pPriv), first, last, replace_string);
591 XmTextSetSelection(M_text(pPriv), first,
593 _DtEditor_CountCharacters(replace_string, strlen(replace_string)),
602 * ReplaceAll replaces all occurrences of search_string with
603 * replacement_string in widget.
608 DtEditorWidget widget,
610 char *replace_string )
612 int replacementLength, searchLength, lastOccurrence, thisOccurrence;
613 Boolean replaceOK = False;
616 * Make sure there is a string to find. Null replacement strings
619 if( search_string && *search_string )
622 * How long is the string we are searching for?
624 searchLength = _DtEditor_CountCharacters( search_string,
625 strlen(search_string) );
628 * How long is the replacement string?
630 replacementLength = _DtEditor_CountCharacters( replace_string,
631 strlen(replace_string) );
634 * Start at the beginning and search for the string
637 while( ((thisOccurrence = SearchForString(widget,
638 (lastOccurrence > 0)? (XmTextPosition)lastOccurrence : 0,
641 thisOccurrence >= lastOccurrence )
643 XmTextReplace( M_text(widget), (XmTextPosition)thisOccurrence,
644 (XmTextPosition) (thisOccurrence + searchLength),
646 lastOccurrence = thisOccurrence + replacementLength;
649 if (lastOccurrence != -1)
656 } /* end ReplaceAll */
659 * DtEditorChange replaces either the current selection, the next occurrence
660 * of a string, or all occurrences of the string with a replacement string.
661 * If no find or change to strings are passed in, DtEditorFindChange uses
662 * the last find and change to strings from the Find/Change dialog.
667 DtEditorChangeValues *findChangeStrings,
668 unsigned int instanceToChange)
671 Boolean returnVal = False;
672 DtEditorWidget editor = (DtEditorWidget) widget;
673 _DtWidgetToAppContext(widget);
676 switch( instanceToChange )
678 case DtEDITOR_NEXT_OCCURRENCE:
681 * Find the next occurrence and replace it (by treating it as
682 * a current selection).
686 * If we were passed a Find string use it. Otherwise, tell
687 * DtEditorFind to use the last search string value
690 if ( findChangeStrings != (DtEditorChangeValues *) NULL )
691 returnVal = DtEditorFind( widget, findChangeStrings->find );
693 returnVal = DtEditorFind( widget, (char *)NULL );
695 if ( returnVal == False)
699 case DtEDITOR_CURRENT_SELECTION:
702 * Replace whatever is selected.
706 * If we were passed a Change To string use it. Otherwise,
707 * use the last replace string value.
709 if ( findChangeStrings != (DtEditorChangeValues *) NULL )
710 returnVal = DoReplace( editor, findChangeStrings->changeTo,
713 returnVal= DoReplace(editor,M_replace_string(editor),CurrentTime);
718 case DtEDITOR_ALL_OCCURRENCES:
720 _DtTurnOnHourGlass( M_topLevelShell(editor) );
723 if ( findChangeStrings != (DtEditorChangeValues *) NULL )
724 returnVal = ReplaceAll( editor, findChangeStrings->find,
725 findChangeStrings->changeTo );
727 returnVal = ReplaceAll( editor, M_search_string(editor),
728 M_replace_string(editor) );
730 _DtTurnOffHourGlass( M_topLevelShell( editor ) );
733 } /* replace all occurrences */
744 } /* end DtEditorChange */
748 _DtEditorSearchMapCB(
756 Position newX, newY, pY, pX;
757 Dimension pHeight, myHeight, pWidth, myWidth;
758 DtEditorWidget pPriv = (DtEditorWidget) client_data;
760 parent = M_topLevelShell(pPriv);
764 pHeight = XtHeight(parent);
765 pWidth = XtWidth(parent);
766 myHeight = XtHeight(w);
767 myWidth = XtWidth(w);
769 if ((newY = pY - (int)myHeight + 5) < 0)
771 newX = pX + pWidth/2 - ((int)myWidth)/2;
774 XtSetArg(al[ac], XmNx, newX); ac++;
775 XtSetArg(al[ac], XmNy, newY); ac++;
776 XtSetValues(w,al,ac);
782 * _DtEditorDialogSearchCB is called whenever the Find button is pressed
783 * in the Find/Change dialog. If the dialog is displayed in Find/Change
784 * mode, it updates the contents of M_search_string() with the contents
785 * of the "Find" text field, and then invokes DtEditorFind(). If the
786 * find is successful, the Change button is enabled, otherwise the
787 * "String not found" dialog is displayed.
789 * When the dialog is in Spell mode, the selected misspelled word is merely
790 * passed to DtEditorFind(). The Change (and Change All) buttons are left
791 * insentive until the user types something into the Change To field
792 * (too many users were replacing misspelled words with blanks).
798 _DtEditorDialogSearchCB(
804 DtEditorWidget pPriv = (DtEditorWidget) client_data;
807 * Is the dialog in Find/Change or Spell mode?
809 if (M_search_dialogMode(pPriv) == REPLACE) {
812 * Free the existing search string and get the new one.
814 XtFree(M_search_string(pPriv));
815 M_search_string(pPriv) = XmTextFieldGetString( M_findText(pPriv) );
820 if( DtEditorFind((Widget)pPriv, M_search_string(pPriv)) ) {
822 * If the string was found then enable the Change button.
823 * It will be disabled when it is pressed or a new Find string is
826 _DtEditorSetReplaceSensitivity( pPriv, True );
830 * Post a dialog informing the user the string was not found.
833 char *tempStr = (char *)XtMalloc(strlen(NO_FIND) +
834 strlen(M_search_string(pPriv)) + 1);
835 sprintf(tempStr, NO_FIND, M_search_string(pPriv));
836 _DtEditorWarning(pPriv, tempStr, XmDIALOG_INFORMATION);
847 M_misspelled_found(pPriv) = DtEditorFind((Widget)pPriv,
848 M_misspelled_string(pPriv) );
850 * If the word was found & there is a Change To string then enable
851 * the Change button. If there is no Change To string, Change will
852 * be enabled when a string is entered if M_misspelled_found is True
853 * (see _DtEditorReplaceTextChangedCB)
855 * Change All is enabled in _DtEditorReplaceTextChangedCB()
856 * (ie. anytime there is a Change To string). It is not
857 * dependent upon a sucessful Find because it initiates its own
860 if ( M_misspelled_found(pPriv) == True ) {
863 * Is there a Change To string?
865 pString = XmTextFieldGetString(M_replaceText(pPriv));
867 if( pString != (char *)NULL && *pString != (char)'\0' )
868 _DtEditorSetReplaceSensitivity( pPriv, True );
874 * Post a dialog informing the user the string was not found.
877 char *tempStr = (char *)XtMalloc(strlen(NO_FIND) +
878 strlen(M_misspelled_string(pPriv)) + 1);
879 sprintf(tempStr, NO_FIND, M_misspelled_string(pPriv));
880 _DtEditorWarning(pPriv, tempStr, XmDIALOG_INFORMATION);
886 } /* end _DtEditorDialogSearchCB */
889 * _DtEditorDialogReplaceCB is called whenever the Change button is pressed
890 * in the Find/Change dialog. If the dialog is displayed in Find/Change
891 * mode, it updates the contents of M_replace_string() with the contents
892 * of the "Change To" text field, and then invokes DtEditorChange().
894 * When the dialog is in Spell mode, the contents of the "Change To" text
895 * field is passed to DtEditorChange() without updating M_replace_string().
897 * In both cases, the Change button is disabled after the change is
903 _DtEditorDialogReplaceCB(
908 DtEditorWidget pPriv = (DtEditorWidget) client_data;
911 * Is the dialog in Find/Change or Spell mode?
913 if (M_search_dialogMode(pPriv) == REPLACE) {
916 * Free the existing Change To string and get the new one.
918 XtFree(M_replace_string(pPriv));
919 M_replace_string(pPriv) = XmTextFieldGetString(M_replaceText(pPriv));
921 DtEditorChange( (Widget)pPriv, (DtEditorChangeValues *)NULL,
922 DtEDITOR_CURRENT_SELECTION );
928 DtEditorChangeValues newWord;
930 newWord.changeTo = XmTextFieldGetString(M_replaceText(pPriv));
931 if (newWord.changeTo != (char *)NULL) {
932 /* This field ignored when changing the current selection */
933 newWord.find = (char *)NULL;
934 DtEditorChange( (Widget)pPriv, &newWord, DtEDITOR_CURRENT_SELECTION );
936 XtFree(newWord.changeTo);
941 * Disable the Change button. In Find/Change mode, it will be enabled
942 * when the Find button is pressed and the Find text is successfully
943 * found. In Spell mode, there must also be a value in the Change To
946 _DtEditorSetReplaceSensitivity(pPriv, False );
949 * Want the traversal to be on the Find button, so that the user
950 * can initiate another search.
952 XmProcessTraversal(M_search_findBtn(pPriv), XmTRAVERSE_CURRENT);
956 * _DtEditorDialogReplaceAllCB is attached to the "Change All" button
957 * in the Find/Change dialog. It replaces all occurances of the "Find"
958 * string with the "Change To" string.
963 _DtEditorDialogReplaceAllCB(
968 DtEditorWidget pPriv = (DtEditorWidget) client_data;
971 * Is the dialog in Find/Change or Spell mode?
973 if (M_search_dialogMode(pPriv) == REPLACE) {
976 * Free any existing search string before getting the current one.
978 XtFree(M_search_string(pPriv));
979 M_search_string(pPriv) = XmTextFieldGetString(M_findText(pPriv));
982 * Free the existing Change To string and get the new one.
984 XtFree(M_replace_string(pPriv));
985 M_replace_string(pPriv) = XmTextFieldGetString(M_replaceText(pPriv));
988 * Make the change with the current values (set above).
990 if( !DtEditorChange((Widget)pPriv, (DtEditorChangeValues *)NULL,
991 DtEDITOR_ALL_OCCURRENCES) ) {
993 * If the replace failed, post a dialog informing the user
994 * the string was not found.
997 char *tempStr = (char *)XtMalloc(strlen(NO_FIND) +
998 strlen(M_search_string(pPriv)) + 1);
999 sprintf(tempStr, NO_FIND, M_search_string(pPriv));
1000 _DtEditorWarning(pPriv, tempStr, XmDIALOG_INFORMATION);
1009 DtEditorChangeValues changeValues;
1011 changeValues.find = M_misspelled_string(pPriv);
1012 changeValues.changeTo = XmTextFieldGetString(M_replaceText(pPriv));
1013 DtEditorChange((Widget)pPriv, &changeValues, DtEDITOR_ALL_OCCURRENCES);
1015 XtFree( changeValues.changeTo );
1020 * Disable the Change button. It will be enabled when the Find
1021 * button is pressed and the Find text is successfully found.
1022 * In Spell mode, there must also be a value in the Change To field.
1024 _DtEditorSetReplaceSensitivity(pPriv, False );
1026 } /* _DtEditorDialogReplaceAllCB */
1030 _DtEditorDialogFindCancelCB(
1032 caddr_t client_data,
1035 DtEditorWidget pPriv = (DtEditorWidget)client_data;
1036 XtUnmanageChild(M_search_dialog(pPriv));
1040 * _DtEditorMisspelledSelectCB is called when a new word has been selected
1041 * from the list of misspelled words.
1045 _DtEditorMisspelledSelectCB(
1047 caddr_t client_data,
1050 XmListCallbackStruct *cb = (XmListCallbackStruct *)call_data;
1051 DtEditorWidget editor = (DtEditorWidget)client_data;
1054 * Get the selected word for use when the Find or Replace All button
1057 XtFree(M_misspelled_string(editor));
1059 M_misspelled_string(editor) =
1060 _XmStringUngenerate(cb->item, NULL, XmCHARSET_TEXT, XmCHARSET_TEXT);
1063 * Mark that it has not been found
1066 M_misspelled_found(editor) = False;
1069 * Enable the Find button
1071 _DtEditorSetFindSensitivity(editor, True );
1074 * Clear the "Change To" text field.
1076 XmTextFieldSetString(M_replaceText(editor), (char *)NULL);
1078 } /* end _DtEditorMisspelledSelectCB */
1081 * _DtEditorMisspelledDblClickCB is called when a word has been double-
1082 * clicked from the list of misspelled words. First, the word will become
1083 * the new misspelled string and, then, a find will be initiated for it.
1087 _DtEditorMisspelledDblClickCB(
1089 caddr_t client_data,
1092 _DtEditorMisspelledSelectCB(w, client_data, call_data );
1093 _DtEditorDialogSearchCB(w, client_data, call_data );
1094 } /* end _DtEditorMisspelledDblClickCB */
1098 * The following functions effectively track whether the user has
1099 * entered or changed the "Find" text. This information is used to make
1100 * the "Find" and "Change All" buttons sensitive/desensitive. The
1101 * "Find" button must be pressed and the Find text found before the
1102 * "Change" button is sensitive. These functions also set the default
1103 * button to either the "Find" or "Close" button.
1107 _DtEditorSetFindSensitivity(
1108 DtEditorWidget widget,
1109 Boolean sensitivity)
1111 XtSetSensitive(M_search_findBtn(widget), sensitivity);
1115 _DtEditorSetReplaceSensitivity(
1116 DtEditorWidget editor,
1117 Boolean sensitivity)
1120 * Cannot enable Change button if widget is read only
1122 if ( M_editable(editor) || !sensitivity )
1123 XtSetSensitive(M_search_replaceBtn(editor), sensitivity);
1127 _DtEditorSetReplaceAllSensitivity(
1128 DtEditorWidget editor,
1129 Boolean sensitivity)
1132 * Cannot enable Change All button if widget is read only
1134 if ( M_editable(editor) || !sensitivity )
1135 XtSetSensitive(M_search_replaceAllBtn(editor), sensitivity);
1140 _DtEditorFindTextChangedCB(
1142 caddr_t client_data,
1145 Arg al[10]; /* arg list */
1146 Widget defaultButton;
1149 DtEditorWidget editor = (DtEditorWidget)client_data;
1152 * Is there a Find string?
1154 pString = XmTextFieldGetString(M_findText(editor));
1157 * Only enable the Find & Change All buttons if there is a
1158 * string to search for (i.e. a Find string).
1160 if(pString == (char *)NULL || *pString == (char)'\0') {
1161 _DtEditorSetFindSensitivity(editor, False );
1162 _DtEditorSetReplaceAllSensitivity(editor, False );
1164 * Make the Close button the default
1166 defaultButton = M_search_closeBtn(editor);
1169 _DtEditorSetFindSensitivity( editor, True );
1170 _DtEditorSetReplaceAllSensitivity(editor, True );
1172 * Make the Find button the default
1174 defaultButton = M_search_findBtn(editor);
1179 * Set the default button
1181 XtSetArg(al[0], XmNdefaultButton, defaultButton);
1182 XtSetValues(M_search_dialog(editor), al, 1);
1185 * Disable the Change button. It will be enabled when the Find
1186 * button is pressed and the Find text is successfully found.
1188 _DtEditorSetReplaceSensitivity(editor, False );
1190 } /* end _DtEditorFindTextChangedCB */
1193 * The following functions effectively track whether the user has
1194 * entered or changed the Change To text. This information is used
1195 * in the Spell dialog to make the Change and Change All buttons
1196 * sensitive/desensitive so users cannot replace a misspelled word with
1202 _DtEditorReplaceTextChangedCB(
1204 caddr_t client_data,
1209 DtEditorWidget editor = (DtEditorWidget)client_data;
1212 * Ignore this callback if it is not being called from the Spell
1216 if( M_search_dialogMode(editor) == SPELL ) {
1218 * Is there a Change To string?
1220 pString = XmTextFieldGetString(M_replaceText(editor));
1223 * Disable the Change & Change All buttons if there is
1224 * no Change To string.
1226 if( pString == (char *)NULL || *pString == (char)'\0' ) {
1227 _DtEditorSetReplaceSensitivity(editor, False );
1228 _DtEditorSetReplaceAllSensitivity(editor, False );
1232 * If there is a Change To string enable the Change
1233 * All button, but only enable the Change button if.
1234 * the Find button has been pressed & the misspelled
1235 * word found (see _DtEditorDialogSearchCB()
1237 _DtEditorSetReplaceAllSensitivity(editor, True );
1238 if ( M_misspelled_found(editor) )
1239 _DtEditorSetReplaceSensitivity(editor, True );
1247 } /* end _DtEditorReplaceTextChangedCB */
1251 Check to see if the process is in the group, gid.
1253 static Boolean IsInGroup(gid_t gid)
1255 gid_t grps[NGROUPS_MAX];
1259 num_grps = getgroups(NGROUPS_MAX, grps);
1264 for (i=0; i < num_grps; i++) {
1274 Check to see if the process can execute the filter.
1276 static Boolean IsExecutable(struct stat statbuf)
1278 Boolean ingroup = IsInGroup(statbuf.st_gid);
1280 if (geteuid() == 0) { /** if root **/
1281 /** if any execute bit is set, root can execute **/
1282 if ((statbuf.st_mode & S_IXUSR)
1283 || (statbuf.st_mode & S_IXGRP)
1284 || (statbuf.st_mode & S_IXOTH))
1293 * if this process is the user and the user
1294 * does have execute permission, then the
1295 * filter will run, so return false
1297 if ((statbuf.st_uid == geteuid())
1298 && (statbuf.st_mode & S_IXUSR))
1304 * if this process is in the group for the
1305 * filter and group execute is set (and the
1306 * process isn't the user, then return true
1309 && (statbuf.st_mode & S_IXGRP)
1310 && (statbuf.st_uid != geteuid()))
1316 * if this process is not in the group or the user
1317 * for the filter and other execute is set, then
1320 if ((statbuf.st_mode & S_IXOTH)
1321 && (statbuf.st_uid != geteuid())
1333 This function checks to makes sure that this filter
1334 can be found, i.e. is in the current path and istalled.
1336 static Boolean IsValidFilter(DtEditorWidget pPriv)
1342 struct stat statbuf;
1343 _Xstrtokparams strtok_buf;
1345 /** check to see if a full path to the filter is given **/
1346 if (*M_spellFilter(pPriv) == '/') {
1347 if (stat(M_spellFilter(pPriv), &statbuf) != -1)
1348 return(IsExecutable(statbuf));
1355 * get the PATH from the environment and check to see if
1356 * the filter is in the path
1358 pathstr = getenv("PATH");
1359 if (pathstr == NULL)
1362 pathtmp = XtNewString(pathstr);
1363 pathtok = _XStrtok(pathtmp, ":", strtok_buf);
1364 while (pathtok != NULL) {
1365 tmp = (char*)XtMalloc((strlen(pathtok)
1366 + strlen(M_spellFilter(pPriv))
1367 + 2) * sizeof(char));
1368 strcpy(tmp, pathtok);
1370 strcat(tmp, M_spellFilter(pPriv));
1371 if (stat(tmp, &statbuf) != -1) {
1374 return(IsExecutable(statbuf));
1377 pathtok = _XStrtok(NULL,":", strtok_buf);