1 /*
2  * Copyright 1991 by OMRON Corporation
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and its
5  * documentation for any purpose is hereby granted without fee, provided that
6  * the above copyright notice appear in all copies and that both that
7  * copyright notice and this permission notice appear in supporting
8  * documentation, and that the name OMRON not be used in
9  * advertising or publicity pertaining to distribution of the software without
10  * specific, written prior permission.  OMRON makes no representations
11  * about the suitability of this software for any purpose.  It is provided
12  * "as is" without express or implied warranty.
13  *
14  * OMRON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16  * EVENT SHALL OMRON BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19  * TORTUOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20  * PERFORMANCE OF THIS SOFTWARE.
21  *
22  *      Authors: Chris Peterson MIT X Consortium
23  *               Li Yuhong      OMRON Corporation
24  *               Frank Sheeran  OMRON Corporation
25  *
26  * Much code taken from X11R3 String and Disk Sources.
27  */
28 
29 /*
30 
31 Copyright (c) 1991, 1994  X Consortium
32 
33 Permission is hereby granted, free of charge, to any person obtaining a copy
34 of this software and associated documentation files (the "Software"), to deal
35 in the Software without restriction, including without limitation the rights
36 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
37 copies of the Software, and to permit persons to whom the Software is
38 furnished to do so, subject to the following conditions:
39 
40 The above copyright notice and this permission notice shall be included in
41 all copies or substantial portions of the Software.
42 
43 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
44 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
45 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
46 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
47 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
48 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
49 
50 Except as contained in this notice, the name of the X Consortium shall not be
51 used in advertising or otherwise to promote the sale, use or other dealings
52 in this Software without prior written authorization from the X Consortium.
53 
54 */
55 
56 /*
57  * MultiSrc.c - MultiSrc object. (For use with the text widget).
58  *
59  */
60 
61 #ifdef HAVE_CONFIG_H
62 #include "config.h"
63 #endif
64 #include <X11/Xaw3dxft/Xaw3dP.h>
65 #include <X11/IntrinsicP.h>
66 #include <X11/StringDefs.h>
67 #include <X11/Xfuncs.h>
68 #include <X11/Xaw3dxft/XawInit.h>
69 #include <X11/Xaw3dxft/MultiSrcP.h>
70 #include <X11/Xaw3dxft/XawImP.h>
71 #include <X11/Xmu/Misc.h>
72 #include <X11/Xmu/CharSet.h>
73 #include "XawI18n.h"
74 #include <X11/Xos.h>
75 #include <stdio.h>
76 #include <ctype.h>
77 #include <errno.h>
78 
79 /****************************************************************
80  *
81  * Full class record constant
82  *
83  ****************************************************************/
84 
85 /* Private Data */
86 
87 static int magic_value = MAGIC_VALUE;
88 
89 #define offset(field) XtOffsetOf(MultiSrcRec, multi_src.field)
90 
91 static XtResource resources[] = {
92     {XtNstring, XtCString, XtRString, sizeof (XtPointer),
93        offset(string), XtRPointer, NULL},
94     {XtNtype, XtCType, XtRMultiType, sizeof (XawAsciiType),
95        offset(type), XtRImmediate, (XtPointer)XawAsciiString},
96     /* not used. */
97     {XtNdataCompression, XtCDataCompression, XtRBoolean, sizeof (Boolean),
98        offset(data_compression), XtRImmediate, (XtPointer) FALSE},
99     {XtNpieceSize, XtCPieceSize, XtRInt, sizeof (XawTextPosition),
100        offset(piece_size), XtRImmediate, (XtPointer) BUFSIZ},
101     {XtNcallback, XtCCallback, XtRCallback, sizeof(XtPointer),
102        offset(callback), XtRCallback, (XtPointer)NULL},
103     {XtNuseStringInPlace, XtCUseStringInPlace, XtRBoolean, sizeof (Boolean),
104        offset(use_string_in_place), XtRImmediate, (XtPointer) FALSE},
105     {XtNlength, XtCLength, XtRInt, sizeof (int),
106        offset(multi_length), XtRInt, (XtPointer) &magic_value},
107 
108 };
109 #undef offset
110 
111 static XawTextPosition Scan(Widget, XawTextPosition, XawTextScanType,
112                             XawTextScanDirection, int, Boolean);
113 static XawTextPosition Search(Widget, XawTextPosition, XawTextScanDirection,
114                               XawTextBlock *);
115 static XawTextPosition ReadText(Widget, XawTextPosition, XawTextBlock *, int);
116 static int ReplaceText(Widget, XawTextPosition, XawTextPosition, XawTextBlock *);
117 static MultiPiece * FindPiece(MultiSrcObject, XawTextPosition, XawTextPosition *);
118 static MultiPiece * AllocNewPiece(MultiSrcObject, MultiPiece *);
119 static FILE * InitStringOrFile(MultiSrcObject, Boolean);
120 static void FreeAllPieces(MultiSrcObject);
121 static void RemovePiece(MultiSrcObject, MultiPiece *);
122 static void BreakPiece(MultiSrcObject, MultiPiece *);
123 static void LoadPieces(MultiSrcObject, FILE *, char *);
124 static void RemoveOldStringOrFile(MultiSrcObject, Boolean);
125 static void  CvtStringToMultiType(XrmValuePtr, Cardinal *, XrmValuePtr, XrmValuePtr);
126 static void ClassInitialize(void);
127 static void Initialize(Widget, Widget, ArgList, Cardinal *);
128 static void Destroy(Widget);
129 static void GetValuesHook(Widget, ArgList, Cardinal *);
130 static String StorePiecesInString(MultiSrcObject);
131 static Boolean SetValues(Widget, Widget, Widget, ArgList, Cardinal *);
132 static Boolean WriteToFile(String, String);
133 
134 #define MyWStrncpy( t,s,wcnt ) (void) memmove( (t), (s), (wcnt)*sizeof(wchar_t))
135 
136 #ifndef MyWStrncpy
137 static void (MyWStrncpy)();
138 #endif
139 
140 extern char *tmpnam(String);
141 #ifdef X_NOT_STDC_ENV
142 extern int errno;
143 #endif
144 
145 #ifdef X_NOT_POSIX
146 #define Off_t long
147 #define Size_t unsigned int
148 #else
149 #define Off_t off_t
150 #define Size_t size_t
151 #endif
152 
153 extern wchar_t* _XawTextMBToWC(Display *, char *, int *);
154 extern char *_XawTextWCToMB(Display *, wchar_t *, int *);
155 
156 #define superclass		(&textSrcClassRec)
157 MultiSrcClassRec multiSrcClassRec = {
158   { /* object_class fields */
159     /* superclass	  	*/	(WidgetClass) superclass,
160     /* class_name	  	*/	"MultiSrc",
161     /* widget_size	  	*/	sizeof(MultiSrcRec),
162     /* class_initialize   	*/	ClassInitialize,
163     /* class_part_initialize	*/	NULL,
164     /* class_inited       	*/	FALSE,
165     /* initialize	  	*/	Initialize,
166     /* initialize_hook		*/	NULL,
167     /* pad		  	*/	NULL,
168     /* pad		  	*/	NULL,
169     /* pad		  	*/	0,
170     /* resources	  	*/	resources,
171     /* num_resources	  	*/	XtNumber(resources),
172     /* xrm_class	  	*/	NULLQUARK,
173     /* pad		  	*/	FALSE,
174     /* pad		  	*/	FALSE,
175     /* pad			*/	FALSE,
176     /* pad		  	*/	FALSE,
177     /* destroy		  	*/	Destroy,
178     /* pad		  	*/	NULL,
179     /* pad		  	*/	NULL,
180     /* set_values	  	*/	SetValues,
181     /* set_values_hook		*/	NULL,
182     /* pad			*/	NULL,
183     /* get_values_hook		*/	GetValuesHook,
184     /* pad		 	*/	NULL,
185     /* version			*/	XtVersion,
186     /* callback_private   	*/	NULL,
187     /* pad		   	*/	NULL,
188     /* pad			*/	NULL,
189     /* pad			*/	NULL,
190     /* extension		*/	NULL
191   },
192   { /* textSrc_class fields */
193     /* Read                     */      ReadText,
194     /* Replace                  */      ReplaceText,
195     /* Scan                     */      Scan,
196     /* Search                   */      Search,
197     /* SetSelection             */      XtInheritSetSelection,
198     /* ConvertSelection         */      XtInheritConvertSelection
199   },
200   { /* multiSrc_class fields */
201     /* Keep the compiler happy */       '\0'
202   }
203 };
204 
205 WidgetClass multiSrcObjectClass = (WidgetClass)&multiSrcClassRec;
206 
207 /************************************************************
208  *
209  * Semi-Public Interfaces.
210  *
211  ************************************************************/
212 
213 /*      Function Name: ClassInitialize
214  *      Description: Class Initialize routine, called only once.
215  *      Arguments: none.
216  *      Returns: none.
217  */
218 
219 static void
ClassInitialize(void)220 ClassInitialize(void)
221 {
222   XawInitializeWidgetSet();
223   XtAddConverter( XtRString, XtRMultiType, CvtStringToMultiType,
224 		 NULL, (Cardinal) 0);
225 }
226 
227 /*      Function Name: Initialize
228  *      Description: Initializes the simple menu widget
229  *      Arguments: request - the widget requested by the argument list.
230  *                 new     - the new widget with both resource and non
231  *                           resource values.
232  *      Returns: none.
233  */
234 
235 /* ARGSUSED */
236 static void
Initialize(Widget request,Widget new,ArgList args,Cardinal * num_args)237 Initialize(Widget request, Widget new, ArgList args, Cardinal *num_args)
238 {
239   MultiSrcObject src = (MultiSrcObject) new;
240   FILE * file;
241 
242 /*
243  * Set correct flags (override resources) depending upon widget class.
244  */
245 
246   src->multi_src.changes = FALSE;
247   src->multi_src.allocated_string = FALSE;
248 
249   file = InitStringOrFile(src, src->multi_src.type == XawAsciiFile);
250   LoadPieces(src, file, NULL);
251 
252   if (file != NULL) fclose(file);
253   src->text_src.text_format = XawFmtWide;
254 
255 }
256 
257 /*	Function Name: ReadText
258  *	Description: This function reads the source.
259  *	Arguments: w - the MultiSource widget.
260  *                 pos - position of the text to retreive.
261  * RETURNED        text - text block that will contain returned text.
262  *                length - maximum number of characters to read.
263  *	Returns: The number of characters read into the buffer.
264  */
265 
266 static XawTextPosition
ReadText(Widget w,XawTextPosition pos,XawTextBlock * text,int length)267 ReadText(Widget w, XawTextPosition pos, XawTextBlock *text, int length)
268 {
269   MultiSrcObject src = (MultiSrcObject) w;
270   XawTextPosition count, start = 0;
271   MultiPiece * piece = FindPiece(src, pos, &start);
272 
273   text->format = XawFmtWide;
274   text->firstPos = pos;
275   text->ptr = (char *)(piece->text + (pos - start));
276   count = piece->used - (pos - start);
277   text->length = (length > count) ? count : length;
278   return(pos + text->length);
279 }
280 
281 /*	Function Name: ReplaceText.
282  *	Description: Replaces a block of text with new text.
283  *	Arguments: w - the MultiSource widget.
284  *                 startPos, endPos - ends of text that will be removed.
285  *                 text - new text to be inserted into buffer at startPos.
286  *	Returns: XawEditError or XawEditDone.
287  */
288 
289 /*ARGSUSED*/
290 static int
ReplaceText(Widget w,XawTextPosition startPos,XawTextPosition endPos,XawTextBlock * u_text_p)291 ReplaceText(Widget w, XawTextPosition startPos, XawTextPosition endPos, XawTextBlock *u_text_p)
292 {
293   MultiSrcObject src = (MultiSrcObject) w;
294   MultiPiece *start_piece, *end_piece, *temp_piece;
295   XawTextPosition start_first = 0, end_first;
296   int length, firstPos;
297   wchar_t *wptr;
298   Boolean local_artificial_block = False;
299   XawTextBlock text;
300 
301   /* STEP 1: The user handed me a text block called `u_text' that may be
302    * in either FMTWIDE or FMT8BIT (ie MB.)  Later code needs the block
303    * `text' to hold FMTWIDE.  So, this copies `u_text' to `text', and if
304    * `u_text' was MB, I knock it up to WIDE. */
305 
306   if ( u_text_p->length == 0 )	/* if so, the block contents never ref'd. */
307       text.length = 0;
308 
309   else if ( u_text_p->format == XawFmtWide) {
310       local_artificial_block = False;		/* ie, don't have to free it ourselves*/
311       text.firstPos = u_text_p->firstPos;
312       text.length =   u_text_p->length;
313       text.ptr =      u_text_p->ptr;
314       /* text.format is unneeded */
315 
316   } else {
317       /* WARNING! u_text->firstPos and length are in units of CHAR, not CHARACTERS! */
318 
319       local_artificial_block = True;	/* ie, have to free it ourselves */
320       text.firstPos = 0;
321       text.length = u_text_p->length; /* _XawTextMBToWC converts this to wchar len. */
322 
323       text.ptr = (char*)_XawTextMBToWC( XtDisplay(XtParent(w)),
324 			 &(u_text_p->ptr[u_text_p->firstPos]), &(text.length) );
325 
326       /* I assert the following assignment is not needed - since Step 4
327       depends on length, it has no need of a terminating NULL.  I think
328       the ASCII-version has the same needless NULL. */
329       /*((wchar_t*)text.ptr)[ text.length ] = NULL;*/
330   }
331 
332 
333   /* STEP 2: some initialization... */
334 
335   if (src->text_src.edit_mode == XawtextRead)
336     return(XawEditError);
337 
338   start_piece = FindPiece(src, startPos, &start_first);
339   end_piece = FindPiece(src, endPos, &end_first);
340 
341 
342   /* STEP 3: remove the empty pieces... */
343 
344   if (start_piece != end_piece) {
345     temp_piece = start_piece->next;
346 
347   /* If empty and not the only piece then remove it. */
348 
349     if ( ((start_piece->used = startPos - start_first) == 0) &&
350 	 !((start_piece->next == NULL) && (start_piece->prev == NULL)) )
351       RemovePiece(src, start_piece);
352 
353     while (temp_piece != end_piece) {
354       temp_piece = temp_piece->next;
355       RemovePiece(src, temp_piece->prev);
356     }
357     end_piece->used -= endPos - end_first;
358     if (end_piece->used != 0)
359       MyWStrncpy(end_piece->text, (end_piece->text + endPos - end_first),
360 		(int) end_piece->used);
361   }
362   else {			/* We are fully in one piece. */
363     if ( (start_piece->used -= endPos - startPos) == 0) {
364       if ( !((start_piece->next == NULL) && (start_piece->prev == NULL)) )
365 	RemovePiece(src, start_piece);
366     }
367     else {
368       MyWStrncpy(start_piece->text + (startPos - start_first),
369 		start_piece->text + (endPos - start_first),
370 		(int) (start_piece->used - (startPos - start_first)) );
371       if ( src->multi_src.use_string_in_place &&
372 	   ((src->multi_src.length - (endPos - startPos)) <
373 	    (src->multi_src.piece_size - 1)) )
374 	start_piece->text[src->multi_src.length - (endPos - startPos)] = (wchar_t)0;
375     }
376   }
377 
378   src->multi_src.length += text.length -(endPos - startPos);
379   /*((TextWidget)src->object.parent)->text.lastPos = src->multi_src.length;*/
380 
381 
382 
383   /* STEP 4: insert the new stuff */
384 
385   if ( text.length != 0) {
386 
387     start_piece = FindPiece(src, startPos, &start_first);
388 
389     length = text.length;
390     firstPos = text.firstPos;
391 
392     while (length > 0) {
393       wchar_t* ptr;
394       int fill;
395 
396       if (src->multi_src.use_string_in_place) {
397 	if (start_piece->used == (src->multi_src.piece_size - 1)) {
398           /*
399            * The string is used in place, then the string
400            * is not allowed to grow.
401            */
402           start_piece->used = src->multi_src.length =
403                                                  src->multi_src.piece_size - 1;
404           /*((TextWidget)src->object.parent)->text.lastPos = src->multi_src.length;*/
405 
406 
407           start_piece->text[src->multi_src.length] = (wchar_t)0;
408 	  return(XawEditError);
409 	}
410       }
411 
412 
413       if (start_piece->used == src->multi_src.piece_size) {
414 	BreakPiece(src, start_piece);
415 	start_piece = FindPiece(src, startPos, &start_first);
416       }
417 
418       fill = Min((int)(src->multi_src.piece_size - start_piece->used), length);
419 
420       ptr = start_piece->text + (startPos - start_first);
421       MyWStrncpy(ptr + fill, ptr,
422 		(int) start_piece->used - (startPos - start_first));
423       wptr =(wchar_t *)text.ptr;
424       (void)wcsncpy(ptr, wptr + firstPos, fill);
425 
426       startPos += fill;
427       firstPos += fill;
428       start_piece->used += fill;
429       length -= fill;
430     }
431   }
432 
433   if ( local_artificial_block == True )
434 
435       /* In other words, text is not the u_text that the user handed me but
436       one I made myself.  I only care, because I need to free the string. */
437 
438       XFree( text.ptr );
439 
440   if (src->multi_src.use_string_in_place)
441     start_piece->text[start_piece->used] = (wchar_t)0;
442 
443   src->multi_src.changes = TRUE;
444 
445   XtCallCallbacks(w, XtNcallback, NULL);
446 
447   return(XawEditDone);
448 }
449 
450 /*	Function Name: Scan
451  *	Description: Scans the text source for the number and type
452  *                   of item specified.
453  *	Arguments: w - the MultiSource widget.
454  *                 position - the position to start scanning.
455  *                 type - type of thing to scan for.
456  *                 dir - direction to scan.
457  *                 count - which occurance if this thing to search for.
458  *                 include - whether or not to include the character found in
459  *                           the position that is returned.
460  *	Returns: the position of the item found.
461  *
462  * Note: While there are only 'n' characters in the file there are n+1
463  *       possible cursor positions (one before the first character and
464  *       one after the last character.
465  */
466 
467 static
468 XawTextPosition
Scan(Widget w,XawTextPosition position,XawTextScanType type,XawTextScanDirection dir,int count,Boolean include)469 Scan(Widget w, XawTextPosition position, XawTextScanType type,
470      XawTextScanDirection dir, int count, Boolean include)
471 {
472   MultiSrcObject src = (MultiSrcObject) w;
473   int inc;
474   MultiPiece * piece;
475   XawTextPosition first = 0, first_eol_position = 0;
476   wchar_t * ptr;
477 
478   if (type == XawstAll) {	/* Optimize this common case. */
479     if (dir == XawsdRight)
480       return(src->multi_src.length);
481     return(0);			/* else. */
482   }
483 
484 
485   /* STEP 1: basic sanity checks */
486 
487   if (position > src->multi_src.length)
488     position = src->multi_src.length;
489 
490 
491   if ( dir == XawsdRight ) {
492     if (position == src->multi_src.length)
493       return(src->multi_src.length);
494     inc = 1;
495   }
496   else {
497     if (position == 0)
498       return(0);
499     inc = -1;
500     position--;
501   }
502 
503   piece = FindPiece(src, position, &first);
504 
505   if ( piece->used == 0 ) return(0); /* i.e., buffer is empty. */
506 
507   ptr = (position - first) + piece->text;
508 
509   switch (type) {
510   case XawstEOL:
511   case XawstParagraph:
512   case XawstWhiteSpace:
513     for ( ; count > 0 ; count-- ) {
514       Boolean non_space = FALSE, first_eol = TRUE;
515       /* CONSTCOND */
516       while (TRUE) {
517         wchar_t c = *ptr;
518 
519 	ptr += inc;
520 	position += inc;
521 
522 	if (type == XawstWhiteSpace) {
523 	  if (iswspace(c)) {
524 	    if (non_space)
525 	      break;
526 	  }
527 	  else
528 	    non_space = TRUE;
529 	}
530 	else if (type == XawstEOL) {
531           if (c == _Xaw_atowc(XawLF)) break;
532 	}
533 	else { /* XawstParagraph */
534 	  if (first_eol) {
535             if (c == _Xaw_atowc(XawLF)) {
536 	      first_eol_position = position;
537 	      first_eol = FALSE;
538 	    }
539 	  }
540 	  else
541             if ( c == _Xaw_atowc(XawLF))
542               break;
543             else if ( !iswspace(c) )
544 	      first_eol = TRUE;
545 	}
546 
547 
548 	if ( ptr < piece->text ) {
549 	  piece = piece->prev;
550 	  if (piece == NULL)	/* Begining of text. */
551 	    return(0);
552 	  ptr = piece->text + piece->used - 1;
553 	}
554 	else if ( ptr >= (piece->text + piece->used) ) {
555 	  piece = piece->next;
556 	  if (piece == NULL)	/* End of text. */
557 	    return(src->multi_src.length);
558 	  ptr = piece->text;
559 	}
560       }
561     }
562     if (!include) {
563       if ( type == XawstParagraph)
564 	position = first_eol_position;
565       position -= inc;
566     }
567     break;
568   case XawstPositions:
569     position += count * inc;
570     break;
571   case XawstAll:		/* handled in special code above */
572   default:
573     break;
574   }
575 
576   if ( dir == XawsdLeft )
577     position++;
578 
579   if (position >= src->multi_src.length)
580     return(src->multi_src.length);
581   if (position < 0)
582     return(0);
583 
584   return(position);
585 }
586 
587 /*	Function Name: Search
588  *	Description: Searchs the text source for the text block passed
589  *	Arguments: w - the MultiSource Widget.
590  *                 position - the position to start scanning.
591  *                 dir - direction to scan.
592  *                 text - the text block to search for.
593  *	Returns: the position of the item found.
594  */
595 
596 static XawTextPosition
Search(Widget w,XawTextPosition position,XawTextScanDirection dir,XawTextBlock * text)597 Search(Widget w, XawTextPosition position, XawTextScanDirection dir, XawTextBlock *text)
598 {
599   MultiSrcObject src = (MultiSrcObject) w;
600   int inc, count = 0;
601   wchar_t * ptr;
602   wchar_t* wtarget;
603   int wtarget_len;
604   Display * d = XtDisplay(XtParent(w));
605   MultiPiece * piece;
606   wchar_t* buf;
607   XawTextPosition first = 0;
608 
609   /* STEP 1: First, a brief sanity check. */
610 
611   if ( dir == XawsdRight )
612     inc = 1;
613   else {
614     inc = -1;
615     if (position == 0)
616       return(XawTextSearchError);	/* scanning left from 0??? */
617     position--;
618   }
619 
620 
621   /* STEP 2: Ensure I have a local wide string.. */
622 
623   /* Since this widget stores 32bit chars, I check here to see if
624   I'm being passed a string claiming to be 8bit chars (ie, MB text.)
625   If that is the case, naturally I convert to 32bit format. */
626 
627   /*if the block was FMT8BIT, length will convert to REAL wchar count below */
628   wtarget_len = text->length;
629 
630   if ( text->format == XawFmtWide )
631       wtarget = &( ((wchar_t*)text->ptr) [text->firstPos] );
632   else
633   {
634       /* The following converts wtarget_len from byte len to wchar count */
635       wtarget = _XawTextMBToWC( d, &text->ptr[ text->firstPos ], &wtarget_len );
636   }
637 
638   /* OK, I can now assert that wtarget holds wide characters, wtarget_len
639   holds an accurate count of those characters, and that firstPos has been
640   effectively factored out of the following computations. */
641 
642 
643   /* STEP 3: SEARCH! */
644 
645   buf = (wchar_t *)XtMalloc((unsigned)sizeof(wchar_t) * wtarget_len );
646   (void)wcsncpy(buf, wtarget, wtarget_len );
647   piece = FindPiece(src, position, &first);
648   ptr = (position - first) + piece->text;
649 
650   /* CONSTCOND */
651   while (TRUE) {
652     if (*ptr == ((dir == XawsdRight) ? *(buf + count)
653 		                     : *(buf + wtarget_len - count - 1)) ) {
654       if (count == (text->length - 1))
655 	break;
656       else
657 	count++;
658     }
659     else {
660       if (count != 0) {
661 	position -=inc * count;
662 	ptr -= inc * count;
663       }
664       count = 0;
665     }
666 
667     ptr += inc;
668     position += inc;
669 
670     while ( ptr < piece->text ) {
671       piece = piece->prev;
672       if (piece == NULL) {	/* Begining of text. */
673 	XtFree((char *)buf);
674 	return(XawTextSearchError);
675       }
676       ptr = piece->text + piece->used - 1;
677     }
678 
679     while ( ptr >= (piece->text + piece->used) ) {
680       piece = piece->next;
681       if (piece == NULL) {	/* End of text. */
682 	XtFree((char *)buf);
683 	return(XawTextSearchError);
684       }
685       ptr = piece->text;
686     }
687   }
688 
689   XtFree( (char *) buf );
690   if (dir == XawsdLeft)
691     return( position );
692   return( position - ( wtarget_len - 1 ) );
693 }
694 
695 /*	Function Name: SetValues
696  *	Description: Sets the values for the MultiSource.
697  *	Arguments: current - current state of the widget.
698  *                 request - what was requested.
699  *                 new - what the widget will become.
700  *	Returns: True if redisplay is needed.
701  */
702 
703 /* ARGSUSED */
704 static Boolean
SetValues(Widget current,Widget request,Widget new,ArgList args,Cardinal * num_args)705 SetValues(Widget current, Widget request, Widget new, ArgList args, Cardinal *num_args)
706 {
707   MultiSrcObject src =      (MultiSrcObject) new;
708   MultiSrcObject old_src = (MultiSrcObject) current;
709   XtAppContext app_con = XtWidgetToApplicationContext(new);
710   Boolean total_reset = FALSE, string_set = FALSE;
711   FILE * file;
712   int i;
713 
714   if ( old_src->multi_src.use_string_in_place !=
715        src->multi_src.use_string_in_place ) {
716       XtAppWarning( app_con,
717 	   "MultiSrc: The XtNuseStringInPlace resources may not be changed.");
718        src->multi_src.use_string_in_place =
719 	   old_src->multi_src.use_string_in_place;
720   }
721 
722   for (i = 0; i < *num_args ; i++ )
723       if (streq(args[i].name, XtNstring)) {
724 	  string_set = TRUE;
725 	  break;
726       }
727 
728   if ( string_set || (old_src->multi_src.type != src->multi_src.type) ) {
729     RemoveOldStringOrFile(old_src, string_set);
730     src->multi_src.allocated_string = old_src->multi_src.allocated_string;
731     file = InitStringOrFile(src, string_set);
732 
733     /* Load pieces does this logic for us, but it shouldn't.  Its messy.*/
734     /*if (old_src->multi_src.type == XawAsciiString)
735         LoadPieces(src, NULL, src->multi_src.string);
736     else*/
737         LoadPieces(src, file, NULL);
738     if (file != NULL) fclose(file);
739     XawTextSetSource( XtParent(new), new, 0);   /* Tell text widget
740 						   what happened. */
741     total_reset = TRUE;
742   }
743 
744   if ( old_src->multi_src.multi_length != src->multi_src.multi_length )
745       src->multi_src.piece_size = src->multi_src.multi_length;
746 
747   if ( !total_reset && (old_src->multi_src.piece_size
748       					!= src->multi_src.piece_size) ) {
749       String mb_string = StorePiecesInString( old_src );
750 
751       if ( mb_string != 0 ) {
752           FreeAllPieces( old_src );
753           LoadPieces( src, NULL, mb_string );
754           XtFree( mb_string );
755       } else {
756           /* If the buffer holds bad chars, don't touch it... */
757           XtAppWarningMsg( app_con,
758 		"convertError", "multiSource", "XawError",
759                  XtName( XtParent( (Widget) old_src ) ), NULL, NULL );
760           XtAppWarningMsg( app_con,
761 		"convertError", "multiSource", "XawError",
762                  "Non-character code(s) in buffer.", NULL, NULL );
763       }
764   }
765 
766   return(FALSE);
767 }
768 
769 /*	Function Name: GetValuesHook
770  *	Description: This is a get values hook routine that sets the
771  *                   values specific to the multi source.
772  *	Arguments: w - the MultiSource Widget.
773  *                 args - the argument list.
774  *                 num_args - the number of args.
775  *	Returns: none.
776  */
777 
778 static void
GetValuesHook(Widget w,ArgList args,Cardinal * num_args)779 GetValuesHook(Widget w, ArgList args, Cardinal *num_args)
780 {
781   MultiSrcObject src = (MultiSrcObject) w;
782   int i;
783 
784   if (src->multi_src.type == XawAsciiString) {
785     for (i = 0; i < *num_args ; i++ )
786       if (streq(args[i].name, XtNstring)) {
787 	  if (src->multi_src.use_string_in_place) {
788               *((char **) args[i].value) = (char *)
789 					src->multi_src.first_piece->text;
790 	  }
791 	  else {
792 	      if (_XawMultiSave(w))	/* If save sucessful. */
793 		  *((char **) args[i].value) = src->multi_src.string;
794 	  }
795 	break;
796       }
797   }
798 }
799 
800 /*	Function Name: Destroy
801  *	Description: Destroys an multi source (frees all data)
802  *	Arguments: src - the Multi source Widget to free.
803  *	Returns: none.
804  */
805 
806 static void
Destroy(Widget w)807 Destroy(Widget w)
808 {
809     RemoveOldStringOrFile((MultiSrcObject) w, True);
810 }
811 
812 /************************************************************
813  *
814  * Public routines
815  *
816  ************************************************************/
817 
818 /*	Function Name: XawMultiSourceFreeString
819  *	Description: Frees the string returned by a get values call
820  *                   on the string when the source is of type string.
821  *	Arguments: w - the MultiSrc widget.
822  *	Returns: none.
823  *
824  * The public interface is XawAsciiSourceFreeString!
825  */
826 
827 void
_XawMultiSourceFreeString(Widget w)828 _XawMultiSourceFreeString(
829     Widget w)
830 {
831   MultiSrcObject src = (MultiSrcObject) w;
832 
833 /*if (src->multi_src.allocated_string&& src->multi_src.type != XawAsciiFile) {*/
834   /* ASSERT: src->multi_src.allocated_string -> we MUST free .string! */
835   if ( src->multi_src.allocated_string ) {
836     XtFree(src->multi_src.string);
837     src->multi_src.allocated_string = FALSE;
838     src->multi_src.string = NULL;
839   }
840 }
841 
842 /*	Function Name: _XawMultiSave
843  *	Description: Saves all the pieces into a file or string as required.
844  *	Arguments: w - the multiSrc Widget.
845  *	Returns: TRUE if the save was successful.
846  *
847  * The public interface is XawAsciiSave(w)!
848  */
849 
850 Boolean
_XawMultiSave(Widget w)851 _XawMultiSave(
852     Widget w)
853 {
854   MultiSrcObject src = (MultiSrcObject) w;
855   XtAppContext app_con = XtWidgetToApplicationContext(w);
856   char * mb_string;
857 
858 /*
859  * If using the string in place then there is no need to play games
860  * to get the internal info into a readable string.
861  */
862 
863   if (src->multi_src.use_string_in_place)
864     return(TRUE);
865 
866   if (src->multi_src.type == XawAsciiFile) {
867 
868       if (!src->multi_src.changes) 		/* No changes to save. */
869           return(TRUE);
870 
871       mb_string = StorePiecesInString( src );
872 
873       if ( mb_string != 0 ) {
874           if ( WriteToFile( mb_string, src->multi_src.string ) == FALSE ) {
875               XtFree( mb_string );
876               return( FALSE );
877           }
878           XtFree( mb_string );
879           src->multi_src.changes = FALSE;
880           return( TRUE );
881       } else {
882           /* If the buffer holds bad chars, don't touch it... */
883           XtAppWarningMsg( app_con,
884 		"convertError", "multiSource", "XawError",
885                 "Due to illegal characters, file not saved.", NULL, NULL);
886           return( FALSE );
887       }
888   }
889   else {
890 
891   /* THIS FUNCTIONALITY IS UNDOCUMENTED, probably UNNEEDED?  The manual
892   says this routine's only function is to save files to disk.  -Sheeran */
893 
894       mb_string = StorePiecesInString( src );
895 
896       if ( mb_string == 0 ) {
897           /* If the buffer holds bad chars, don't touch it... */
898           XtAppWarningMsg( app_con,
899 		"convertError", "multiSource", "XawError",
900                  XtName( XtParent( (Widget) src ) ), NULL, NULL);
901           return( FALSE );
902       }
903 
904       /* assert: mb_string holds good characters so the buffer is fine */
905       if (src->multi_src.allocated_string == TRUE)
906           XtFree(src->multi_src.string);
907       else
908           src->multi_src.allocated_string = TRUE;
909 
910       src->multi_src.string = mb_string;
911   }
912   src->multi_src.changes = FALSE;
913   return(TRUE);
914 }
915 
916 /*	Function Name: XawMultiSaveAsFile
917  *	Description: Save the current buffer as a file.
918  *	Arguments: w - the MultiSrc widget.
919  *                 name - name of the file to save this file into.
920  *	Returns: True if the save was sucessful.
921  *
922  * The public interface is XawAsciiSaveAsFile!
923  */
924 
925 Boolean
_XawMultiSaveAsFile(Widget w,_Xconst char * name)926 _XawMultiSaveAsFile(
927     Widget w,
928     _Xconst char* name)
929 {
930   MultiSrcObject src = (MultiSrcObject) w;
931   String mb_string;
932   Boolean ret;
933 
934   mb_string = StorePiecesInString( src );
935 
936   if ( mb_string != 0 ) {
937       ret = WriteToFile( mb_string, (char *)name );
938       XtFree( mb_string );
939       return( ret );
940   }
941 
942   /* otherwise there was a conversion error.  So print widget name too. */
943   XtAppWarningMsg( XtWidgetToApplicationContext(w),
944 		"convertError", "multiSource", "XawError",
945 		XtName( XtParent( (Widget) src ) ), NULL, NULL);
946   return( False );
947 }
948 
949 /************************************************************
950  *
951  * Private Functions.
952  *
953  ************************************************************/
954 
955 static void
RemoveOldStringOrFile(MultiSrcObject src,Boolean checkString)956 RemoveOldStringOrFile(MultiSrcObject src, Boolean checkString)
957 {
958   FreeAllPieces(src);
959 
960   if (checkString && src->multi_src.allocated_string) {
961     XtFree(src->multi_src.string);
962     src->multi_src.allocated_string = False;
963     src->multi_src.string = NULL;
964   }
965 }
966 
967 /*	Function Name: WriteToFile
968  *	Description: Write the string specified to the begining of the file
969  *                   specified.
970  *	Arguments: string - string to write.
971  *                 name - the name of the file
972  *	Returns: returns TRUE if sucessful, FALSE otherwise.
973  */
974 
975 static Boolean
WriteToFile(String string,String name)976 WriteToFile(String string, String name)
977 {
978   int fd;
979 
980   if ( ((fd = creat(name, 0666)) == -1 ) ||
981        (write(fd, string, sizeof(unsigned char) * strlen(string)) == -1) )
982     return(FALSE);
983 
984   if ( close(fd) == -1 )
985     return(FALSE);
986 
987   return(TRUE);
988 }
989 
990 
991 /*	Function Name: StorePiecesInString
992  *	Description:   store the pieces in memory into a char string.
993  *	Arguments:     src - the multiSrc to gather data from
994  *	Returns:       char *mb_string.     Caller must free.
995  *                  or 0: conversion error. Caller must panic!
996  */
997 
998 static String
StorePiecesInString(MultiSrcObject src)999 StorePiecesInString(MultiSrcObject src)
1000 {
1001   wchar_t* wc_string;
1002   char *mb_string;
1003   int char_count = src->multi_src.length;
1004   XawTextPosition first;
1005   MultiPiece * piece;
1006 
1007   /* I believe the char_count + 1 and the NULL termination are unneeded! FS*/
1008 
1009   wc_string = (wchar_t*) XtMalloc((unsigned)(char_count + 1) * sizeof(wchar_t));
1010 
1011   for (first = 0, piece = src->multi_src.first_piece ; piece != NULL;
1012       				first += piece->used, piece = piece->next)
1013       (void) wcsncpy( wc_string + first, piece->text, piece->used );
1014 
1015   wc_string[ char_count ] = (wchar_t)0; /* NULL terminate this sucker. */
1016 
1017 
1018   /* This will refill all pieces to capacity. */
1019 
1020   if ( src->multi_src.data_compression ) {
1021     FreeAllPieces( src );
1022     LoadPieces( src, NULL, (char *)wc_string );
1023   }
1024 
1025   /* Lastly, convert it to a MB format and send it back. */
1026 
1027   mb_string = _XawTextWCToMB( XtDisplayOfObject( (Widget)src ),
1028 						wc_string, &char_count );
1029 
1030   /* NOTE THAT mb_string MAY BE ZERO IF THE CONVERSION FAILED. */
1031   XtFree( (char*) wc_string );
1032   return( mb_string );
1033 }
1034 
1035 
1036 /*	Function Name: InitStringOrFile.
1037  *	Description: Initializes the string or file.
1038  *	Arguments: src - the MultiSource.
1039  *	Returns: none - May exit though.
1040  */
1041 
1042 static FILE *
InitStringOrFile(MultiSrcObject src,Boolean newString)1043 InitStringOrFile(MultiSrcObject src, Boolean newString)
1044 {
1045     char * open_mode = NULL;
1046     FILE * file;
1047     char fileName[TMPSIZ];
1048     Display *d = XtDisplayOfObject((Widget)src);
1049 
1050     if (src->multi_src.type == XawAsciiString) {
1051 
1052 	if (src->multi_src.string == NULL)
1053 	    src->multi_src.length = 0;
1054 
1055 	else if (! src->multi_src.use_string_in_place) {
1056 	    int length;
1057             String temp = XtNewString(src->multi_src.string);
1058             if ( src->multi_src.allocated_string )
1059                 XtFree( src->multi_src.string );
1060             src->multi_src.allocated_string = True;
1061 	    src->multi_src.string = temp;
1062 
1063 	    length = strlen(src->multi_src.string);
1064 
1065 	    /* Wasteful, throwing away the WC string, but need side effect! */
1066             (void) _XawTextMBToWC(d, src->multi_src.string, &length);
1067 	    src->multi_src.length = (XawTextPosition) length;
1068 	} else {
1069 	    src->multi_src.length = strlen(src->multi_src.string);
1070 	    /* In case the length resource is incorrectly set */
1071 	    if (src->multi_src.length > src->multi_src.multi_length)
1072 		src->multi_src.multi_length = src->multi_src.length;
1073 
1074 	    if (src->multi_src.multi_length == MAGIC_VALUE)
1075 		src->multi_src.piece_size = src->multi_src.length;
1076 	    else
1077 		src->multi_src.piece_size = src->multi_src.multi_length + 1;
1078 	}
1079 
1080        /*((TextWidget)src->object.parent)->text.lastPos = src->multi_src.length;*/
1081 	return(NULL);
1082     }
1083 
1084 /*
1085  * type is XawAsciiFile.
1086  */
1087 
1088     src->multi_src.is_tempfile = FALSE;
1089 
1090     switch (src->text_src.edit_mode) {
1091     case XawtextRead:
1092 	if (src->multi_src.string == NULL)
1093 	    XtErrorMsg("NoFile", "multiSourceCreate", "XawError",
1094 		     "Creating a read only disk widget and no file specified.",
1095 		       NULL, 0);
1096 	open_mode = "r";
1097 	break;
1098     case XawtextAppend:
1099     case XawtextEdit:
1100 	if (src->multi_src.string == NULL) {
1101 
1102             if ( src->multi_src.allocated_string )
1103                 XtFree( src->multi_src.string );
1104             src->multi_src.allocated_string = False;
1105 	    src->multi_src.string = fileName;
1106 
1107 	    (void) tmpnam(src->multi_src.string);
1108 	    src->multi_src.is_tempfile = TRUE;
1109 	    open_mode = "w";
1110 	} else
1111 	    open_mode = "r+";
1112 	break;
1113     default:
1114 	XtErrorMsg("badMode", "multiSourceCreate", "XawError",
1115 		"Bad editMode for multi source; must be Read, Append or Edit.",
1116 		   NULL, NULL);
1117     }
1118 
1119     /* Allocate new memory for the temp filename, because it is held in
1120      * a stack memory buffer.  We must verify that all routines that set
1121      * .string first check .allocated_string and free it - plumbing Sheeran.
1122      */
1123     if (newString || src->multi_src.is_tempfile) {
1124 	if ( src->multi_src.allocated_string )
1125 	    src->multi_src.string = XtNewString(src->multi_src.string);
1126 	src->multi_src.allocated_string = TRUE;
1127     }
1128 
1129     if (!src->multi_src.is_tempfile) {
1130 	if ((file = fopen(src->multi_src.string, open_mode)) != 0) {
1131 	    (void) fseek(file, (Off_t)0, 2);
1132             src->multi_src.length = ftell (file);
1133 	    return file;
1134 	} else {
1135 	    String params[2];
1136 	    Cardinal num_params = 2;
1137 
1138 	    params[0] = src->multi_src.string;
1139 	    params[1] = strerror(errno);
1140 	    XtAppWarningMsg(XtWidgetToApplicationContext((Widget)src),
1141 			    "openError", "multiSourceCreate", "XawWarning",
1142 			    "Cannot open file %s; %s", params, &num_params);
1143 	}
1144     }
1145     src->multi_src.length = 0;
1146     return((FILE *)NULL);
1147 #undef StrLen
1148 }
1149 
1150 /* LoadPieces:  This routine takes either the MB contents of open file `file' or the
1151 MB contents of string or the MB contents of src->multi_src.string and places
1152 them in Pieces in WC format.
1153 
1154 CAUTION: You must have src->multi_src.length set to file length bytes
1155 when src->multi_src.type == XawAsciiFile.  src->multi_src.length must be
1156 the length of the parameter string if string is non-NULL.		*/
1157 
1158 static void
LoadPieces(MultiSrcObject src,FILE * file,char * string)1159 LoadPieces(MultiSrcObject src, FILE *file, char *string)
1160 {
1161   Display *d = XtDisplayOfObject((Widget)src);
1162   wchar_t* local_str, *ptr;
1163   MultiPiece* piece = NULL;
1164   XawTextPosition left;
1165   int bytes = sizeof(wchar_t);
1166   char* temp_mb_holder = NULL;
1167 
1168   /*
1169    * This is tricky - the _XawTextMBtoWC converter uses its 3rd arg
1170    * in as MB length, out as WC length.  We want local_length to be
1171    * WC count.
1172    */
1173   int local_length = src->multi_src.length;
1174 
1175   if (string != NULL) {
1176     /*
1177      * ASSERT: IF our caller passed a non-null string, THEN
1178      * src->multi_src.length is currently string's * byte count,
1179      * AND string is in a MB format.
1180      */
1181     local_str = _XawTextMBToWC(d, (char *)string, &local_length);
1182     src->multi_src.length = (XawTextPosition) local_length;
1183   } else if (src->multi_src.type != XawAsciiFile) {
1184     /*
1185      * here, we are not changing the contents, just reloading,
1186      * so don't change len...
1187      */
1188     local_length = src->multi_src.string ?
1189 		   strlen( src->multi_src.string ) : 0;
1190     local_str = _XawTextMBToWC( d, (char*)src->multi_src.string, &local_length );
1191   } else {
1192     if (src->multi_src.length != 0) {
1193       temp_mb_holder =
1194 	XtMalloc((unsigned)(src->multi_src.length + 1) * sizeof(unsigned char));
1195       fseek(file, (Off_t)0, 0);
1196       src->multi_src.length = fread (temp_mb_holder,
1197 				     (Size_t)sizeof(unsigned char),
1198 				     (Size_t)src->multi_src.length, file);
1199       if (src->multi_src.length <= 0)
1200 	XtAppErrorMsg( XtWidgetToApplicationContext ((Widget) src),
1201 		       "readError", "multiSource", "XawError",
1202 		       "fread returned error.", NULL, NULL);
1203       local_length = src->multi_src.length;
1204       local_str = _XawTextMBToWC(d, temp_mb_holder, &local_length);
1205       src->multi_src.length = local_length;
1206 
1207       if ( local_str == 0 ) {
1208 	String params[2];
1209 	Cardinal num_params;
1210 	static char err_text[] =
1211 		"<<< FILE CONTENTS NOT REPRESENTABLE IN THIS LOCALE >>>";
1212 
1213 	params[0] = XtName(XtParent((Widget)src));
1214 	params[1] = src->multi_src.string;
1215 	num_params = 2;
1216 
1217 	XtAppWarningMsg( XtWidgetToApplicationContext((Widget)src),
1218 			 "readLocaleError", "multiSource", "XawError",
1219     "%s: The file `%s' contains characters not representable in this locale.",
1220 			 params, &num_params);
1221 	src->multi_src.length = sizeof err_text;
1222 	local_length = src->multi_src.length;
1223         local_str = _XawTextMBToWC(d, err_text, &local_length);
1224 	src->multi_src.length = local_length;
1225       }
1226     } else { /*ASSERT that since following while loop looks at local_length
1227         this isn't needed.  Sheeran, Omron KK, 1993/07/15
1228         temp_mb_holder[src->multi_src.length] = '\0';*/
1229         local_str = (wchar_t*)temp_mb_holder;
1230     }
1231   }
1232 
1233   if (src->multi_src.use_string_in_place) {
1234       piece = AllocNewPiece(src, piece);
1235       piece->used = Min(src->multi_src.length, src->multi_src.piece_size);
1236       piece->text = (wchar_t*)src->multi_src.string;
1237       return;
1238   }
1239 
1240   ptr = local_str;
1241   left = local_length;
1242 
1243   do {
1244       piece = AllocNewPiece(src, piece);
1245 
1246       piece->text = (wchar_t*)XtMalloc(src->multi_src.piece_size * bytes);
1247       piece->used = Min(left, src->multi_src.piece_size);
1248       if (piece->used != 0)
1249           (void) wcsncpy(piece->text, ptr, piece->used);
1250 
1251       left -= piece->used;
1252       ptr += piece->used;
1253   } while (left > 0);
1254 
1255   if ( temp_mb_holder )
1256       XtFree( (char*) temp_mb_holder );
1257 }
1258 
1259 
1260 /*	Function Name: AllocNewPiece
1261  *	Description: Allocates a new piece of memory.
1262  *	Arguments: src - The MultiSrc Widget.
1263  *                 prev - the piece just before this one, or NULL.
1264  *	Returns: the allocated piece.
1265  */
1266 
1267 static MultiPiece *
AllocNewPiece(MultiSrcObject src,MultiPiece * prev)1268 AllocNewPiece(MultiSrcObject src, MultiPiece *prev)
1269 {
1270   MultiPiece * piece = XtNew(MultiPiece);
1271 
1272   if (prev == NULL) {
1273     src->multi_src.first_piece = piece;
1274     piece->next = NULL;
1275   }
1276   else {
1277     if (prev->next != NULL)
1278       (prev->next)->prev = piece;
1279     piece->next = prev->next;
1280     prev->next = piece;
1281   }
1282 
1283   piece->prev = prev;
1284 
1285   return(piece);
1286 }
1287 
1288 /*	Function Name: FreeAllPieces
1289  *	Description: Frees all the pieces
1290  *	Arguments: src - The MultiSrc Widget.
1291  *	Returns: none.
1292  */
1293 
1294 static void
FreeAllPieces(MultiSrcObject src)1295 FreeAllPieces(MultiSrcObject src)
1296 {
1297   MultiPiece * next, * first = src->multi_src.first_piece;
1298 
1299   if (first->prev != NULL)
1300     printf("Xaw MultiSrc Object: possible memory leak in FreeAllPieces().\n");
1301 
1302   for ( ; first != NULL ; first = next ) {
1303     next = first->next;
1304     RemovePiece(src, first);
1305   }
1306 }
1307 
1308 /*	Function Name: RemovePiece
1309  *	Description: Removes a piece from the list.
1310  *	Arguments:
1311  *                 piece - the piece to remove.
1312  *	Returns: none.
1313  */
1314 
1315 static void
RemovePiece(MultiSrcObject src,MultiPiece * piece)1316 RemovePiece(MultiSrcObject src, MultiPiece *piece)
1317 {
1318   if (piece->prev == NULL)
1319     src->multi_src.first_piece = piece->next;
1320   else
1321     (piece->prev)->next = piece->next;
1322 
1323   if (piece->next != NULL)
1324     (piece->next)->prev = piece->prev;
1325 
1326   if (!src->multi_src.use_string_in_place)
1327     XtFree((char *)piece->text);
1328 
1329   XtFree((char *)piece);
1330 }
1331 
1332 /*	Function Name: FindPiece
1333  *	Description: Finds the piece containing the position indicated.
1334  *	Arguments: src - The MultiSrc Widget.
1335  *                 position - the position that we are searching for.
1336  * RETURNED        first - the position of the first character in this piece.
1337  *	Returns: piece - the piece that contains this position.
1338  */
1339 
1340 static MultiPiece *
FindPiece(MultiSrcObject src,XawTextPosition position,XawTextPosition * first)1341 FindPiece(MultiSrcObject src, XawTextPosition position, XawTextPosition *first)
1342 {
1343   MultiPiece * old_piece = NULL, * piece = src->multi_src.first_piece;
1344   XawTextPosition temp;
1345 
1346   for ( temp = 0 ; piece != NULL ; temp += piece->used, piece = piece->next ) {
1347     *first = temp;
1348     old_piece = piece;
1349 
1350     if ((temp + piece->used) > position)
1351       return(piece);
1352   }
1353   return(old_piece);	  /* if we run off the end the return the last piece */
1354 }
1355 
1356 /*	Function Name: BreakPiece
1357  *	Description: Breaks a full piece into two new pieces.
1358  *	Arguments: src - The MultiSrc Widget.
1359  *                 piece - the piece to break.
1360  *	Returns: none.
1361  */
1362 
1363 #define HALF_PIECE (src->multi_src.piece_size/2)
1364 
1365 static void
BreakPiece(MultiSrcObject src,MultiPiece * piece)1366 BreakPiece(MultiSrcObject src, MultiPiece *piece)
1367 {
1368   MultiPiece * new = AllocNewPiece(src, piece);
1369 
1370   new->text = (wchar_t*)XtMalloc(src->multi_src.piece_size * sizeof(wchar_t));
1371   (void) wcsncpy(new->text, piece->text + HALF_PIECE,
1372           src->multi_src.piece_size - HALF_PIECE);
1373   piece->used = HALF_PIECE;
1374   new->used = src->multi_src.piece_size - HALF_PIECE;
1375 }
1376 
1377 /* Convert string "XawAsciiString" and "XawAsciiFile" to quarks. */
1378 
1379 /* ARGSUSED */
1380 static void
CvtStringToMultiType(XrmValuePtr args,Cardinal * num_args,XrmValuePtr fromVal,XrmValuePtr toVal)1381 CvtStringToMultiType(XrmValuePtr args, Cardinal *num_args, XrmValuePtr fromVal,
1382                      XrmValuePtr toVal)
1383 {
1384   static XawAsciiType type;
1385   static XrmQuark  XtQEstring = NULLQUARK;
1386   static XrmQuark  XtQEfile;
1387   XrmQuark q;
1388   char lowerName[40];
1389 
1390   if (XtQEstring == NULLQUARK) {
1391     XtQEstring = XrmPermStringToQuark(XtEstring);
1392     XtQEfile   = XrmPermStringToQuark(XtEfile);
1393   }
1394 
1395   if (strlen ((char*) fromVal->addr) < sizeof lowerName) {
1396     XmuCopyISOLatin1Lowered(lowerName, (char *) fromVal->addr);
1397     q = XrmStringToQuark(lowerName);
1398 
1399     if (q == XtQEstring)     type = XawAsciiString;
1400     else if (q == XtQEfile)  type = XawAsciiFile;
1401     else {
1402       toVal->size = 0;
1403       toVal->addr = NULL;
1404       return;
1405     }
1406     toVal->size = sizeof type;
1407     toVal->addr = (XPointer) &type;
1408     return;
1409   }
1410   toVal->size = 0;
1411   toVal->addr = NULL;
1412 }
1413