SearchCalls.c 37 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382
  1. /*
  2. * CDE - Common Desktop Environment
  3. *
  4. * Copyright (c) 1993-2012, The Open Group. All rights reserved.
  5. *
  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)
  10. * any later version.
  11. *
  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
  16. * details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with these libraries and programs; if not, write
  20. * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
  21. * Floor, Boston, MA 02110-1301 USA
  22. */
  23. /* $XConsortium: SearchCalls.c /main/13 1996/11/21 20:00:02 drk $ */
  24. /**********************************<+>*************************************
  25. ***************************************************************************
  26. **
  27. ** File: SearchCalls.c
  28. **
  29. ** Project: DtEditor widget for editing services
  30. **
  31. ** Description: Spell and Find functions
  32. ** -----------
  33. **
  34. *******************************************************************
  35. *
  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.
  44. *
  45. ********************************************************************/
  46. #include "EditorP.h"
  47. #include <Xm/TextF.h>
  48. #include <Xm/MessageB.h>
  49. #include <Xm/List.h>
  50. #include <ctype.h>
  51. #include <limits.h>
  52. #include <Dt/DtMsgsP.h>
  53. #include <Dt/HourGlass.h>
  54. #include "DtWidgetI.h"
  55. #include <Xm/XmPrivate.h> /* _XmStringSourceGetString */
  56. #define X_INCLUDE_STRING_H
  57. #define XOS_USE_XT_LOCKING
  58. #include <X11/Xos_r.h>
  59. extern XtPointer
  60. _XmStringUngenerate(XmString string,
  61. XmStringTag tag,
  62. XmTextType tag_type,
  63. XmTextType output_type);
  64. static Boolean DoReplace(
  65. DtEditorWidget pPriv,
  66. char *replace_string,
  67. Time time);
  68. static int SearchForString(
  69. DtEditorWidget pPriv,
  70. XmTextPosition startLocation,
  71. char *searchString);
  72. static Boolean DoSearch(
  73. DtEditorWidget pPriv,
  74. char *search_string,
  75. Time time);
  76. static Boolean IsValidFilter(
  77. DtEditorWidget pPriv);
  78. static Boolean IsInGroup(
  79. gid_t gid);
  80. static Boolean IsExecutable(
  81. struct stat statbuf);
  82. static void DestroyThisWidgetCB(
  83. Widget w,
  84. XtPointer client,
  85. XtPointer call);
  86. DtEditorErrorCode
  87. DtEditorInvokeSpellDialog(
  88. Widget widget)
  89. {
  90. DtEditorWidget pPriv = (DtEditorWidget) widget;
  91. char fileName[L_tmpnam], com[L_tmpnam + 7], *string, newline[1];
  92. char *line;
  93. FILE *fp; /* pipe to read words from */
  94. int len = 0; /* length of line read in */
  95. int maxLen = 0; /* max length of the line buffer */
  96. XmString word; /* processed word ready to add to list */
  97. DtEditorErrorCode error = DtEDITOR_NO_TMP_FILE;
  98. _DtWidgetToAppContext(widget);
  99. _DtAppLock(app);
  100. newline[0]='\n';
  101. if (!IsValidFilter(pPriv)) {
  102. error = DtEDITOR_SPELL_FILTER_FAILED;
  103. }
  104. else {
  105. _DtTurnOnHourGlass(M_topLevelShell(pPriv));
  106. /*
  107. * Write out to a tmp file, getting the name back
  108. */
  109. (void)tmpnam(fileName);
  110. if((fp = fopen(fileName, "w")) != (FILE *)NULL)
  111. {
  112. /*
  113. * Temporary file created sucessfully so write out contents of
  114. * widget in preparation of feeding it to the 'spell' filter.
  115. */
  116. string = (char *)XmTextGetString(M_text(pPriv));
  117. fwrite(string, sizeof(char), strlen(string), fp);
  118. XtFree(string);
  119. /*
  120. * Tack on a final newline (\n) cuz spell(1) does not spell-check
  121. * lines which do not terminate with a newline.
  122. */
  123. fwrite(newline, sizeof(char), 1, fp);
  124. fclose(fp);
  125. /* start spell command */
  126. sprintf(com, "%s %s", M_spellFilter(pPriv), fileName);
  127. fp = popen(com, "r");
  128. if ( fp == (FILE *)NULL )
  129. error = DtEDITOR_SPELL_FILTER_FAILED;
  130. else {
  131. error = DtEDITOR_NO_ERRORS;
  132. /*
  133. * The filter was started successfully.
  134. * Initialize the Spell dialog and get ready to receive
  135. * the list of misspelled words.
  136. */
  137. _DtEditorSearch(pPriv, True, True);
  138. _DtTurnOnHourGlass(M_search_dialog(pPriv));
  139. /* needed for bug in list */
  140. XmListSetPos(M_search_spellList(pPriv), 1);
  141. XmListDeleteAllItems(M_search_spellList(pPriv));
  142. /*
  143. * malloc the buffer
  144. */
  145. maxLen = 50;
  146. line = (char *) XtMalloc (sizeof(char) * (maxLen + 1));
  147. len = 0;
  148. /*
  149. * Now, get each word and hand it to the list
  150. */
  151. while(fgets(&line[len], maxLen - len, fp))
  152. {
  153. len += strlen(&line[len]);
  154. if (len > 0)
  155. {
  156. if (line[len - 1] == '\n')
  157. {
  158. line[len - 1] = '\0';
  159. word = XmStringCreateLocalized(line);
  160. XmListAddItemUnselected(M_search_spellList(pPriv), word, 0);
  161. XmStringFree(word);
  162. len = 0;
  163. }
  164. else
  165. {
  166. maxLen += 50;
  167. line = (char *) XtRealloc (line, sizeof(char) * (maxLen + 1));
  168. }
  169. }
  170. }
  171. /* clean up and display the results */
  172. XtFree(line);
  173. pclose(fp);
  174. _DtEditorSearch(pPriv, True, False);
  175. _DtTurnOffHourGlass(M_search_dialog(pPriv));
  176. } /* end start the spell filter */
  177. unlink(fileName);
  178. } /* end create temporary file */
  179. _DtTurnOffHourGlass(M_topLevelShell(pPriv));
  180. }
  181. if (error != DtEDITOR_NO_ERRORS) {
  182. XmString title, msg1, msg2, msg3;
  183. Arg al[10];
  184. Cardinal ac;
  185. char *buf;
  186. Widget dialog;
  187. buf = XtMalloc((strlen(BAD_FILTER2) +
  188. strlen(M_spellFilter(pPriv)) + 1) *
  189. sizeof(char));
  190. sprintf(buf, BAD_FILTER2, M_spellFilter(pPriv));
  191. msg1 = XmStringGenerate(BAD_FILTER,
  192. XmFONTLIST_DEFAULT_TAG,
  193. XmCHARSET_TEXT, NULL);
  194. msg2 = XmStringSeparatorCreate();
  195. msg3= XmStringConcatAndFree(msg1, msg2);
  196. msg1 = XmStringGenerate(buf,
  197. XmFONTLIST_DEFAULT_TAG,
  198. XmCHARSET_TEXT, NULL);
  199. msg2 = XmStringConcatAndFree(msg3, msg1);
  200. XtFree(buf);
  201. title = XmStringCreateLocalized(ERROR_TITLE);
  202. ac = 0;
  203. XtSetArg(al[ac], XmNdialogTitle, title); ac++;
  204. XtSetArg(al[ac], XmNdialogType, XmDIALOG_ERROR); ac++;
  205. XtSetArg(al[ac], XmNmessageString, msg2); ac++;
  206. dialog = XmCreateMessageDialog((Widget)pPriv,
  207. "Spell Error", al, ac
  208. );
  209. XtUnmanageChild(XmMessageBoxGetChild(dialog,
  210. XmDIALOG_HELP_BUTTON));
  211. XtUnmanageChild(XmMessageBoxGetChild(dialog,
  212. XmDIALOG_CANCEL_BUTTON));
  213. XtAddCallback(dialog, XmNokCallback, DestroyThisWidgetCB, NULL);
  214. XtVaSetValues(XtParent(dialog),
  215. XmNdeleteResponse, XmDESTROY,
  216. NULL);
  217. XtManageChild(dialog);
  218. XmStringFree(msg2);
  219. XmStringFree(title);
  220. }
  221. _DtAppUnlock(app);
  222. return( error );
  223. } /* end DtEditorInvokeSpellDialog */
  224. static void DestroyThisWidgetCB (
  225. Widget w,
  226. XtPointer client,
  227. XtPointer call)
  228. {
  229. XtDestroyWidget(w);
  230. }
  231. /* ARGSUSED */
  232. Boolean
  233. DtEditorFind(
  234. Widget widget,
  235. char *find)
  236. {
  237. DtEditorWidget editor = (DtEditorWidget) widget;
  238. Boolean foundIt = True;
  239. _DtWidgetToAppContext(widget);
  240. _DtAppLock(app);
  241. /*
  242. * If we were passed a string to find, then use it. Otherwise,
  243. * use the last find string entered in the Find/Change dialog.
  244. */
  245. if ( find != (char *)NULL )
  246. foundIt = DoSearch(editor, find, CurrentTime);
  247. else
  248. {
  249. /*
  250. * If there is no value from the dialog, then post the Find/Change
  251. * dialog to get one.
  252. */
  253. if (!M_search_string(editor))
  254. _DtEditorSearch(editor, False, False);
  255. else
  256. foundIt = DoSearch(editor, M_search_string(editor), CurrentTime);
  257. }
  258. _DtAppUnlock(app);
  259. return( foundIt );
  260. } /* DtEditorFind */
  261. /* Count the number of characters represented in the char* str.
  262. * By definition, if MB_CUR_MAX == 1 then numBytes == number of characters.
  263. * Otherwise, use mblen to calculate.
  264. */
  265. int
  266. _DtEditor_CountCharacters(
  267. char *str,
  268. int numBytes)
  269. {
  270. char *bptr;
  271. int count = 0;
  272. int char_size = 0;
  273. int mbCurMax = MB_CUR_MAX; /* invoke the macro just once */
  274. if (mbCurMax <= 1)
  275. return (numBytes < 0)? 0 : numBytes;
  276. if (numBytes <=0 || str == NULL || *str == '\0')
  277. return 0;
  278. for(bptr = str; numBytes > 0; count++, bptr+= char_size)
  279. {
  280. char_size = mblen(bptr, mbCurMax);
  281. if (char_size <= 0)
  282. break; /* error */
  283. numBytes -= char_size;
  284. }
  285. return count;
  286. }
  287. /*
  288. * SearchForString takes an Editor widget, a position at which
  289. * to begin its search, and the string for which it is to search.
  290. * It searches first from startLocation to the end of the file, and
  291. * then if necessary from the start of the file to startLocation.
  292. * It returns an integer indicating the location of the string, or
  293. * -1 if the string is not found.
  294. */
  295. static int
  296. SearchForString(
  297. DtEditorWidget pPriv,
  298. XmTextPosition startLocation,
  299. char *searchString)
  300. {
  301. XmTextPosition pos, searchAnchor, topAnchor, cursorLocation,
  302. lastPosition = XmTextGetLastPosition(M_text(pPriv));
  303. topAnchor = 0;
  304. searchAnchor = cursorLocation = startLocation;
  305. while((Boolean)XmTextFindString(M_text(pPriv), searchAnchor,
  306. searchString, XmTEXT_FORWARD,
  307. &pos) ||
  308. ((Boolean)XmTextFindString(M_text(pPriv), topAnchor,
  309. searchString, XmTEXT_FORWARD, &pos) &&
  310. pos < cursorLocation))
  311. {
  312. char *word, leadingChar, trailingChar;
  313. XmTextPosition endPos;
  314. int length;
  315. /*
  316. * Do some extra work for the Spell case, so we find only "words"
  317. * and not strings.
  318. * Get the word with the leading & trailing characters.
  319. * It's a word if it's bounded by:
  320. * a. 16-bit characters
  321. * b. Spaces
  322. * c. Punctuation
  323. */
  324. /*
  325. * Variables:
  326. *
  327. * 0 (constant) - first character position in the document.
  328. * lastPosition - last character position in the document.
  329. *
  330. * pos - Position in the document of the first character
  331. * of the word. Does not include leading character.
  332. * endPos - Position in the document of the last character
  333. * of the word + 1. Points to the trailing character,
  334. * if any.
  335. *
  336. * word - The string we have matched. Includes the leading
  337. * & trailing characters, if any.
  338. * word[0] - Leading character, if any, otherwise first
  339. * character of the matched string.
  340. * word[length] - Trailing character, if any, otherwise last
  341. * character of the matched string.
  342. *
  343. */
  344. endPos = pos + 1 + _DtEditor_CountCharacters(searchString,
  345. strlen(searchString));
  346. if(pos < cursorLocation)
  347. topAnchor = pos + 1;
  348. else
  349. searchAnchor = pos + 1;
  350. /*
  351. * If the first character of the word is the first character in
  352. * the document there is no leading character. Likewise, if the
  353. * last character of the word is the last character in the document
  354. * there is no trailing character.
  355. */
  356. if( pos > 0 ) {
  357. /*
  358. * There is a leading character.
  359. */
  360. if (endPos <= lastPosition) {
  361. /*
  362. * There is a trailing character.
  363. */
  364. word = (char *)_XmStringSourceGetString(
  365. (XmTextWidget) M_text(pPriv),
  366. pos - 1, endPos, False);
  367. length = strlen(word) - 1;
  368. trailingChar = word[length];
  369. }
  370. else {
  371. /*
  372. * There is no trailing character.
  373. */
  374. word = (char *)_XmStringSourceGetString(
  375. (XmTextWidget) M_text(pPriv),
  376. pos - 1, lastPosition, False);
  377. length = strlen(word);
  378. trailingChar = ' ';
  379. }
  380. leadingChar = word[0];
  381. }
  382. else {
  383. /*
  384. * There is no leading character.
  385. */
  386. if (endPos <= lastPosition) {
  387. /*
  388. * There is a trailing character.
  389. */
  390. word = (char *)_XmStringSourceGetString(
  391. (XmTextWidget) M_text(pPriv),
  392. 0, endPos, False);
  393. length = strlen(word) - 1;
  394. trailingChar = word[length];
  395. }
  396. else {
  397. /*
  398. * There is no trailing character.
  399. */
  400. word = (char *)_XmStringSourceGetString(
  401. (XmTextWidget) M_text(pPriv),
  402. 0, lastPosition, False);
  403. length = strlen(word);
  404. trailingChar = ' ';
  405. }
  406. leadingChar = ' ';
  407. }
  408. if ((M_search_dialogMode(pPriv) != SPELL) ||
  409. (
  410. ((mblen(word, MB_CUR_MAX) > 1) ||
  411. ( isascii(leadingChar) &&
  412. (isspace(leadingChar) || ispunct(leadingChar))
  413. )
  414. ) &&
  415. ((mblen(word+length-1, MB_CUR_MAX) > 1) ||
  416. ( isascii(trailingChar) &&
  417. (isspace(trailingChar) || ispunct(trailingChar))
  418. )
  419. )
  420. )
  421. )
  422. {
  423. /*
  424. * Either we are not in Spell mode or we have a word
  425. * so return
  426. */
  427. if (word != (char *)NULL)
  428. XtFree(word);
  429. return (int)pos;
  430. }
  431. XtFree(word);
  432. }
  433. return -1;
  434. }
  435. static Boolean
  436. DoSearch(
  437. DtEditorWidget widget,
  438. char *search_string,
  439. Time time)
  440. {
  441. int stringPosition;
  442. Boolean foundIt = False;
  443. stringPosition = SearchForString(widget,
  444. XmTextGetInsertionPosition(M_text(widget)),
  445. search_string);
  446. if(stringPosition == -1) {
  447. /*
  448. * If the string was not found unselect everything
  449. */
  450. XmTextClearSelection(M_text(widget), time);
  451. }
  452. else {
  453. /*
  454. * The string was found so highlight the word and scroll the window
  455. * if it is not visible.
  456. */
  457. XmTextPosition pos = (XmTextPosition) stringPosition;
  458. XmTextWidget tw = (XmTextWidget)M_text(widget);
  459. foundIt = True;
  460. XmTextSetInsertionPosition(M_text(widget), pos);
  461. XmTextSetSelection( M_text(widget), pos,
  462. pos+_DtEditor_CountCharacters(search_string, strlen(search_string)),
  463. XtLastTimestampProcessed(XtDisplay(M_text(widget))) );
  464. /*
  465. * Scroll the widget, if necessary
  466. */
  467. if (pos < tw->text.top_character || pos >= tw->text.bottom_position)
  468. {
  469. Arg al[5];
  470. int ac;
  471. Dimension height;
  472. short rows;
  473. Position x, y;
  474. ac = 0;
  475. XtSetArg(al[ac], XmNheight, &height); ac++;
  476. XtSetArg(al[ac], XmNrows, &rows); ac++;
  477. XtGetValues(M_text(widget), al, ac);
  478. if(XmTextPosToXY(M_text(widget), pos, &x, &y) == True)
  479. {
  480. int offset = (int)((y - height/2) * rows) / (int)height;
  481. XmTextScroll(M_text(widget), offset);
  482. }
  483. }
  484. }
  485. return ( foundIt );
  486. } /* end DoSearch */
  487. /*
  488. * DtEditorInvokeFindChangeDialog posts the "Find/Change" dialog.
  489. */
  490. void
  491. DtEditorInvokeFindChangeDialog(
  492. Widget widget)
  493. {
  494. DtEditorWidget pPriv = (DtEditorWidget) widget;
  495. _DtWidgetToAppContext(widget);
  496. _DtAppLock(app);
  497. _DtEditorSearch(pPriv, False, False);
  498. _DtAppUnlock(app);
  499. }
  500. /*
  501. * DoReplace checks that there is a non-null selection, and
  502. * if so, replaces the selection with the replace_string argument.
  503. */
  504. static Boolean
  505. DoReplace(
  506. DtEditorWidget pPriv,
  507. char *replace_string,
  508. Time time)
  509. {
  510. XmTextPosition first, last;
  511. Boolean replaced = False;
  512. /*
  513. * Only do a replace if we have a non-null selection.
  514. * We could check that the selection == the Find string, but
  515. * this allows a little more flexibility for the user.
  516. */
  517. if (XmTextGetSelectionPosition(M_text(pPriv), &first, &last) &&
  518. first != last)
  519. {
  520. XmTextReplace(M_text(pPriv), first, last, replace_string);
  521. XmTextSetSelection(M_text(pPriv), first,
  522. first +
  523. _DtEditor_CountCharacters(replace_string, strlen(replace_string)),
  524. time);
  525. replaced = True;
  526. }
  527. return( replaced );
  528. }
  529. /*
  530. * ReplaceAll replaces all occurrences of search_string with
  531. * replacement_string in widget.
  532. */
  533. static Boolean
  534. ReplaceAll(
  535. DtEditorWidget widget,
  536. char *search_string,
  537. char *replace_string )
  538. {
  539. int replacementLength, searchLength, lastOccurrence, thisOccurrence;
  540. Boolean replaceOK = False;
  541. /*
  542. * Make sure there is a string to find. Null replacement strings
  543. * are OK.
  544. */
  545. if( search_string && *search_string )
  546. {
  547. /*
  548. * How long is the string we are searching for?
  549. */
  550. searchLength = _DtEditor_CountCharacters( search_string,
  551. strlen(search_string) );
  552. /*
  553. * How long is the replacement string?
  554. */
  555. replacementLength = _DtEditor_CountCharacters( replace_string,
  556. strlen(replace_string) );
  557. /*
  558. * Start at the beginning and search for the string
  559. */
  560. lastOccurrence = -1;
  561. while( ((thisOccurrence = SearchForString(widget,
  562. (lastOccurrence > 0)? (XmTextPosition)lastOccurrence : 0,
  563. search_string)
  564. ) != -1 ) &&
  565. thisOccurrence >= lastOccurrence )
  566. {
  567. XmTextReplace( M_text(widget), (XmTextPosition)thisOccurrence,
  568. (XmTextPosition) (thisOccurrence + searchLength),
  569. replace_string );
  570. lastOccurrence = thisOccurrence + replacementLength;
  571. } /* end while */
  572. if (lastOccurrence != -1)
  573. replaceOK = True;
  574. }
  575. return( replaceOK );
  576. } /* end ReplaceAll */
  577. /*
  578. * DtEditorChange replaces either the current selection, the next occurrence
  579. * of a string, or all occurrences of the string with a replacement string.
  580. * If no find or change to strings are passed in, DtEditorFindChange uses
  581. * the last find and change to strings from the Find/Change dialog.
  582. */
  583. Boolean
  584. DtEditorChange(
  585. Widget widget,
  586. DtEditorChangeValues *findChangeStrings,
  587. unsigned int instanceToChange)
  588. {
  589. Boolean returnVal = False;
  590. DtEditorWidget editor = (DtEditorWidget) widget;
  591. _DtWidgetToAppContext(widget);
  592. _DtAppLock(app);
  593. switch( instanceToChange )
  594. {
  595. case DtEDITOR_NEXT_OCCURRENCE:
  596. {
  597. /*
  598. * Find the next occurrence and replace it (by treating it as
  599. * a current selection).
  600. */
  601. /*
  602. * If we were passed a Find string use it. Otherwise, tell
  603. * DtEditorFind to use the last search string value
  604. * (M_search_string).
  605. */
  606. if ( findChangeStrings != (DtEditorChangeValues *) NULL )
  607. returnVal = DtEditorFind( widget, findChangeStrings->find );
  608. else
  609. returnVal = DtEditorFind( widget, (char *)NULL );
  610. if ( returnVal == False)
  611. break;
  612. }
  613. case DtEDITOR_CURRENT_SELECTION:
  614. {
  615. /*
  616. * Replace whatever is selected.
  617. */
  618. /*
  619. * If we were passed a Change To string use it. Otherwise,
  620. * use the last replace string value.
  621. */
  622. if ( findChangeStrings != (DtEditorChangeValues *) NULL )
  623. returnVal = DoReplace( editor, findChangeStrings->changeTo,
  624. CurrentTime );
  625. else
  626. returnVal= DoReplace(editor,M_replace_string(editor),CurrentTime);
  627. break;
  628. }
  629. case DtEDITOR_ALL_OCCURRENCES:
  630. {
  631. _DtTurnOnHourGlass( M_topLevelShell(editor) );
  632. if ( findChangeStrings != (DtEditorChangeValues *) NULL )
  633. returnVal = ReplaceAll( editor, findChangeStrings->find,
  634. findChangeStrings->changeTo );
  635. else
  636. returnVal = ReplaceAll( editor, M_search_string(editor),
  637. M_replace_string(editor) );
  638. _DtTurnOffHourGlass( M_topLevelShell( editor ) );
  639. break;
  640. } /* replace all occurrences */
  641. default :
  642. {
  643. }
  644. } /* end switch */
  645. _DtAppUnlock(app);
  646. return( returnVal );
  647. } /* end DtEditorChange */
  648. /* ARGSUSED */
  649. void
  650. _DtEditorSearchMapCB(
  651. Widget w,
  652. caddr_t client_data,
  653. caddr_t call_data )
  654. {
  655. int ac;
  656. Arg al[4];
  657. Widget parent;
  658. Position newX, newY, pY, pX;
  659. Dimension pHeight, myHeight, pWidth, myWidth;
  660. DtEditorWidget pPriv = (DtEditorWidget) client_data;
  661. parent = M_topLevelShell(pPriv);
  662. pX = XtX(parent);
  663. pY = XtY(parent);
  664. pHeight = XtHeight(parent);
  665. pWidth = XtWidth(parent);
  666. myHeight = XtHeight(w);
  667. myWidth = XtWidth(w);
  668. if ((newY = pY - (int)myHeight + 5) < 0)
  669. newY = pY + pHeight;
  670. newX = pX + pWidth/2 - ((int)myWidth)/2;
  671. ac = 0;
  672. XtSetArg(al[ac], XmNx, newX); ac++;
  673. XtSetArg(al[ac], XmNy, newY); ac++;
  674. XtSetValues(w,al,ac);
  675. }
  676. /*
  677. *
  678. * _DtEditorDialogSearchCB is called whenever the Find button is pressed
  679. * in the Find/Change dialog. If the dialog is displayed in Find/Change
  680. * mode, it updates the contents of M_search_string() with the contents
  681. * of the "Find" text field, and then invokes DtEditorFind(). If the
  682. * find is successful, the Change button is enabled, otherwise the
  683. * "String not found" dialog is displayed.
  684. *
  685. * When the dialog is in Spell mode, the selected misspelled word is merely
  686. * passed to DtEditorFind(). The Change (and Change All) buttons are left
  687. * insentive until the user types something into the Change To field
  688. * (too many users were replacing misspelled words with blanks).
  689. *
  690. */
  691. /* ARGSUSED */
  692. void
  693. _DtEditorDialogSearchCB(
  694. Widget w,
  695. caddr_t client_data,
  696. caddr_t call_data )
  697. {
  698. DtEditorWidget pPriv = (DtEditorWidget) client_data;
  699. /*
  700. * Is the dialog in Find/Change or Spell mode?
  701. */
  702. if (M_search_dialogMode(pPriv) == REPLACE) {
  703. /*
  704. * Find/Change mode
  705. * Free the existing search string and get the new one.
  706. */
  707. XtFree(M_search_string(pPriv));
  708. M_search_string(pPriv) = XmTextFieldGetString( M_findText(pPriv) );
  709. /*
  710. * Find the string
  711. */
  712. if( DtEditorFind((Widget)pPriv, M_search_string(pPriv)) ) {
  713. /*
  714. * If the string was found then enable the Change button.
  715. * It will be disabled when it is pressed or a new Find string is
  716. * entered.
  717. */
  718. _DtEditorSetReplaceSensitivity( pPriv, True );
  719. }
  720. else {
  721. /*
  722. * Post a dialog informing the user the string was not found.
  723. */
  724. char *tempStr = (char *)XtMalloc(strlen(NO_FIND) +
  725. strlen(M_search_string(pPriv)) + 1);
  726. sprintf(tempStr, NO_FIND, M_search_string(pPriv));
  727. _DtEditorWarning(pPriv, tempStr, XmDIALOG_INFORMATION);
  728. XtFree(tempStr);
  729. }
  730. }
  731. else {
  732. /*
  733. * Spell mode.
  734. */
  735. char *pString;
  736. M_misspelled_found(pPriv) = DtEditorFind((Widget)pPriv,
  737. M_misspelled_string(pPriv) );
  738. /*
  739. * If the word was found & there is a Change To string then enable
  740. * the Change button. If there is no Change To string, Change will
  741. * be enabled when a string is entered if M_misspelled_found is True
  742. * (see _DtEditorReplaceTextChangedCB)
  743. *
  744. * Change All is enabled in _DtEditorReplaceTextChangedCB()
  745. * (ie. anytime there is a Change To string). It is not
  746. * dependent upon a sucessful Find because it initiates its own
  747. * find.
  748. */
  749. if ( M_misspelled_found(pPriv) == True ) {
  750. /*
  751. * Is there a Change To string?
  752. */
  753. pString = XmTextFieldGetString(M_replaceText(pPriv));
  754. if( pString != (char *)NULL && *pString != (char)'\0' )
  755. _DtEditorSetReplaceSensitivity( pPriv, True );
  756. XtFree(pString);
  757. }
  758. else {
  759. /*
  760. * Post a dialog informing the user the string was not found.
  761. */
  762. char *tempStr = (char *)XtMalloc(strlen(NO_FIND) +
  763. strlen(M_misspelled_string(pPriv)) + 1);
  764. sprintf(tempStr, NO_FIND, M_misspelled_string(pPriv));
  765. _DtEditorWarning(pPriv, tempStr, XmDIALOG_INFORMATION);
  766. XtFree(tempStr);
  767. }
  768. }
  769. } /* end _DtEditorDialogSearchCB */
  770. /*
  771. * _DtEditorDialogReplaceCB is called whenever the Change button is pressed
  772. * in the Find/Change dialog. If the dialog is displayed in Find/Change
  773. * mode, it updates the contents of M_replace_string() with the contents
  774. * of the "Change To" text field, and then invokes DtEditorChange().
  775. *
  776. * When the dialog is in Spell mode, the contents of the "Change To" text
  777. * field is passed to DtEditorChange() without updating M_replace_string().
  778. *
  779. * In both cases, the Change button is disabled after the change is
  780. * complete.
  781. */
  782. /* ARGSUSED */
  783. void
  784. _DtEditorDialogReplaceCB(
  785. Widget w,
  786. caddr_t client_data,
  787. caddr_t call_data )
  788. {
  789. DtEditorWidget pPriv = (DtEditorWidget) client_data;
  790. /*
  791. * Is the dialog in Find/Change or Spell mode?
  792. */
  793. if (M_search_dialogMode(pPriv) == REPLACE) {
  794. /*
  795. * Find/Change mode
  796. * Free the existing Change To string and get the new one.
  797. */
  798. XtFree(M_replace_string(pPriv));
  799. M_replace_string(pPriv) = XmTextFieldGetString(M_replaceText(pPriv));
  800. DtEditorChange( (Widget)pPriv, (DtEditorChangeValues *)NULL,
  801. DtEDITOR_CURRENT_SELECTION );
  802. }
  803. else {
  804. /*
  805. * Spell mode.
  806. */
  807. DtEditorChangeValues newWord;
  808. newWord.changeTo = XmTextFieldGetString(M_replaceText(pPriv));
  809. if (newWord.changeTo != (char *)NULL) {
  810. /* This field ignored when changing the current selection */
  811. newWord.find = (char *)NULL;
  812. DtEditorChange( (Widget)pPriv, &newWord, DtEDITOR_CURRENT_SELECTION );
  813. XtFree(newWord.changeTo);
  814. }
  815. }
  816. /*
  817. * Disable the Change button. In Find/Change mode, it will be enabled
  818. * when the Find button is pressed and the Find text is successfully
  819. * found. In Spell mode, there must also be a value in the Change To
  820. * field.
  821. */
  822. _DtEditorSetReplaceSensitivity(pPriv, False );
  823. /*
  824. * Want the traversal to be on the Find button, so that the user
  825. * can initiate another search.
  826. */
  827. XmProcessTraversal(M_search_findBtn(pPriv), XmTRAVERSE_CURRENT);
  828. }
  829. /*
  830. * _DtEditorDialogReplaceAllCB is attached to the "Change All" button
  831. * in the Find/Change dialog. It replaces all occurrences of the "Find"
  832. * string with the "Change To" string.
  833. */
  834. /* ARGSUSED */
  835. void
  836. _DtEditorDialogReplaceAllCB(
  837. Widget w,
  838. caddr_t client_data,
  839. caddr_t call_data )
  840. {
  841. DtEditorWidget pPriv = (DtEditorWidget) client_data;
  842. /*
  843. * Is the dialog in Find/Change or Spell mode?
  844. */
  845. if (M_search_dialogMode(pPriv) == REPLACE) {
  846. /*
  847. * Find/Change mode
  848. * Free any existing search string before getting the current one.
  849. */
  850. XtFree(M_search_string(pPriv));
  851. M_search_string(pPriv) = XmTextFieldGetString(M_findText(pPriv));
  852. /*
  853. * Free the existing Change To string and get the new one.
  854. */
  855. XtFree(M_replace_string(pPriv));
  856. M_replace_string(pPriv) = XmTextFieldGetString(M_replaceText(pPriv));
  857. /*
  858. * Make the change with the current values (set above).
  859. */
  860. if( !DtEditorChange((Widget)pPriv, (DtEditorChangeValues *)NULL,
  861. DtEDITOR_ALL_OCCURRENCES) ) {
  862. /*
  863. * If the replace failed, post a dialog informing the user
  864. * the string was not found.
  865. */
  866. char *tempStr = (char *)XtMalloc(strlen(NO_FIND) +
  867. strlen(M_search_string(pPriv)) + 1);
  868. sprintf(tempStr, NO_FIND, M_search_string(pPriv));
  869. _DtEditorWarning(pPriv, tempStr, XmDIALOG_INFORMATION);
  870. XtFree(tempStr);
  871. }
  872. }
  873. else {
  874. /*
  875. * Spell mode.
  876. */
  877. DtEditorChangeValues changeValues;
  878. changeValues.find = M_misspelled_string(pPriv);
  879. changeValues.changeTo = XmTextFieldGetString(M_replaceText(pPriv));
  880. DtEditorChange((Widget)pPriv, &changeValues, DtEDITOR_ALL_OCCURRENCES);
  881. XtFree( changeValues.changeTo );
  882. }
  883. /*
  884. * Disable the Change button. It will be enabled when the Find
  885. * button is pressed and the Find text is successfully found.
  886. * In Spell mode, there must also be a value in the Change To field.
  887. */
  888. _DtEditorSetReplaceSensitivity(pPriv, False );
  889. } /* _DtEditorDialogReplaceAllCB */
  890. /* ARGSUSED */
  891. void
  892. _DtEditorDialogFindCancelCB(
  893. Widget w,
  894. caddr_t client_data,
  895. caddr_t call_data )
  896. {
  897. DtEditorWidget pPriv = (DtEditorWidget)client_data;
  898. XtUnmanageChild(M_search_dialog(pPriv));
  899. }
  900. /*
  901. * _DtEditorMisspelledSelectCB is called when a new word has been selected
  902. * from the list of misspelled words.
  903. */
  904. /* ARGSUSED */
  905. void
  906. _DtEditorMisspelledSelectCB(
  907. Widget w,
  908. caddr_t client_data,
  909. caddr_t call_data )
  910. {
  911. XmListCallbackStruct *cb = (XmListCallbackStruct *)call_data;
  912. DtEditorWidget editor = (DtEditorWidget)client_data;
  913. /*
  914. * Get the selected word for use when the Find or Replace All button
  915. * is pressed.
  916. */
  917. XtFree(M_misspelled_string(editor));
  918. M_misspelled_string(editor) =
  919. _XmStringUngenerate(cb->item, NULL, XmCHARSET_TEXT, XmCHARSET_TEXT);
  920. /*
  921. * Mark that it has not been found
  922. */
  923. M_misspelled_found(editor) = False;
  924. /*
  925. * Enable the Find button
  926. */
  927. _DtEditorSetFindSensitivity(editor, True );
  928. /*
  929. * Clear the "Change To" text field.
  930. */
  931. XmTextFieldSetString(M_replaceText(editor), (char *)NULL);
  932. } /* end _DtEditorMisspelledSelectCB */
  933. /*
  934. * _DtEditorMisspelledDblClickCB is called when a word has been double-
  935. * clicked from the list of misspelled words. First, the word will become
  936. * the new misspelled string and, then, a find will be initiated for it.
  937. */
  938. /* ARGSUSED */
  939. void
  940. _DtEditorMisspelledDblClickCB(
  941. Widget w,
  942. caddr_t client_data,
  943. caddr_t call_data )
  944. {
  945. _DtEditorMisspelledSelectCB(w, client_data, call_data );
  946. _DtEditorDialogSearchCB(w, client_data, call_data );
  947. } /* end _DtEditorMisspelledDblClickCB */
  948. /*
  949. * The following functions effectively track whether the user has
  950. * entered or changed the "Find" text. This information is used to make
  951. * the "Find" and "Change All" buttons sensitive/desensitive. The
  952. * "Find" button must be pressed and the Find text found before the
  953. * "Change" button is sensitive. These functions also set the default
  954. * button to either the "Find" or "Close" button.
  955. */
  956. void
  957. _DtEditorSetFindSensitivity(
  958. DtEditorWidget widget,
  959. Boolean sensitivity)
  960. {
  961. XtSetSensitive(M_search_findBtn(widget), sensitivity);
  962. }
  963. void
  964. _DtEditorSetReplaceSensitivity(
  965. DtEditorWidget editor,
  966. Boolean sensitivity)
  967. {
  968. /*
  969. * Cannot enable Change button if widget is read only
  970. */
  971. if ( M_editable(editor) || !sensitivity )
  972. XtSetSensitive(M_search_replaceBtn(editor), sensitivity);
  973. }
  974. void
  975. _DtEditorSetReplaceAllSensitivity(
  976. DtEditorWidget editor,
  977. Boolean sensitivity)
  978. {
  979. /*
  980. * Cannot enable Change All button if widget is read only
  981. */
  982. if ( M_editable(editor) || !sensitivity )
  983. XtSetSensitive(M_search_replaceAllBtn(editor), sensitivity);
  984. }
  985. /* ARGSUSED */
  986. void
  987. _DtEditorFindTextChangedCB(
  988. Widget w,
  989. caddr_t client_data,
  990. caddr_t call_data )
  991. {
  992. Arg al[10]; /* arg list */
  993. Widget defaultButton;
  994. char *pString;
  995. DtEditorWidget editor = (DtEditorWidget)client_data;
  996. /*
  997. * Is there a Find string?
  998. */
  999. pString = XmTextFieldGetString(M_findText(editor));
  1000. /*
  1001. * Only enable the Find & Change All buttons if there is a
  1002. * string to search for (i.e. a Find string).
  1003. */
  1004. if(pString == (char *)NULL || *pString == (char)'\0') {
  1005. _DtEditorSetFindSensitivity(editor, False );
  1006. _DtEditorSetReplaceAllSensitivity(editor, False );
  1007. /*
  1008. * Make the Close button the default
  1009. */
  1010. defaultButton = M_search_closeBtn(editor);
  1011. }
  1012. else {
  1013. _DtEditorSetFindSensitivity( editor, True );
  1014. _DtEditorSetReplaceAllSensitivity(editor, True );
  1015. /*
  1016. * Make the Find button the default
  1017. */
  1018. defaultButton = M_search_findBtn(editor);
  1019. }
  1020. XtFree(pString);
  1021. /*
  1022. * Set the default button
  1023. */
  1024. XtSetArg(al[0], XmNdefaultButton, defaultButton);
  1025. XtSetValues(M_search_dialog(editor), al, 1);
  1026. /*
  1027. * Disable the Change button. It will be enabled when the Find
  1028. * button is pressed and the Find text is successfully found.
  1029. */
  1030. _DtEditorSetReplaceSensitivity(editor, False );
  1031. } /* end _DtEditorFindTextChangedCB */
  1032. /*
  1033. * The following functions effectively track whether the user has
  1034. * entered or changed the Change To text. This information is used
  1035. * in the Spell dialog to make the Change and Change All buttons
  1036. * sensitive/desensitive so users cannot replace a misspelled word with
  1037. * a null string.
  1038. */
  1039. /* ARGSUSED */
  1040. void
  1041. _DtEditorReplaceTextChangedCB(
  1042. Widget w,
  1043. caddr_t client_data,
  1044. caddr_t call_data )
  1045. {
  1046. char *pString;
  1047. DtEditorWidget editor = (DtEditorWidget)client_data;
  1048. /*
  1049. * Ignore this callback if it is not being called from the Spell
  1050. * dialog.
  1051. */
  1052. if( M_search_dialogMode(editor) == SPELL ) {
  1053. /*
  1054. * Is there a Change To string?
  1055. */
  1056. pString = XmTextFieldGetString(M_replaceText(editor));
  1057. /*
  1058. * Disable the Change & Change All buttons if there is
  1059. * no Change To string.
  1060. */
  1061. if( pString == (char *)NULL || *pString == (char)'\0' ) {
  1062. _DtEditorSetReplaceSensitivity(editor, False );
  1063. _DtEditorSetReplaceAllSensitivity(editor, False );
  1064. }
  1065. else {
  1066. /*
  1067. * If there is a Change To string enable the Change
  1068. * All button, but only enable the Change button if.
  1069. * the Find button has been pressed & the misspelled
  1070. * word found (see _DtEditorDialogSearchCB()
  1071. */
  1072. _DtEditorSetReplaceAllSensitivity(editor, True );
  1073. if ( M_misspelled_found(editor) )
  1074. _DtEditorSetReplaceSensitivity(editor, True );
  1075. XtFree(pString);
  1076. }
  1077. }
  1078. } /* end _DtEditorReplaceTextChangedCB */
  1079. /***
  1080. IsInGroup -
  1081. Check to see if the process is in the group, gid.
  1082. ***/
  1083. static Boolean IsInGroup(gid_t gid)
  1084. {
  1085. gid_t grps[NGROUPS_MAX];
  1086. int i;
  1087. int num_grps;
  1088. num_grps = getgroups(NGROUPS_MAX, grps);
  1089. if (num_grps == -1)
  1090. return(False);
  1091. for (i=0; i < num_grps; i++) {
  1092. if (gid == grps[i])
  1093. return(True);
  1094. }
  1095. return(False);
  1096. }
  1097. /***
  1098. IsExecutable -
  1099. Check to see if the process can execute the filter.
  1100. ****/
  1101. static Boolean IsExecutable(struct stat statbuf)
  1102. {
  1103. Boolean ingroup = IsInGroup(statbuf.st_gid);
  1104. if (geteuid() == 0) { /** if root **/
  1105. /** if any execute bit is set, root can execute **/
  1106. if ((statbuf.st_mode & S_IXUSR)
  1107. || (statbuf.st_mode & S_IXGRP)
  1108. || (statbuf.st_mode & S_IXOTH))
  1109. {
  1110. return (True);
  1111. }
  1112. else {
  1113. return (False);
  1114. }
  1115. }
  1116. /*
  1117. * if this process is the user and the user
  1118. * does have execute permission, then the
  1119. * filter will run, so return false
  1120. */
  1121. if ((statbuf.st_uid == geteuid())
  1122. && (statbuf.st_mode & S_IXUSR))
  1123. {
  1124. return(True);
  1125. }
  1126. /*
  1127. * if this process is in the group for the
  1128. * filter and group execute is set (and the
  1129. * process isn't the user, then return true
  1130. */
  1131. if (ingroup
  1132. && (statbuf.st_mode & S_IXGRP)
  1133. && (statbuf.st_uid != geteuid()))
  1134. {
  1135. return(True);
  1136. }
  1137. /*
  1138. * if this process is not in the group or the user
  1139. * for the filter and other execute is set, then
  1140. * return true
  1141. */
  1142. if ((statbuf.st_mode & S_IXOTH)
  1143. && (statbuf.st_uid != geteuid())
  1144. && !ingroup)
  1145. {
  1146. return(True);
  1147. }
  1148. return(False);
  1149. }
  1150. /*****
  1151. IsValidFilter -
  1152. This function checks to makes sure that this filter
  1153. can be found, i.e. is in the current path and istalled.
  1154. *****/
  1155. static Boolean IsValidFilter(DtEditorWidget pPriv)
  1156. {
  1157. char *pathstr;
  1158. char *pathtmp;
  1159. char *pathtok;
  1160. char *tmp;
  1161. struct stat statbuf;
  1162. _Xstrtokparams strtok_buf;
  1163. /** check to see if a full path to the filter is given **/
  1164. if (*M_spellFilter(pPriv) == '/') {
  1165. if (stat(M_spellFilter(pPriv), &statbuf) != -1)
  1166. return(IsExecutable(statbuf));
  1167. else
  1168. return(False);
  1169. }
  1170. /*
  1171. * get the PATH from the environment and check to see if
  1172. * the filter is in the path
  1173. */
  1174. pathstr = getenv("PATH");
  1175. if (pathstr == NULL)
  1176. return(FALSE);
  1177. pathtmp = XtNewString(pathstr);
  1178. pathtok = _XStrtok(pathtmp, ":", strtok_buf);
  1179. while (pathtok != NULL) {
  1180. tmp = (char*)XtMalloc((strlen(pathtok)
  1181. + strlen(M_spellFilter(pPriv))
  1182. + 2) * sizeof(char));
  1183. strcpy(tmp, pathtok);
  1184. strcat(tmp, "/");
  1185. strcat(tmp, M_spellFilter(pPriv));
  1186. if (stat(tmp, &statbuf) != -1) {
  1187. XtFree(pathtmp);
  1188. XtFree(tmp);
  1189. return(IsExecutable(statbuf));
  1190. }
  1191. XtFree(tmp);
  1192. pathtok = _XStrtok(NULL,":", strtok_buf);
  1193. }
  1194. XtFree(pathtmp);
  1195. return(False);
  1196. }