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