Home | History | Annotate | Line # | Download | only in src
      1 /*
      2 
      3 Copyright 1989, 1994, 1998  The Open Group
      4 
      5 Permission to use, copy, modify, distribute, and sell this software and its
      6 documentation for any purpose is hereby granted without fee, provided that
      7 the above copyright notice appear in all copies and that both that
      8 copyright notice and this permission notice appear in supporting
      9 documentation.
     10 
     11 The above copyright notice and this permission notice shall be included in
     12 all copies or substantial portions of the Software.
     13 
     14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
     17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
     18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     20 
     21 Except as contained in this notice, the name of The Open Group shall not be
     22 used in advertising or otherwise to promote the sale, use or other dealings
     23 in this Software without prior written authorization from The Open Group.
     24 
     25 */
     26 
     27 /*
     28  * Author:  Chris Peterson, MIT X Consortium.
     29  * Much code taken from X11R3 String and Disk Sources.
     30  */
     31 
     32 #ifdef HAVE_CONFIG_H
     33 #include <config.h>
     34 #endif
     35 #include <stdio.h>
     36 #include <ctype.h>
     37 #include <X11/IntrinsicP.h>
     38 #include <X11/StringDefs.h>
     39 #include <X11/Xfuncs.h>
     40 #include <X11/Xutil.h>
     41 #include <X11/Xmu/Atoms.h>
     42 #include <X11/Xmu/CharSet.h>
     43 #include <X11/Xaw/TextSrcP.h>
     44 #include <X11/Xaw/XawInit.h>
     45 #include "XawI18n.h"
     46 #include "Private.h"
     47 
     48 #ifndef OLDXAW
     49 #define UNDO_DEPTH	16384
     50 
     51 #define ANCHORS_DIST	4096	/* default distance between anchors */
     52 
     53 /*
     54  * Types
     55  */
     56 typedef struct {
     57     XawTextPosition position;
     58     char *buffer;
     59     unsigned length;
     60     unsigned refcount;
     61     unsigned long format;
     62 } XawTextUndoBuffer;
     63 
     64 typedef struct _XawTextUndoList XawTextUndoList;
     65 struct _XawTextUndoList {
     66     XawTextUndoBuffer *left, *right;
     67     XawTextUndoList *undo, *redo;
     68 };
     69 
     70 struct _XawTextUndo {
     71     XawTextUndoBuffer **undo;
     72     unsigned num_undo;
     73     XawTextUndoList *list, *pointer, *end_mark, *head;
     74     unsigned num_list;
     75     XawTextScanDirection dir;
     76     XawTextUndoBuffer *l_save, *r_save;
     77     XawTextUndoList *u_save;
     78     XawTextUndoBuffer *l_no_change, *r_no_change;
     79     int merge;
     80     int erase;		/* there are two types of erases */
     81 };
     82 #endif	/* OLDXAW */
     83 
     84 /*
     85  * Class Methods
     86  */
     87 static Boolean ConvertSelection(Widget, Atom*, Atom*, Atom*, XtPointer*,
     88 				unsigned long*, int*);
     89 static XawTextPosition Read(Widget, XawTextPosition, XawTextBlock*, int);
     90 static int  Replace(Widget, XawTextPosition, XawTextPosition, XawTextBlock*);
     91 static  XawTextPosition Scan(Widget, XawTextPosition, XawTextScanType,
     92 			      XawTextScanDirection, int, Bool);
     93 static XawTextPosition Search(Widget, XawTextPosition, XawTextScanDirection,
     94 			      XawTextBlock*);
     95 static void SetSelection(Widget, XawTextPosition, XawTextPosition, Atom);
     96 static void XawTextSrcClassInitialize(void);
     97 static void XawTextSrcClassPartInitialize(WidgetClass);
     98 static void XawTextSrcInitialize(Widget, Widget, ArgList, Cardinal*);
     99 static void XawTextSrcDestroy(Widget);
    100 static Boolean XawTextSrcSetValues(Widget, Widget, Widget, ArgList, Cardinal*);
    101 /*
    102  * Prototypes
    103  */
    104 static void CvtStringToEditMode(XrmValuePtr, Cardinal*,
    105 				 XrmValuePtr, XrmValuePtr);
    106 static Boolean CvtEditModeToString(Display*, XrmValuePtr, Cardinal*,
    107 				   XrmValuePtr, XrmValuePtr, XtPointer*);
    108 #ifndef OLDXAW
    109 static void FreeUndoBuffer(XawTextUndo*);
    110 static void UndoGC(XawTextUndo*);
    111 static void TellSourceChanged(TextSrcObject, XawTextPosition, XawTextPosition,
    112 			      XawTextBlock*, int);
    113 Bool _XawTextSrcUndo(TextSrcObject, XawTextPosition*);
    114 Bool _XawTextSrcToggleUndo(TextSrcObject);
    115 XawTextAnchor *_XawTextSourceFindAnchor(Widget, XawTextPosition);
    116 
    117 /*
    118  * External
    119  */
    120 void _XawSourceAddText(Widget, Widget);
    121 void _XawSourceRemoveText(Widget, Widget, Bool);
    122 Bool _XawTextSourceNewLineAtEOF(Widget);
    123 void _XawSourceSetUndoErase(TextSrcObject, int);
    124 void _XawSourceSetUndoMerge(TextSrcObject, Bool);
    125 #endif /* OLDXAW */
    126 
    127 /*
    128  * Defined in Text.c
    129  */
    130 char *_XawTextGetText(TextWidget, XawTextPosition, XawTextPosition);
    131 void _XawTextSourceChanged(Widget, XawTextPosition, XawTextPosition,
    132 			   XawTextBlock*, int);
    133 
    134 /*
    135  * Initialization
    136  */
    137 #define offset(field) XtOffsetOf(TextSrcRec, textSrc.field)
    138 static XtResource resources[] = {
    139   {
    140     XtNeditType,
    141     XtCEditType,
    142     XtREditMode,
    143     sizeof(XawTextEditType),
    144     offset(edit_mode),
    145     XtRString,
    146     (XtPointer)"read"
    147   },
    148 #ifndef OLDXAW
    149   {
    150     XtNcallback,
    151     XtCCallback,
    152     XtRCallback,
    153     sizeof(XtPointer),
    154     offset(callback),
    155     XtRCallback,
    156     NULL
    157   },
    158   {
    159     XtNsourceChanged,
    160     XtCChanged,
    161     XtRBoolean,
    162     sizeof(Boolean),
    163     offset(changed),
    164     XtRImmediate,
    165     (XtPointer)False
    166   },
    167   {
    168     XtNenableUndo,
    169     XtCUndo,
    170     XtRBoolean,
    171     sizeof(Boolean),
    172     offset(enable_undo),
    173     XtRImmediate,
    174     (XtPointer)False
    175   },
    176   {
    177     XtNpropertyCallback,
    178     XtCCallback,
    179     XtRCallback,
    180     sizeof(XtPointer),
    181     offset(property_callback),
    182     XtRCallback,
    183     NULL
    184   },
    185 #endif /* OLDXAW */
    186 };
    187 #undef offset
    188 
    189 #define Superclass	(&objectClassRec)
    190 TextSrcClassRec textSrcClassRec = {
    191   /* object */
    192   {
    193     (WidgetClass)Superclass,		/* superclass */
    194     "TextSrc",				/* class_name */
    195     sizeof(TextSrcRec),			/* widget_size */
    196     XawTextSrcClassInitialize,		/* class_initialize */
    197     XawTextSrcClassPartInitialize,	/* class_part_initialize */
    198     False,				/* class_inited */
    199     XawTextSrcInitialize,		/* initialize */
    200     NULL,				/* initialize_hook */
    201     NULL,				/* realize */
    202     NULL,				/* actions */
    203     0,					/* num_actions */
    204     resources,				/* resources */
    205     XtNumber(resources),		/* num_resources */
    206     NULLQUARK,				/* xrm_class */
    207     False,				/* compress_motion */
    208     False,				/* compress_exposure */
    209     False,				/* compress_enterleave */
    210     False,				/* visible_interest */
    211     XawTextSrcDestroy,			/* destroy */
    212     NULL,				/* resize */
    213     NULL,				/* expose */
    214     XawTextSrcSetValues,		/* set_values */
    215     NULL,				/* set_values_hook */
    216     NULL,				/* set_values_almost */
    217     NULL,				/* get_values_hook */
    218     NULL,				/* accept_focus */
    219     XtVersion,				/* version */
    220     NULL,				/* callback_private */
    221     NULL,				/* tm_table */
    222     NULL,				/* query_geometry */
    223     NULL,				/* display_accelerator */
    224     NULL,				/* extension */
    225   },
    226   /* text_src */
    227   {
    228     Read,				/* Read */
    229     Replace,				/* Replace */
    230     Scan,				/* Scan */
    231     Search,				/* Search */
    232     SetSelection,			/* SetSelection */
    233     ConvertSelection,			/* ConvertSelection */
    234 #ifndef OLDXAW
    235     NULL,				/* extension */
    236 #endif
    237   },
    238 };
    239 
    240 WidgetClass textSrcObjectClass = (WidgetClass)&textSrcClassRec;
    241 
    242 static XrmQuark QRead, QAppend, QEdit;
    243 #ifndef OLDXAW
    244 static char *SrcNL = (char*)"\n";
    245 static wchar_t SrcWNL[2];
    246 #endif
    247 
    248 /*
    249  * Implementation
    250  */
    251 static void
    252 XawTextSrcClassInitialize(void)
    253 {
    254     XawInitializeWidgetSet();
    255 
    256 #ifndef OLDXAW
    257     SrcWNL[0] = _Xaw_atowc(XawLF);
    258     SrcWNL[1] = 0;
    259 #endif
    260     QRead   = XrmPermStringToQuark(XtEtextRead);
    261     QAppend = XrmPermStringToQuark(XtEtextAppend);
    262     QEdit   = XrmPermStringToQuark(XtEtextEdit);
    263     XtAddConverter(XtRString, XtREditMode,   CvtStringToEditMode,   NULL, 0);
    264     XtSetTypeConverter(XtREditMode, XtRString, CvtEditModeToString, NULL, 0,
    265 		       XtCacheNone, NULL);
    266 }
    267 
    268 static void
    269 XawTextSrcClassPartInitialize(WidgetClass wc)
    270 {
    271     TextSrcObjectClass t_src, superC;
    272 
    273     t_src = (TextSrcObjectClass)wc;
    274     superC = (TextSrcObjectClass)t_src->object_class.superclass;
    275 
    276     /*
    277      * We don't need to check for null super since we'll get to TextSrc
    278      * eventually
    279      */
    280     if (t_src->textSrc_class.Read == XtInheritRead)
    281 	t_src->textSrc_class.Read = superC->textSrc_class.Read;
    282 
    283     if (t_src->textSrc_class.Replace == XtInheritReplace)
    284 	t_src->textSrc_class.Replace = superC->textSrc_class.Replace;
    285 
    286     if (t_src->textSrc_class.Scan == XtInheritScan)
    287 	t_src->textSrc_class.Scan = superC->textSrc_class.Scan;
    288 
    289     if (t_src->textSrc_class.Search == XtInheritSearch)
    290 	t_src->textSrc_class.Search = superC->textSrc_class.Search;
    291 
    292     if (t_src->textSrc_class.SetSelection == XtInheritSetSelection)
    293 	t_src->textSrc_class.SetSelection = superC->textSrc_class.SetSelection;
    294 
    295     if (t_src->textSrc_class.ConvertSelection == XtInheritConvertSelection)
    296 	t_src->textSrc_class.ConvertSelection =
    297 	    superC->textSrc_class.ConvertSelection;
    298 }
    299 
    300 /*ARGSUSED*/
    301 static void
    302 XawTextSrcInitialize(Widget request _X_UNUSED, Widget cnew _X_UNUSED,
    303 		     ArgList args _X_UNUSED, Cardinal *num_args _X_UNUSED)
    304 {
    305 #ifndef OLDXAW
    306     TextSrcObject src = (TextSrcObject)cnew;
    307 
    308     if (src->textSrc.enable_undo) {
    309 	src->textSrc.undo = (XawTextUndo*)XtCalloc(1, sizeof(XawTextUndo));
    310 	src->textSrc.undo->dir = XawsdLeft;
    311     }
    312     else
    313 	src->textSrc.undo = NULL;
    314     src->textSrc.undo_state = False;
    315     if (XtIsSubclass(XtParent(cnew), textWidgetClass)) {
    316 	src->textSrc.text = (WidgetList)XtMalloc(sizeof(Widget*));
    317 	src->textSrc.text[0] = XtParent(cnew);
    318 	src->textSrc.num_text = 1;
    319     }
    320     else {
    321 	src->textSrc.text = NULL;
    322 	src->textSrc.num_text = 0;
    323     }
    324 
    325     src->textSrc.anchors = NULL;
    326     src->textSrc.num_anchors = 0;
    327     (void)XawTextSourceAddAnchor(cnew, 0);
    328 #endif /* OLDXAW */
    329 }
    330 
    331 static void
    332 XawTextSrcDestroy(Widget w _X_UNUSED)
    333 {
    334 #ifndef OLDXAW
    335     TextSrcObject src = (TextSrcObject)w;
    336 
    337     if (src->textSrc.enable_undo) {
    338 	FreeUndoBuffer(src->textSrc.undo);
    339 	XtFree((char*)src->textSrc.undo);
    340     }
    341     XtFree((char*)src->textSrc.text);
    342 
    343     if (src->textSrc.num_anchors) {
    344 	XawTextEntity *entity, *enext;
    345 	int i;
    346 
    347 	for (i = 0; i < src->textSrc.num_anchors; i++) {
    348 	    entity = src->textSrc.anchors[i]->entities;
    349 	    while (entity) {
    350 		enext = entity->next;
    351 		XtFree((XtPointer)entity);
    352 		entity = enext;
    353 	    }
    354 	    XtFree((XtPointer)src->textSrc.anchors[i]);
    355 	}
    356 	XtFree((XtPointer)src->textSrc.anchors);
    357     }
    358 #endif /* OLDXAW */
    359 }
    360 
    361 /*ARGSUSED*/
    362 static Boolean
    363 XawTextSrcSetValues(Widget current _X_UNUSED, Widget request _X_UNUSED, Widget cnew _X_UNUSED,
    364 		    ArgList args _X_UNUSED, Cardinal *num_args _X_UNUSED)
    365 {
    366 #ifndef OLDXAW
    367     TextSrcObject oldtw = (TextSrcObject)current;
    368     TextSrcObject newtw = (TextSrcObject)cnew;
    369 
    370     if (oldtw->textSrc.enable_undo != newtw->textSrc.enable_undo) {
    371 	if (newtw->textSrc.enable_undo) {
    372 	    newtw->textSrc.undo = (XawTextUndo*)
    373 		XtCalloc(1, sizeof(XawTextUndo));
    374 	    newtw->textSrc.undo->dir = XawsdLeft;
    375 	}
    376 	else {
    377 	    FreeUndoBuffer(newtw->textSrc.undo);
    378 	    XtFree((char*)newtw->textSrc.undo);
    379 	    newtw->textSrc.undo = NULL;
    380 	}
    381     }
    382     if (oldtw->textSrc.changed != newtw->textSrc.changed) {
    383 	if (newtw->textSrc.enable_undo) {
    384 	    if (newtw->textSrc.undo->list) {
    385 		newtw->textSrc.undo->l_no_change =
    386 		    newtw->textSrc.undo->list->left;
    387 		newtw->textSrc.undo->r_no_change =
    388 		    newtw->textSrc.undo->list->right;
    389 	    }
    390 	    else
    391 		newtw->textSrc.undo->l_no_change =
    392 		    newtw->textSrc.undo->r_no_change = NULL;
    393 	}
    394     }
    395 #endif /* OLDXAW */
    396     return (False);
    397 }
    398 
    399 /*
    400  * Function:
    401  *	Read
    402  *
    403  * Parameters:
    404  *	w      - TextSrc Object
    405  *	pos    - position of the text to retrieve
    406  *	text   - text block that will contain returned text
    407  *	length - maximum number of characters to read
    408  *
    409  * Description:
    410  *	This function reads the source.
    411  *
    412  * Returns:
    413  *	The character position following the retrieved text.
    414  */
    415 /*ARGSUSED*/
    416 static XawTextPosition
    417 Read(Widget w _X_UNUSED, XawTextPosition pos _X_UNUSED, XawTextBlock *text _X_UNUSED, int length _X_UNUSED)
    418 {
    419     return ((XawTextPosition)0);
    420 }
    421 
    422 /*
    423  * Function:
    424  *	Replace
    425  *
    426  * Parameters:
    427  *	src	 - Text Source Object
    428  *	startPos - ends of text that will be removed
    429  *	endPos	 - ""
    430  *	text	 - new text to be inserted into buffer at startPos
    431  *
    432  * Description:
    433  *	Replaces a block of text with new text.
    434  */
    435 /*ARGSUSED*/
    436 static int
    437 Replace(Widget w _X_UNUSED, XawTextPosition startPos _X_UNUSED, XawTextPosition endPos _X_UNUSED,
    438 	XawTextBlock *text _X_UNUSED)
    439 {
    440     return (XawEditError);
    441 }
    442 
    443 /*
    444  * Function:
    445  *	Scan
    446  *
    447  * Parameters:
    448  *	w	 - TextSrc Object
    449  *	position - position to start scanning
    450  *	type	 - type of thing to scan for
    451  *	dir	 - direction to scan
    452  *	count	 - which occurrence 0f this thing to search for
    453  *	include  - whether or not to include the character found in
    454  *		   the position that is returned
    455  *
    456  * Description:
    457  *	Scans the text source for the number and type of item specified.
    458  */
    459 /*ARGSUSED*/
    460 static XawTextPosition
    461 Scan(Widget w _X_UNUSED, XawTextPosition position _X_UNUSED, XawTextScanType type _X_UNUSED,
    462      XawTextScanDirection dir _X_UNUSED, int count _X_UNUSED, Bool include _X_UNUSED)
    463 {
    464     return ((XawTextPosition)0);
    465 }
    466 
    467 /*
    468  * Function:
    469  *	Search
    470  *
    471  * Parameters:
    472  *	w	 - TextSource Object
    473  *	position - position to start searching
    474  *	dir	 - direction to search
    475  *	text	 - the text block to search for
    476  *
    477  * Description:
    478  *	Searches the text source for the text block passed
    479  */
    480 /*ARGSUSED*/
    481 static XawTextPosition
    482 Search(Widget w _X_UNUSED, XawTextPosition position _X_UNUSED, XawTextScanDirection dir _X_UNUSED,
    483        XawTextBlock *text _X_UNUSED)
    484 {
    485     return (XawTextSearchError);
    486 }
    487 
    488 /*ARGSUSED*/
    489 static Boolean
    490 ConvertSelection(Widget w _X_UNUSED, Atom *selection _X_UNUSED, Atom *target _X_UNUSED, Atom *type _X_UNUSED,
    491 		 XtPointer *value _X_UNUSED, unsigned long *length _X_UNUSED, int *format _X_UNUSED)
    492 {
    493     return (False);
    494 }
    495 
    496 /*ARGSUSED*/
    497 static void
    498 SetSelection(Widget w _X_UNUSED, XawTextPosition left _X_UNUSED, XawTextPosition right _X_UNUSED,
    499 	     Atom selection _X_UNUSED)
    500 {
    501 }
    502 
    503 /*ARGSUSED*/
    504 static void
    505 CvtStringToEditMode(XrmValuePtr args _X_UNUSED, Cardinal *num_args _X_UNUSED,
    506 		    XrmValuePtr fromVal, XrmValuePtr toVal)
    507 {
    508     static XawTextEditType editType;
    509     XrmQuark	q;
    510     char name[7];
    511 
    512     XmuNCopyISOLatin1Lowered(name, (char *)fromVal->addr, sizeof(name));
    513     q = XrmStringToQuark(name);
    514 
    515     if (q == QRead)
    516 	editType = XawtextRead;
    517     else if (q == QAppend)
    518 	editType = XawtextAppend;
    519     else if (q == QEdit)
    520 	editType = XawtextEdit;
    521     else {
    522 	toVal->size = 0;
    523 	toVal->addr = NULL;
    524 	XtStringConversionWarning((char *)fromVal->addr, XtREditMode);
    525     }
    526     toVal->size = sizeof(XawTextEditType);
    527     toVal->addr = (XPointer)&editType;
    528 }
    529 
    530 /*ARGSUSED*/
    531 static Boolean
    532 CvtEditModeToString(Display *dpy, XrmValuePtr args _X_UNUSED, Cardinal *num_args _X_UNUSED,
    533 		    XrmValuePtr fromVal, XrmValuePtr toVal,
    534 		    XtPointer *data _X_UNUSED)
    535 {
    536     static String buffer;
    537     Cardinal size;
    538 
    539     switch (*(XawTextEditType *)fromVal->addr) {
    540 	case XawtextRead:
    541 	    buffer = XtEtextRead;
    542 	    break;
    543 	case XawtextAppend:
    544 	    buffer = XtEtextAppend;
    545 	    break;
    546 	case XawtextEdit:
    547 	    buffer = XtEtextEdit;
    548 	    break;
    549 	default:
    550 	    XawTypeToStringWarning(dpy, XtREditMode);
    551 	    toVal->addr = NULL;
    552 	    toVal->size = 0;
    553 	    return (False);
    554     }
    555 
    556     size = (Cardinal)(strlen(buffer) + 1);
    557     if (toVal->addr != NULL) {
    558 	if (toVal->size < size) {
    559 	    toVal->size = size;
    560 	    return (False);
    561 	}
    562 	strcpy((char *)toVal->addr, buffer);
    563     }
    564     else
    565 	toVal->addr = (XPointer)buffer;
    566     toVal->size = sizeof(String);
    567 
    568     return (True);
    569 }
    570 
    571 #ifndef OLDXAW
    572 Bool
    573 _XawTextSourceNewLineAtEOF(Widget w)
    574 {
    575     TextSrcObject src = (TextSrcObject)w;
    576     XawTextBlock text;
    577 
    578     text.firstPos = 0;
    579     if ((text.format = (unsigned long)src->textSrc.text_format) == XawFmt8Bit)
    580 	text.ptr = SrcNL;
    581     else
    582 	text.ptr = (char*)SrcWNL;
    583     text.length = 1;
    584 
    585     return (XawTextSourceSearch(w, XawTextSourceScan(w, 0, XawstAll,
    586 						     XawsdRight, 1, True) - 1,
    587 				XawsdRight, &text) != XawTextSearchError);
    588 }
    589 
    590 void
    591 _XawSourceAddText(Widget source, Widget text)
    592 {
    593     TextSrcObject src = (TextSrcObject)source;
    594     Bool found = False;
    595     Cardinal i;
    596 
    597     for (i = 0; i < src->textSrc.num_text; i++)
    598 	if (src->textSrc.text[i] == text) {
    599 	    found = True;
    600 	    break;
    601 	}
    602 
    603     if (!found) {
    604 	src->textSrc.text = (WidgetList)
    605 	    XtRealloc((char*)src->textSrc.text,
    606 		      (Cardinal)(sizeof(Widget) * (src->textSrc.num_text + 1)));
    607 	src->textSrc.text[src->textSrc.num_text++] = text;
    608     }
    609 }
    610 
    611 void
    612 _XawSourceRemoveText(Widget source, Widget text, Bool destroy)
    613 {
    614     TextSrcObject src = (TextSrcObject)source;
    615     Bool found = False;
    616     Cardinal i;
    617 
    618     if (src == NULL)
    619 	return;
    620 
    621     for (i = 0; i < src->textSrc.num_text; i++)
    622 	if (src->textSrc.text[i] == text) {
    623 	    found = True;
    624 	    break;
    625 	}
    626 
    627     if (found) {
    628 	if (--src->textSrc.num_text == 0) {
    629 	    if (destroy) {
    630 		XtDestroyWidget(source);
    631 		return;
    632 	    }
    633 	    else {
    634 		XtFree((char*)src->textSrc.text);
    635 		src->textSrc.text = NULL;	/* for realloc "magic" */
    636 	    }
    637 	}
    638 	else if (i < src->textSrc.num_text)
    639 	    memmove(&src->textSrc.text[i], &src->textSrc.text[i + 1],
    640 		    sizeof(Widget) * (src->textSrc.num_text - i));
    641     }
    642 }
    643 #endif /* OLDXAW */
    644 
    645 /*
    646  * Function:
    647  *	XawTextSourceRead
    648  *
    649  * Parameters:
    650  *	w      - TextSrc Object
    651  *	pos    - position of the text to retrieve
    652  *	text   - text block that will contain returned text (return)
    653  *	length - maximum number of characters to read
    654  *
    655  * Description:
    656  *	This function reads the source.
    657  *
    658  * Returns:
    659  *	The number of characters read into the buffer
    660  */
    661 XawTextPosition
    662 XawTextSourceRead(Widget w, XawTextPosition pos, XawTextBlock *text,
    663 		  int length)
    664 {
    665   TextSrcObjectClass cclass = (TextSrcObjectClass)w->core.widget_class;
    666 
    667   return ((*cclass->textSrc_class.Read)(w, pos, text, length));
    668 }
    669 
    670 #ifndef OLDXAW
    671 static void
    672 TellSourceChanged(TextSrcObject src, XawTextPosition left,
    673 		  XawTextPosition right, XawTextBlock *block, int lines)
    674 {
    675     Cardinal i;
    676 
    677     for (i = 0; i < src->textSrc.num_text; i++)
    678 	_XawTextSourceChanged(src->textSrc.text[i], left, right, block, lines);
    679 }
    680 
    681 /*
    682  * This function is required because there is no way to diferentiate
    683  * if the first erase was generated by a backward-kill-char and the
    684  * second by a forward-kill-char (or vice-versa) from XawTextSourceReplace.
    685  * It is only possible to diferentiate after the second character is
    686  * killed, but then, it is too late.
    687  */
    688 void
    689 _XawSourceSetUndoErase(TextSrcObject src, int value)
    690 {
    691     if (src && src->textSrc.enable_undo)
    692 	src->textSrc.undo->erase = value;
    693 }
    694 
    695 /*
    696  * To differentiate insert-char's separated by cursor movements.
    697  */
    698 void
    699 _XawSourceSetUndoMerge(TextSrcObject src, Bool state)
    700 {
    701     if (src && src->textSrc.enable_undo)
    702 	src->textSrc.undo->merge += state ? 1 : -1;
    703 }
    704 #endif /* OLDXAW */
    705 
    706 /*
    707  * Public Functions
    708  */
    709 /*
    710  * Function:
    711  *	XawTextSourceReplace
    712  *
    713  * Parameters:
    714  *	src	 - Text Source Object
    715  *	startPos - ends of text that will be removed
    716  *	endPos	 - ""
    717  *	text	 - new text to be inserted into buffer at startPos
    718  *
    719  * Description:
    720  *	Replaces a block of text with new text.
    721  *
    722  * Returns:
    723  *	XawEditError or XawEditDone.
    724  */
    725 /*ARGSUSED*/
    726 int
    727 XawTextSourceReplace(Widget w, XawTextPosition left,
    728 		      XawTextPosition right, XawTextBlock *block)
    729 {
    730     TextSrcObjectClass cclass = (TextSrcObjectClass)w->core.widget_class;
    731 #ifndef OLDXAW
    732     TextSrcObject src = (TextSrcObject)w;
    733     XawTextUndoBuffer *l_state, *r_state;
    734     XawTextUndoList *undo;
    735     Bool enable_undo;
    736     XawTextPosition start, end;
    737     int i, error, lines = 0;
    738     Cardinal j;
    739 
    740     if (src->textSrc.edit_mode == XawtextRead)
    741 	return (XawEditError);
    742 
    743     enable_undo = src->textSrc.enable_undo && src->textSrc.undo_state == False;
    744     if (enable_undo) {
    745 	unsigned size, total;
    746 
    747 	if (src->textSrc.undo->l_save) {
    748 	    l_state = src->textSrc.undo->l_save;
    749 	    src->textSrc.undo->l_save = NULL;
    750 	}
    751 	else
    752 	    l_state = XtNew(XawTextUndoBuffer);
    753 	l_state->refcount = 1;
    754 	l_state->position = left;
    755 	if (left < right) {
    756 	    Widget ctx = NULL;
    757 
    758 	    for (j = 0; j < src->textSrc.num_text; j++)
    759 		if (XtIsSubclass(src->textSrc.text[j], textWidgetClass)) {
    760 		    ctx = src->textSrc.text[j];
    761 		    break;
    762 		}
    763 	    l_state->buffer = _XawTextGetText((TextWidget)ctx, left, right);
    764 	    l_state->length = (unsigned)(right - left);
    765 	}
    766 	else {
    767 	    l_state->length = 0;
    768 	    l_state->buffer = NULL;
    769 	}
    770 	l_state->format = (unsigned long)src->textSrc.text_format;
    771 	if (l_state->length == 1) {
    772 	    if (l_state->format == XawFmtWide &&
    773 		*(wchar_t*)l_state->buffer == *SrcWNL) {
    774 		XtFree(l_state->buffer);
    775 		l_state->buffer = (char*)SrcWNL;
    776 	    }
    777 	    else if (*l_state->buffer == '\n') {
    778 		XtFree(l_state->buffer);
    779 		l_state->buffer = SrcNL;
    780 	    }
    781 	}
    782 
    783 	if (src->textSrc.undo->r_save) {
    784 	    r_state = src->textSrc.undo->r_save;
    785 	    src->textSrc.undo->r_save = NULL;
    786 	}
    787 	else
    788 	    r_state = XtNew(XawTextUndoBuffer);
    789 	r_state->refcount = 1;
    790 	r_state->position = left;
    791 	r_state->format = block->format;
    792 	size = block->format == XawFmtWide ? sizeof(wchar_t) : sizeof(char);
    793 	total = (size * (unsigned)block->length);
    794 	r_state->length = (unsigned)block->length;
    795 	r_state->buffer = NULL;
    796 	if (total == size) {
    797 	    if (r_state->format == XawFmtWide &&
    798 		*(wchar_t*)block->ptr == *SrcWNL)
    799 		r_state->buffer = (char*)SrcWNL;
    800 	    else if (*block->ptr == '\n')
    801 		r_state->buffer = SrcNL;
    802 	}
    803 	if (total && !r_state->buffer) {
    804 	    r_state->buffer = XtMalloc(total);
    805 	    memcpy(r_state->buffer, block->ptr, total);
    806 	}
    807 
    808 	if (src->textSrc.undo->u_save) {
    809 	    undo = src->textSrc.undo->u_save;
    810 	    src->textSrc.undo->u_save = NULL;
    811 	}
    812 	else
    813 	    undo = XtNew(XawTextUndoList);
    814 	undo->left = l_state;
    815 	undo->right = r_state;
    816 	undo->undo = src->textSrc.undo->list;
    817 	undo->redo = NULL;
    818     }
    819     else {
    820 	undo = NULL;
    821 	l_state = r_state = NULL;
    822     }
    823 
    824 #define	LARGE_VALUE	262144	/* 256 K */
    825     /* optimization, to avoid long delays recalculating the line number
    826      * when editing huge files
    827      */
    828     if (left > LARGE_VALUE) {
    829 	start = XawTextSourceScan(w, left, XawstEOL, XawsdLeft, 2, False);
    830 	for (j = 0; j < src->textSrc.num_text; j++) {
    831 	    TextWidget tw = (TextWidget)src->textSrc.text[j];
    832 
    833 	    if (left <= tw->text.lt.top &&
    834 		left + block->length - (right - left) > tw->text.lt.top)
    835 		_XawTextBuildLineTable(tw, start, False);
    836 	}
    837     }
    838 #undef LARGE_VALUE
    839 
    840     start = left;
    841     end = right;
    842     while (start < end) {
    843 	start = XawTextSourceScan(w, start, XawstEOL, XawsdRight, 1, True);
    844 	if (start <= end) {
    845 	    --lines;
    846 	    if (start == XawTextSourceScan(w, 0, XawstAll, XawsdRight, 1, True)) {
    847 		lines += !_XawTextSourceNewLineAtEOF(w);
    848 		break;
    849 	    }
    850 	}
    851     }
    852 #else
    853     int error;
    854 #endif /* OLDXAW */
    855 
    856     error = (*cclass->textSrc_class.Replace)(w, left, right, block);
    857 
    858 #ifndef OLDXAW
    859     if (error != XawEditDone) {
    860 	if (enable_undo) {
    861 	    if (l_state->buffer) {
    862 		if (l_state->buffer != SrcNL && l_state->buffer != (char*)SrcWNL)
    863 		    XtFree(l_state->buffer);
    864 		l_state->buffer = NULL;
    865 	    }
    866 	     src->textSrc.undo->l_save = l_state;
    867 	     if (r_state->buffer) {
    868 		if (r_state->buffer != SrcNL && r_state->buffer != (char*)SrcWNL)
    869 		    XtFree(r_state->buffer);
    870 		r_state->buffer = NULL;
    871 	    }
    872 	    src->textSrc.undo->r_save = r_state;
    873 
    874 	    src->textSrc.undo->u_save = undo;
    875 	}
    876     }
    877     else if (enable_undo) {
    878 	XawTextUndoList *list = src->textSrc.undo->list;
    879 	XawTextUndoBuffer *unl, *lnl;
    880 	int erase = undo->right->length == 0 && undo->left->length == 1 && list
    881 		    && list->right->length == 0;
    882 
    883 	if (erase) {
    884 	    erase = list->left->position - 1 == undo->left->position ? -1 :
    885 		    list->left->position == undo->left->position ? 1 : 0;
    886 	    if (src->textSrc.undo->erase && erase != src->textSrc.undo->erase)
    887 		erase = 0;
    888 	    else
    889 		src->textSrc.undo->erase = erase;
    890 	}
    891 
    892 	if (erase) {
    893 	    unl = l_state;
    894 	    lnl = list->left;
    895 	}
    896 	else {
    897 	    unl = r_state;
    898 	    lnl = list ? list->right : NULL;
    899 	}
    900 
    901 	/* Try to merge the undo buffers */
    902 	if (src->textSrc.undo->merge > 0 && ((erase ||
    903 	     (list && ((list->left->length == 0 && undo->left->length == 0) ||
    904 		       (list->left->length == list->right->length &&
    905 			undo->left->length == 1)) &&
    906 	      undo->right->length == 1 &&
    907 	      list->right->position + list->right->length
    908 	      == undo->right->position))
    909 	    && src->textSrc.undo->pointer == list
    910 	    && unl->format == list->right->format
    911 	    && ((unl->format == XawFmt8Bit && unl->buffer[0] != XawLF) ||
    912 		(unl->format == XawFmtWide &&
    913 		 *(wchar_t*)(unl->buffer) != _Xaw_atowc(XawLF)))
    914 	    && ((lnl->format == XawFmt8Bit && lnl->buffer[0] != XawLF) ||
    915 		(lnl->format == XawFmtWide &&
    916 		 *(wchar_t*)(lnl->buffer) != _Xaw_atowc(XawLF))))) {
    917 	    unsigned size = lnl->format == XawFmtWide ?
    918 		sizeof(wchar_t) : sizeof(char);
    919 
    920 	    if (!erase) {
    921 		list->right->buffer = XtRealloc(list->right->buffer,
    922 						(list->right->length + 1) * size);
    923 		memcpy(list->right->buffer + list->right->length * size,
    924 		       undo->right->buffer, size);
    925 		++list->right->length;
    926 		XtFree(r_state->buffer);
    927 	    }
    928 	    else if (erase < 0) {
    929 		--list->left->position;
    930 		--list->right->position;
    931 	    }
    932 
    933 	    src->textSrc.undo->l_save = l_state;
    934 	    src->textSrc.undo->r_save = r_state;
    935 	    src->textSrc.undo->u_save = undo;
    936 
    937 	    if (list->left->length) {
    938 		list->left->buffer = XtRealloc(list->left->buffer,
    939 					       (list->left->length + 1) * size);
    940 		if (erase >= 0)
    941 		    memcpy(list->left->buffer + list->left->length * size,
    942 			   undo->left->buffer, size);
    943 		else {
    944 		    /* use memmove, since strings overlap */
    945 		    memmove(list->left->buffer + size, list->left->buffer,
    946 			    list->left->length * size);
    947 		    memcpy(list->left->buffer, undo->left->buffer, size);
    948 		}
    949 		++list->left->length;
    950 		if (l_state->buffer != SrcNL && l_state->buffer != (char*)SrcWNL)
    951 		    XtFree(l_state->buffer);
    952 	    }
    953 
    954 	    if (src->textSrc.undo->num_list >= UNDO_DEPTH)
    955 		UndoGC(src->textSrc.undo);
    956 	}
    957 	else {
    958 	    src->textSrc.undo->undo = (XawTextUndoBuffer**)
    959 		XtRealloc((char*)src->textSrc.undo->undo,
    960 			  (Cardinal)((2 + src->textSrc.undo->num_undo)
    961 				     * sizeof(XawTextUndoBuffer)));
    962 	    src->textSrc.undo->undo[src->textSrc.undo->num_undo++] = l_state;
    963 	    src->textSrc.undo->undo[src->textSrc.undo->num_undo++] = r_state;
    964 
    965 	    if (src->textSrc.undo->list)
    966 		src->textSrc.undo->list->redo = undo;
    967 	    else
    968 		src->textSrc.undo->head = undo;
    969 
    970 	    src->textSrc.undo->merge = l_state->length <= 1 &&
    971 				       r_state->length <= 1;
    972 
    973 	    src->textSrc.undo->list = src->textSrc.undo->pointer =
    974 		src->textSrc.undo->end_mark = undo;
    975 
    976 	    if (++src->textSrc.undo->num_list >= UNDO_DEPTH)
    977 		UndoGC(src->textSrc.undo);
    978 	}
    979 	src->textSrc.undo->dir = XawsdLeft;
    980 	if (!src->textSrc.changed) {
    981 	    src->textSrc.undo->l_no_change = src->textSrc.undo->list->right;
    982 	    src->textSrc.undo->r_no_change = src->textSrc.undo->list->left;
    983 	    src->textSrc.changed = True;
    984 	}
    985     }
    986     else if (!src->textSrc.enable_undo)
    987 	src->textSrc.changed = True;
    988 
    989     if (error == XawEditDone) {
    990 	XawTextAnchor *anchor;
    991 
    992 	/* find anchor and index */
    993 	/* XXX index (i) could be returned by XawTextSourceFindAnchor
    994 	 * or similar function, to speed up */
    995 	if ((anchor = XawTextSourceFindAnchor(w, left))) {
    996 	    XawTextEntity *eprev, *entity, *enext;
    997 	    XawTextPosition offset = 0, diff = block->length - (right - left);
    998 
    999 	    for (i = 0; i < src->textSrc.num_anchors; i++)
   1000 		if (src->textSrc.anchors[i] == anchor)
   1001 		    break;
   1002 	    if (anchor->cache && anchor->position + anchor->cache->offset +
   1003 		anchor->cache->length <= left)
   1004 		eprev = entity = anchor->cache;
   1005 	    else
   1006 		eprev = entity = anchor->entities;
   1007 	    while (entity) {
   1008 		offset = anchor->position + entity->offset;
   1009 
   1010 		if (offset > left)
   1011 		    break;
   1012 		if (offset + entity->length > left)
   1013 		    break;
   1014 
   1015 		eprev = entity;
   1016 		entity = entity->next;
   1017 	    }
   1018 
   1019 	    /* try to do the right thing here (and most likely correct), but
   1020 	     * other code needs to check what was done */
   1021 
   1022 	    /* adjust entity length */
   1023 	    if (entity && offset <= left) {
   1024 		if (offset + entity->length < right)
   1025 		    entity->length = (Cardinal)(left - offset + block->length);
   1026 		else
   1027 		    entity->length = (Cardinal)(entity->length + diff);
   1028 
   1029 		if (entity->length == 0) {
   1030 		    enext = entity->next;
   1031 		    eprev->next = enext;
   1032 		    anchor->cache = NULL;
   1033 		    XtFree((XtPointer)entity);
   1034 		    if (entity == anchor->entities) {
   1035 			if ((anchor->entities = enext) == NULL) {
   1036 			    eprev = NULL;
   1037 			    anchor = XawTextSourceRemoveAnchor(w, anchor);
   1038 			    entity = anchor ? anchor->entities : NULL;
   1039 			}
   1040 			else
   1041 			    eprev = entity = enext;
   1042 		    }
   1043 		    else
   1044 			entity = enext;
   1045 		}
   1046 		else {
   1047 		    eprev = entity;
   1048 		    entity = entity->next;
   1049 		}
   1050 	    }
   1051 
   1052 	    while (anchor) {
   1053 		while (entity) {
   1054 		    offset = anchor->position + entity->offset + entity->length;
   1055 
   1056 		    if (offset > right) {
   1057 			entity->length = (Cardinal) (XawMin(entity->length, offset - right));
   1058 			goto exit_anchor_loop;
   1059 		    }
   1060 
   1061 		    enext = entity->next;
   1062 		    if (eprev)
   1063 			eprev->next = enext;
   1064 		    XtFree((XtPointer)entity);
   1065 		    anchor->cache = NULL;
   1066 		    if (entity == anchor->entities) {
   1067 			eprev = NULL;
   1068 			if ((anchor->entities = enext) == NULL) {
   1069 			    if (i == 0)
   1070 				++i;
   1071 			    else if (i < --src->textSrc.num_anchors) {
   1072 				memmove(&src->textSrc.anchors[i],
   1073 					&src->textSrc.anchors[i + 1],
   1074 					(size_t)(src->textSrc.num_anchors - i) *
   1075 					sizeof(XawTextAnchor*));
   1076 				XtFree((XtPointer)anchor);
   1077 			    }
   1078 			    if (i >= src->textSrc.num_anchors) {
   1079 				anchor = NULL;
   1080 				entity = NULL;
   1081 				break;
   1082 			    }
   1083 			    anchor = src->textSrc.anchors[i];
   1084 			    entity = anchor->entities;
   1085 			    continue;
   1086 			}
   1087 		    }
   1088 		    entity = enext;
   1089 		}
   1090 		if (i + 1 < src->textSrc.num_anchors) {
   1091 		    anchor = src->textSrc.anchors[++i];
   1092 		    entity = anchor->entities;
   1093 		    eprev = NULL;
   1094 		}
   1095 		else {
   1096 		    anchor = NULL;
   1097 		    break;
   1098 		}
   1099 		eprev = NULL;
   1100 	    }
   1101 
   1102 exit_anchor_loop:
   1103 	    if (anchor) {
   1104 		XawTextAnchor *aprev;
   1105 
   1106 		if (anchor->position >= XawMax(right, left + block->length))
   1107 		    anchor->position += diff;
   1108 		else if (anchor->position > left &&
   1109 			 (aprev = XawTextSourcePrevAnchor(w, anchor))) {
   1110 		    XawTextPosition tmp = anchor->position - aprev->position;
   1111 
   1112 		    if (diff) {
   1113 			while (entity) {
   1114 			    entity->offset += diff;
   1115 			    entity = entity->next;
   1116 			}
   1117 		    }
   1118 		    entity = anchor->entities;
   1119 		    while (entity) {
   1120 			entity->offset += tmp;
   1121 			entity = entity->next;
   1122 		    }
   1123 		    if ((entity = aprev->entities) == NULL)
   1124 			aprev->entities = anchor->entities;
   1125 		    else {
   1126 			while (entity->next)
   1127 			    entity = entity->next;
   1128 			entity->next = anchor->entities;
   1129 		    }
   1130 		    anchor->entities = NULL;
   1131 		    (void)XawTextSourceRemoveAnchor(w, anchor);
   1132 		    --i;
   1133 		}
   1134 		else if (diff) {
   1135 		    while (entity) {
   1136 			entity->offset += diff;
   1137 			entity = entity->next;
   1138 		    }
   1139 		}
   1140 	    }
   1141 
   1142 	    if (diff) {
   1143 		/*   The first anchor is never removed, and should
   1144 		 * have position 0.
   1145 		 *   i should be -1 if attempted to removed the first
   1146 		 * anchor, what can be caused when removing a chunk
   1147 		 * of text of the first entity.
   1148 		 * */
   1149 		if (++i == 0) {
   1150 		    anchor = src->textSrc.anchors[0];
   1151 		    eprev = entity = anchor->entities;
   1152 		    while (entity) {
   1153 			enext = entity->next;
   1154 			if (entity->offset + entity->length <= -diff)
   1155 			    XtFree((XtPointer)entity);
   1156 			else
   1157 			    break;
   1158 			entity = enext;
   1159 		    }
   1160 		    if (eprev != entity) {
   1161 			anchor->cache = NULL;
   1162 			if ((anchor->entities = entity) != NULL) {
   1163 			    if ((entity->offset += diff) < 0) {
   1164 				entity->length = (Cardinal)(entity->length + entity->offset);
   1165 				entity->offset = 0;
   1166 			    }
   1167 			}
   1168 		    }
   1169 		    ++i;
   1170 		}
   1171 		for (; i < src->textSrc.num_anchors; i++)
   1172 		    src->textSrc.anchors[i]->position += diff;
   1173 	    }
   1174 	}
   1175 
   1176 	start = left;
   1177 	end = start + block->length;
   1178 	while (start < end) {
   1179 	    start = XawTextSourceScan(w, start, XawstEOL, XawsdRight, 1, True);
   1180 	    if (start <= end) {
   1181 		++lines;
   1182 		if (start == XawTextSourceScan(w, 0, XawstAll, XawsdRight, 1, True)) {
   1183 		    lines -= !_XawTextSourceNewLineAtEOF(w);
   1184 		    break;
   1185 		}
   1186 	    }
   1187 	}
   1188 
   1189 	{
   1190 	    XawTextPropertyInfo info = {
   1191 		.left = left,
   1192 		.right = right,
   1193 		.block = block
   1194 	    };
   1195 
   1196 	    XtCallCallbacks(w, XtNpropertyCallback, &info);
   1197 	}
   1198 
   1199 	TellSourceChanged(src, left, right, block, lines);
   1200 	/* Call callbacks, we have changed the buffer */
   1201 	XtCallCallbacks(w, XtNcallback,
   1202 			(XtPointer)((long)src->textSrc.changed));
   1203     }
   1204 
   1205 #endif /* OLDXAW */
   1206     return (error);
   1207 }
   1208 
   1209 #ifndef OLDXAW
   1210 Bool
   1211 _XawTextSrcUndo(TextSrcObject src, XawTextPosition *insert_pos)
   1212 {
   1213     static wchar_t wnull = 0;
   1214     XawTextBlock block;
   1215     XawTextUndoList *list, *nlist;
   1216     XawTextUndoBuffer *l_state, *r_state;
   1217     Boolean changed = src->textSrc.changed;
   1218 
   1219     if (!src->textSrc.enable_undo || !src->textSrc.undo->num_undo)
   1220 	return (False);
   1221 
   1222     list = src->textSrc.undo->pointer;
   1223 
   1224     if (src->textSrc.undo->dir == XawsdLeft) {
   1225 	l_state = list->right;
   1226 	r_state = list->left;
   1227     }
   1228     else {
   1229 	l_state = list->left;
   1230 	r_state = list->right;
   1231     }
   1232 
   1233     if (src->textSrc.undo->l_no_change == l_state
   1234 	&& src->textSrc.undo->r_no_change == r_state)
   1235 	src->textSrc.changed = False;
   1236     else
   1237 	src->textSrc.changed = True;
   1238 
   1239     block.firstPos = 0;
   1240     block.length = (int)r_state->length;
   1241     block.ptr = r_state->buffer ? r_state->buffer : (char*)&wnull;
   1242     block.format = r_state->format;
   1243 
   1244     src->textSrc.undo_state = True;
   1245     if (XawTextSourceReplace((Widget)src, l_state->position, l_state->position
   1246 			     + l_state->length, &block) != XawEditDone) {
   1247 	src->textSrc.undo_state = False;
   1248 	src->textSrc.changed = changed;
   1249 	return (False);
   1250     }
   1251     src->textSrc.undo_state = False;
   1252 
   1253     ++l_state->refcount;
   1254     ++r_state->refcount;
   1255     nlist = XtNew(XawTextUndoList);
   1256     nlist->left = l_state;
   1257     nlist->right = r_state;
   1258     nlist->undo = src->textSrc.undo->list;
   1259     nlist->redo = NULL;
   1260 
   1261     if (list == src->textSrc.undo->list)
   1262 	src->textSrc.undo->end_mark = nlist;
   1263 
   1264     if (src->textSrc.undo->dir == XawsdLeft) {
   1265 	if (list->undo == NULL)
   1266 	    src->textSrc.undo->dir = XawsdRight;
   1267 	else
   1268 	    list = list->undo;
   1269     }
   1270     else {
   1271 	if (list->redo == NULL || list->redo == src->textSrc.undo->end_mark)
   1272 	    src->textSrc.undo->dir = XawsdLeft;
   1273 	else
   1274 	    list = list->redo;
   1275     }
   1276     *insert_pos = r_state->position + r_state->length;
   1277     src->textSrc.undo->pointer = list;
   1278     src->textSrc.undo->list->redo = nlist;
   1279     src->textSrc.undo->list = nlist;
   1280     src->textSrc.undo->merge = src->textSrc.undo->erase = 0;
   1281 
   1282     if (++src->textSrc.undo->num_list >= UNDO_DEPTH)
   1283 	UndoGC(src->textSrc.undo);
   1284 
   1285     return (True);
   1286 }
   1287 
   1288 Bool
   1289 _XawTextSrcToggleUndo(TextSrcObject src)
   1290 {
   1291     if (!src->textSrc.enable_undo || !src->textSrc.undo->num_undo)
   1292 	return (False);
   1293 
   1294     if (src->textSrc.undo->pointer != src->textSrc.undo->list) {
   1295 	if (src->textSrc.undo->dir == XawsdLeft) {
   1296 	    if (src->textSrc.undo->pointer->redo
   1297 		&& (src->textSrc.undo->pointer->redo
   1298 		    != src->textSrc.undo->end_mark)) {
   1299 		src->textSrc.undo->pointer = src->textSrc.undo->pointer->redo;
   1300 		src->textSrc.undo->dir = XawsdRight;
   1301 	    }
   1302 	}
   1303 	else {
   1304 	    if (src->textSrc.undo->pointer->undo
   1305 		&& (src->textSrc.undo->pointer != src->textSrc.undo->head)) {
   1306 		src->textSrc.undo->pointer = src->textSrc.undo->pointer->undo;
   1307 		src->textSrc.undo->dir = XawsdLeft;
   1308 	    }
   1309 	}
   1310     }
   1311 
   1312     return (True);
   1313 }
   1314 
   1315 static void
   1316 FreeUndoBuffer(XawTextUndo *undo)
   1317 {
   1318     unsigned i;
   1319     XawTextUndoList *head, *del;
   1320 
   1321     for (i = 0; i < undo->num_undo; i++) {
   1322 	if (undo->undo[i]->buffer && undo->undo[i]->buffer != SrcNL &&
   1323 	    undo->undo[i]->buffer != (char*)SrcWNL)
   1324 	    XtFree(undo->undo[i]->buffer);
   1325 	XtFree((char*)undo->undo[i]);
   1326     }
   1327     XtFree((char*)undo->undo);
   1328     head = undo->head;
   1329 
   1330     del = head;
   1331     while (head) {
   1332 	head = head->redo;
   1333 	XtFree((char*)del);
   1334 	del = head;
   1335     }
   1336 
   1337     if (undo->l_save) {
   1338 	XtFree((char*)undo->l_save);
   1339 	undo->l_save = NULL;
   1340     }
   1341     if (undo->r_save) {
   1342 	XtFree((char*)undo->r_save);
   1343 	undo->r_save = NULL;
   1344     }
   1345     if (undo->u_save) {
   1346 	XtFree((char*)undo->u_save);
   1347 	undo->u_save = NULL;
   1348     }
   1349 
   1350     undo->list = undo->pointer = undo->head = undo->end_mark = NULL;
   1351     undo->l_no_change = undo->r_no_change = NULL;
   1352     undo->undo = NULL;
   1353     undo->dir = XawsdLeft;
   1354     undo->num_undo = undo->num_list = (unsigned)(undo->erase = undo->merge = 0);
   1355 }
   1356 
   1357 static void
   1358 UndoGC(XawTextUndo *undo)
   1359 {
   1360     XawTextUndoList *head = undo->head, *redo = head->redo;
   1361 
   1362     if (head == undo->pointer || head == undo->end_mark
   1363 	|| undo->l_no_change == NULL
   1364 	|| head->left == undo->l_no_change || head->right == undo->l_no_change)
   1365       return;
   1366 
   1367     undo->head = redo;
   1368     redo->undo = NULL;
   1369 
   1370     --head->left->refcount;
   1371     if (--head->right->refcount == 0) {
   1372 	unsigned i;
   1373 
   1374 	for (i = 0; i < undo->num_undo; i+= 2)
   1375 	    if (head->left == undo->undo[i] || head->left == undo->undo[i+1]) {
   1376 		if (head->left == undo->undo[i+1]) {
   1377 		    XawTextUndoBuffer *tmp = redo->left;
   1378 
   1379 		    redo->left = redo->right;
   1380 		    redo->right = tmp;
   1381 		}
   1382 		if (head->left->buffer && head->left->buffer != SrcNL &&
   1383 		    head->left->buffer != (char*)SrcWNL)
   1384 		    XtFree(head->left->buffer);
   1385 		XtFree((char*)head->left);
   1386 		if (head->right->buffer && head->right->buffer != SrcNL &&
   1387 		    head->right->buffer != (char*)SrcWNL)
   1388 		    XtFree(head->right->buffer);
   1389 		XtFree((char*)head->right);
   1390 
   1391 		undo->num_undo -= 2;
   1392 		memmove(&undo->undo[i], &undo->undo[i + 2],
   1393 			(undo->num_undo - i) * sizeof(XawTextUndoBuffer*));
   1394 		break;
   1395 	    }
   1396     }
   1397     XtFree((char*)head);
   1398     --undo->num_list;
   1399 }
   1400 #endif /* OLDXAW */
   1401 
   1402 /*
   1403  * Function:
   1404  *	XawTextSourceScan
   1405  *
   1406  * Parameters:
   1407  *	w	 - TextSrc Object
   1408  *	position - position to start scanning
   1409  *	type	 - type of thing to scan for
   1410  *	dir	 - direction to scan
   1411  *	count	 - which occurrence if this thing to search for
   1412  *	include  - whether or not to include the character found in
   1413  *		   the position that is returned.
   1414  *
   1415  * Description:
   1416  *	Scans the text source for the number and type of item specified.
   1417  *
   1418  * Returns:
   1419  *	The position of the text
   1420  */
   1421 XawTextPosition
   1422 XawTextSourceScan(Widget w, XawTextPosition position,
   1423 #if NeedWidePrototypes
   1424 		  int type, int dir, int count, int include
   1425 #else
   1426 		  XawTextScanType type, XawTextScanDirection dir,
   1427 		  int count, Boolean include
   1428 #endif
   1429 )
   1430 {
   1431     TextSrcObjectClass cclass = (TextSrcObjectClass)w->core.widget_class;
   1432 
   1433     return ((*cclass->textSrc_class.Scan)
   1434 	    (w, position, type, dir, count, include));
   1435 }
   1436 
   1437 /*
   1438  * Function:
   1439  *	XawTextSourceSearch
   1440  *
   1441  * Parameters:
   1442  *	w	 - TextSource Object
   1443  *	position - position to start scanning
   1444  *	dir	 - direction to scan
   1445  *	text	 - the text block to search for.
   1446  *
   1447  * Returns:
   1448  *	The position of the text we are searching for or XawTextSearchError.
   1449  *
   1450  * Description:
   1451  *	Searches the text source for the text block passed
   1452  */
   1453 XawTextPosition
   1454 XawTextSourceSearch(Widget w, XawTextPosition position,
   1455 #if NeedWidePrototypes
   1456 		    int dir,
   1457 #else
   1458 		    XawTextScanDirection dir,
   1459 #endif
   1460 		    XawTextBlock *text)
   1461 {
   1462     TextSrcObjectClass cclass = (TextSrcObjectClass)w->core.widget_class;
   1463 
   1464     return ((*cclass->textSrc_class.Search)(w, position, dir, text));
   1465 }
   1466 
   1467 /*
   1468  * Function:
   1469  *	XawTextSourceConvertSelection
   1470  *
   1471  * Parameters:
   1472  *	w	  - TextSrc object
   1473  *	selection - current selection atom
   1474  *	target	  - current target atom
   1475  *	type	  - type to convert the selection to
   1476  *	value	  - return value that has been converted
   1477  *	length	  - ""
   1478  *	format	  - format of the returned value
   1479  *
   1480  * Returns:
   1481  *	True if the selection has been converted
   1482  */
   1483 Boolean
   1484 XawTextSourceConvertSelection(Widget w, Atom *selection, Atom *target,
   1485 			      Atom *type, XtPointer *value,
   1486 			      unsigned long *length, int *format)
   1487 {
   1488     TextSrcObjectClass cclass = (TextSrcObjectClass)w->core.widget_class;
   1489 
   1490     return((*cclass->textSrc_class.ConvertSelection)
   1491 	   (w, selection, target, type, value, length, format));
   1492 }
   1493 
   1494 /*
   1495  * Function:
   1496  *	XawTextSourceSetSelection
   1497  *
   1498  * Parameters:
   1499  *	w	  - TextSrc object
   1500  *	left	  - bounds of the selection
   1501  *	right	  - ""
   1502  *	selection - selection atom
   1503  *
   1504  * Description:
   1505  *	Allows special setting of the selection.
   1506  */
   1507 void
   1508 XawTextSourceSetSelection(Widget w, XawTextPosition left,
   1509 			  XawTextPosition right, Atom selection)
   1510 {
   1511     TextSrcObjectClass cclass = (TextSrcObjectClass)w->core.widget_class;
   1512 
   1513     (*cclass->textSrc_class.SetSelection)(w, left, right, selection);
   1514 }
   1515 
   1516 /*
   1517  * External Functions for Multi Text
   1518  */
   1519 /*
   1520  * TextFormat():
   1521  *	returns the format of text: FMT8BIT or FMTWIDE
   1522  */
   1523 XrmQuark
   1524 _XawTextFormat(TextWidget tw)
   1525 {
   1526     return (((TextSrcObject)(tw->text.source))->textSrc.text_format);
   1527 }
   1528 
   1529 /* _XawTextWCToMB():
   1530  *	Convert the wchar string to external encoding
   1531  *	The caller is responsible for freeing both the source and ret string
   1532  *
   1533  *	wstr	   - source wchar string
   1534  *	len_in_out - length of string.
   1535  *		     As In, length of source wchar string, measured in wchar
   1536  *		     As Out, length of returned string
   1537  */
   1538 char *
   1539 _XawTextWCToMB(Display *d, wchar_t *wstr, int *len_in_out)
   1540 {
   1541     XTextProperty textprop;
   1542 
   1543     if (XwcTextListToTextProperty(d, (wchar_t**)&wstr, 1,
   1544 				XTextStyle, &textprop) < Success) {
   1545 	XtWarningMsg("convertError", "textSource", "XawError",
   1546 		     "Non-character code(s) in buffer.", NULL, NULL);
   1547 	*len_in_out = 0;
   1548 	return (NULL);
   1549     }
   1550     *len_in_out = (int)textprop.nitems;
   1551 
   1552     return ((char *)textprop.value);
   1553 }
   1554 
   1555 /* _XawTextMBToWC():
   1556  *	Convert the string to internal processing codeset WC.
   1557  *   The caller is responsible for freeing both the source and ret string.
   1558  *
   1559  *	str	   - source string
   1560  *	len_in_out - length of string
   1561  *		     As In, it is length of source string
   1562  *		     As Out, it is length of returned string, measured in wchar
   1563  */
   1564 wchar_t *
   1565 _XawTextMBToWC(Display *d, char *str, int *len_in_out)
   1566 {
   1567     XTextProperty textprop;
   1568     char *buf;
   1569     wchar_t **wlist, *wstr;
   1570     int count;
   1571 
   1572     if (*len_in_out == 0)
   1573 	return (NULL);
   1574 
   1575     buf = XtMalloc((Cardinal)(*len_in_out + 1));
   1576 
   1577     strncpy(buf, str, (size_t)*len_in_out);
   1578     *(buf + *len_in_out) = '\0';
   1579     if (XmbTextListToTextProperty(d, &buf, 1, XTextStyle, &textprop) != Success) {
   1580 	XtWarningMsg("convertError", "textSource", "XawError",
   1581 		     "No Memory, or Locale not supported.", NULL, NULL);
   1582 	XtFree(buf);
   1583 	*len_in_out = 0;
   1584 	return (NULL);
   1585     }
   1586 
   1587     XtFree(buf);
   1588     if (XwcTextPropertyToTextList(d, &textprop,
   1589 				  (wchar_t***)&wlist, &count) != Success) {
   1590 	XtWarningMsg("convertError", "multiSourceCreate", "XawError",
   1591 		     "Non-character code(s) in source.", NULL, NULL);
   1592 	*len_in_out = 0;
   1593 	return (NULL);
   1594     }
   1595     wstr = wlist[0];
   1596     *len_in_out = (int)wcslen(wstr);
   1597     XtFree((XtPointer)wlist);
   1598 
   1599     return (wstr);
   1600 }
   1601 
   1602 #ifndef OLDXAW
   1603 static int
   1604 qcmp_anchors(_Xconst void *left, _Xconst void *right)
   1605 {
   1606     return (int)((*(XawTextAnchor**)left)->position -
   1607 		 (*(XawTextAnchor**)right)->position);
   1608 }
   1609 
   1610 XawTextAnchor *
   1611 XawTextSourceAddAnchor(Widget w, XawTextPosition position)
   1612 {
   1613     TextSrcObject src = (TextSrcObject)w;
   1614     XawTextAnchor *anchor, *panchor;
   1615 
   1616     if ((panchor = XawTextSourceFindAnchor(w, position)) != NULL) {
   1617 	XawTextEntity *pentity, *entity;
   1618 
   1619 	if (position - panchor->position < ANCHORS_DIST)
   1620 	    return (panchor);
   1621 
   1622 	if (panchor->cache && panchor->position + panchor->cache->offset +
   1623 	    panchor->cache->length < position)
   1624 	    pentity = entity = panchor->cache;
   1625 	else
   1626 	    pentity = entity = panchor->entities;
   1627 
   1628 	while (entity && panchor->position + entity->offset +
   1629 	       entity->length < position) {
   1630 	    pentity = entity;
   1631 	    entity = entity->next;
   1632 	}
   1633 	if (entity) {
   1634 	    XawTextPosition diff;
   1635 
   1636 	    if (panchor->position + entity->offset < position)
   1637 		position = panchor->position + entity->offset;
   1638 
   1639 	    if (position == panchor->position)
   1640 		return (panchor);
   1641 
   1642 	    anchor = XtNew(XawTextAnchor);
   1643 	    diff = position - panchor->position;
   1644 
   1645 	    panchor->cache = NULL;
   1646 	    anchor->entities = entity;
   1647 	    if (pentity != entity)
   1648 		pentity->next = NULL;
   1649 	    else
   1650 		panchor->entities = NULL;
   1651 	    while (entity) {
   1652 		entity->offset -= diff;
   1653 		entity = entity->next;
   1654 	    }
   1655 	}
   1656 	else {
   1657 	    anchor = XtNew(XawTextAnchor);
   1658 	    anchor->entities = NULL;
   1659 	}
   1660     }
   1661     else {
   1662 	anchor = XtNew(XawTextAnchor);
   1663 	anchor->entities = NULL;
   1664     }
   1665 
   1666     anchor->position = position;
   1667     anchor->cache = NULL;
   1668 
   1669     src->textSrc.anchors = (XawTextAnchor**)
   1670 	XtRealloc((XtPointer)src->textSrc.anchors,
   1671 		  (Cardinal)(sizeof(XawTextAnchor*) *
   1672 			     (size_t)(src->textSrc.num_anchors + 1)));
   1673     src->textSrc.anchors[src->textSrc.num_anchors++] = anchor;
   1674     qsort((void*)src->textSrc.anchors,
   1675 	  (size_t)src->textSrc.num_anchors,
   1676 	  sizeof(XawTextAnchor*), qcmp_anchors);
   1677 
   1678     return (anchor);
   1679 }
   1680 
   1681 XawTextAnchor *
   1682 XawTextSourceFindAnchor(Widget w, XawTextPosition position)
   1683 {
   1684     TextSrcObject src = (TextSrcObject)w;
   1685     int left, right, nmemb = src->textSrc.num_anchors;
   1686     XawTextAnchor **anchors = src->textSrc.anchors;
   1687 
   1688     left = 0;
   1689     right = nmemb - 1;
   1690     while (left <= right) {
   1691 	int i = (left + right) >> 1;
   1692 	XawTextAnchor *anchor = anchors[i];
   1693 
   1694 	if (anchor->position == position)
   1695 	    return (anchor);
   1696 	else if (position < anchor->position)
   1697 	    right = i - 1;
   1698 	else
   1699 	    left = i + 1;
   1700     }
   1701 
   1702     if (nmemb)
   1703 	return (right < 0 ? anchors[0] : anchors[right]);
   1704 
   1705     return (NULL);
   1706 }
   1707 
   1708 Bool
   1709 XawTextSourceAnchorAndEntity(Widget w, XawTextPosition position,
   1710 			     XawTextAnchor **anchor_return,
   1711 			     XawTextEntity **entity_return)
   1712 {
   1713     XawTextAnchor *anchor = XawTextSourceFindAnchor(w, position);
   1714     XawTextEntity *pentity, *entity;
   1715     Bool next_anchor = True, retval = False;
   1716 
   1717     if (anchor->cache && anchor->position + anchor->cache->offset +
   1718 	anchor->cache->length <= position)
   1719 	pentity = entity = anchor->cache;
   1720     else
   1721 	pentity = entity = anchor->entities;
   1722     while (entity) {
   1723 	XawTextPosition offset = anchor->position + entity->offset;
   1724 
   1725 	if (offset > position) {
   1726 	    retval = next_anchor = False;
   1727 	    break;
   1728 	}
   1729 	if (offset + entity->length > position) {
   1730 	    retval = True;
   1731 	    next_anchor = False;
   1732 	    break;
   1733 	}
   1734 	pentity = entity;
   1735 	entity = entity->next;
   1736     }
   1737 
   1738     if (next_anchor) {
   1739 	*anchor_return = anchor = XawTextSourceNextAnchor(w, anchor);
   1740 	*entity_return = anchor ? anchor->entities : NULL;
   1741     }
   1742     else {
   1743 	*anchor_return = anchor;
   1744 	*entity_return = retval ? entity : pentity;
   1745     }
   1746 
   1747     if (*anchor_return)
   1748 	(*anchor_return)->cache = *entity_return;
   1749 
   1750     return (retval);
   1751 }
   1752 
   1753 XawTextAnchor *
   1754 XawTextSourceNextAnchor(Widget w, XawTextAnchor *anchor)
   1755 {
   1756     int i;
   1757     TextSrcObject src = (TextSrcObject)w;
   1758 
   1759     for (i = 0; i < src->textSrc.num_anchors - 1; i++)
   1760 	if (src->textSrc.anchors[i] == anchor)
   1761 	    return (src->textSrc.anchors[i + 1]);
   1762 
   1763     return (NULL);
   1764 }
   1765 
   1766 XawTextAnchor *
   1767 XawTextSourcePrevAnchor(Widget w, XawTextAnchor *anchor)
   1768 {
   1769     int i;
   1770     TextSrcObject src = (TextSrcObject)w;
   1771 
   1772     for (i = src->textSrc.num_anchors - 1; i > 0; i--)
   1773 	if (src->textSrc.anchors[i] == anchor)
   1774 	    return (src->textSrc.anchors[i - 1]);
   1775 
   1776     return (NULL);
   1777 }
   1778 
   1779 XawTextAnchor *
   1780 XawTextSourceRemoveAnchor(Widget w, XawTextAnchor *anchor)
   1781 {
   1782     int i;
   1783     TextSrcObject src = (TextSrcObject)w;
   1784 
   1785     for (i = 0; i < src->textSrc.num_anchors; i++)
   1786 	if (src->textSrc.anchors[i] == anchor)
   1787 	    break;
   1788 
   1789     if (i == 0)
   1790 	return (src->textSrc.num_anchors > 1 ? src->textSrc.anchors[1] : NULL);
   1791 
   1792     if (i < src->textSrc.num_anchors) {
   1793 	XtFree((XtPointer)anchor);
   1794 	if (i < --src->textSrc.num_anchors) {
   1795 	    memmove(&src->textSrc.anchors[i],
   1796 		    &src->textSrc.anchors[i + 1],
   1797 		    (size_t)(src->textSrc.num_anchors - i) *
   1798 		    sizeof(XawTextAnchor*));
   1799 
   1800 	    return (src->textSrc.anchors[i]);
   1801 	}
   1802     }
   1803 
   1804     return (NULL);
   1805 }
   1806 
   1807 XawTextEntity *
   1808 XawTextSourceAddEntity(Widget w, int type, int flags, XtPointer data,
   1809 		       XawTextPosition position, Cardinal length,
   1810 		       XrmQuark property)
   1811 {
   1812     XawTextAnchor *next, *anchor = _XawTextSourceFindAnchor(w, position);
   1813     XawTextEntity *entity, *eprev;
   1814 
   1815     /* There is no support for zero length entities for now */
   1816     if (length == 0)
   1817 	return (NULL);
   1818 
   1819     if (anchor->cache && anchor->position + anchor->cache->offset +
   1820 	anchor->cache->length <= position)
   1821 	eprev = entity = anchor->cache;
   1822     else
   1823 	eprev = entity = anchor->entities;
   1824 
   1825     while (entity && anchor->position + entity->offset + entity->length <=
   1826 	   position) {
   1827 	eprev = entity;
   1828 	entity = entity->next;
   1829     }
   1830     if (entity && anchor->position + entity->offset < position + length) {
   1831 	fprintf(stderr, "Cannot (yet) add more than one entity to same region.\n");
   1832 	return (NULL);
   1833     }
   1834 
   1835     next = XawTextSourceFindAnchor(w, position + length);
   1836     if (next && next != anchor) {
   1837 	if ((entity = next->entities) != NULL) {
   1838 	    if (next->position + entity->offset < position + length) {
   1839 		fprintf(stderr, "Cannot (yet) add more than one entity to same region.\n");
   1840 		return (NULL);
   1841 	    }
   1842 	}
   1843 	if (position + length > next->position) {
   1844 	    XawTextPosition diff = position + length - next->position;
   1845 
   1846 	    next->position += diff;
   1847 	    entity = next->entities;
   1848 	    while (entity) {
   1849 		entity->offset -= diff;
   1850 		entity = entity->next;
   1851 	    }
   1852 	    entity = anchor->entities;
   1853 	    while (entity && entity->offset < 0)
   1854 		entity = entity->next;
   1855 	    if (entity && entity->offset < 0) {
   1856 		if (eprev)
   1857 		    eprev->next = next->entities;
   1858 		else
   1859 		    anchor->entities = next->entities;
   1860 		if ((next->entities = entity->next) == NULL)
   1861 		    (void)XawTextSourceRemoveAnchor(w, next);
   1862 		entity->next = NULL;
   1863 
   1864 		return (XawTextSourceAddEntity(w, type, flags, data, position,
   1865 					       length, property));
   1866 	    }
   1867 	}
   1868     }
   1869 
   1870     /* Automatically join sequential entities if possible */
   1871     if (eprev &&
   1872 	anchor->position + eprev->offset + eprev->length == position &&
   1873 	eprev->property == property && eprev->type == type &&
   1874 	eprev->flags == flags && eprev->data == data) {
   1875 	eprev->length += length;
   1876 	return (eprev);
   1877     }
   1878 
   1879     entity = XtNew(XawTextEntity);
   1880     entity->type = (short)type;
   1881     entity->flags = (short)flags;
   1882     entity->data = data;
   1883     entity->offset = position - anchor->position;
   1884     entity->length = length;
   1885     entity->property = property;
   1886 
   1887     if (eprev == NULL) {
   1888 	anchor->entities = entity;
   1889 	entity->next = NULL;
   1890 	anchor->cache = NULL;
   1891     }
   1892     else if (eprev->offset > entity->offset) {
   1893 	anchor->cache = NULL;
   1894 	anchor->entities = entity;
   1895 	entity->next = eprev;
   1896     }
   1897     else {
   1898 	anchor->cache = eprev;
   1899 	entity->next = eprev->next;
   1900 	eprev->next = entity;
   1901     }
   1902 
   1903     return (entity);
   1904 }
   1905 
   1906 void
   1907 XawTextSourceClearEntities(Widget w, XawTextPosition left, XawTextPosition right)
   1908 {
   1909     XawTextAnchor *anchor = XawTextSourceFindAnchor(w, left);
   1910     XawTextEntity *entity, *eprev, *enext;
   1911     XawTextPosition offset;
   1912 
   1913     while (anchor && anchor->entities == NULL)
   1914 	anchor = XawTextSourceRemoveAnchor(w, anchor);
   1915 
   1916     if (anchor == NULL || left >= right)
   1917 	return;
   1918 
   1919     if (anchor->cache && anchor->position + anchor->cache->offset +
   1920 	anchor->cache->length < left)
   1921 	eprev = entity = anchor->cache;
   1922     else
   1923 	eprev = entity = anchor->entities;
   1924 
   1925     /* find first entity before left position */
   1926     while (anchor->position + entity->offset + entity->length < left) {
   1927 	eprev = entity;
   1928 	if ((entity = entity->next) == NULL) {
   1929 	    if ((anchor = XawTextSourceNextAnchor(w, anchor)) == NULL)
   1930 		return;
   1931 	    if ((eprev = entity = anchor->entities) == NULL) {
   1932 		fprintf(stderr, "Bad anchor found!\n");
   1933 		return;
   1934 	    }
   1935 	}
   1936     }
   1937 
   1938     offset = anchor->position + entity->offset;
   1939     if (offset <= left) {
   1940 	int length = (int) (XawMin(entity->length, left - offset));
   1941 
   1942 	if (length <= 0) {
   1943 	    enext = entity->next;
   1944 	    eprev->next = enext;
   1945 	    XtFree((XtPointer)entity);
   1946 	    anchor->cache = NULL;
   1947 	    if (entity == anchor->entities) {
   1948 		eprev = NULL;
   1949 		if ((anchor->entities = enext) == NULL) {
   1950 		    if ((anchor = XawTextSourceRemoveAnchor(w, anchor)) == NULL)
   1951 			return;
   1952 		    entity = anchor->entities;
   1953 		}
   1954 		else
   1955 		    entity = enext;
   1956 	    }
   1957 	    else
   1958 		entity = enext;
   1959 	}
   1960 	else {
   1961 	    entity->length = (Cardinal)length;
   1962 	    eprev = entity;
   1963 	    entity = entity->next;
   1964 	}
   1965     }
   1966 
   1967     /* clean everything until right position is reached */
   1968     while (anchor) {
   1969 	while (entity) {
   1970 	    offset = anchor->position + entity->offset + entity->length;
   1971 
   1972 	    if (offset > right) {
   1973 		anchor->cache = NULL;
   1974 		entity->offset = XawMax(entity->offset, right - anchor->position);
   1975 		entity->length = (Cardinal) (XawMin(entity->length, offset - right));
   1976 		return;
   1977 	    }
   1978 
   1979 	    enext = entity->next;
   1980 	    if (eprev)
   1981 		eprev->next = enext;
   1982 	    XtFree((XtPointer)entity);
   1983 	    if (entity == anchor->entities) {
   1984 		eprev = anchor->cache = NULL;
   1985 		if ((anchor->entities = enext) == NULL) {
   1986 		    if ((anchor = XawTextSourceRemoveAnchor(w, anchor)) == NULL)
   1987 			return;
   1988 		    entity = anchor->entities;
   1989 		    continue;
   1990 		}
   1991 	    }
   1992 	    entity = enext;
   1993 	}
   1994 	if (anchor)
   1995 	    anchor->cache = NULL;
   1996 	if ((anchor = XawTextSourceNextAnchor(w, anchor)) != NULL)
   1997 	    entity = anchor->entities;
   1998 	eprev = NULL;
   1999     }
   2000 }
   2001 
   2002 /* checks the anchors up to position, and create an appropriate anchor
   2003  * at position, if required.
   2004  */
   2005 XawTextAnchor *
   2006 _XawTextSourceFindAnchor(Widget w, XawTextPosition position)
   2007 {
   2008     XawTextAnchor *anchor;
   2009 
   2010     anchor = XawTextSourceFindAnchor(w, position);
   2011 
   2012     position -= position % ANCHORS_DIST;
   2013 
   2014     if (position - anchor->position >= ANCHORS_DIST)
   2015 	return (XawTextSourceAddAnchor(w, position));
   2016 
   2017     return (anchor);
   2018 }
   2019 #endif
   2020