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