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