MultiSrc.c revision c889a3bf
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    Bool result = True;
1096
1097    if ((fd = creat(name, 0666)) == -1)
1098	return (False);
1099
1100    if (write(fd, string, strlen(string)) == -1)
1101        result = False;
1102
1103    if (close(fd) == -1)
1104	return (False);
1105
1106    return (result);
1107}
1108
1109
1110/*
1111 * Function:
1112 *	StorePiecesInString
1113 *
1114 * Parameters:
1115 *	src - the multiSrc object to gather data from
1116 *
1117 * Description:
1118 *	Store the pieces in memory into a char string.
1119 *
1120 * Returns:
1121 *	mb_string:	Caller must free
1122 *	(or)
1123 *	NULL:		conversion error
1124 */
1125static String
1126StorePiecesInString(MultiSrcObject src)
1127{
1128    wchar_t *wc_string;
1129    char *mb_string;
1130    int char_count = src->multi_src.length;
1131    XawTextPosition first;
1132    MultiPiece *piece;
1133
1134    /* I believe the char_count + 1 and the NULL termination are unneeded! FS */
1135    wc_string = (wchar_t*)XtMalloc((char_count + 1) * sizeof(wchar_t));
1136
1137    for (first = 0, piece = src->multi_src.first_piece ; piece != NULL;
1138	 first += piece->used, piece = piece->next)
1139	(void)wcsncpy(wc_string + first, piece->text, piece->used);
1140
1141    wc_string[char_count] = 0;
1142
1143    /* This will refill all pieces to capacity */
1144    if (src->multi_src.data_compression) {
1145	FreeAllPieces(src);
1146	LoadPieces(src, NULL, (char *)wc_string);
1147    }
1148
1149    /* Lastly, convert it to a MB format and send it back */
1150    mb_string = _XawTextWCToMB(XtDisplayOfObject((Widget)src),
1151			       wc_string, &char_count);
1152
1153    /* NOTE THAT mb_string MAY BE ZERO IF THE CONVERSION FAILED */
1154    XtFree((char*)wc_string);
1155
1156    return (mb_string);
1157}
1158
1159/*
1160 * Function:
1161 *	InitStringOrFile
1162 *
1163 * Parameters:
1164 *	src - MultiSource
1165 *
1166 * Description:
1167 *	Initializes the string or file.
1168 */
1169static FILE *
1170InitStringOrFile(MultiSrcObject src, Bool newString)
1171{
1172    mode_t open_mode = 0;
1173    const char *fdopen_mode = NULL;
1174    int fd;
1175    FILE *file;
1176    Display *d = XtDisplayOfObject((Widget)src);
1177
1178    if (src->multi_src.type == XawAsciiString) {
1179	if (src->multi_src.string == NULL)
1180	    src->multi_src.length = 0;
1181
1182	else if (!src->multi_src.use_string_in_place) {
1183	    int length;
1184	    String temp = XtNewString((char *)src->multi_src.string);
1185
1186	    if (src->multi_src.allocated_string)
1187		XtFree((char *)src->multi_src.string);
1188	    src->multi_src.allocated_string = True;
1189	    src->multi_src.string = temp;
1190
1191	    length = strlen((char *)src->multi_src.string);
1192
1193	    /* Wasteful, throwing away the WC string, but need side effect! */
1194	    (void)_XawTextMBToWC(d, (char *)src->multi_src.string, &length);
1195	    src->multi_src.length = (XawTextPosition)length;
1196	}
1197	else {
1198	    src->multi_src.length = strlen((char *)src->multi_src.string);
1199	    /* In case the length resource is incorrectly set */
1200	    if (src->multi_src.length > src->multi_src.multi_length)
1201		src->multi_src.multi_length = src->multi_src.length;
1202
1203	    if (src->multi_src.multi_length == MAGIC_VALUE)
1204		src->multi_src.piece_size = src->multi_src.length;
1205	    else
1206		src->multi_src.piece_size = src->multi_src.multi_length + 1;
1207	}
1208
1209	return (NULL);
1210    }
1211
1212    /*
1213     * type is XawAsciiFile
1214     */
1215    src->multi_src.is_tempfile = False;
1216
1217    switch (src->text_src.edit_mode) {
1218	case XawtextRead:
1219	    if (src->multi_src.string == NULL)
1220		XtErrorMsg("NoFile", "multiSourceCreate", "XawError",
1221			   "Creating a read only disk widget and no file specified.",
1222			   NULL, 0);
1223	    open_mode = O_RDONLY;
1224	    fdopen_mode = "r";
1225	    break;
1226	case XawtextAppend:
1227	case XawtextEdit:
1228	    if (src->multi_src.string == NULL) {
1229		src->multi_src.string = "*multi-src*";
1230		src->multi_src.is_tempfile = True;
1231	    }
1232	    else {
1233/* O_NOFOLLOW is a BSD & Linux extension */
1234#ifdef O_NOFOLLOW
1235		open_mode = O_RDWR | O_NOFOLLOW;
1236#else
1237		open_mode = O_RDWR; /* unsafe; subject to race conditions */
1238#endif
1239		fdopen_mode = "r+";
1240	    }
1241	    break;
1242	default:
1243	    XtErrorMsg("badMode", "multiSourceCreate", "XawError",
1244		       "Bad editMode for multi source; must be "
1245		       "Read, Append or Edit.", NULL, NULL);
1246    }
1247
1248    /* If is_tempfile, allocate a private copy of the text
1249     * Unlikely to be changed, just to set allocated_string */
1250    if (newString || src->multi_src.is_tempfile) {
1251	String temp = XtNewString((char *)src->multi_src.string);
1252
1253	if (src->multi_src.allocated_string)
1254	    XtFree((char *)src->multi_src.string);
1255	src->multi_src.string = temp;
1256	src->multi_src.allocated_string = True;
1257    }
1258
1259    if (!src->multi_src.is_tempfile) {
1260	if ((fd = open((char *)src->multi_src.string, open_mode, 0666)) != -1) {
1261	    if ((file = fdopen(fd, fdopen_mode)) != NULL) {
1262		(void)fseek(file, 0, SEEK_END);
1263		src->multi_src.length = (XawTextPosition)ftell(file);
1264		return(file);
1265	    }
1266	    else
1267		close(fd);
1268	}
1269	{
1270	    String params[2];
1271	    Cardinal num_params = 2;
1272
1273	    params[0] = (String)src->multi_src.string;
1274	    params[1] = strerror(errno);
1275	    XtAppWarningMsg(XtWidgetToApplicationContext((Widget)src),
1276			    "openError", "multiSourceCreate", "XawWarning",
1277			    "Cannot open file %s; %s", params, &num_params);
1278	}
1279    }
1280    src->multi_src.length = 0;
1281    return (NULL);
1282}
1283
1284/* LoadPieces:  This routine takes either the MB contents of open file
1285   `file' or the MB contents of string or the MB contents of
1286   src->multi_src.string and places them in Pieces in WC format.
1287
1288   CAUTION: You must have src->multi_src.length set to file length bytes
1289   when src->multi_src.type == XawAsciiFile.  src->multi_src.length must be
1290   the length of the parameter string if string is non-NULL
1291*/
1292static void
1293LoadPieces(MultiSrcObject src, FILE *file, char *string)
1294{
1295    Display *d = XtDisplayOfObject((Widget)src);
1296    wchar_t* local_str, *ptr;
1297    MultiPiece* piece = NULL;
1298    XawTextPosition left;
1299    int bytes = sizeof(wchar_t);
1300    char* temp_mb_holder = NULL;
1301
1302    /*
1303     * This is tricky - the _XawTextMBtoWC converter uses its 3rd arg
1304     * in as MB length, out as WC length.  We want local_length to be
1305     * WC count.
1306     */
1307    int local_length = src->multi_src.length;
1308
1309    if (string != NULL) {
1310	/*
1311	 * ASSERT: IF our caller passed a non-null string, THEN
1312	 * src->multi_src.length is currently string's * byte count,
1313	 * AND string is in a MB format
1314	*/
1315	local_str = _XawTextMBToWC(d, (char *)string, &local_length);
1316	src->multi_src.length = (XawTextPosition) local_length;
1317    }
1318    else if (src->multi_src.type != XawAsciiFile) {
1319	/*
1320	 * here, we are not changing the contents, just reloading,
1321	 * so don't change len...
1322	 */
1323	local_length = src->multi_src.string ?
1324	    strlen((char *)src->multi_src.string) : 0;
1325	local_str = _XawTextMBToWC(d, (char *)src->multi_src.string,
1326				   &local_length);
1327    }
1328    else {
1329	if (src->multi_src.length != 0) {
1330	    temp_mb_holder =
1331		XtMalloc((src->multi_src.length + 1) * sizeof(unsigned char));
1332	    fseek(file, 0, 0);
1333	    src->multi_src.length = fread(temp_mb_holder,
1334					  (Size_t)sizeof(unsigned char),
1335					  (Size_t)src->multi_src.length, file);
1336	    if (src->multi_src.length <= 0)
1337		XtAppErrorMsg(XtWidgetToApplicationContext ((Widget) src),
1338			      "readError", "multiSource", "XawError",
1339			      "fread returned error.", NULL, NULL);
1340	    local_length = src->multi_src.length;
1341	    local_str = _XawTextMBToWC(d, temp_mb_holder, &local_length);
1342	    src->multi_src.length = local_length;
1343
1344	    if (local_str == 0) {
1345		String params[2];
1346		Cardinal num_params;
1347		static char err_text[] =
1348		    "<<< FILE CONTENTS NOT REPRESENTABLE IN THIS LOCALE >>>";
1349
1350		params[0] = XtName(XtParent((Widget)src));
1351		params[1] = src->multi_src.string;
1352		num_params = 2;
1353
1354		XtAppWarningMsg(XtWidgetToApplicationContext((Widget)src),
1355				"readLocaleError", "multiSource", "XawError",
1356				"%s: The file `%s' contains characters "
1357				"not representable in this locale.",
1358				params, &num_params);
1359		src->multi_src.length = sizeof err_text;
1360		local_length = src->multi_src.length;
1361		local_str = _XawTextMBToWC(d, err_text, &local_length);
1362		src->multi_src.length = local_length;
1363	    }
1364	}
1365	else
1366	    /* ASSERT that since following while loop looks at local_length
1367	       this isn't needed.	Sheeran, Omron KK, 1993/07/15
1368	       temp_mb_holder[src->multi_src.length] = '\0'; */
1369	    local_str = (wchar_t*)temp_mb_holder;
1370    }
1371
1372    if (src->multi_src.use_string_in_place) {
1373	piece = AllocNewPiece(src, piece);
1374	piece->used = Min(src->multi_src.length, src->multi_src.piece_size);
1375	piece->text = (wchar_t*)src->multi_src.string;
1376	return;
1377    }
1378
1379    ptr = local_str;
1380    left = local_length;
1381
1382    do {
1383	piece = AllocNewPiece(src, piece);
1384
1385	piece->text = (wchar_t*)XtMalloc((unsigned)(src->multi_src.piece_size
1386						    * bytes));
1387	piece->used = Min(left, src->multi_src.piece_size);
1388	if (piece->used != 0)
1389	(void)wcsncpy(piece->text, ptr, piece->used);
1390
1391	left -= piece->used;
1392	ptr += piece->used;
1393    } while (left > 0);
1394
1395    if (temp_mb_holder)
1396	XtFree((char*)temp_mb_holder);
1397}
1398
1399/*
1400 * Function:
1401 *	AllocNewPiece
1402 *
1403 * Parameters:
1404 *	src  - MultiSrc Widget
1405 *	prev - the piece just before this one, or NULL
1406 *
1407 * Description:
1408 *	Allocates a new piece of memory.
1409 *
1410 * Returns:
1411 *	The allocated piece
1412 */
1413static MultiPiece *
1414AllocNewPiece(MultiSrcObject src, MultiPiece *prev)
1415{
1416    MultiPiece *piece = XtNew(MultiPiece);
1417
1418    if (prev == NULL) {
1419	src->multi_src.first_piece = piece;
1420	piece->next = NULL;
1421    }
1422    else {
1423	if (prev->next != NULL)
1424	    (prev->next)->prev = piece;
1425	piece->next = prev->next;
1426	prev->next = piece;
1427    }
1428
1429    piece->prev = prev;
1430
1431    return (piece);
1432}
1433
1434/*
1435 * Function:
1436 *	FreeAllPieces
1437 *
1438 * Parameters:
1439 *	src - MultiSrc Widget
1440 *
1441 * Description:
1442 *	Frees all the pieces
1443 */
1444static void
1445FreeAllPieces(MultiSrcObject src)
1446{
1447    MultiPiece *next, *first = src->multi_src.first_piece;
1448
1449#ifdef DEBUG
1450    if (first->prev != NULL)
1451	printf("Xaw MultiSrc Object: possible memory leak in FreeAllPieces().\n");
1452#endif
1453
1454    for (; first != NULL ; first = next) {
1455	next = first->next;
1456	RemovePiece(src, first);
1457    }
1458}
1459
1460/*
1461 * Function:
1462 *	RemovePiece
1463 *
1464 * Parameters:
1465 *	piece - piece to remove
1466 *
1467 * Description:
1468 *	Removes a piece from the list.
1469 */
1470static void
1471RemovePiece(MultiSrcObject src, MultiPiece *piece)
1472{
1473    if (piece->prev == NULL)
1474	src->multi_src.first_piece = piece->next;
1475    else
1476	piece->prev->next = piece->next;
1477
1478    if (piece->next != NULL)
1479	piece->next->prev = piece->prev;
1480
1481    if (!src->multi_src.use_string_in_place)
1482	XtFree((char *)piece->text);
1483
1484    XtFree((char *)piece);
1485}
1486
1487/*
1488 * Function:
1489 *	FindPiece
1490 *
1491 * Parameters:
1492 *	src - MultiSrc Widget
1493 *	position - position that we are searching for
1494 *	first - position of the first character in this piece (return)
1495 *
1496 * Description:
1497 *	Finds the piece containing the position indicated.
1498 *
1499 * Returns:
1500 *	Piece that contains this position
1501 */
1502static MultiPiece *
1503FindPiece(MultiSrcObject src, XawTextPosition position, XawTextPosition *first)
1504{
1505    MultiPiece *old_piece, *piece;
1506    XawTextPosition temp;
1507
1508    for (old_piece = NULL, piece = src->multi_src.first_piece, temp = 0;
1509         piece; old_piece = piece, piece = piece->next)
1510	if ((temp += piece->used) > position) {
1511	    *first = temp - piece->used;
1512	    return (piece);
1513	}
1514
1515    *first = temp - (old_piece ? old_piece->used : 0);
1516
1517    return (old_piece);	  /* if we run off the end the return the last piece */
1518}
1519
1520/*
1521 * Function:
1522 *	BreakPiece
1523 *
1524 * Parameters:
1525 *	src - MultiSrc Widget
1526 *	piece - piece to break
1527 *
1528 * Description:
1529 *	Breaks a full piece into two new pieces.
1530 */
1531#define HALF_PIECE (src->multi_src.piece_size >> 1)
1532static void
1533BreakPiece(MultiSrcObject src, MultiPiece *piece)
1534{
1535    MultiPiece *cnew = AllocNewPiece(src, piece);
1536
1537    cnew->text = (wchar_t *)
1538	XtMalloc(src->multi_src.piece_size * sizeof(wchar_t));
1539    (void)wcsncpy(cnew->text, piece->text + HALF_PIECE,
1540		  src->multi_src.piece_size - HALF_PIECE);
1541    piece->used = HALF_PIECE;
1542    cnew->used = src->multi_src.piece_size - HALF_PIECE;
1543}
1544
1545/*ARGSUSED*/
1546static void
1547CvtStringToMultiType(XrmValuePtr args, Cardinal *num_args,
1548		     XrmValuePtr fromVal, XrmValuePtr toVal)
1549{
1550    static XawAsciiType type = XawAsciiString;
1551    XrmQuark q;
1552    char name[7];
1553
1554    XmuNCopyISOLatin1Lowered(name, (char *)fromVal->addr, sizeof(name));
1555    q = XrmStringToQuark(name);
1556
1557    if (q == Qstring)
1558	type = XawAsciiString;
1559    if (q == Qfile)
1560	type = XawAsciiFile;
1561    else {
1562	toVal->size = 0;
1563	toVal->addr = NULL;
1564	XtStringConversionWarning((char *)fromVal->addr, XtRAsciiType);
1565    }
1566
1567    toVal->size = sizeof(XawAsciiType);
1568    toVal->addr = (XPointer)&type;
1569}
1570
1571/*ARGSUSED*/
1572static Boolean
1573CvtMultiTypeToString(Display *dpy, XrmValuePtr args, Cardinal *num_args,
1574		     XrmValuePtr fromVal, XrmValuePtr toVal,
1575		     XtPointer *data)
1576{
1577    static String buffer;
1578    Cardinal size;
1579
1580    switch (*(XawAsciiType *)fromVal->addr) {
1581	case XawAsciiFile:
1582	    buffer = XtEfile;
1583	    break;
1584	case XawAsciiString:
1585	    buffer = XtEstring;
1586	    break;
1587	default:
1588	    XawTypeToStringWarning(dpy, XtRAsciiType);
1589	    toVal->addr = NULL;
1590	    toVal->size = 0;
1591	    return (False);
1592    }
1593
1594    size = strlen(buffer) + 1;
1595    if (toVal->addr != NULL) {
1596	if (toVal->size < size) {
1597	    toVal->size = size;
1598	    return (False);
1599	}
1600	strcpy((char *)toVal->addr, buffer);
1601    }
1602    else
1603	toVal->addr = (XPointer)buffer;
1604    toVal->size = sizeof(String);
1605
1606    return (True);
1607}
1608
1609/*ARGSUSED*/
1610static void
1611GetDefaultPieceSize(Widget w, int offset, XrmValue *value)
1612{
1613    static XPointer pagesize;
1614
1615    if (pagesize == 0) {
1616	pagesize = (XPointer)((long)_XawGetPageSize());
1617	if (pagesize < (XPointer)BUFSIZ)
1618	    pagesize = (XPointer)BUFSIZ;
1619    }
1620
1621    value->addr = (XPointer)&pagesize;
1622}
1623