EditAreaData.c 49 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880
  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. /* $TOG: EditAreaData.c /main/6 1998/03/03 16:18:13 mgreess $ */
  24. /**********************************<+>*************************************
  25. ***************************************************************************
  26. **
  27. ** File: EditAreaData.c
  28. **
  29. ** Project: DtEditor widget for editing services
  30. **
  31. ** Description: Contains functions for getting and setting the data
  32. ** on which the editor operates.
  33. ** -----------
  34. **
  35. *******************************************************************
  36. *
  37. * (c) Copyright 1993, 1994 Unix System Labs, Inc., a subsidiary of Novell, Inc.
  38. * (c) Copyright 1996 Digital Equipment Corporation.
  39. * (c) Copyright 1993, 1994, 1996 Hewlett-Packard Company.
  40. * (c) Copyright 1993, 1994, 1996 International Business Machines Corp.
  41. * (c) Copyright 1993, 1994, 1996 Sun Microsystems, Inc.
  42. * (c) Copyright 1996 Novell, Inc.
  43. * (c) Copyright 1996 FUJITSU LIMITED.
  44. * (c) Copyright 1996 Hitachi.
  45. *
  46. ********************************************************************
  47. **
  48. **
  49. **************************************************************************
  50. **********************************<+>*************************************/
  51. #include "EditorP.h"
  52. #include <X11/Xutil.h>
  53. #include <Xm/TextP.h>
  54. #include <unistd.h>
  55. #include "DtWidgetI.h"
  56. typedef enum _LoadActionType {
  57. LOAD_DATA,
  58. INSERT_DATA,
  59. APPEND_DATA,
  60. REPLACE_DATA
  61. } LoadActionType;
  62. static DtEditorErrorCode Check4EnoughMemory(
  63. int numBytes);
  64. static DtEditorErrorCode StripEmbeddedNulls(
  65. char *stringData,
  66. int *length);
  67. static DtEditorErrorCode LoadFile(
  68. Widget w,
  69. char *fileName,
  70. LoadActionType action,
  71. XmTextPosition startReplace,
  72. XmTextPosition endReplace );
  73. #ifdef NEED_STRCASECMP
  74. /*
  75. * in case strcasecmp is not provided by the system here is one
  76. * which does the trick
  77. */
  78. static int
  79. strcasecmp(s1, s2)
  80. char *s1, *s2;
  81. {
  82. int c1, c2;
  83. while (*s1 && *s2) {
  84. c1 = isupper(*s1) ? tolower(*s1) : *s1;
  85. c2 = isupper(*s2) ? tolower(*s2) : *s2;
  86. if (c1 != c2)
  87. return (1);
  88. s1++;
  89. s2++;
  90. }
  91. if (*s1 || *s2)
  92. return (1);
  93. return (0);
  94. }
  95. #endif
  96. /*****************************************************************************
  97. *
  98. * Check4EnoughMemory - estimates whether there is enough memory to malloc
  99. * "numBytes" of memory. This routine doubles the amount needed because the
  100. * routines that use it are putting data into the text widget & we must make
  101. * sure the widget will have room, too.
  102. *
  103. * Returns DtEDITOR_NO_ERRORS
  104. * DtEDITOR_ILLEGAL_SIZE
  105. * DtEDITOR_INSUFFICIENT_MEMORY
  106. *
  107. *****************************************************************************/
  108. static DtEditorErrorCode
  109. Check4EnoughMemory(
  110. int numBytes)
  111. {
  112. DtEditorErrorCode returnVal = DtEDITOR_ILLEGAL_SIZE;
  113. if (numBytes > 0) {
  114. char *tmpString = (char *)malloc((2 * numBytes) + (numBytes/10));
  115. if(tmpString == (char *)NULL)
  116. returnVal = DtEDITOR_INSUFFICIENT_MEMORY;
  117. else {
  118. returnVal = DtEDITOR_NO_ERRORS;
  119. free(tmpString);
  120. }
  121. }
  122. return( returnVal );
  123. } /* end Check4EnoughMemory */
  124. /*****************************************************************************
  125. *
  126. * StripEmbeddedNulls - removes any embedded NULLs (\0) in a string of length
  127. * 'length'. The removal occurs in place, with 'length' set to the
  128. * new, stripped length. The resulting string is terminated with a
  129. * trailing NULL.
  130. *
  131. * Returns DtEDITOR_NO_ERRORS - the string did not contain any embedded NULLs
  132. * DtEDITOR_NULLS_REMOVED - the string did contain embedded
  133. * NULLs that were removed.
  134. *
  135. *****************************************************************************/
  136. static DtEditorErrorCode
  137. StripEmbeddedNulls(
  138. char *stringData,
  139. int *length)
  140. {
  141. DtEditorErrorCode returnVal = DtEDITOR_NO_ERRORS;
  142. if (strlen(stringData) != *length)
  143. {
  144. int firstNull;
  145. returnVal = DtEDITOR_NULLS_REMOVED;
  146. /*
  147. * The file contains NULL characters, so we strip them out and
  148. * report that we have done so.
  149. */
  150. while((firstNull = strlen(stringData)) != *length)
  151. {
  152. int lastNull = firstNull;
  153. while((lastNull + 1) < *length &&
  154. stringData[lastNull + 1] == (char)'\0')
  155. lastNull++;
  156. memcpy(&stringData[firstNull], &stringData[lastNull + 1],
  157. *length - lastNull);
  158. *length -= 1 + lastNull - firstNull;
  159. }
  160. }
  161. return( returnVal);
  162. } /* end StripEmbeddedNulls */
  163. /*****************************************************************************
  164. *
  165. * Retrieves the current location of the insert cursor
  166. *
  167. *****************************************************************************/
  168. XmTextPosition
  169. DtEditorGetInsertionPosition(
  170. Widget widget)
  171. {
  172. DtEditorWidget editor = (DtEditorWidget) widget;
  173. XmTextPosition result;
  174. _DtWidgetToAppContext(widget);
  175. _DtAppLock(app);
  176. result = XmTextGetInsertionPosition(M_text(editor));
  177. _DtAppUnlock(app);
  178. return result;
  179. }
  180. /*****************************************************************************
  181. *
  182. * Retrieves the current location of the last character in the widget
  183. *
  184. *****************************************************************************/
  185. XmTextPosition
  186. DtEditorGetLastPosition(
  187. Widget widget)
  188. {
  189. DtEditorWidget editor = (DtEditorWidget) widget;
  190. XmTextPosition result;
  191. _DtWidgetToAppContext(widget);
  192. _DtAppLock(app);
  193. result = XmTextGetLastPosition(M_text(editor));
  194. _DtAppUnlock(app);
  195. return result;
  196. }
  197. /*****************************************************************************
  198. *
  199. * Changes the current location of the insert cursor
  200. *
  201. *****************************************************************************/
  202. void
  203. DtEditorSetInsertionPosition(
  204. Widget widget,
  205. XmTextPosition position)
  206. {
  207. DtEditorWidget editor = (DtEditorWidget) widget;
  208. _DtWidgetToAppContext(widget);
  209. _DtAppLock(app);
  210. XmTextSetInsertionPosition(M_text(editor), position);
  211. _DtAppUnlock(app);
  212. }
  213. static DtEditorErrorCode
  214. setStringValue(
  215. DtEditorWidget editor,
  216. char *data)
  217. {
  218. /*
  219. * Tell _DtEditorModifyVerifyCB() that we're replacing the entire
  220. * contents, so it doesn't try to save the current document in an
  221. * undo structure for a later undo.
  222. */
  223. M_loadingAllNewData(editor) = True;
  224. XmTextSetString( M_text(editor), data );
  225. /*
  226. * If the _DtEditorModifyVerifyCB() did not get called, reset the
  227. * things which usually get reset there. The modifyVerify callback
  228. * will not get called if the contents are being set to a null string
  229. * and the widget is already empty.
  230. */
  231. if (M_loadingAllNewData(editor) == True) {
  232. M_loadingAllNewData(editor) = False;
  233. M_unreadChanges(editor) = False;
  234. _DtEditorResetUndo(editor);
  235. }
  236. return( DtEDITOR_NO_ERRORS );
  237. } /* end setStringValue */
  238. static DtEditorErrorCode
  239. setDataValue(
  240. DtEditorWidget widget,
  241. void *rawData,
  242. int length)
  243. {
  244. DtEditorErrorCode status = DtEDITOR_NULL_ITEM, tmpError;
  245. /*
  246. * Validate input
  247. */
  248. if (rawData != (void *)NULL)
  249. {
  250. /*
  251. * Check to see if we have a valid buffer size & enough memory to
  252. * load the buffer into the text widget. This is only an estimate
  253. * of our needs.
  254. * Check4EnoughMemory() returns DtEDITOR_NO_ERRORS,
  255. * DtEDITOR_ILLEGAL_SIZE, or DtEDITOR_INSUFFICIENT_MEMORY.
  256. */
  257. status = Check4EnoughMemory( length );
  258. if (status == DtEDITOR_NO_ERRORS)
  259. {
  260. /*
  261. * Convert the data buffer into a string & insert into the widget
  262. */
  263. char *textData = (char *)XtMalloc(length + 1);
  264. memcpy( textData, rawData, length );
  265. textData[length] = '\0';
  266. /*
  267. * Strip out any embedded NULLs because the text widget will only
  268. * accept data up to the first NULL.
  269. *
  270. * StripEmbeddedNulls() returns DtEDITOR_NO_ERRORS or
  271. * DtEDITOR_NULLS_REMOVED
  272. */
  273. status = StripEmbeddedNulls( textData, &length );
  274. /*
  275. * Now, insert the converted string into the text widget
  276. */
  277. tmpError = setStringValue( widget, textData );
  278. if (tmpError != DtEDITOR_NO_ERRORS)
  279. status = tmpError;
  280. XtFree( (char *)textData );
  281. }
  282. }
  283. return( status );
  284. } /* end setDataValue */
  285. static DtEditorErrorCode
  286. setWcharValue(
  287. DtEditorWidget editor,
  288. wchar_t *data)
  289. {
  290. DtEditorErrorCode status;
  291. wchar_t *tmp_wc;
  292. int result, num_chars=0;
  293. char *mb_value = (char *)NULL;
  294. /*
  295. * Convert the wide char string to a multi-byte string & stick it in
  296. * the text widget.
  297. */
  298. /*
  299. * Determine how big the resulting mb string may be
  300. */
  301. for (num_chars = 0, tmp_wc = data; *tmp_wc != (wchar_t)0L; num_chars++)
  302. tmp_wc++;
  303. /*
  304. * Check to see if we have enough memory to load the string
  305. * into the text widget. This is only an estimate of our needs.
  306. * status will be set to DtEDITOR_NO_ERRORS, DtEDITOR_ILLEGAL_SIZE, or
  307. * DtEDITOR_INSUFFICIENT_MEMORY.
  308. */
  309. status = Check4EnoughMemory( (num_chars + 1) * MB_CUR_MAX );
  310. if (status != DtEDITOR_NO_ERRORS) return status;
  311. mb_value = XtMalloc( (unsigned)(num_chars + 1) * MB_CUR_MAX );
  312. /*
  313. * Convert the wchar string
  314. * If wcstombs fails it returns (size_t) -1, so pass in empty
  315. * string.
  316. */
  317. result = wcstombs( mb_value, data, (num_chars + 1) * MB_CUR_MAX );
  318. if (result == (size_t)-1)
  319. result = 0;
  320. /*
  321. * wcstombs doesn't guarantee string is NULL terminated
  322. */
  323. mb_value[result] = 0;
  324. status = setStringValue( editor, mb_value );
  325. XtFree(mb_value);
  326. return( status );
  327. } /* end setWcharValue */
  328. static DtEditorErrorCode
  329. insertStringValue(
  330. DtEditorWidget editor,
  331. char *data,
  332. LoadActionType typeOfInsert,
  333. XmTextPosition beginInsert,
  334. XmTextPosition endInsert)
  335. {
  336. int numInserted;
  337. switch( typeOfInsert )
  338. {
  339. case INSERT_DATA:
  340. {
  341. beginInsert = endInsert = XmTextGetInsertionPosition( M_text(editor) );
  342. break;
  343. }
  344. case APPEND_DATA:
  345. {
  346. beginInsert = endInsert = XmTextGetLastPosition( M_text(editor) );
  347. break;
  348. }
  349. case REPLACE_DATA:
  350. {
  351. break;
  352. }
  353. default:
  354. {
  355. }
  356. } /* end switch */
  357. /*
  358. * Insert/Replace/Append the data and move the insertion cursor to
  359. * the end of the inserted data.
  360. */
  361. numInserted = _DtEditor_CountCharacters( data, strlen(data) );
  362. XmTextReplace(M_text(editor), beginInsert, endInsert, data);
  363. XmTextSetInsertionPosition( M_text(editor),
  364. (XmTextPosition)(beginInsert + numInserted) );
  365. return( DtEDITOR_NO_ERRORS );
  366. } /* insertStringValue */
  367. static DtEditorErrorCode
  368. insertDataValue(
  369. DtEditorWidget widget,
  370. void *rawData,
  371. int length,
  372. LoadActionType typeOfInsert,
  373. XmTextPosition beginInsert,
  374. XmTextPosition endInsert)
  375. {
  376. DtEditorErrorCode status = DtEDITOR_NULL_ITEM, loadError;
  377. /*
  378. * Validate input
  379. */
  380. if (rawData != (void *) NULL)
  381. {
  382. /*
  383. * Check to see if we have a valid buffer size & enough memory to
  384. * insert the buffer into the text widget. This is only an estimate
  385. * of our needs.
  386. * status will be set to DtEDITOR_NO_ERRORS, DtEDITOR_ILLEGAL_SIZE, or
  387. * DtEDITOR_INSUFFICIENT_MEMORY.
  388. */
  389. status = Check4EnoughMemory( length );
  390. if (status == DtEDITOR_NO_ERRORS)
  391. {
  392. /*
  393. * Convert the data buffer into a string & insert into the widget
  394. */
  395. char *textData = (char *)XtMalloc(length + 1);
  396. memcpy( textData, rawData, length );
  397. textData[length] = '\0';
  398. /*
  399. * Strip out any embedded NULLs because the text widget will only
  400. * accept data up to the first NULL.
  401. *
  402. * StripEmbeddedNulls() returns DtEDITOR_NO_ERRORS or
  403. * DtEDITOR_NULLS_REMOVED
  404. */
  405. status = StripEmbeddedNulls( textData, &length );
  406. /*
  407. * Now, insert the converted string into the text widget
  408. */
  409. loadError = insertStringValue( widget, textData, typeOfInsert,
  410. beginInsert, endInsert );
  411. if (loadError != DtEDITOR_NO_ERRORS)
  412. status = loadError;
  413. XtFree( (char *)textData );
  414. }
  415. }
  416. return( status );
  417. } /* insertDataValue */
  418. static DtEditorErrorCode
  419. insertWcharValue(
  420. DtEditorWidget editor,
  421. wchar_t *data,
  422. LoadActionType typeOfInsert,
  423. XmTextPosition beginInsert,
  424. XmTextPosition endInsert)
  425. {
  426. wchar_t *tmp_wc;
  427. int result, num_chars=0;
  428. char *mb_value = (char *)NULL;
  429. DtEditorErrorCode status;
  430. /*
  431. * Convert the wide char string to a multi-byte string & insert it into
  432. * the text widget.
  433. */
  434. /*
  435. * Determine how big the resulting mb string may be
  436. */
  437. for (num_chars = 0, tmp_wc = data; *tmp_wc != (wchar_t)0L; num_chars++)
  438. tmp_wc++;
  439. /*
  440. * Check to see if we have enough memory to insert the string
  441. * into the text widget. This is only an estimate of our needs.
  442. * status will be set to DtEDITOR_NO_ERRORS, DtEDITOR_ILLEGAL_SIZE, or
  443. * DtEDITOR_INSUFFICIENT_MEMORY.
  444. */
  445. status = Check4EnoughMemory( (num_chars + 1) * MB_CUR_MAX );
  446. if(status != DtEDITOR_NO_ERRORS) return status;
  447. mb_value = XtMalloc( (unsigned)(num_chars + 1) * MB_CUR_MAX );
  448. /*
  449. * Convert the wchar string.
  450. * If wcstombs fails it returns (size_t) -1, so pass in empty
  451. * string.
  452. */
  453. result = wcstombs( mb_value, data, (num_chars + 1) * MB_CUR_MAX );
  454. if (result == (size_t)-1)
  455. result = 0;
  456. /*
  457. * wcstombs doesn't guarantee string is NULL terminated
  458. */
  459. mb_value[result] = 0;
  460. status = insertStringValue( editor, mb_value, typeOfInsert,
  461. beginInsert, endInsert );
  462. XtFree( mb_value );
  463. return( status );
  464. } /* insertWcharValue */
  465. /***************************************************************************
  466. *
  467. * DtEditorSetContents - sets the contents of the DtEditor widget.
  468. *
  469. * Inputs: widget to set the contents
  470. *
  471. * a data structure containing the data to put into the
  472. * widget. Depending upon the type of data being set, this
  473. * structure will contain various fields:
  474. *
  475. * string - \0-terminated string of characters
  476. * data - the data, the size of the data
  477. *
  478. * Returns 0 - contents were set sucessfully
  479. * !0 - an error occurred while setting the contents
  480. *
  481. ***************************************************************************/
  482. extern DtEditorErrorCode
  483. DtEditorSetContents(
  484. Widget widget,
  485. DtEditorContentRec *data )
  486. {
  487. DtEditorErrorCode error = DtEDITOR_INVALID_TYPE;
  488. DtEditorWidget editor = (DtEditorWidget) widget;
  489. _DtWidgetToAppContext(widget);
  490. _DtAppLock(app);
  491. switch( data->type )
  492. {
  493. case DtEDITOR_TEXT:
  494. {
  495. error = setStringValue ( editor, data->value.string );
  496. break;
  497. }
  498. case DtEDITOR_DATA:
  499. {
  500. error = setDataValue ( editor, data->value.data.buf,
  501. data->value.data.length);
  502. break;
  503. }
  504. case DtEDITOR_WCHAR:
  505. {
  506. error = setWcharValue ( editor, data->value.wchar );
  507. break;
  508. }
  509. default :
  510. {
  511. error = DtEDITOR_INVALID_TYPE;
  512. }
  513. } /* end switch */
  514. /*
  515. * Update the current-line-display in the status line
  516. */
  517. if (error == DtEDITOR_NO_ERRORS)
  518. _DtEditorUpdateLineDisplay(editor, 1, False );
  519. _DtAppUnlock(app);
  520. return( error );
  521. }
  522. /***************************************************************************
  523. *
  524. * DtEditorSetContentsFromFile - read a data file, putting the contents
  525. * into a DtEditor widget.
  526. *
  527. * Inputs: widget to load the file into
  528. *
  529. * to indicate the type of contents loaded from the file:
  530. * string - a \0-terminated string of characters
  531. * data - untyped data
  532. *
  533. * filename - name of the file to read
  534. *
  535. * Returns 0 - contents were loaded sucessfully
  536. * !0 - an error occurred while loading the contents
  537. *
  538. ***************************************************************************/
  539. extern DtEditorErrorCode
  540. DtEditorSetContentsFromFile(
  541. Widget widget,
  542. char *fileName)
  543. {
  544. DtEditorErrorCode result;
  545. _DtWidgetToAppContext(widget);
  546. _DtAppLock(app);
  547. result = LoadFile(widget, fileName, LOAD_DATA, 0, 0);
  548. _DtAppUnlock(app);
  549. return result;
  550. }
  551. /***************************************************************************
  552. *
  553. * DtEditorAppend - append data to the contents of the DtEditor widget.
  554. *
  555. * Inputs: widget to add to the contents
  556. *
  557. * a data structure containing the data to append to the
  558. * widget. Depending upon the type of data being set, this
  559. * structure will contain various fields:
  560. *
  561. * string - \0-terminated string of characters
  562. * data - the data, the size of the data
  563. *
  564. * Returns 0 - contents were set sucessfully
  565. * !0 - an error occurred while setting the contents
  566. *
  567. ***************************************************************************/
  568. extern DtEditorErrorCode
  569. DtEditorAppend(
  570. Widget widget,
  571. DtEditorContentRec *data )
  572. {
  573. DtEditorErrorCode error = DtEDITOR_INVALID_TYPE;
  574. DtEditorWidget editor = (DtEditorWidget) widget;
  575. _DtWidgetToAppContext(widget);
  576. _DtAppLock(app);
  577. switch( data->type )
  578. {
  579. case DtEDITOR_TEXT:
  580. {
  581. error = insertStringValue ( editor, data->value.string,
  582. APPEND_DATA, 0, 0 );
  583. break;
  584. }
  585. case DtEDITOR_DATA:
  586. {
  587. error = insertDataValue ( editor, data->value.data.buf,
  588. data->value.data.length, APPEND_DATA, 0,0);
  589. break;
  590. }
  591. case DtEDITOR_WCHAR:
  592. {
  593. error = insertWcharValue ( editor, data->value.wchar,
  594. APPEND_DATA, 0, 0 );
  595. break;
  596. }
  597. default:
  598. {
  599. error = DtEDITOR_INVALID_TYPE;
  600. }
  601. } /* end switch */
  602. _DtAppUnlock(app);
  603. return( error );
  604. }
  605. /***************************************************************************
  606. *
  607. * DtEditorAppendFromFile - read a data file, appending the contents
  608. * into a DtEditor widget.
  609. *
  610. * Inputs: widget to append the file to
  611. *
  612. * to indicate the type of contents appended from the file:
  613. * string - a \0-terminated string of characters
  614. * data - untyped data
  615. *
  616. * filename - name of the file to read
  617. *
  618. * Returns 0 - contents were appended sucessfully
  619. * !0 - an error occurred while appending the contents
  620. *
  621. ***************************************************************************/
  622. extern DtEditorErrorCode
  623. DtEditorAppendFromFile(
  624. Widget widget,
  625. char *fileName)
  626. {
  627. DtEditorErrorCode result;
  628. _DtWidgetToAppContext(widget);
  629. _DtAppLock(app);
  630. result = LoadFile(widget, fileName, APPEND_DATA, 0, 0);
  631. _DtAppUnlock(app);
  632. return result;
  633. }
  634. /***************************************************************************
  635. *
  636. * DtEditorInsert - insert data into the contents of the DtEditor widget.
  637. *
  638. * Inputs: widget to add to the contents
  639. *
  640. * a data structure containing the data to insert into the
  641. * widget. Depending upon the type of data being set, this
  642. * structure will contain various fields:
  643. *
  644. * string - \0-terminated string of characters
  645. * data - the data, the size of the data
  646. *
  647. * Returns 0 - contents were set sucessfully
  648. * !0 - an error occurred while setting the contents
  649. *
  650. ***************************************************************************/
  651. extern DtEditorErrorCode
  652. DtEditorInsert(
  653. Widget widget,
  654. DtEditorContentRec *data )
  655. {
  656. DtEditorErrorCode error = DtEDITOR_INVALID_TYPE;
  657. DtEditorWidget editor = (DtEditorWidget) widget;
  658. _DtWidgetToAppContext(widget);
  659. _DtAppLock(app);
  660. switch( data->type )
  661. {
  662. case DtEDITOR_TEXT:
  663. {
  664. error = insertStringValue ( editor, data->value.string,
  665. INSERT_DATA, 0, 0 );
  666. break;
  667. }
  668. case DtEDITOR_DATA:
  669. {
  670. error = insertDataValue ( editor, data->value.data.buf,
  671. data->value.data.length, INSERT_DATA, 0,0);
  672. break;
  673. }
  674. case DtEDITOR_WCHAR:
  675. {
  676. error = insertWcharValue ( editor, data->value.wchar,
  677. INSERT_DATA, 0, 0 );
  678. break;
  679. }
  680. default :
  681. {
  682. error = DtEDITOR_INVALID_TYPE;
  683. }
  684. } /* end switch */
  685. _DtAppUnlock(app);
  686. return( error );
  687. }
  688. /***************************************************************************
  689. *
  690. * DtEditorInsertFromFile - read a data file, inserting the contents
  691. * into a DtEditor widget.
  692. *
  693. * Inputs: widget to insert the file to
  694. *
  695. * to indicate the type of contents inserted from the file:
  696. * string - a \0-terminated string of characters
  697. * data - untyped data
  698. *
  699. * filename - name of the file to read
  700. *
  701. * Returns 0 - contents were inserted sucessfully
  702. * !0 - an error occurred while inserting the contents
  703. *
  704. ***************************************************************************/
  705. extern DtEditorErrorCode
  706. DtEditorInsertFromFile(
  707. Widget widget,
  708. char *fileName)
  709. {
  710. DtEditorErrorCode result;
  711. _DtWidgetToAppContext(widget);
  712. _DtAppLock(app);
  713. result = LoadFile(widget, fileName, INSERT_DATA, 0, 0);
  714. _DtAppUnlock(app);
  715. return result;
  716. }
  717. /***************************************************************************
  718. *
  719. * DtEditorReplace - replace a specified portion of the contents of the
  720. * DtEditor widget with the supplied data.
  721. *
  722. * Inputs: widget to replace a portion of its contents
  723. *
  724. * starting character position of the portion to replace
  725. *
  726. * ending character position of the portion to replace
  727. *
  728. * a data structure containing the data to replace some data
  729. * in the widget. Depending upon the type of data being set,
  730. * this structure will contain various fields:
  731. *
  732. * string - \0-terminated string of characters
  733. * data - the data, the size of the data
  734. *
  735. *
  736. * Returns 0 - the portion was replaced sucessfully
  737. * !0 - an error occurred while replacing the portion
  738. *
  739. ***************************************************************************/
  740. extern DtEditorErrorCode
  741. DtEditorReplace(
  742. Widget widget,
  743. XmTextPosition startPos,
  744. XmTextPosition endPos,
  745. DtEditorContentRec *data)
  746. {
  747. DtEditorErrorCode error = DtEDITOR_INVALID_TYPE;
  748. DtEditorWidget editor = (DtEditorWidget) widget;
  749. XmTextWidget tw;
  750. _DtWidgetToAppContext(widget);
  751. _DtAppLock(app);
  752. tw = (XmTextWidget) M_text(editor);
  753. if( startPos < 0 )
  754. startPos = 0;
  755. if( startPos > tw->text.last_position )
  756. startPos = tw->text.last_position;
  757. if( endPos < 0 )
  758. endPos = 0;
  759. if( endPos > tw->text.last_position )
  760. endPos = tw->text.last_position;
  761. if( startPos > endPos )
  762. {
  763. error = DtEDITOR_INVALID_RANGE;
  764. }
  765. else
  766. {
  767. switch( data->type )
  768. {
  769. case DtEDITOR_TEXT:
  770. {
  771. error = insertStringValue ( editor, data->value.string,
  772. REPLACE_DATA, startPos, endPos );
  773. break;
  774. }
  775. case DtEDITOR_DATA:
  776. {
  777. error = insertDataValue ( editor, data->value.data.buf,
  778. data->value.data.length, REPLACE_DATA,
  779. startPos, endPos );
  780. break;
  781. }
  782. case DtEDITOR_WCHAR:
  783. {
  784. error = insertWcharValue ( editor, data->value.wchar,
  785. REPLACE_DATA, startPos, endPos );
  786. break;
  787. }
  788. default :
  789. {
  790. error = DtEDITOR_INVALID_TYPE;
  791. }
  792. } /* end switch */
  793. }
  794. _DtAppUnlock(app);
  795. return( error );
  796. }
  797. /***************************************************************************
  798. *
  799. * DtEditorReplaceFromFile - read a data file, using the contents to replace
  800. * a specified portion of the contntes of a
  801. * DtEditor widget.
  802. *
  803. * Inputs: widget to insert the file to
  804. *
  805. * starting character position of the portion to replace
  806. *
  807. * ending character position of the portion to replace
  808. *
  809. * to indicate the type of contents inserted from the file:
  810. * string - a \0-terminated string of characters
  811. * data - untyped data
  812. *
  813. * filename - local name of the file to read
  814. *
  815. * Returns 0 - contents were inserted sucessfully
  816. * !0 - an error occurred while inserting the contents
  817. *
  818. ***************************************************************************/
  819. extern DtEditorErrorCode
  820. DtEditorReplaceFromFile(
  821. Widget widget,
  822. XmTextPosition startPos,
  823. XmTextPosition endPos,
  824. char *fileName)
  825. {
  826. DtEditorWidget editor = (DtEditorWidget) widget;
  827. XmTextWidget tw;
  828. DtEditorErrorCode result;
  829. _DtWidgetToAppContext(widget);
  830. _DtAppLock(app);
  831. tw = (XmTextWidget) M_text(editor);
  832. if( startPos < 0)
  833. startPos = 0;
  834. if( startPos > tw->text.last_position )
  835. startPos = tw->text.last_position;
  836. if( endPos < 0 )
  837. endPos = 0;
  838. if( endPos > tw->text.last_position )
  839. endPos = tw->text.last_position;
  840. if(startPos > endPos)
  841. {
  842. result = DtEDITOR_INVALID_RANGE;
  843. }
  844. else
  845. {
  846. result = LoadFile(widget, fileName, REPLACE_DATA, startPos, endPos);
  847. }
  848. _DtAppUnlock(app);
  849. return result;
  850. }
  851. /***************************************************************************
  852. *
  853. * _DtEditorValidateFileAccess - check to see if file exists, whether we
  854. * can get to it, and whether it is readable
  855. * or writable.
  856. *
  857. * Note: does not check whether files for reading are read only.
  858. *
  859. * Inputs: filename - name of the local file to read
  860. * flag indicating whether we want to read or write
  861. * the file.
  862. *
  863. * Returns 0 file exists & we have read or write permissions.
  864. *
  865. * >0 if file cannot be read from/written to.
  866. * errno is set to one of the following values:
  867. *
  868. * General errors:
  869. * DtEDITOR_INVALID_FILENAME - 0 length filename
  870. * DtEDITOR_NONEXISTENT_FILE - file does not exist
  871. * (Note: this may not be considered an error when saving
  872. * to a file. The file may just need to be created.)
  873. * DtEDITOR_NO_FILE_ACCESS - cannot stat existing file
  874. * DtEDITOR_DIRECTORY - file is a directory
  875. * DtEDITOR_CHAR_SPECIAL_FILE - file is a device special file
  876. * DtEDITOR_BLOCK_MODE_FILE - file is a block mode file
  877. *
  878. * additional READ_ACCESS errors:
  879. * DtEDITOR_UNREADABLE_FILE -
  880. *
  881. * additional WRITE_ACCESS errors:
  882. * DtEDITOR_UNWRITABLE_FILE -
  883. * file or directory is write protected for
  884. * another reason
  885. *
  886. ***************************************************************************/
  887. extern DtEditorErrorCode
  888. _DtEditorValidateFileAccess(
  889. char *fileName,
  890. int accessType )
  891. {
  892. struct stat statbuf; /* Information on a file. */
  893. DtEditorErrorCode error = DtEDITOR_INVALID_FILENAME;
  894. /*
  895. * First, make sure we were given a name
  896. */
  897. if (fileName && *fileName )
  898. {
  899. /*
  900. * Does the file already exist?
  901. */
  902. if ( access(fileName, F_OK) != 0 )
  903. error = DtEDITOR_NONEXISTENT_FILE;
  904. else
  905. {
  906. error = DtEDITOR_NO_ERRORS;
  907. /*
  908. * The file exists, so lets do some type checking
  909. */
  910. if( stat(fileName, &statbuf) != 0 )
  911. error = DtEDITOR_NO_FILE_ACCESS;
  912. else
  913. {
  914. /* if its a directory - can't save */
  915. if( (statbuf.st_mode & S_IFMT) == S_IFDIR )
  916. {
  917. error = DtEDITOR_DIRECTORY;
  918. return( error );
  919. }
  920. /* if its a character special device - can't save */
  921. if( (statbuf.st_mode & S_IFMT) == S_IFCHR )
  922. {
  923. error = DtEDITOR_CHAR_SPECIAL_FILE;
  924. return( error );
  925. }
  926. /* if its a block mode device - can't save */
  927. if((statbuf.st_mode & S_IFMT) == S_IFBLK)
  928. {
  929. error = DtEDITOR_BLOCK_MODE_FILE;
  930. return( error );
  931. }
  932. /*
  933. * We now know that it's a regular file so check to whether we
  934. * can read or write to it, as appropriate.
  935. */
  936. switch( accessType )
  937. {
  938. case READ_ACCESS:
  939. {
  940. if( access(fileName, R_OK) != 0 )
  941. error = DtEDITOR_UNREADABLE_FILE;
  942. break;
  943. }
  944. case WRITE_ACCESS:
  945. {
  946. if( access(fileName, W_OK) == 0 )
  947. {
  948. /*
  949. * Can write to it.
  950. */
  951. error = DtEDITOR_WRITABLE_FILE;
  952. }
  953. else
  954. {
  955. /*
  956. * Can't write to it.
  957. */
  958. error = DtEDITOR_UNWRITABLE_FILE;
  959. } /* end no write permission */
  960. break;
  961. }
  962. default:
  963. {
  964. break;
  965. }
  966. } /* end switch */
  967. } /* end stat suceeded */
  968. } /* end file exists */
  969. } /* end filename passed in */
  970. return( error );
  971. } /* end _DtEditorValidateFileAccess */
  972. /************************************************************************
  973. *
  974. * LoadFile - Check if file exists, whether we can get to it, etc.
  975. * If so, type and read its contents.
  976. *
  977. * Inputs: widget to set, add, or insert contents of file into
  978. *
  979. * name of file to read
  980. *
  981. * type of file (NULL). This will be set by LoadFile
  982. *
  983. * action to perform with the data (load, append, insert,
  984. * replace a portion, attach)
  985. *
  986. * The following information will be used if the file
  987. * contents will replace a portion of the widget's contents:
  988. *
  989. * starting character position of the portion to replace
  990. *
  991. * ending character position of the portion to replace
  992. *
  993. * Returns: DtEDITOR_NO_ERRORS - file was read sucessfully
  994. * DtEDITOR_READ_ONLY_FILE - file was read sucessfully but
  995. * is read only
  996. * DtEDITOR_DIRECTORY - the file is a directory
  997. * DtEDITOR_CHAR_SPECIAL_FILE - the file is a character
  998. * special device
  999. * DtEDITOR_BLOCK_MODE_FILE - the file is a block mode device
  1000. * DtEDITOR_NONEXISTENT_FILE - file does not exist
  1001. * DtEDITOR_NULLS_REMOVED - file contained embedded NULLs
  1002. * that were removed
  1003. * DtEDITOR_INSUFFICIENT_MEMORY - unable to allocate
  1004. * enough memory for contents of file
  1005. *
  1006. ************************************************************************/
  1007. static DtEditorErrorCode
  1008. LoadFile(
  1009. Widget w,
  1010. char *fileName,
  1011. LoadActionType action,
  1012. XmTextPosition startReplace,
  1013. XmTextPosition endReplace )
  1014. {
  1015. DtEditorContentRec cr; /* Structure for passing data to widget */
  1016. struct stat statbuf; /* Information on a file. */
  1017. int file_length; /* Length of file. */
  1018. FILE *fp = NULL; /* Pointer to open file */
  1019. DtEditorErrorCode returnVal = DtEDITOR_NONEXISTENT_FILE;
  1020. /* Error accessing file & reading contents */
  1021. DtEditorErrorCode loadError=DtEDITOR_NO_ERRORS;
  1022. /* Error from placing bits into text widget */
  1023. /*
  1024. * First, make sure we were given a name
  1025. */
  1026. if (fileName && *fileName )
  1027. {
  1028. /*
  1029. * Can we read the file?
  1030. */
  1031. returnVal = _DtEditorValidateFileAccess( fileName, READ_ACCESS );
  1032. if( returnVal == DtEDITOR_NO_ERRORS )
  1033. {
  1034. /*
  1035. * Open the file for reading. If we can read/write, then we're
  1036. * cool, otherwise we might need to tell the user that the
  1037. * file's read-only, or that we can't even read from it.
  1038. */
  1039. if( (fp = fopen(fileName, "r+")) == NULL )
  1040. {
  1041. /*
  1042. * We can't update (read/write) the file so try opening read-
  1043. * only
  1044. */
  1045. if( (fp = fopen(fileName, "r")) == NULL )
  1046. {
  1047. /*
  1048. * We can't read from the file.
  1049. */
  1050. return ( DtEDITOR_UNREADABLE_FILE );
  1051. }
  1052. else
  1053. {
  1054. /*
  1055. * Tell the application that the file's read-only.
  1056. * Becareful not to overwrite this value with one of the calls
  1057. * to set the widget's contents.
  1058. */
  1059. returnVal = DtEDITOR_READ_ONLY_FILE;
  1060. }
  1061. } /* end open for read/write */
  1062. } /* end try to read the file */
  1063. } /* end if no filename */
  1064. /* If a file is open, get the bytes */
  1065. if ( fp )
  1066. {
  1067. stat( fileName, &statbuf );
  1068. file_length = statbuf.st_size;
  1069. /*
  1070. * Check to see if we have enough memory to load the file contents
  1071. * into the text widget. This is only an estimate of our needs.
  1072. * Check4EnoughMemory() returns DtEDITOR_NO_ERRORS,
  1073. * DtEDITOR_ILLEGAL_SIZE, or DtEDITOR_INSUFFICIENT_MEMORY.
  1074. */
  1075. loadError = Check4EnoughMemory( file_length );
  1076. if (loadError == DtEDITOR_INSUFFICIENT_MEMORY)
  1077. returnVal = loadError;
  1078. else {
  1079. /*
  1080. * Read the file contents (with room for null) & convert to a
  1081. * string. We want to use a string because the
  1082. * DtEditorSetContents/Append/Insert/... functions create another
  1083. * copy of the data before actually putting it into the widget.
  1084. */
  1085. char *file_string = (char*) XtMalloc(file_length + 1);
  1086. file_length = fread(file_string, sizeof(char), file_length, fp);
  1087. file_string[file_length] = '\0';
  1088. /*
  1089. * Strip out any embedded NULLs because the text widget will only
  1090. * accept data up to the first NULL.
  1091. *
  1092. * StripEmbeddedNulls() returns DtEDITOR_NO_ERRORS or
  1093. * DtEDITOR_NULLS_REMOVED
  1094. */
  1095. loadError = StripEmbeddedNulls( file_string, &file_length );
  1096. if ( loadError != DtEDITOR_NO_ERRORS )
  1097. returnVal = loadError;
  1098. /*
  1099. * Insert it as a string, otherwise the following DtEditor*()
  1100. * functions will make another copy of the data.
  1101. */
  1102. cr.type = DtEDITOR_TEXT;
  1103. cr.value.string = file_string;
  1104. /*
  1105. * Load, insert, append, or attach the file, as specified
  1106. */
  1107. switch( action )
  1108. {
  1109. case LOAD_DATA:
  1110. {
  1111. loadError = DtEditorSetContents ( w, &cr );
  1112. break;
  1113. }
  1114. case INSERT_DATA:
  1115. {
  1116. loadError = DtEditorInsert ( w, &cr );
  1117. break;
  1118. }
  1119. case APPEND_DATA:
  1120. {
  1121. loadError = DtEditorAppend ( w, &cr );
  1122. break;
  1123. }
  1124. case REPLACE_DATA:
  1125. {
  1126. loadError = DtEditorReplace(w, startReplace, endReplace, &cr);
  1127. break;
  1128. }
  1129. default:
  1130. {
  1131. }
  1132. } /* end switch */
  1133. if ( loadError != DtEDITOR_NO_ERRORS )
  1134. returnVal = loadError;
  1135. /*
  1136. * The file is loaded, clean up.
  1137. */
  1138. XtFree( file_string );
  1139. } /* end there is enough memory */
  1140. /* Close the file */
  1141. fclose(fp);
  1142. } /* end if a file is open */
  1143. return( returnVal );
  1144. } /* end LoadFile */
  1145. static char *
  1146. StringAdd(
  1147. char *destination,
  1148. char *source,
  1149. int number)
  1150. {
  1151. memcpy(destination, source, number);
  1152. destination[number] = (char)'\0';
  1153. destination += number;
  1154. return destination;
  1155. }
  1156. /***************************************************************************
  1157. *
  1158. * CopySubstring - copies out a portion of the text, optionally
  1159. * adding newlines at any and all wordwrap-caused
  1160. * "virtual" lines.
  1161. *
  1162. * Inputs: widget from which we get the data to write;
  1163. * startPos determines the first character to write out;
  1164. * endPos determines the last character to write out;
  1165. * buf is the character buffer into which we write. It
  1166. * is assumed to be large enough - be careful.
  1167. * addNewlines specifies whether to add '/n' to "virtual" lines.
  1168. * Returns Nuthin'
  1169. *
  1170. *
  1171. ***************************************************************************/
  1172. static char *
  1173. CopySubstring(
  1174. XmTextWidget widget,
  1175. XmTextPosition startPos,
  1176. XmTextPosition endPos,
  1177. char *buf,
  1178. Boolean addNewlines)
  1179. {
  1180. XmTextLineTable line_table = widget->text.line_table;
  1181. int currLine, firstLine;
  1182. char *pString, *pCurrChar, *pLastChar;
  1183. int numToCopy;
  1184. if(startPos < 0)
  1185. startPos = 0;
  1186. if(startPos > widget->text.last_position)
  1187. startPos = widget->text.last_position;
  1188. if(endPos < 0)
  1189. endPos = 0;
  1190. if(endPos > widget->text.last_position)
  1191. endPos = widget->text.last_position;
  1192. if(startPos > endPos)
  1193. return buf;
  1194. pString = XmTextGetString((Widget)widget);
  1195. if(addNewlines == False)
  1196. {
  1197. pCurrChar = _DtEditorGetPointer(pString, startPos);
  1198. pLastChar = _DtEditorGetPointer(pString, endPos);
  1199. numToCopy = pLastChar - pCurrChar + mblen(pLastChar, MB_CUR_MAX);
  1200. buf = StringAdd(buf, pCurrChar, numToCopy);
  1201. }
  1202. else
  1203. {
  1204. int *mb_str_loc, total, z, siz;
  1205. char *bptr;
  1206. mb_str_loc = (int *) XtMalloc(sizeof(int) * ((endPos-startPos)+1));
  1207. if (NULL == mb_str_loc)
  1208. {
  1209. /* Should figure out some way to pass back an error code. */
  1210. buf = CopySubstring(widget, startPos, endPos, buf, False);
  1211. return buf;
  1212. }
  1213. /*
  1214. * mb_str_loc[] is being used to replace the call
  1215. * to _DtEditorGetPointer. That function used
  1216. * mbtowc() to count the number of chars between the
  1217. * beginning of pString and startChar. The problem
  1218. * was that it sat in a loop and was also called for
  1219. * every line, so it was SLOW. Now, we count once
  1220. * and store the results in mb_str_loc[].
  1221. */
  1222. /* Because startPos may not always == 0: */
  1223. /* mb_str_loc[0] = startPos */
  1224. /* mb_str_loc[endPos - startPos] = endPos */
  1225. /* */
  1226. /* So when accessing items, dereference off of */
  1227. /* startPos. */
  1228. mb_str_loc[0] = 0;
  1229. for(total=0, bptr=pString, z=1;
  1230. z <= (endPos - startPos); bptr += siz, z++)
  1231. {
  1232. if (MB_CUR_MAX > 1)
  1233. {
  1234. if ( (siz = mblen(bptr, MB_CUR_MAX)) < 0)
  1235. {
  1236. siz = 1;
  1237. total += 1;
  1238. }
  1239. else
  1240. total += siz;
  1241. }
  1242. else
  1243. {
  1244. siz = 1;
  1245. total += 1;
  1246. }
  1247. mb_str_loc[z] = total;
  1248. }
  1249. firstLine = currLine = _DtEditorGetLineIndex(widget, startPos);
  1250. do
  1251. {
  1252. if(startPos > (XmTextPosition)line_table[currLine].start_pos)
  1253. pCurrChar = pString + mb_str_loc[0];
  1254. else
  1255. {
  1256. z = line_table[currLine].start_pos;
  1257. pCurrChar = pString +
  1258. mb_str_loc[z - startPos];
  1259. }
  1260. if(addNewlines == True && currLine > firstLine &&
  1261. line_table[currLine].virt_line != 0)
  1262. {
  1263. buf[0] = (char)'\n';
  1264. buf[1] = (char)'\0';
  1265. buf++;
  1266. }
  1267. if(currLine >= (widget->text.total_lines - 1))
  1268. pLastChar = pString +
  1269. mb_str_loc[endPos - startPos];
  1270. else if((XmTextPosition)line_table[currLine + 1].start_pos <= endPos)
  1271. {
  1272. z = line_table[currLine+1].start_pos - 1;
  1273. pLastChar = pString +
  1274. mb_str_loc[z - startPos];
  1275. }
  1276. else
  1277. pLastChar = pString +
  1278. mb_str_loc[endPos - startPos];
  1279. numToCopy = pLastChar - pCurrChar + mblen(pLastChar, MB_CUR_MAX);
  1280. buf = StringAdd(buf, pCurrChar, numToCopy);
  1281. currLine++;
  1282. } while(currLine < widget->text.total_lines &&
  1283. (XmTextPosition)line_table[currLine].start_pos <= endPos);
  1284. XtFree((char*)mb_str_loc);
  1285. }
  1286. XtFree(pString);
  1287. return buf;
  1288. }
  1289. /*************************************************************************
  1290. *
  1291. * _DtEditorCopyDataOut - Writes the entire text editor buffer contents to
  1292. * the specified character array.
  1293. *
  1294. * Inputs: tw, to supply the data.
  1295. * buf, specifying the array to which to write the data.
  1296. *
  1297. *************************************************************************/
  1298. static char *
  1299. _DtEditorCopyDataOut(
  1300. XmTextWidget tw,
  1301. char *buf,
  1302. Boolean addNewlines)
  1303. {
  1304. buf = CopySubstring(tw, 0, tw->text.last_position, buf, addNewlines);
  1305. return buf;
  1306. }
  1307. static DtEditorErrorCode
  1308. getStringValue(
  1309. DtEditorWidget editor,
  1310. char **buf,
  1311. Boolean insertNewlines)
  1312. {
  1313. XmTextWidget tw = (XmTextWidget) M_text(editor);
  1314. int bufSize;
  1315. char *lastChar;
  1316. DtEditorErrorCode returnVal = DtEDITOR_NO_ERRORS;
  1317. /*
  1318. * Calculate the size of the buffer we need for the data.
  1319. * 1. Start with MB_CUR_MAX for each char in the text.
  1320. * 3. Add in 1 char for each line, if we have to insert newlines.
  1321. * 4. Add 1 for a terminating NULL.
  1322. */
  1323. bufSize = tw->text.last_position * MB_CUR_MAX;
  1324. if(insertNewlines == True)
  1325. bufSize += tw->text.total_lines;
  1326. bufSize += 1;
  1327. returnVal = Check4EnoughMemory(bufSize);
  1328. if (DtEDITOR_NO_ERRORS != returnVal) return returnVal;
  1329. *buf = (char *) XtMalloc(bufSize);
  1330. lastChar = _DtEditorCopyDataOut(tw, *buf, insertNewlines);
  1331. return returnVal;
  1332. } /* end getStringValue */
  1333. static DtEditorErrorCode
  1334. getDataValue(
  1335. DtEditorWidget editor,
  1336. void **buf,
  1337. unsigned int *size,
  1338. Boolean insertNewlines)
  1339. {
  1340. DtEditorErrorCode error;
  1341. error = getStringValue(editor, (char **)buf, insertNewlines);
  1342. *size = strlen( *buf ); /* remember, strlen doesn't count \0 at end */
  1343. return( error );
  1344. } /* end getDataValue */
  1345. static DtEditorErrorCode
  1346. getWcharValue(
  1347. DtEditorWidget editor,
  1348. wchar_t **data,
  1349. Boolean insertNewlines)
  1350. {
  1351. DtEditorErrorCode error;
  1352. char *mb_value;
  1353. wchar_t *pWchar_value;
  1354. int num_char, result;
  1355. size_t nbytes;
  1356. error = getStringValue(editor, &mb_value, insertNewlines);
  1357. if (error == DtEDITOR_NO_ERRORS)
  1358. {
  1359. /*
  1360. * Allocate space for the wide character string
  1361. */
  1362. num_char = _DtEditor_CountCharacters(mb_value, strlen(mb_value)) + 1;
  1363. nbytes = (size_t) num_char * sizeof(wchar_t);
  1364. error = Check4EnoughMemory(nbytes);
  1365. if (DtEDITOR_NO_ERRORS != error) return error;
  1366. pWchar_value = (wchar_t*) XtMalloc(nbytes);
  1367. /*
  1368. * Convert the multi-byte string to wide character
  1369. */
  1370. result = mbstowcs(pWchar_value, mb_value, num_char*sizeof(wchar_t) );
  1371. if (result < 0) pWchar_value[0] = 0L;
  1372. *data = pWchar_value;
  1373. XtFree( mb_value );
  1374. }
  1375. return( error );
  1376. } /* end getWcharValue */
  1377. /***************************************************************************
  1378. *
  1379. * DtEditorGetContents - gets the contents of the DtEditor widget.
  1380. *
  1381. * Inputs: widget to retrieve the contents
  1382. *
  1383. * pointer to a data structure indicating how the retrieved
  1384. * data should be formatted. Depending upon the type of format,
  1385. * this structure will contain various fields:
  1386. * string - a NULL pointer (char *) to hold the data
  1387. * a new container will be created.
  1388. * data - void pointer to hold the data, unsigned int for the
  1389. * size of the data,
  1390. * a Boolean indicating whether Newline characters should be
  1391. * inserted at the end of each line, in string format.
  1392. * a Boolean indicating whether the the unsaved changes
  1393. * flag should be cleared. There may be times when an
  1394. * application will want to request a copy of the contents
  1395. * without effecting whether DtEditorCheckForUnsavedChanges
  1396. * reports there are unsaved changes.
  1397. *
  1398. * Returns 0 - contents were retrieved sucessfully
  1399. * !0 - an error occurred while retrieving the contents
  1400. *
  1401. * The structure passed in will be set according to the
  1402. * requested format:
  1403. * string - a \0-terminated string of characters with
  1404. * optional Newlines
  1405. * container - handle to a Bento container
  1406. * data - the data, the size of the data
  1407. *
  1408. * The application is responsible for free'ing any data in the
  1409. * above structure.
  1410. *
  1411. ***************************************************************************/
  1412. extern DtEditorErrorCode
  1413. DtEditorGetContents(
  1414. Widget widget,
  1415. DtEditorContentRec *data,
  1416. Boolean hardCarriageReturns,
  1417. Boolean markContentsAsSaved )
  1418. {
  1419. DtEditorErrorCode error = DtEDITOR_INVALID_TYPE;
  1420. DtEditorWidget editor = (DtEditorWidget) widget;
  1421. _DtWidgetToAppContext(widget);
  1422. _DtAppLock(app);
  1423. switch( data->type )
  1424. {
  1425. case DtEDITOR_TEXT:
  1426. {
  1427. error = getStringValue( editor, &(data->value.string),
  1428. hardCarriageReturns );
  1429. break;
  1430. }
  1431. case DtEDITOR_DATA:
  1432. {
  1433. error = getDataValue( editor, &(data->value.data.buf),
  1434. &(data->value.data.length),
  1435. hardCarriageReturns );
  1436. break;
  1437. }
  1438. case DtEDITOR_WCHAR:
  1439. {
  1440. error = getWcharValue( editor, &(data->value.wchar),
  1441. hardCarriageReturns );
  1442. break;
  1443. }
  1444. default :
  1445. {
  1446. error = DtEDITOR_INVALID_TYPE;
  1447. }
  1448. } /* end switch */
  1449. /*
  1450. * If there were no errors, mark there are now no unsaved changes (unless
  1451. * we were told not to).
  1452. */
  1453. if ( error == DtEDITOR_NO_ERRORS && markContentsAsSaved == True )
  1454. M_unreadChanges( editor ) = False;
  1455. _DtAppUnlock(app);
  1456. return( error );
  1457. }
  1458. /***************************************************************************
  1459. *
  1460. * DtEditorSaveContentsToFile - saves the contents of the DtEditor
  1461. * widget to a disc file as string/data
  1462. * or a CDE Document (Bento container).
  1463. *
  1464. * Inputs: widget to retrieve the contents
  1465. *
  1466. * filename - name of the file to read
  1467. * a Boolean indicating whether the file should be
  1468. * overwritten if it currently exists.
  1469. * a Boolean indicating whether Newline characters should be
  1470. * inserted at the end of each line (string format only).
  1471. * a Boolean indicating whether the the unsaved changes
  1472. * flag should be cleared. There may be times when an
  1473. * application will want to request a copy of the contents
  1474. * without effecting whether DtEditorCheckForUnsavedChanges
  1475. * reports there are unsaved changes.
  1476. *
  1477. * Returns DtEDITOR_NO_ERRORS - contents were saved sucessfully
  1478. * DtEDITOR_UNWRITABLE_FILE - file is write protected
  1479. * DtEDITOR_WRITABLE_FILE - file exists and the
  1480. * overwriteIfExists parameter is False.
  1481. * DtEDITOR_SAVE_FAILED - write to the file failed; check
  1482. * disk space, etc.
  1483. * OR any errors from DtEditorGetContents
  1484. *
  1485. ***************************************************************************/
  1486. extern DtEditorErrorCode
  1487. DtEditorSaveContentsToFile(
  1488. Widget widget,
  1489. char *fileName,
  1490. Boolean overwriteIfExists,
  1491. Boolean hardCarriageReturns,
  1492. Boolean markContentsAsSaved )
  1493. {
  1494. FILE *pFile;
  1495. DtEditorContentRec cr; /* Structure for retrieving contents of widget */
  1496. DtEditorWidget editor = (DtEditorWidget) widget;
  1497. DtEditorErrorCode error = DtEDITOR_INVALID_FILENAME;
  1498. _DtWidgetToAppContext(widget);
  1499. _DtAppLock(app);
  1500. /*
  1501. * First, make sure we were given a name
  1502. */
  1503. if (fileName && *fileName )
  1504. {
  1505. /*
  1506. * Can we save to the file?
  1507. */
  1508. error = _DtEditorValidateFileAccess( fileName, WRITE_ACCESS );
  1509. if( error == DtEDITOR_NO_ERRORS ||
  1510. error == DtEDITOR_NONEXISTENT_FILE ||
  1511. error == DtEDITOR_WRITABLE_FILE )
  1512. {
  1513. /*
  1514. * Don't overwrite an existing file if we've been told not to
  1515. */
  1516. if( error == DtEDITOR_WRITABLE_FILE && overwriteIfExists == False )
  1517. {
  1518. _DtAppUnlock(app);
  1519. return( error );
  1520. }
  1521. /*
  1522. * Open the file for writing
  1523. */
  1524. if ( (pFile = fopen(fileName, "w")) == NULL )
  1525. {
  1526. _DtAppUnlock(app);
  1527. return( DtEDITOR_UNWRITABLE_FILE );
  1528. }
  1529. else
  1530. {
  1531. /*
  1532. * Save the unsaved changes flag so we can restore it if the write
  1533. * to the file fails.
  1534. */
  1535. Boolean saved_state = M_unreadChanges( editor );
  1536. /*
  1537. * Now, get the contents of the widget and write it to the file,
  1538. * depending upon the format requested.
  1539. */
  1540. cr.type = DtEDITOR_DATA;
  1541. error = DtEditorGetContents( widget, &cr, hardCarriageReturns,
  1542. markContentsAsSaved );
  1543. if ( error == DtEDITOR_NO_ERRORS )
  1544. {
  1545. /*
  1546. * Write it to the file
  1547. */
  1548. size_t size_written = fwrite( cr.value.data.buf, 1,
  1549. cr.value.data.length, pFile );
  1550. if( cr.value.data.length != size_written )
  1551. error = DtEDITOR_SAVE_FAILED;
  1552. XtFree( cr.value.data.buf );
  1553. }
  1554. fclose(pFile);
  1555. if( error == DtEDITOR_SAVE_FAILED )
  1556. {
  1557. /*
  1558. * Restore the unsaved changes flag since the save failed
  1559. */
  1560. M_unreadChanges( editor ) = saved_state;
  1561. }
  1562. } /* end file is writable */
  1563. } /* end filename is valid */
  1564. }
  1565. _DtAppUnlock(app);
  1566. return( error );
  1567. } /* end DtEditorSaveContentsToFile */
  1568. /*
  1569. * _DtEditorGetPointer returns a pointer to the _character_
  1570. * numbered by startChar within the string pString.
  1571. * It accounts for possible multibyte chars.
  1572. */
  1573. char *
  1574. _DtEditorGetPointer(
  1575. char *pString,
  1576. int startChar)
  1577. {
  1578. char *bptr;
  1579. int curChar, char_size;
  1580. if(MB_CUR_MAX > 1)
  1581. {
  1582. for(bptr = pString, curChar = 0;
  1583. curChar < startChar && *bptr != (char)'\0';
  1584. curChar++, bptr += char_size)
  1585. {
  1586. if ( (char_size = mblen(bptr, MB_CUR_MAX)) < 0)
  1587. char_size = 1;
  1588. }
  1589. }
  1590. else
  1591. {
  1592. bptr = pString + startChar;
  1593. }
  1594. return bptr;
  1595. } /* end _DtEditorGetPointer */