SearchCalls.c 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392
  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 librararies 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 mispelled 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. if (word != (char *)NULL)
  432. XtFree(word);
  433. }
  434. return -1;
  435. }
  436. static Boolean
  437. DoSearch(
  438. DtEditorWidget widget,
  439. char *search_string,
  440. Time time)
  441. {
  442. int stringPosition;
  443. Boolean foundIt = False;
  444. stringPosition = SearchForString(widget,
  445. XmTextGetInsertionPosition(M_text(widget)),
  446. search_string);
  447. if(stringPosition == -1) {
  448. /*
  449. * If the string was not found unselect everything
  450. */
  451. XmTextClearSelection(M_text(widget), time);
  452. }
  453. else {
  454. /*
  455. * The string was found so highlight the word and scroll the window
  456. * if it is not visible.
  457. */
  458. XmTextPosition pos = (XmTextPosition) stringPosition;
  459. XmTextWidget tw = (XmTextWidget)M_text(widget);
  460. foundIt = True;
  461. XmTextSetInsertionPosition(M_text(widget), pos);
  462. XmTextSetSelection( M_text(widget), pos,
  463. pos+_DtEditor_CountCharacters(search_string, strlen(search_string)),
  464. XtLastTimestampProcessed(XtDisplay(M_text(widget))) );
  465. /*
  466. * Scroll the widget, if necessary
  467. */
  468. if (pos < tw->text.top_character || pos >= tw->text.bottom_position)
  469. {
  470. Arg al[5];
  471. int ac;
  472. Dimension height;
  473. short rows;
  474. Position x, y;
  475. ac = 0;
  476. XtSetArg(al[ac], XmNheight, &height); ac++;
  477. XtSetArg(al[ac], XmNrows, &rows); ac++;
  478. XtGetValues(M_text(widget), al, ac);
  479. if(XmTextPosToXY(M_text(widget), pos, &x, &y) == True)
  480. {
  481. int offset = (int)((y - height/2) * rows) / (int)height;
  482. XmTextScroll(M_text(widget), offset);
  483. }
  484. }
  485. }
  486. return ( foundIt );
  487. } /* end DoSearch */
  488. /*
  489. * DtEditorInvokeFindChangeDialog posts the "Find/Change" dialog.
  490. */
  491. void
  492. DtEditorInvokeFindChangeDialog(
  493. Widget widget)
  494. {
  495. DtEditorWidget pPriv = (DtEditorWidget) widget;
  496. _DtWidgetToAppContext(widget);
  497. _DtAppLock(app);
  498. _DtEditorSearch(pPriv, False, False);
  499. _DtAppUnlock(app);
  500. }
  501. /*
  502. * DoReplace checks that there is a non-null selection, and
  503. * if so, replaces the selection with the replace_string argument.
  504. */
  505. static Boolean
  506. DoReplace(
  507. DtEditorWidget pPriv,
  508. char *replace_string,
  509. Time time)
  510. {
  511. XmTextPosition first, last;
  512. Boolean replaced = False;
  513. /*
  514. * Only do a replace if we have a non-null selection.
  515. * We could check that the selection == the Find string, but
  516. * this allows a little more flexibility for the user.
  517. */
  518. if (XmTextGetSelectionPosition(M_text(pPriv), &first, &last) &&
  519. first != last)
  520. {
  521. XmTextReplace(M_text(pPriv), first, last, replace_string);
  522. XmTextSetSelection(M_text(pPriv), first,
  523. first +
  524. _DtEditor_CountCharacters(replace_string, strlen(replace_string)),
  525. time);
  526. replaced = True;
  527. }
  528. return( replaced );
  529. }
  530. /*
  531. * ReplaceAll replaces all occurrences of search_string with
  532. * replacement_string in widget.
  533. */
  534. static Boolean
  535. ReplaceAll(
  536. DtEditorWidget widget,
  537. char *search_string,
  538. char *replace_string )
  539. {
  540. int replacementLength, searchLength, lastOccurrence, thisOccurrence;
  541. Boolean replaceOK = False;
  542. /*
  543. * Make sure there is a string to find. Null replacement strings
  544. * are OK.
  545. */
  546. if( search_string && *search_string )
  547. {
  548. /*
  549. * How long is the string we are searching for?
  550. */
  551. searchLength = _DtEditor_CountCharacters( search_string,
  552. strlen(search_string) );
  553. /*
  554. * How long is the replacement string?
  555. */
  556. replacementLength = _DtEditor_CountCharacters( replace_string,
  557. strlen(replace_string) );
  558. /*
  559. * Start at the beginning and search for the string
  560. */
  561. lastOccurrence = -1;
  562. while( ((thisOccurrence = SearchForString(widget,
  563. (lastOccurrence > 0)? (XmTextPosition)lastOccurrence : 0,
  564. search_string)
  565. ) != -1 ) &&
  566. thisOccurrence >= lastOccurrence )
  567. {
  568. XmTextReplace( M_text(widget), (XmTextPosition)thisOccurrence,
  569. (XmTextPosition) (thisOccurrence + searchLength),
  570. replace_string );
  571. lastOccurrence = thisOccurrence + replacementLength;
  572. } /* end while */
  573. if (lastOccurrence != -1)
  574. replaceOK = True;
  575. }
  576. return( replaceOK );
  577. } /* end ReplaceAll */
  578. /*
  579. * DtEditorChange replaces either the current selection, the next occurrence
  580. * of a string, or all occurrences of the string with a replacement string.
  581. * If no find or change to strings are passed in, DtEditorFindChange uses
  582. * the last find and change to strings from the Find/Change dialog.
  583. */
  584. Boolean
  585. DtEditorChange(
  586. Widget widget,
  587. DtEditorChangeValues *findChangeStrings,
  588. unsigned int instanceToChange)
  589. {
  590. Boolean returnVal = False;
  591. DtEditorWidget editor = (DtEditorWidget) widget;
  592. _DtWidgetToAppContext(widget);
  593. _DtAppLock(app);
  594. switch( instanceToChange )
  595. {
  596. case DtEDITOR_NEXT_OCCURRENCE:
  597. {
  598. /*
  599. * Find the next occurrence and replace it (by treating it as
  600. * a current selection).
  601. */
  602. /*
  603. * If we were passed a Find string use it. Otherwise, tell
  604. * DtEditorFind to use the last search string value
  605. * (M_search_string).
  606. */
  607. if ( findChangeStrings != (DtEditorChangeValues *) NULL )
  608. returnVal = DtEditorFind( widget, findChangeStrings->find );
  609. else
  610. returnVal = DtEditorFind( widget, (char *)NULL );
  611. if ( returnVal == False)
  612. break;
  613. }
  614. case DtEDITOR_CURRENT_SELECTION:
  615. {
  616. /*
  617. * Replace whatever is selected.
  618. */
  619. /*
  620. * If we were passed a Change To string use it. Otherwise,
  621. * use the last replace string value.
  622. */
  623. if ( findChangeStrings != (DtEditorChangeValues *) NULL )
  624. returnVal = DoReplace( editor, findChangeStrings->changeTo,
  625. CurrentTime );
  626. else
  627. returnVal= DoReplace(editor,M_replace_string(editor),CurrentTime);
  628. break;
  629. }
  630. case DtEDITOR_ALL_OCCURRENCES:
  631. {
  632. _DtTurnOnHourGlass( M_topLevelShell(editor) );
  633. if ( findChangeStrings != (DtEditorChangeValues *) NULL )
  634. returnVal = ReplaceAll( editor, findChangeStrings->find,
  635. findChangeStrings->changeTo );
  636. else
  637. returnVal = ReplaceAll( editor, M_search_string(editor),
  638. M_replace_string(editor) );
  639. _DtTurnOffHourGlass( M_topLevelShell( editor ) );
  640. break;
  641. } /* replace all occurrences */
  642. default :
  643. {
  644. }
  645. } /* end switch */
  646. _DtAppUnlock(app);
  647. return( returnVal );
  648. } /* end DtEditorChange */
  649. /* ARGSUSED */
  650. void
  651. _DtEditorSearchMapCB(
  652. Widget w,
  653. caddr_t client_data,
  654. caddr_t call_data )
  655. {
  656. int ac;
  657. Arg al[4];
  658. Widget parent;
  659. Position newX, newY, pY, pX;
  660. Dimension pHeight, myHeight, pWidth, myWidth;
  661. DtEditorWidget pPriv = (DtEditorWidget) client_data;
  662. parent = M_topLevelShell(pPriv);
  663. pX = XtX(parent);
  664. pY = XtY(parent);
  665. pHeight = XtHeight(parent);
  666. pWidth = XtWidth(parent);
  667. myHeight = XtHeight(w);
  668. myWidth = XtWidth(w);
  669. if ((newY = pY - (int)myHeight + 5) < 0)
  670. newY = pY + pHeight;
  671. newX = pX + pWidth/2 - ((int)myWidth)/2;
  672. ac = 0;
  673. XtSetArg(al[ac], XmNx, newX); ac++;
  674. XtSetArg(al[ac], XmNy, newY); ac++;
  675. XtSetValues(w,al,ac);
  676. }
  677. /*
  678. *
  679. * _DtEditorDialogSearchCB is called whenever the Find button is pressed
  680. * in the Find/Change dialog. If the dialog is displayed in Find/Change
  681. * mode, it updates the contents of M_search_string() with the contents
  682. * of the "Find" text field, and then invokes DtEditorFind(). If the
  683. * find is successful, the Change button is enabled, otherwise the
  684. * "String not found" dialog is displayed.
  685. *
  686. * When the dialog is in Spell mode, the selected misspelled word is merely
  687. * passed to DtEditorFind(). The Change (and Change All) buttons are left
  688. * insentive until the user types something into the Change To field
  689. * (too many users were replacing misspelled words with blanks).
  690. *
  691. */
  692. /* ARGSUSED */
  693. void
  694. _DtEditorDialogSearchCB(
  695. Widget w,
  696. caddr_t client_data,
  697. caddr_t call_data )
  698. {
  699. DtEditorWidget pPriv = (DtEditorWidget) client_data;
  700. /*
  701. * Is the dialog in Find/Change or Spell mode?
  702. */
  703. if (M_search_dialogMode(pPriv) == REPLACE) {
  704. /*
  705. * Find/Change mode
  706. * Free the existing search string and get the new one.
  707. */
  708. if (M_search_string(pPriv))
  709. XtFree(M_search_string(pPriv));
  710. M_search_string(pPriv) = XmTextFieldGetString( M_findText(pPriv) );
  711. /*
  712. * Find the string
  713. */
  714. if( DtEditorFind((Widget)pPriv, M_search_string(pPriv)) ) {
  715. /*
  716. * If the string was found then enable the Change button.
  717. * It will be disabled when it is pressed or a new Find string is
  718. * entered.
  719. */
  720. _DtEditorSetReplaceSensitivity( pPriv, True );
  721. }
  722. else {
  723. /*
  724. * Post a dialog informing the user the string was not found.
  725. */
  726. char *tempStr = (char *)XtMalloc(strlen(NO_FIND) +
  727. strlen(M_search_string(pPriv)) + 1);
  728. sprintf(tempStr, NO_FIND, M_search_string(pPriv));
  729. _DtEditorWarning(pPriv, tempStr, XmDIALOG_INFORMATION);
  730. XtFree(tempStr);
  731. }
  732. }
  733. else {
  734. /*
  735. * Spell mode.
  736. */
  737. char *pString;
  738. M_misspelled_found(pPriv) = DtEditorFind((Widget)pPriv,
  739. M_misspelled_string(pPriv) );
  740. /*
  741. * If the word was found & there is a Change To string then enable
  742. * the Change button. If there is no Change To string, Change will
  743. * be enabled when a string is entered if M_misspelled_found is True
  744. * (see _DtEditorReplaceTextChangedCB)
  745. *
  746. * Change All is enabled in _DtEditorReplaceTextChangedCB()
  747. * (ie. anytime there is a Change To string). It is not
  748. * dependent upon a sucessful Find because it initiates its own
  749. * find.
  750. */
  751. if ( M_misspelled_found(pPriv) == True ) {
  752. /*
  753. * Is there a Change To string?
  754. */
  755. pString = XmTextFieldGetString(M_replaceText(pPriv));
  756. if( pString != (char *)NULL && *pString != (char)'\0' )
  757. _DtEditorSetReplaceSensitivity( pPriv, True );
  758. if(pString != (char *)NULL)
  759. XtFree(pString);
  760. }
  761. else {
  762. /*
  763. * Post a dialog informing the user the string was not found.
  764. */
  765. char *tempStr = (char *)XtMalloc(strlen(NO_FIND) +
  766. strlen(M_misspelled_string(pPriv)) + 1);
  767. sprintf(tempStr, NO_FIND, M_misspelled_string(pPriv));
  768. _DtEditorWarning(pPriv, tempStr, XmDIALOG_INFORMATION);
  769. XtFree(tempStr);
  770. }
  771. }
  772. } /* end _DtEditorDialogSearchCB */
  773. /*
  774. * _DtEditorDialogReplaceCB is called whenever the Change button is pressed
  775. * in the Find/Change dialog. If the dialog is displayed in Find/Change
  776. * mode, it updates the contents of M_replace_string() with the contents
  777. * of the "Change To" text field, and then invokes DtEditorChange().
  778. *
  779. * When the dialog is in Spell mode, the contents of the "Change To" text
  780. * field is passed to DtEditorChange() without updating M_replace_string().
  781. *
  782. * In both cases, the Change button is disabled after the change is
  783. * complete.
  784. */
  785. /* ARGSUSED */
  786. void
  787. _DtEditorDialogReplaceCB(
  788. Widget w,
  789. caddr_t client_data,
  790. caddr_t call_data )
  791. {
  792. DtEditorWidget pPriv = (DtEditorWidget) client_data;
  793. /*
  794. * Is the dialog in Find/Change or Spell mode?
  795. */
  796. if (M_search_dialogMode(pPriv) == REPLACE) {
  797. /*
  798. * Find/Change mode
  799. * Free the existing Change To string and get the new one.
  800. */
  801. if (M_replace_string(pPriv))
  802. XtFree(M_replace_string(pPriv));
  803. M_replace_string(pPriv) = XmTextFieldGetString(M_replaceText(pPriv));
  804. DtEditorChange( (Widget)pPriv, (DtEditorChangeValues *)NULL,
  805. DtEDITOR_CURRENT_SELECTION );
  806. }
  807. else {
  808. /*
  809. * Spell mode.
  810. */
  811. DtEditorChangeValues newWord;
  812. newWord.changeTo = XmTextFieldGetString(M_replaceText(pPriv));
  813. if (newWord.changeTo != (char *)NULL) {
  814. /* This field ignored when changing the current selection */
  815. newWord.find = (char *)NULL;
  816. DtEditorChange( (Widget)pPriv, &newWord, DtEDITOR_CURRENT_SELECTION );
  817. XtFree(newWord.changeTo);
  818. }
  819. }
  820. /*
  821. * Disable the Change button. In Find/Change mode, it will be enabled
  822. * when the Find button is pressed and the Find text is successfully
  823. * found. In Spell mode, there must also be a value in the Change To
  824. * field.
  825. */
  826. _DtEditorSetReplaceSensitivity(pPriv, False );
  827. /*
  828. * Want the traversal to be on the Find button, so that the user
  829. * can initiate another search.
  830. */
  831. XmProcessTraversal(M_search_findBtn(pPriv), XmTRAVERSE_CURRENT);
  832. }
  833. /*
  834. * _DtEditorDialogReplaceAllCB is attached to the "Change All" button
  835. * in the Find/Change dialog. It replaces all occurances of the "Find"
  836. * string with the "Change To" string.
  837. */
  838. /* ARGSUSED */
  839. void
  840. _DtEditorDialogReplaceAllCB(
  841. Widget w,
  842. caddr_t client_data,
  843. caddr_t call_data )
  844. {
  845. DtEditorWidget pPriv = (DtEditorWidget) client_data;
  846. /*
  847. * Is the dialog in Find/Change or Spell mode?
  848. */
  849. if (M_search_dialogMode(pPriv) == REPLACE) {
  850. /*
  851. * Find/Change mode
  852. * Free any existing search string before getting the current one.
  853. */
  854. if (M_search_string(pPriv))
  855. XtFree(M_search_string(pPriv));
  856. M_search_string(pPriv) = XmTextFieldGetString(M_findText(pPriv));
  857. /*
  858. * Free the existing Change To string and get the new one.
  859. */
  860. if (M_replace_string(pPriv))
  861. XtFree(M_replace_string(pPriv));
  862. M_replace_string(pPriv) = XmTextFieldGetString(M_replaceText(pPriv));
  863. /*
  864. * Make the change with the current values (set above).
  865. */
  866. if( !DtEditorChange((Widget)pPriv, (DtEditorChangeValues *)NULL,
  867. DtEDITOR_ALL_OCCURRENCES) ) {
  868. /*
  869. * If the replace failed, post a dialog informing the user
  870. * the string was not found.
  871. */
  872. char *tempStr = (char *)XtMalloc(strlen(NO_FIND) +
  873. strlen(M_search_string(pPriv)) + 1);
  874. sprintf(tempStr, NO_FIND, M_search_string(pPriv));
  875. _DtEditorWarning(pPriv, tempStr, XmDIALOG_INFORMATION);
  876. XtFree(tempStr);
  877. }
  878. }
  879. else {
  880. /*
  881. * Spell mode.
  882. */
  883. DtEditorChangeValues changeValues;
  884. changeValues.find = M_misspelled_string(pPriv);
  885. changeValues.changeTo = XmTextFieldGetString(M_replaceText(pPriv));
  886. DtEditorChange((Widget)pPriv, &changeValues, DtEDITOR_ALL_OCCURRENCES);
  887. if( changeValues.changeTo != (char *)NULL )
  888. XtFree( changeValues.changeTo );
  889. }
  890. /*
  891. * Disable the Change button. It will be enabled when the Find
  892. * button is pressed and the Find text is successfully found.
  893. * In Spell mode, there must also be a value in the Change To field.
  894. */
  895. _DtEditorSetReplaceSensitivity(pPriv, False );
  896. } /* _DtEditorDialogReplaceAllCB */
  897. /* ARGSUSED */
  898. void
  899. _DtEditorDialogFindCancelCB(
  900. Widget w,
  901. caddr_t client_data,
  902. caddr_t call_data )
  903. {
  904. DtEditorWidget pPriv = (DtEditorWidget)client_data;
  905. XtUnmanageChild(M_search_dialog(pPriv));
  906. }
  907. /*
  908. * _DtEditorMisspelledSelectCB is called when a new word has been selected
  909. * from the list of misspelled words.
  910. */
  911. /* ARGSUSED */
  912. void
  913. _DtEditorMisspelledSelectCB(
  914. Widget w,
  915. caddr_t client_data,
  916. caddr_t call_data )
  917. {
  918. XmListCallbackStruct *cb = (XmListCallbackStruct *)call_data;
  919. DtEditorWidget editor = (DtEditorWidget)client_data;
  920. /*
  921. * Get the selected word for use when the Find or Replace All button
  922. * is pressed.
  923. */
  924. if (M_misspelled_string(editor))
  925. XtFree(M_misspelled_string(editor));
  926. M_misspelled_string(editor) =
  927. _XmStringUngenerate(cb->item, NULL, XmCHARSET_TEXT, XmCHARSET_TEXT);
  928. /*
  929. * Mark that it has not been found
  930. */
  931. M_misspelled_found(editor) = False;
  932. /*
  933. * Enable the Find button
  934. */
  935. _DtEditorSetFindSensitivity(editor, True );
  936. /*
  937. * Clear the "Change To" text field.
  938. */
  939. XmTextFieldSetString(M_replaceText(editor), (char *)NULL);
  940. } /* end _DtEditorMisspelledSelectCB */
  941. /*
  942. * _DtEditorMisspelledDblClickCB is called when a word has been double-
  943. * clicked from the list of misspelled words. First, the word will become
  944. * the new misspelled string and, then, a find will be initiated for it.
  945. */
  946. /* ARGSUSED */
  947. void
  948. _DtEditorMisspelledDblClickCB(
  949. Widget w,
  950. caddr_t client_data,
  951. caddr_t call_data )
  952. {
  953. _DtEditorMisspelledSelectCB(w, client_data, call_data );
  954. _DtEditorDialogSearchCB(w, client_data, call_data );
  955. } /* end _DtEditorMisspelledDblClickCB */
  956. /*
  957. * The following functions effectively track whether the user has
  958. * entered or changed the "Find" text. This information is used to make
  959. * the "Find" and "Change All" buttons sensitive/desensitive. The
  960. * "Find" button must be pressed and the Find text found before the
  961. * "Change" button is sensitive. These functions also set the default
  962. * button to either the "Find" or "Close" button.
  963. */
  964. void
  965. _DtEditorSetFindSensitivity(
  966. DtEditorWidget widget,
  967. Boolean sensitivity)
  968. {
  969. XtSetSensitive(M_search_findBtn(widget), sensitivity);
  970. }
  971. void
  972. _DtEditorSetReplaceSensitivity(
  973. DtEditorWidget editor,
  974. Boolean sensitivity)
  975. {
  976. /*
  977. * Cannot enable Change button if widget is read only
  978. */
  979. if ( M_editable(editor) || !sensitivity )
  980. XtSetSensitive(M_search_replaceBtn(editor), sensitivity);
  981. }
  982. void
  983. _DtEditorSetReplaceAllSensitivity(
  984. DtEditorWidget editor,
  985. Boolean sensitivity)
  986. {
  987. /*
  988. * Cannot enable Change All button if widget is read only
  989. */
  990. if ( M_editable(editor) || !sensitivity )
  991. XtSetSensitive(M_search_replaceAllBtn(editor), sensitivity);
  992. }
  993. /* ARGSUSED */
  994. void
  995. _DtEditorFindTextChangedCB(
  996. Widget w,
  997. caddr_t client_data,
  998. caddr_t call_data )
  999. {
  1000. Arg al[10]; /* arg list */
  1001. Widget defaultButton;
  1002. char *pString;
  1003. DtEditorWidget editor = (DtEditorWidget)client_data;
  1004. /*
  1005. * Is there a Find string?
  1006. */
  1007. pString = XmTextFieldGetString(M_findText(editor));
  1008. /*
  1009. * Only enable the Find & Change All buttons if there is a
  1010. * string to search for (i.e. a Find string).
  1011. */
  1012. if(pString == (char *)NULL || *pString == (char)'\0') {
  1013. _DtEditorSetFindSensitivity(editor, False );
  1014. _DtEditorSetReplaceAllSensitivity(editor, False );
  1015. /*
  1016. * Make the Close button the default
  1017. */
  1018. defaultButton = M_search_closeBtn(editor);
  1019. }
  1020. else {
  1021. _DtEditorSetFindSensitivity( editor, True );
  1022. _DtEditorSetReplaceAllSensitivity(editor, True );
  1023. /*
  1024. * Make the Find button the default
  1025. */
  1026. defaultButton = M_search_findBtn(editor);
  1027. }
  1028. if(pString != (char *)NULL)
  1029. XtFree(pString);
  1030. /*
  1031. * Set the default button
  1032. */
  1033. XtSetArg(al[0], XmNdefaultButton, defaultButton);
  1034. XtSetValues(M_search_dialog(editor), al, 1);
  1035. /*
  1036. * Disable the Change button. It will be enabled when the Find
  1037. * button is pressed and the Find text is successfully found.
  1038. */
  1039. _DtEditorSetReplaceSensitivity(editor, False );
  1040. } /* end _DtEditorFindTextChangedCB */
  1041. /*
  1042. * The following functions effectively track whether the user has
  1043. * entered or changed the Change To text. This information is used
  1044. * in the Spell dialog to make the Change and Change All buttons
  1045. * sensitive/desensitive so users cannot replace a misspelled word with
  1046. * a null string.
  1047. */
  1048. /* ARGSUSED */
  1049. void
  1050. _DtEditorReplaceTextChangedCB(
  1051. Widget w,
  1052. caddr_t client_data,
  1053. caddr_t call_data )
  1054. {
  1055. char *pString;
  1056. DtEditorWidget editor = (DtEditorWidget)client_data;
  1057. /*
  1058. * Ignore this callback if it is not being called from the Spell
  1059. * dialog.
  1060. */
  1061. if( M_search_dialogMode(editor) == SPELL ) {
  1062. /*
  1063. * Is there a Change To string?
  1064. */
  1065. pString = XmTextFieldGetString(M_replaceText(editor));
  1066. /*
  1067. * Disable the Change & Change All buttons if there is
  1068. * no Change To string.
  1069. */
  1070. if( pString == (char *)NULL || *pString == (char)'\0' ) {
  1071. _DtEditorSetReplaceSensitivity(editor, False );
  1072. _DtEditorSetReplaceAllSensitivity(editor, False );
  1073. }
  1074. else {
  1075. /*
  1076. * If there is a Change To string enable the Change
  1077. * All button, but only enable the Change button if.
  1078. * the Find button has been pressed & the misspelled
  1079. * word found (see _DtEditorDialogSearchCB()
  1080. */
  1081. _DtEditorSetReplaceAllSensitivity(editor, True );
  1082. if ( M_misspelled_found(editor) )
  1083. _DtEditorSetReplaceSensitivity(editor, True );
  1084. if(pString != (char *)NULL)
  1085. XtFree(pString);
  1086. }
  1087. }
  1088. } /* end _DtEditorReplaceTextChangedCB */
  1089. /***
  1090. IsInGroup -
  1091. Check to see if the process is in the group, gid.
  1092. ***/
  1093. static Boolean IsInGroup(gid_t gid)
  1094. {
  1095. gid_t grps[NGROUPS_MAX];
  1096. int i;
  1097. int num_grps;
  1098. num_grps = getgroups(NGROUPS_MAX, grps);
  1099. if (num_grps == -1)
  1100. return(False);
  1101. for (i=0; i < num_grps; i++) {
  1102. if (gid == grps[i])
  1103. return(True);
  1104. }
  1105. return(False);
  1106. }
  1107. /***
  1108. IsExecutable -
  1109. Check to see if the process can execute the filter.
  1110. ****/
  1111. static Boolean IsExecutable(struct stat statbuf)
  1112. {
  1113. Boolean ingroup = IsInGroup(statbuf.st_gid);
  1114. if (geteuid() == 0) { /** if root **/
  1115. /** if any execute bit is set, root can execute **/
  1116. if ((statbuf.st_mode & S_IXUSR)
  1117. || (statbuf.st_mode & S_IXGRP)
  1118. || (statbuf.st_mode & S_IXOTH))
  1119. {
  1120. return (True);
  1121. }
  1122. else {
  1123. return (False);
  1124. }
  1125. }
  1126. /*
  1127. * if this process is the user and the user
  1128. * does have execute permission, then the
  1129. * filter will run, so return false
  1130. */
  1131. if ((statbuf.st_uid == geteuid())
  1132. && (statbuf.st_mode & S_IXUSR))
  1133. {
  1134. return(True);
  1135. }
  1136. /*
  1137. * if this process is in the group for the
  1138. * filter and group execute is set (and the
  1139. * process isn't the user, then return true
  1140. */
  1141. if (ingroup
  1142. && (statbuf.st_mode & S_IXGRP)
  1143. && (statbuf.st_uid != geteuid()))
  1144. {
  1145. return(True);
  1146. }
  1147. /*
  1148. * if this process is not in the group or the user
  1149. * for the filter and other execute is set, then
  1150. * return true
  1151. */
  1152. if ((statbuf.st_mode & S_IXOTH)
  1153. && (statbuf.st_uid != geteuid())
  1154. && !ingroup)
  1155. {
  1156. return(True);
  1157. }
  1158. return(False);
  1159. }
  1160. /*****
  1161. IsValidFilter -
  1162. This function checks to makes sure that this filter
  1163. can be found, i.e. is in the current path and istalled.
  1164. *****/
  1165. static Boolean IsValidFilter(DtEditorWidget pPriv)
  1166. {
  1167. char *pathstr;
  1168. char *pathtmp;
  1169. char *pathtok;
  1170. char *tmp;
  1171. struct stat statbuf;
  1172. _Xstrtokparams strtok_buf;
  1173. /** check to see if a full path to the filter is given **/
  1174. if (*M_spellFilter(pPriv) == '/') {
  1175. if (stat(M_spellFilter(pPriv), &statbuf) != -1)
  1176. return(IsExecutable(statbuf));
  1177. else
  1178. return(False);
  1179. }
  1180. /*
  1181. * get the PATH from the environment and check to see if
  1182. * the filter is in the path
  1183. */
  1184. pathstr = getenv("PATH");
  1185. if (pathstr == NULL)
  1186. return(FALSE);
  1187. pathtmp = XtNewString(pathstr);
  1188. pathtok = _XStrtok(pathtmp, ":", strtok_buf);
  1189. while (pathtok != NULL) {
  1190. tmp = (char*)XtMalloc((strlen(pathtok)
  1191. + strlen(M_spellFilter(pPriv))
  1192. + 2) * sizeof(char));
  1193. strcpy(tmp, pathtok);
  1194. strcat(tmp, "/");
  1195. strcat(tmp, M_spellFilter(pPriv));
  1196. if (stat(tmp, &statbuf) != -1) {
  1197. XtFree(pathtmp);
  1198. XtFree(tmp);
  1199. return(IsExecutable(statbuf));
  1200. }
  1201. XtFree(tmp);
  1202. pathtok = _XStrtok(NULL,":", strtok_buf);
  1203. }
  1204. XtFree(pathtmp);
  1205. return(False);
  1206. }