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