text:
/* $Xorg: TextSrc.c,v 1.5 2001/02/09 02:03:47 xorgcvs Exp $ */
/*

Copyright 1989, 1994, 1998  The Open Group

Permission to use, copy, modify, distribute, and sell this software and its
documentation for any purpose is hereby granted without fee, provided that
the above copyright notice appear in all copies and that both that
copyright notice and this permission notice appear in supporting
documentation.

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Except as contained in this notice, the name of The Open Group shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from The Open Group.

*/

/* $XFree86: xc/lib/Xaw/TextSrc.c,v 1.33 2002/09/08 02:29:47 paulo Exp $ */

/*
 * Author:  Chris Peterson, MIT X Consortium.
 * Much code taken from X11R3 String and Disk Sources.
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <ctype.h>
#include <X11/IntrinsicP.h>
#include <X11/StringDefs.h>
#include <X11/Xfuncs.h>
#include <X11/Xutil.h>
#include <X11/Xmu/Atoms.h>
#include <X11/Xmu/CharSet.h>
#include <X11/Xaw/TextSrcP.h>
#include <X11/Xaw/XawInit.h>
#include "XawI18n.h"
#include "Private.h"

#ifndef OLDXAW
#define UNDO_DEPTH	16384

#define ANCHORS_DIST	4096	/* default distance between anchors */

/*
 * Types
 */
typedef struct {
    XawTextPosition position;
    char *buffer;
    unsigned length;
    unsigned refcount;
    unsigned long format;
} XawTextUndoBuffer;

typedef struct _XawTextUndoList XawTextUndoList;
struct _XawTextUndoList {
    XawTextUndoBuffer *left, *right;
    XawTextUndoList *undo, *redo;
};

struct _XawTextUndo {
    XawTextUndoBuffer **undo;
    unsigned num_undo;
    XawTextUndoList *list, *pointer, *end_mark, *head;
    unsigned num_list;
    XawTextScanDirection dir;
    XawTextUndoBuffer *l_save, *r_save;
    XawTextUndoList *u_save;
    XawTextUndoBuffer *l_no_change, *r_no_change;
    int merge;
    int erase;		/* there are two types of erases */
};
#endif	/* OLDXAW */

/*
 * Class Methods
 */
static Boolean ConvertSelection(Widget, Atom*, Atom*, Atom*, XtPointer*,
				unsigned long*, int*);
static XawTextPosition Read(Widget, XawTextPosition, XawTextBlock*, int);
static int  Replace(Widget, XawTextPosition, XawTextPosition, XawTextBlock*);
static  XawTextPosition Scan(Widget, XawTextPosition, XawTextScanType,
			      XawTextScanDirection, int, Bool);
static XawTextPosition Search(Widget, XawTextPosition, XawTextScanDirection,
			      XawTextBlock*);
static void SetSelection(Widget, XawTextPosition, XawTextPosition, Atom);
static void XawTextSrcClassInitialize(void);
static void XawTextSrcClassPartInitialize(WidgetClass);
static void XawTextSrcInitialize(Widget, Widget, ArgList, Cardinal*);
static void XawTextSrcDestroy(Widget);
static Boolean XawTextSrcSetValues(Widget, Widget, Widget, ArgList, Cardinal*);
/*
 * Prototypes
 */
static void CvtStringToEditMode(XrmValuePtr, Cardinal*,
				 XrmValuePtr, XrmValuePtr);
static Boolean CvtEditModeToString(Display*, XrmValuePtr, Cardinal*,
				   XrmValuePtr, XrmValuePtr, XtPointer*);
#ifndef OLDXAW
static void FreeUndoBuffer(XawTextUndo*);
static void UndoGC(XawTextUndo*);
static void TellSourceChanged(TextSrcObject, XawTextPosition, XawTextPosition,
			      XawTextBlock*, int);
Bool _XawTextSrcUndo(TextSrcObject, XawTextPosition*);
Bool _XawTextSrcToggleUndo(TextSrcObject);
XawTextAnchor *_XawTextSourceFindAnchor(Widget, XawTextPosition);

/*
 * External
 */
void _XawSourceAddText(Widget, Widget);
void _XawSourceRemoveText(Widget, Widget, Bool);
Bool _XawTextSourceNewLineAtEOF(Widget);
void _XawSourceSetUndoErase(TextSrcObject, int);
void _XawSourceSetUndoMerge(TextSrcObject, Bool);
#endif /* OLDXAW */

/*
 * Defined in Text.c
 */
char *_XawTextGetText(TextWidget, XawTextPosition, XawTextPosition);
void _XawTextSourceChanged(Widget, XawTextPosition, XawTextPosition,
			   XawTextBlock*, int);

/*
 * Initialization
 */
#define offset(field) XtOffsetOf(TextSrcRec, textSrc.field)
static XtResource resources[] = {
  {
    XtNeditType,
    XtCEditType,
    XtREditMode,
    sizeof(XawTextEditType),
    offset(edit_mode),
    XtRString,
    "read"
  },
#ifndef OLDXAW
  {
    XtNcallback,
    XtCCallback,
    XtRCallback,
    sizeof(XtPointer),
    offset(callback),
    XtRCallback,
    NULL
  },
  {
    XtNsourceChanged,
    XtCChanged,
    XtRBoolean,
    sizeof(Boolean),
    offset(changed),
    XtRImmediate,
    (XtPointer)False
  },
  {
    XtNenableUndo,
    XtCUndo,
    XtRBoolean,
    sizeof(Boolean),
    offset(enable_undo),
    XtRImmediate,
    (XtPointer)False
  },
  {
    XtNpropertyCallback,
    XtCCallback,
    XtRCallback,
    sizeof(XtPointer),
    offset(property_callback),
    XtRCallback,
    NULL
  },
#endif /* OLDXAW */
};
#undef offset

#define Superclass	(&objectClassRec)
TextSrcClassRec textSrcClassRec = {
  /* object */
  {
    (WidgetClass)Superclass,		/* superclass */
    "TextSrc",				/* class_name */
    sizeof(TextSrcRec),			/* widget_size */
    XawTextSrcClassInitialize,		/* class_initialize */
    XawTextSrcClassPartInitialize,	/* class_part_initialize */
    False,				/* class_inited */
    XawTextSrcInitialize,		/* initialize */
    NULL,				/* initialize_hook */
    NULL,				/* realize */
    NULL,				/* actions */
    0,					/* num_actions */
    resources,				/* resources */
    XtNumber(resources),		/* num_resources */
    NULLQUARK,				/* xrm_class */
    False,				/* compress_motion */
    False,				/* compress_exposure */
    False,				/* compress_enterleave */
    False,				/* visible_interest */
    XawTextSrcDestroy,			/* destroy */
    NULL,				/* resize */
    NULL,				/* expose */
    XawTextSrcSetValues,		/* set_values */
    NULL,				/* set_values_hook */
    NULL,				/* set_values_almost */
    NULL,				/* get_values_hook */
    NULL,				/* accept_focus */
    XtVersion,				/* version */
    NULL,				/* callback_private */
    NULL,				/* tm_table */
    NULL,				/* query_geometry */
    NULL,				/* display_accelerator */
    NULL,				/* extension */
  },
  /* text_src */
  {
    Read,				/* Read */
    Replace,				/* Replace */
    Scan,				/* Scan */
    Search,				/* Search */
    SetSelection,			/* SetSelection */
    ConvertSelection,			/* ConvertSelection */
  },
};

WidgetClass textSrcObjectClass = (WidgetClass)&textSrcClassRec;

static XrmQuark QRead, QAppend, QEdit;
#ifndef OLDXAW
static char *SrcNL = "\n";
static wchar_t SrcWNL[2];
#endif

/*
 * Implementation
 */
static void
XawTextSrcClassInitialize(void)
{
    XawInitializeWidgetSet();

#ifndef OLDXAW
    SrcWNL[0] = _Xaw_atowc(XawLF);
    SrcWNL[1] = 0;
#endif
    QRead   = XrmPermStringToQuark(XtEtextRead);
    QAppend = XrmPermStringToQuark(XtEtextAppend);
    QEdit   = XrmPermStringToQuark(XtEtextEdit);
    XtAddConverter(XtRString, XtREditMode,   CvtStringToEditMode,   NULL, 0);
    XtSetTypeConverter(XtREditMode, XtRString, CvtEditModeToString, NULL, 0,
		       XtCacheNone, NULL);
}

static void
XawTextSrcClassPartInitialize(WidgetClass wc)
{
    TextSrcObjectClass t_src, superC;

    t_src = (TextSrcObjectClass)wc;
    superC = (TextSrcObjectClass)t_src->object_class.superclass;

    /*
     * We don't need to check for null super since we'll get to TextSrc
     * eventually
     */
    if (t_src->textSrc_class.Read == XtInheritRead)
	t_src->textSrc_class.Read = superC->textSrc_class.Read;

    if (t_src->textSrc_class.Replace == XtInheritReplace)
	t_src->textSrc_class.Replace = superC->textSrc_class.Replace;

    if (t_src->textSrc_class.Scan == XtInheritScan)
	t_src->textSrc_class.Scan = superC->textSrc_class.Scan;

    if (t_src->textSrc_class.Search == XtInheritSearch)
	t_src->textSrc_class.Search = superC->textSrc_class.Search;

    if (t_src->textSrc_class.SetSelection == XtInheritSetSelection)
	t_src->textSrc_class.SetSelection = superC->textSrc_class.SetSelection;

    if (t_src->textSrc_class.ConvertSelection == XtInheritConvertSelection)
	t_src->textSrc_class.ConvertSelection =
	    superC->textSrc_class.ConvertSelection;
}

/*ARGSUSED*/
static void
XawTextSrcInitialize(Widget request, Widget cnew,
		     ArgList args, Cardinal *num_args)
{
#ifndef OLDXAW
    TextSrcObject src = (TextSrcObject)cnew;

    if (src->textSrc.enable_undo) {
	src->textSrc.undo = (XawTextUndo*)XtCalloc(1, sizeof(XawTextUndo));
	src->textSrc.undo->dir = XawsdLeft;
    }
    else
	src->textSrc.undo = NULL;
    src->textSrc.undo_state = False;
    if (XtIsSubclass(XtParent(cnew), textWidgetClass)) {
	src->textSrc.text = (WidgetList)XtMalloc(sizeof(Widget*));
	src->textSrc.text[0] = XtParent(cnew);
	src->textSrc.num_text = 1;
    }
    else {
	src->textSrc.text = NULL;
	src->textSrc.num_text = 0;
    }

    src->textSrc.anchors = NULL;
    src->textSrc.num_anchors = 0;
    (void)XawTextSourceAddAnchor(cnew, 0);
#endif /* OLDXAW */
}

static void
XawTextSrcDestroy(Widget w)
{
#ifndef OLDXAW
    TextSrcObject src = (TextSrcObject)w;

    if (src->textSrc.enable_undo) {
	FreeUndoBuffer(src->textSrc.undo);
	XtFree((char*)src->textSrc.undo);
    }
    XtFree((char*)src->textSrc.text);

    if (src->textSrc.num_anchors) {
	XawTextEntity *entity, *enext;
	int i;

	for (i = 0; i < src->textSrc.num_anchors; i++) {
	    entity = src->textSrc.anchors[i]->entities;
	    while (entity) {
		enext = entity->next;
		XtFree((XtPointer)entity);
		entity = enext;
	    }
	    XtFree((XtPointer)src->textSrc.anchors[i]);
	}
	XtFree((XtPointer)src->textSrc.anchors);
    }
#endif /* OLDXAW */
}

/*ARGSUSED*/
static Boolean
XawTextSrcSetValues(Widget current, Widget request, Widget cnew,
		    ArgList args, Cardinal *num_args)
{
#ifndef OLDXAW
    TextSrcObject oldtw = (TextSrcObject)current;
    TextSrcObject newtw = (TextSrcObject)cnew;

    if (oldtw->textSrc.enable_undo != newtw->textSrc.enable_undo) {
	if (newtw->textSrc.enable_undo) {
	    newtw->textSrc.undo = (XawTextUndo*)
		XtCalloc(1, sizeof(XawTextUndo));
	    newtw->textSrc.undo->dir = XawsdLeft;
	}
	else {
	    FreeUndoBuffer(newtw->textSrc.undo);
	    XtFree((char*)newtw->textSrc.undo);
	    newtw->textSrc.undo = NULL;
	}
    }
    if (oldtw->textSrc.changed != newtw->textSrc.changed) {
	if (newtw->textSrc.enable_undo) {
	    if (newtw->textSrc.undo->list) {
		newtw->textSrc.undo->l_no_change =
		    newtw->textSrc.undo->list->left;
		newtw->textSrc.undo->r_no_change =
		    newtw->textSrc.undo->list->right;
	    }
	    else
		newtw->textSrc.undo->l_no_change =
		    newtw->textSrc.undo->r_no_change = NULL;
	}
    }
#endif /* OLDXAW */
    return (False);
}

/*
 * Function:
 *	Read
 *
 * Parameters:
 *	w      - TextSrc Object
 *	pos    - position of the text to retreive
 *	text   - text block that will contain returned text
 *	length - maximum number of characters to read
 *
 * Description:
 *	This function reads the source.
 *
 * Returns:
 *	The character position following the retrieved text.
 */
/*ARGSUSED*/
static XawTextPosition
Read(Widget w, XawTextPosition pos, XawTextBlock *text, int length)
{
    return ((XawTextPosition)0);
}

/*
 * Function:
 *	Replace
 *
 * Parameters:
 *	src	 - Text Source Object
 *	startPos - ends of text that will be removed
 *	endPos	 - ""
 *	text	 - new text to be inserted into buffer at startPos
 *
 * Description:
 *	Replaces a block of text with new text.
 */
/*ARGSUSED*/
static int
Replace(Widget w, XawTextPosition startPos, XawTextPosition endPos,
	XawTextBlock *text)
{
    return (XawEditError);
}

/*
 * Function:
 *	Scan
 *
 * Parameters:
 *	w	 - TextSrc Object
 *	position - position to start scanning
 *	type	 - type of thing to scan for
 *	dir	 - direction to scan
 *	count	 - which occurance if this thing to search for
 *		 include - whether or not to include the character found in
 *		   the position that is returned
 *
 * Description:
 *	Scans the text source for the number and type of item specified.
 */
/*ARGSUSED*/
static XawTextPosition
Scan(Widget w, XawTextPosition position, XawTextScanType type,
     XawTextScanDirection dir, int count, Bool include)
{
    return ((XawTextPosition)0);
}

/*
 * Function:
 *	Search
 *
 * Parameters:
 *	w	 - TextSource Object
 *	position - position to start searching
 *	dir	 - direction to search
 *	text	 - the text block to search for
 *
 * Description:
 *	Searchs the text source for the text block passed
 */
/*ARGSUSED*/
static XawTextPosition
Search(Widget w, XawTextPosition position, XawTextScanDirection dir,
       XawTextBlock *text)
{
    return (XawTextSearchError);
}

/*ARGSUSED*/
static Boolean
ConvertSelection(Widget w, Atom *selection, Atom *target, Atom *type,
		 XtPointer *value, unsigned long *length, int *format)
{
    return (False);
}

/*ARGSUSED*/
static void
SetSelection(Widget w, XawTextPosition left, XawTextPosition right,
	     Atom selection)
{
}

/*ARGSUSED*/
static void
CvtStringToEditMode(XrmValuePtr args, Cardinal *num_args,
		    XrmValuePtr fromVal, XrmValuePtr toVal)
{
    static XawTextEditType editType;
    XrmQuark	q;
    char name[7];

    XmuNCopyISOLatin1Lowered(name, (char *)fromVal->addr, sizeof(name));
    q = XrmStringToQuark(name);

    if (q == QRead)
	editType = XawtextRead;
    else if (q == QAppend)
	editType = XawtextAppend;
    else if (q == QEdit)
	editType = XawtextEdit;
    else {
	toVal->size = 0;
	toVal->addr = NULL;
	XtStringConversionWarning((char *)fromVal->addr, XtREditMode);
    }
    toVal->size = sizeof(XawTextEditType);
    toVal->addr = (XPointer)&editType;
}

/*ARGSUSED*/
static Boolean
CvtEditModeToString(Display *dpy, XrmValuePtr args, Cardinal *num_args,
		    XrmValuePtr fromVal, XrmValuePtr toVal,
		    XtPointer *data)
{
    static String buffer;
    Cardinal size;

    switch (*(XawTextEditType *)fromVal->addr) {
	case XawtextAppend:
	case XawtextRead:
	    buffer = XtEtextRead;
	    break;
	    buffer = XtEtextAppend;
	    break;
	case XawtextEdit:
	    buffer = XtEtextEdit;
	    break;
	default:
	    XawTypeToStringWarning(dpy, XtREditMode);
	    toVal->addr = NULL;
	    toVal->size = 0;
	    return (False);
    }

    size = strlen(buffer) + 1;
    if (toVal->addr != NULL) {
	if (toVal->size < size) {
	    toVal->size = size;
	    return (False);
	}
	strcpy((char *)toVal->addr, buffer);
    }
    else
	toVal->addr = (XPointer)buffer;
    toVal->size = sizeof(String);

    return (True);
}

#ifndef OLDXAW
Bool
_XawTextSourceNewLineAtEOF(Widget w)
{
    TextSrcObject src = (TextSrcObject)w;
    XawTextBlock text;

    text.firstPos = 0;
    if ((text.format = src->textSrc.text_format) == XawFmt8Bit)
	text.ptr = SrcNL;
    else
	text.ptr = (char*)SrcWNL;
    text.length = 1;

    return (XawTextSourceSearch(w, XawTextSourceScan(w, 0, XawstAll,
						     XawsdRight, 1, True) - 1,
				XawsdRight, &text) != XawTextSearchError);
}

void
_XawSourceAddText(Widget source, Widget text)
{
    TextSrcObject src = (TextSrcObject)source;
    Bool found = False;
    Cardinal i;

    for (i = 0; i < src->textSrc.num_text; i++)
	if (src->textSrc.text[i] == text) {
	    found = True;
	    break;
	}

    if (!found) {
	src->textSrc.text = (WidgetList)
	    XtRealloc((char*)src->textSrc.text,
		      sizeof(Widget) * (src->textSrc.num_text + 1));
	src->textSrc.text[src->textSrc.num_text++] = text;
    }
}

void
_XawSourceRemoveText(Widget source, Widget text, Bool destroy)
{
    TextSrcObject src = (TextSrcObject)source;
    Bool found = False;
    Cardinal i;

    if (src == NULL)
	return;

    for (i = 0; i < src->textSrc.num_text; i++)
	if (src->textSrc.text[i] == text) {
	    found = True;
	    break;
	}

    if (found) {
	if (--src->textSrc.num_text == 0) {
	    if (destroy) {
		XtDestroyWidget(source);
		return;
	    }
	    else {
		XtFree((char*)src->textSrc.text);
		src->textSrc.text = NULL;	/* for realloc "magic" */
	    }
	}
	else if (i < src->textSrc.num_text)
	    memmove(&src->textSrc.text[i], &src->textSrc.text[i + 1],
		    sizeof(Widget) * (src->textSrc.num_text - i));
    }
}
#endif /* OLDXAW */

/*
 * Function:
 *	XawTextSourceRead
 *
 * Parameters:
 *	w      - TextSrc Object
 *	pos    - position of the text to retrieve
 *	text   - text block that will contain returned text (return)
 *	length - maximum number of characters to read
 *
 * Description:
 *	This function reads the source.
 *
 * Returns:
 *	The number of characters read into the buffer
 */
XawTextPosition
XawTextSourceRead(Widget w, XawTextPosition pos, XawTextBlock *text,
		  int length)
{
  TextSrcObjectClass cclass = (TextSrcObjectClass)w->core.widget_class;

  return ((*cclass->textSrc_class.Read)(w, pos, text, length));
}

#ifndef OLDXAW
static void
TellSourceChanged(TextSrcObject src, XawTextPosition left,
		  XawTextPosition right, XawTextBlock *block, int lines)
{
    Cardinal i;

    for (i = 0; i < src->textSrc.num_text; i++)
	_XawTextSourceChanged(src->textSrc.text[i], left, right, block, lines);
}

/*
 * This function is required because there is no way to diferentiate
 * if the first erase was generated by a backward-kill-char and the
 * second by a forward-kill-char (or vice-versa) from XawTextSourceReplace.
 * It is only possible to diferentiate after the second character is
 * killed, but then, it is too late.
 */
void
_XawSourceSetUndoErase(TextSrcObject src, int value)
{
    if (src && src->textSrc.enable_undo)
	src->textSrc.undo->erase = value;
}

/*
 * To diferentiate insert-char's separeted by cursor movements.
 */
void
_XawSourceSetUndoMerge(TextSrcObject src, Bool state)
{
    if (src && src->textSrc.enable_undo)
	src->textSrc.undo->merge += state ? 1 : -1;
}
#endif /* OLDXAW */

/*
 * Public Functions
 */
/*
 * Function:
 *	XawTextSourceReplace
 *
 * Parameters:
 *	src	 - Text Source Object
 *	startPos - ends of text that will be removed
 *	endPos	 - ""
 *	text	 - new text to be inserted into buffer at startPos
 *
 * Description:
 *	Replaces a block of text with new text.
 *
 * Returns:
 *	XawEditError or XawEditDone.
 */
/*ARGSUSED*/
int
XawTextSourceReplace(Widget w, XawTextPosition left,
		      XawTextPosition right, XawTextBlock *block)
{
    TextSrcObjectClass cclass = (TextSrcObjectClass)w->core.widget_class;
#ifndef OLDXAW
    TextSrcObject src = (TextSrcObject)w;
    XawTextUndoBuffer *l_state, *r_state;
    XawTextUndoList *undo;
    Bool enable_undo;
    XawTextPosition start, end;
    int i, error, lines = 0;

    if (src->textSrc.edit_mode == XawtextRead)
	return (XawEditError);

    enable_undo = src->textSrc.enable_undo && src->textSrc.undo_state == False;
    if (enable_undo) {
	unsigned size, total;

	if (src->textSrc.undo->l_save) {
	    l_state = src->textSrc.undo->l_save;
	    src->textSrc.undo->l_save = NULL;
	}
	else
	    l_state = XtNew(XawTextUndoBuffer);
	l_state->refcount = 1;
	l_state->position = left;
	if (left < right) {
	    Widget ctx = NULL;

	    for (i = 0; i < src->textSrc.num_text; i++)
		if (XtIsSubclass(src->textSrc.text[i], textWidgetClass)) {
		    ctx = src->textSrc.text[i];
		    break;
		}
	    l_state->buffer = _XawTextGetText((TextWidget)ctx, left, right);
	    l_state->length = right - left;
	}
	else {
	    l_state->length = 0;
	    l_state->buffer = NULL;
	}
	l_state->format = src->textSrc.text_format;
	if (l_state->length == 1) {
	    if (l_state->format == XawFmtWide &&
		*(wchar_t*)l_state->buffer == *SrcWNL) {
		XtFree(l_state->buffer);
		l_state->buffer = (char*)SrcWNL;
	    }
	    else if (*l_state->buffer == '\n') {
		XtFree(l_state->buffer);
		l_state->buffer = SrcNL;
	    }
	}

	if (src->textSrc.undo->r_save) {
	    r_state = src->textSrc.undo->r_save;
	    src->textSrc.undo->r_save = NULL;
	}
	else
	    r_state = XtNew(XawTextUndoBuffer);
	r_state->refcount = 1;
	r_state->position = left;
	r_state->format = block->format;
	size = block->format == XawFmtWide ? sizeof(wchar_t) : sizeof(char);
	total = size * block->length;
	r_state->length = block->length;
	r_state->buffer = NULL;
	if (total == size) {
	    if (r_state->format == XawFmtWide &&
		*(wchar_t*)block->ptr == *SrcWNL)
		r_state->buffer = (char*)SrcWNL;
	    else if (*block->ptr == '\n')
		r_state->buffer = SrcNL;
	}
	if (total && !r_state->buffer) {
	    r_state->buffer = XtMalloc(total);
	    memcpy(r_state->buffer, block->ptr, total);
	}

	if (src->textSrc.undo->u_save) {
	    undo = src->textSrc.undo->u_save;
	    src->textSrc.undo->u_save = NULL;
	}
	else
	    undo = XtNew(XawTextUndoList);
	undo->left = l_state;
	undo->right = r_state;
	undo->undo = src->textSrc.undo->list;
	undo->redo = NULL;
    }
    else {
	undo = NULL;
	l_state = r_state = NULL;
    }

#define	LARGE_VALUE	262144	/* 256 K */
    /* optimization, to avoid long delays recalculating the line number
     * when editing huge files
     */
    if (left > LARGE_VALUE) {
	start = XawTextSourceScan(w, left, XawstEOL, XawsdLeft, 2, False);
	for (i = 0; i < src->textSrc.num_text; i++) {
	    TextWidget tw = (TextWidget)src->textSrc.text[i];

	    if (left <= tw->text.lt.top &&
		left + block->length - (right - left) > tw->text.lt.top)
		_XawTextBuildLineTable(tw, start, False);
	}
    }
#undef LARGE_VALUE

    start = left;
    end = right;
    while (start < end) {
	start = XawTextSourceScan(w, start, XawstEOL, XawsdRight, 1, True);
	if (start <= end) {
	    --lines;
	    if (start == XawTextSourceScan(w, 0, XawstAll, XawsdRight, 1, True)) {
		lines += !_XawTextSourceNewLineAtEOF(w);
		break;
	    }
	}
    }
#else
    int error;
#endif /* OLDXAW */

    error = (*cclass->textSrc_class.Replace)(w, left, right, block);

#ifndef OLDXAW
    if (error != XawEditDone) {
	if (enable_undo) {
	    if (l_state->buffer) {
		if (l_state->buffer != SrcNL && l_state->buffer != (char*)SrcWNL)
		    XtFree(l_state->buffer);
		l_state->buffer = NULL;
	    }
	     src->textSrc.undo->l_save = l_state;
	     if (r_state->buffer) {
		if (r_state->buffer != SrcNL && r_state->buffer != (char*)SrcWNL)
		    XtFree(r_state->buffer);
		r_state->buffer = NULL;
	    }
	    src->textSrc.undo->r_save = r_state;

	    src->textSrc.undo->u_save = undo;
	}
    }
    else if (enable_undo) {
	XawTextUndoList *list = src->textSrc.undo->list;
	XawTextUndoBuffer *unl, *lnl;
	int erase = undo->right->length == 0 && undo->left->length == 1 && list
		    && list->right->length == 0;

	if (erase) {
	    erase = list->left->position - 1 == undo->left->position ? -1 :
		    list->left->position == undo->left->position ? 1 : 0;
	    if (src->textSrc.undo->erase && erase != src->textSrc.undo->erase)
		erase = 0;
	    else
		src->textSrc.undo->erase = erase;
	}

	if (erase) {
	    unl = l_state;
	    lnl = list->left;
	}
	else {
	    unl = r_state;
	    lnl = list ? list->right : NULL;
	}

	/* Try to merge the undo buffers */
	if (src->textSrc.undo->merge > 0 && ((erase ||
	     (list && ((list->left->length == 0 && undo->left->length == 0) ||
		       (list->left->length == list->right->length &&
			undo->left->length == 1)) &&
	      undo->right->length == 1 &&
	      list->right->position + list->right->length
	      == undo->right->position))
	    && src->textSrc.undo->pointer == list
	    && unl->format == list->right->format
	    && ((unl->format == XawFmt8Bit && unl->buffer[0] != XawLF) ||
		(unl->format == XawFmtWide &&
		 *(wchar_t*)(unl->buffer) != _Xaw_atowc(XawLF)))
	    && ((lnl->format == XawFmt8Bit && lnl->buffer[0] != XawLF) ||
		(lnl->format == XawFmtWide &&
		 *(wchar_t*)(lnl->buffer) != _Xaw_atowc(XawLF))))) {
	    unsigned size = lnl->format == XawFmtWide ?
		sizeof(wchar_t) : sizeof(char);

	    if (!erase) {
		list->right->buffer = XtRealloc(list->right->buffer,
						(list->right->length + 1) * size);
		memcpy(list->right->buffer + list->right->length * size,
		       undo->right->buffer, size);
		++list->right->length;
		XtFree(r_state->buffer);
	    }
	    else if (erase < 0) {
		--list->left->position;
		--list->right->position;
	    }

	    src->textSrc.undo->l_save = l_state;
	    src->textSrc.undo->r_save = r_state;
	    src->textSrc.undo->u_save = undo;

	    if (list->left->length) {
		list->left->buffer = XtRealloc(list->left->buffer,
					       (list->left->length + 1) * size);
		if (erase >= 0)
		    memcpy(list->left->buffer + list->left->length * size,
			   undo->left->buffer, size);
		else {
		    /* use memmove, since strings overlap */
		    memmove(list->left->buffer + size, list->left->buffer,
			    list->left->length * size);
		    memcpy(list->left->buffer, undo->left->buffer, size);
		}
		++list->left->length;
		if (l_state->buffer != SrcNL && l_state->buffer != (char*)SrcWNL)
		    XtFree(l_state->buffer);
	    }

	    if (src->textSrc.undo->num_list >= UNDO_DEPTH)
		UndoGC(src->textSrc.undo);
	}
	else {
	    src->textSrc.undo->undo = (XawTextUndoBuffer**)
		XtRealloc((char*)src->textSrc.undo->undo,
			  (2 + src->textSrc.undo->num_undo)
			  * sizeof(XawTextUndoBuffer));
	    src->textSrc.undo->undo[src->textSrc.undo->num_undo++] = l_state;
	    src->textSrc.undo->undo[src->textSrc.undo->num_undo++] = r_state;

	    if (src->textSrc.undo->list)
		src->textSrc.undo->list->redo = undo;
	    else
		src->textSrc.undo->head = undo;

	    src->textSrc.undo->merge = l_state->length <= 1 &&
				       r_state->length <= 1;

	    src->textSrc.undo->list = src->textSrc.undo->pointer =
		src->textSrc.undo->end_mark = undo;

	    if (++src->textSrc.undo->num_list >= UNDO_DEPTH)
		UndoGC(src->textSrc.undo);
	}
	src->textSrc.undo->dir = XawsdLeft;
	if (!src->textSrc.changed) {
	    src->textSrc.undo->l_no_change = src->textSrc.undo->list->right;
	    src->textSrc.undo->r_no_change = src->textSrc.undo->list->left;
	    src->textSrc.changed = True;
	}
    }
    else if (!src->textSrc.enable_undo)
	src->textSrc.changed = True;

    if (error == XawEditDone) {
	XawTextPropertyInfo info;
	XawTextAnchor *anchor;

	/* find anchor and index */
	/* XXX index (i) could be returned by XawTextSourceFindAnchor
	 * or similar function, to speed up */
	if ((anchor = XawTextSourceFindAnchor(w, left))) {
	    XawTextEntity *eprev, *entity, *enext;
	    XawTextPosition offset = 0, diff = block->length - (right - left);

	    for (i = 0; i < src->textSrc.num_anchors; i++)
		if (src->textSrc.anchors[i] == anchor)
		    break;
	    if (anchor->cache && anchor->position + anchor->cache->offset +
		anchor->cache->length <= left)
		eprev = entity = anchor->cache;
	    else
		eprev = entity = anchor->entities;
	    while (entity) {
		offset = anchor->position + entity->offset;

		if (offset > left)
		    break;
		if (offset + entity->length > left)
		    break;

		eprev = entity;
		entity = entity->next;
	    }

	    /* try to do the right thing here (and most likely correct), but
	     * other code needs to check what was done */

	    /* adjust entity length */
	    if (entity && offset <= left) {
		if (offset + entity->length < right)
		    entity->length = left - offset + block->length;
		else
		    entity->length += diff;

		if (entity->length == 0) {
		    enext = entity->next;
		    eprev->next = enext;
		    anchor->cache = NULL;
		    XtFree((XtPointer)entity);
		    if (entity == anchor->entities) {
			if ((anchor->entities = enext) == NULL) {
			    eprev = NULL;
			    anchor = XawTextSourceRemoveAnchor(w, anchor);
			    entity = anchor ? anchor->entities : NULL;
			}
			else
			    eprev = entity = enext;
		    }
		    else
			entity = enext;
		}
		else {
		    eprev = entity;
		    entity = entity->next;
		}
	    }

	    while (anchor) {
		while (entity) {
		    offset = anchor->position + entity->offset + entity->length;

		    if (offset > right) {
			entity->length = XawMin(entity->length, offset - right);
			goto exit_anchor_loop;
		    }

		    enext = entity->next;
		    if (eprev)
			eprev->next = enext;
		    XtFree((XtPointer)entity);
		    anchor->cache = NULL;
		    if (entity == anchor->entities) {
			eprev = NULL;
			if ((anchor->entities = enext) == NULL) {
			    if (i == 0)
				++i;
			    else if (i < --src->textSrc.num_anchors) {
				memmove(&src->textSrc.anchors[i],
					&src->textSrc.anchors[i + 1],
					(src->textSrc.num_anchors - i) *
					sizeof(XawTextAnchor*));
				XtFree((XtPointer)anchor);
			    }
			    if (i >= src->textSrc.num_anchors) {
				anchor = NULL;
				entity = NULL;
				break;
			    }
			    anchor = src->textSrc.anchors[i];
			    entity = anchor->entities;
			    continue;
			}
		    }
		    entity = enext;
		}
		if (i + 1 < src->textSrc.num_anchors) {
		    anchor = src->textSrc.anchors[++i];
		    entity = anchor->entities;
		    eprev = NULL;
		}
		else
		    break;
		eprev = NULL;
	    }

exit_anchor_loop:
	    if (anchor) {
		XawTextAnchor *aprev;

		if (anchor->position >= XawMax(right, left + block->length))
		    anchor->position += diff;
		else if (anchor->position > left &&
			 (aprev = XawTextSourcePrevAnchor(w, anchor))) {
		    XawTextPosition tmp = anchor->position - aprev->position;

		    if (diff) {
			while (entity) {
			    entity->offset += diff;
			    entity = entity->next;
			}
		    }
		    entity = anchor->entities;
		    while (entity) {
			entity->offset += tmp;
			entity = entity->next;
		    }
		    if ((entity = aprev->entities) == NULL)
			aprev->entities = anchor->entities;
		    else {
			while (entity->next)
			    entity = entity->next;
			entity->next = anchor->entities;
		    }
		    anchor->entities = NULL;
		    (void)XawTextSourceRemoveAnchor(w, anchor);
		    --i;
		}
		else if (diff) {
		    while (entity) {
			entity->offset += diff;
			entity = entity->next;
		    }
		}
	    }

	    if (diff) {
		for (++i; i < src->textSrc.num_anchors; i++)
		    src->textSrc.anchors[i]->position += diff;
	    }
	}

	start = left;
	end = start + block->length;
	while (start < end) {
	    start = XawTextSourceScan(w, start, XawstEOL, XawsdRight, 1, True);
	    if (start <= end) {
		++lines;
		if (start == XawTextSourceScan(w, 0, XawstAll, XawsdRight, 1, True)) {
		    lines -= !_XawTextSourceNewLineAtEOF(w);
		    break;
		}
	    }
	}

	info.left = left;
	info.right = right;
	info.block = block;
	XtCallCallbacks(w, XtNpropertyCallback, &info);

	TellSourceChanged(src, left, right, block, lines);
	/* Call callbacks, we have changed the buffer */
	XtCallCallbacks(w, XtNcallback,
			(XtPointer)((long)src->textSrc.changed));
    }

#endif /* OLDXAW */
    return (error);
}

#ifndef OLDXAW
Bool
_XawTextSrcUndo(TextSrcObject src, XawTextPosition *insert_pos)
{
    static wchar_t wnull = 0;
    XawTextBlock block;
    XawTextUndoList *list, *nlist;
    XawTextUndoBuffer *l_state, *r_state;
    Boolean changed = src->textSrc.changed;

    if (!src->textSrc.enable_undo || !src->textSrc.undo->num_undo)
	return (False);

    list = src->textSrc.undo->pointer;

    if (src->textSrc.undo->dir == XawsdLeft) {
	l_state = list->right;
	r_state = list->left;
    }
    else {
	l_state = list->left;
	r_state = list->right;
    }

    if (src->textSrc.undo->l_no_change == l_state
	&& src->textSrc.undo->r_no_change == r_state)
	src->textSrc.changed = False;
    else
	src->textSrc.changed = True;

    block.firstPos = 0;
    block.length = r_state->length;
    block.ptr = r_state->buffer ? r_state->buffer : (char*)&wnull;
    block.format = r_state->format;

    src->textSrc.undo_state = True;
    if (XawTextSourceReplace((Widget)src, l_state->position, l_state->position
			     + l_state->length, &block) != XawEditDone) {
	src->textSrc.undo_state = False;
	src->textSrc.changed = changed;
	return (False);
    }
    src->textSrc.undo_state = False;

    ++l_state->refcount;
    ++r_state->refcount;
    nlist = XtNew(XawTextUndoList);
    nlist->left = l_state;
    nlist->right = r_state;
    nlist->undo = src->textSrc.undo->list;
    nlist->redo = NULL;

    if (list == src->textSrc.undo->list)
	src->textSrc.undo->end_mark = nlist;

    if (src->textSrc.undo->dir == XawsdLeft) {
	if (list->undo == NULL)
	    src->textSrc.undo->dir = XawsdRight;
	else
	    list = list->undo;
    }
    else {
	if (list->redo == NULL || list->redo == src->textSrc.undo->end_mark)
	    src->textSrc.undo->dir = XawsdLeft;
	else
	    list = list->redo;
    }
    *insert_pos = r_state->position + r_state->length;
    src->textSrc.undo->pointer = list;
    src->textSrc.undo->list->redo = nlist;
    src->textSrc.undo->list = nlist;
    src->textSrc.undo->merge = src->textSrc.undo->erase = 0;

    if (++src->textSrc.undo->num_list >= UNDO_DEPTH)
	UndoGC(src->textSrc.undo);

    return (True);
}

Bool
_XawTextSrcToggleUndo(TextSrcObject src)
{
    if (!src->textSrc.enable_undo || !src->textSrc.undo->num_undo)
	return (False);

    if (src->textSrc.undo->pointer != src->textSrc.undo->list) {
	if (src->textSrc.undo->dir == XawsdLeft) {
	    if (src->textSrc.undo->pointer->redo
		&& (src->textSrc.undo->pointer->redo
		    != src->textSrc.undo->end_mark)) {
		src->textSrc.undo->pointer = src->textSrc.undo->pointer->redo;
		src->textSrc.undo->dir = XawsdRight;
	    }
	}
	else {
	    if (src->textSrc.undo->pointer->undo
		&& (src->textSrc.undo->pointer != src->textSrc.undo->head)) {
		src->textSrc.undo->pointer = src->textSrc.undo->pointer->undo;
		src->textSrc.undo->dir = XawsdLeft;
	    }
	}
    }

    return (True);
}

static void
FreeUndoBuffer(XawTextUndo *undo)
{
    unsigned i;
    XawTextUndoList *head, *del;

    for (i = 0; i < undo->num_undo; i++) {
	if (undo->undo[i]->buffer && undo->undo[i]->buffer != SrcNL &&
	    undo->undo[i]->buffer != (char*)SrcWNL)
	    XtFree(undo->undo[i]->buffer);
	XtFree((char*)undo->undo[i]);
    }
    XtFree((char*)undo->undo);
    head = undo->head;

    del = head;
    while (head) {
	head = head->redo;
	XtFree((char*)del);
	del = head;
    }

    if (undo->l_save) {
	XtFree((char*)undo->l_save);
	undo->l_save = NULL;
    }
    if (undo->r_save) {
	XtFree((char*)undo->r_save);
	undo->r_save = NULL;
    }
    if (undo->u_save) {
	XtFree((char*)undo->u_save);
	undo->u_save = NULL;
    }

    undo->list = undo->pointer = undo->head = undo->end_mark = NULL;
    undo->l_no_change = undo->r_no_change = NULL;
    undo->undo = NULL;
    undo->dir = XawsdLeft;
    undo->num_undo = undo->num_list = undo->erase = undo->merge = 0;
}

static void
UndoGC(XawTextUndo *undo)
{
    unsigned i;
    XawTextUndoList *head = undo->head, *redo = head->redo;

    if (head == undo->pointer || head == undo->end_mark
	|| undo->l_no_change == NULL
	|| head->left == undo->l_no_change || head->right == undo->l_no_change)
      return;

    undo->head = redo;
    redo->undo = NULL;

    --head->left->refcount;
    if (--head->right->refcount == 0) {
	for (i = 0; i < undo->num_undo; i+= 2)
	    if (head->left == undo->undo[i] || head->left == undo->undo[i+1]) {
		if (head->left == undo->undo[i+1]) {
		    XawTextUndoBuffer *tmp = redo->left;

		    redo->left = redo->right;
		    redo->right = tmp;
		}
		if (head->left->buffer && head->left->buffer != SrcNL &&
		    head->left->buffer != (char*)SrcWNL)
		    XtFree(head->left->buffer);
		XtFree((char*)head->left);
		if (head->right->buffer && head->right->buffer != SrcNL &&
		    head->right->buffer != (char*)SrcWNL)
		    XtFree(head->right->buffer);
		XtFree((char*)head->right);

		undo->num_undo -= 2;
		memmove(&undo->undo[i], &undo->undo[i + 2],
			(undo->num_undo - i) * sizeof(XawTextUndoBuffer*));
		break;
	    }
    }
    XtFree((char*)head);
    --undo->num_list;
}
#endif /* OLDXAW */

/*
 * Function:
 *	XawTextSourceScan
 *
 * Parameters:
 *	w	 - TextSrc Object
 *	position - position to start scanning
 *	type	 - type of thing to scan for
 *	dir	 - direction to scan
 *	count	 - which occurance if this thing to search for
 *	include  - whether or not to include the character found in
 *		   the position that is returned.
 *
 * Description:
 *	Scans the text source for the number and type of item specified.
 *
 * Returns:
 *	The position of the text
 */
XawTextPosition
XawTextSourceScan(Widget w, XawTextPosition position,
#if NeedWidePrototypes
		  int type, int dir, int count, int include
#else
		  XawTextScanType type, XawTextScanDirection dir,
		  int count, Boolean include
#endif
)
{
    TextSrcObjectClass cclass = (TextSrcObjectClass)w->core.widget_class;

    return ((*cclass->textSrc_class.Scan)
	    (w, position, type, dir, count, include));
}

/*
 * Function:
 *	XawTextSourceSearch
 *
 * Parameters:
 *	w	 - TextSource Object
 *	position - position to start scanning
 *	dir	 - direction to scan
 *	text	 - the text block to search for.
 *
 * Returns:
 *	The position of the text we are searching for or XawTextSearchError.
 *
 * Description:
 *	Searchs the text source for the text block passed
 */
XawTextPosition
XawTextSourceSearch(Widget w, XawTextPosition position,
#if NeedWidePrototypes
		    int dir,
#else
		    XawTextScanDirection dir,
#endif
		    XawTextBlock *text)
{
    TextSrcObjectClass cclass = (TextSrcObjectClass)w->core.widget_class;

    return ((*cclass->textSrc_class.Search)(w, position, dir, text));
}

/*
 * Function:
 *	XawTextSourceConvertSelection
 *
 * Parameters:
 *	w	  - TextSrc object
 *	selection - current selection atom
 *	target	  - current target atom
 *	type	  - type to conver the selection to
 *	value	  - return value that has been converted
 *	length	  - ""
 *	format	  - format of the returned value
 *
 * Returns:
 *	True if the selection has been converted
 */
Boolean
XawTextSourceConvertSelection(Widget w, Atom *selection, Atom *target,
			      Atom *type, XtPointer *value,
			      unsigned long *length, int *format)
{
    TextSrcObjectClass cclass = (TextSrcObjectClass)w->core.widget_class;

    return((*cclass->textSrc_class.ConvertSelection)
	   (w, selection, target, type, value, length, format));
}

/*
 * Function:
 *	XawTextSourceSetSelection
 *
 * Parameters:
 *	w	  - TextSrc object
 *	left	  - bounds of the selection
 *	rigth	  - ""
 *	selection - selection atom
 *
 * Description:
 *	Allows special setting of the selection.
 */
void
XawTextSourceSetSelection(Widget w, XawTextPosition left,
			  XawTextPosition right, Atom selection)
{
    TextSrcObjectClass cclass = (TextSrcObjectClass)w->core.widget_class;

    (*cclass->textSrc_class.SetSelection)(w, left, right, selection);
}

/*
 * External Functions for Multi Text
 */
/*
 * TextFormat():
 *	returns the format of text: FMT8BIT or FMTWIDE
 */
XrmQuark
_XawTextFormat(TextWidget tw)
{
    return (((TextSrcObject)(tw->text.source))->textSrc.text_format);
}

/* _XawTextWCToMB():
 *	Convert the wchar string to external encoding
 *	The caller is responsible for freeing both the source and ret string
 *
 *	wstr	   - source wchar string
 * len_in_out - lengh of string.
 *		     As In, length of source wchar string, measured in wchar
 *		     As Out, length of returned string
 */
char *
_XawTextWCToMB(Display *d, wchar_t *wstr, int *len_in_out)
{
    XTextProperty textprop;

    if (XwcTextListToTextProperty(d, (wchar_t**)&wstr, 1,
				XTextStyle, &textprop) < Success) {
	XtWarningMsg("convertError", "textSource", "XawError",
		     "Non-character code(s) in buffer.", NULL, NULL);
	*len_in_out = 0;
	return (NULL);
    }
    *len_in_out = textprop.nitems;

    return ((char *)textprop.value);
}

/* _XawTextMBToWC():
 *	Convert the string to internal processing codeset WC.
 *   The caller is responsible for freeing both the source and ret string.
 *
 *	str	   - source string
 *	len_in_out - lengh of string
 *		     As In, it is length of source string
 *		     As Out, it is length of returned string, measured in wchar
 */
wchar_t *
_XawTextMBToWC(Display *d, char *str, int *len_in_out)
{
    XTextProperty textprop;
    char *buf;
    wchar_t **wlist, *wstr;
    int count;

    if (*len_in_out == 0)
	return (NULL);

    buf = XtMalloc(*len_in_out + 1);

    strncpy(buf, str, *len_in_out);
    *(buf + *len_in_out) = '\0';
    if (XmbTextListToTextProperty(d, &buf, 1, XTextStyle, &textprop) != Success) {
	XtWarningMsg("convertError", "textSource", "XawError",
		     "No Memory, or Locale not supported.", NULL, NULL);
	XtFree(buf);
	*len_in_out = 0;
	return (NULL);
    }

    XtFree(buf);
    if (XwcTextPropertyToTextList(d, &textprop,
				  (wchar_t***)&wlist, &count) != Success) {
	XtWarningMsg("convertError", "multiSourceCreate", "XawError",
		     "Non-character code(s) in source.", NULL, NULL);
	*len_in_out = 0;
	return (NULL);
    }
    wstr = wlist[0];
    *len_in_out = wcslen(wstr);
    XtFree((XtPointer)wlist);

    return (wstr);
}

#ifndef OLDXAW
static int
qcmp_anchors(_Xconst void *left, _Xconst void *right)
{
    return ((*(XawTextAnchor**)left)->position -
	    (*(XawTextAnchor**)right)->position);
}

XawTextAnchor *
XawTextSourceAddAnchor(Widget w, XawTextPosition position)
{
    TextSrcObject src = (TextSrcObject)w;
    XawTextAnchor *anchor, *panchor;

    if ((panchor = XawTextSourceFindAnchor(w, position)) != NULL) {
	XawTextEntity *pentity, *entity;

	if (position - panchor->position < ANCHORS_DIST)
	    return (panchor);

	if (panchor->cache && panchor->position + panchor->cache->offset +
	    panchor->cache->length < position)
	    pentity = entity = panchor->cache;
	else
	    pentity = entity = panchor->entities;

	while (entity && panchor->position + entity->offset +
	       entity->length < position) {
	    pentity = entity;
	    entity = entity->next;
	}
	if (entity) {
	    XawTextPosition diff;

	    if (panchor->position + entity->offset < position)
		position = panchor->position + entity->offset;

	    if (position == panchor->position)
		return (panchor);

	    anchor = XtNew(XawTextAnchor);
	    diff = position - panchor->position;

	    panchor->cache = NULL;
	    anchor->entities = entity;
	    if (pentity != entity)
		pentity->next = NULL;
	    else
		panchor->entities = NULL;
	    while (entity) {
		entity->offset -= diff;
		entity = entity->next;
	    }
	}
	else {
	    anchor = XtNew(XawTextAnchor);
	    anchor->entities = NULL;
	}
    }
    else {
	anchor = XtNew(XawTextAnchor);
	anchor->entities = NULL;
    }

    anchor->position = position;
    anchor->cache = NULL;

    src->textSrc.anchors = (XawTextAnchor**)
	XtRealloc((XtPointer)src->textSrc.anchors, sizeof(XawTextAnchor*) *
		  (src->textSrc.num_anchors + 1));
    src->textSrc.anchors[src->textSrc.num_anchors++] = anchor;
    qsort((void*)src->textSrc.anchors, src->textSrc.num_anchors,
	  sizeof(XawTextAnchor*), qcmp_anchors);

    return (anchor);
}

XawTextAnchor *
XawTextSourceFindAnchor(Widget w, XawTextPosition position)
{
    TextSrcObject src = (TextSrcObject)w;
    int i = 0, left, right, nmemb = src->textSrc.num_anchors;
    XawTextAnchor *anchor, **anchors = src->textSrc.anchors;

    left = 0;
    right = nmemb - 1;
    while (left <= right) {
	anchor = anchors[i = (left + right) >> 1];
	if (anchor->position == position)
	    return (anchor);
	else if (position < anchor->position)
	    right = i - 1;
	else
	    left = i + 1;
    }

    if (nmemb)
	return (right < 0 ? anchors[0] : anchors[right]);

    return (NULL);
}

Bool
XawTextSourceAnchorAndEntity(Widget w, XawTextPosition position,
			     XawTextAnchor **anchor_return,
			     XawTextEntity **entity_return)
{
    XawTextAnchor *anchor = XawTextSourceFindAnchor(w, position);
    XawTextEntity *pentity, *entity;
    XawTextPosition offset;
    Bool next_anchor = True, retval = False;

    if (anchor->cache && anchor->position + anchor->cache->offset +
	anchor->cache->length <= position)
	pentity = entity = anchor->cache;
    else
	pentity = entity = anchor->entities;
    while (entity) {
	offset = anchor->position + entity->offset;

	if (offset > position) {
	    retval = next_anchor = False;
	    break;
	}
	if (offset + entity->length > position) {
	    retval = True;
	    next_anchor = False;
	    break;
	}
	pentity = entity;
	entity = entity->next;
    }

    if (next_anchor) {
	*anchor_return = anchor = XawTextSourceNextAnchor(w, anchor);
	*entity_return = anchor ? anchor->entities : NULL;
    }
    else {
	*anchor_return = anchor;
	*entity_return = retval ? entity : pentity;
    }

    if (*anchor_return)
	(*anchor_return)->cache = *entity_return;

    return (retval);
}

XawTextAnchor *
XawTextSourceNextAnchor(Widget w, XawTextAnchor *anchor)
{
    int i;
    TextSrcObject src = (TextSrcObject)w;

    for (i = 0; i < src->textSrc.num_anchors - 1; i++)
	if (src->textSrc.anchors[i] == anchor)
	    return (src->textSrc.anchors[i + 1]);

    return (NULL);
}

XawTextAnchor *
XawTextSourcePrevAnchor(Widget w, XawTextAnchor *anchor)
{
    int i;
    TextSrcObject src = (TextSrcObject)w;

    for (i = src->textSrc.num_anchors - 1; i > 0; i--)
	if (src->textSrc.anchors[i] == anchor)
	    return (src->textSrc.anchors[i - 1]);

    return (NULL);
}

XawTextAnchor *
XawTextSourceRemoveAnchor(Widget w, XawTextAnchor *anchor)
{
    int i;
    TextSrcObject src = (TextSrcObject)w;

    for (i = 0; i < src->textSrc.num_anchors; i++)
	if (src->textSrc.anchors[i] == anchor)
	    break;

    if (i == 0)
	return (src->textSrc.num_anchors > 1 ? src->textSrc.anchors[1] : NULL);

    if (i < src->textSrc.num_anchors) {
	XtFree((XtPointer)anchor);
	if (i < --src->textSrc.num_anchors) {
	    memmove(&src->textSrc.anchors[i],
		    &src->textSrc.anchors[i + 1],
		    (src->textSrc.num_anchors - i) *
		    sizeof(XawTextAnchor*));

	    return (src->textSrc.anchors[i]);
	}
    }

    return (NULL);
}

XawTextEntity *
XawTextSourceAddEntity(Widget w, int type, int flags, XtPointer data,
		       XawTextPosition position, Cardinal length,
		       XrmQuark property)
{
    XawTextAnchor *next, *anchor = _XawTextSourceFindAnchor(w, position);
    XawTextEntity *entity, *eprev;

    /* There is no support for zero length entities for now */
    if (length == 0)
	return (NULL);

    if (anchor->cache && anchor->position + anchor->cache->offset +
	anchor->cache->length <= position)
	eprev = entity = anchor->cache;
    else
	eprev = entity = anchor->entities;

    while (entity && anchor->position + entity->offset + entity->length <=
	   position) {
	eprev = entity;
	entity = entity->next;
    }
    if (entity && anchor->position + entity->offset < position + length) {
	fprintf(stderr, "Cannot (yet) add more than one entity to same region.\n");
	return (NULL);
    }

    next = XawTextSourceFindAnchor(w, position + length);
    if (next && next != anchor) {
	if ((entity = next->entities) != NULL) {
	    if (next->position + entity->offset < position + length) {
		fprintf(stderr, "Cannot (yet) add more than one entity to same region.\n");
		return (NULL);
	    }
	}
	if (position + length > next->position) {
	    XawTextPosition diff = position + length - next->position;

	    next->position += diff;
	    entity = next->entities;
	    while (entity) {
		entity->offset -= diff;
		entity = entity->next;
	    }
	    entity = anchor->entities;
	    while (entity && entity->offset < 0)
		entity = entity->next;
	    if (entity && entity->offset < 0) {
		if (eprev)
		    eprev->next = next->entities;
		else
		    anchor->entities = next->entities;
		if ((next->entities = entity->next) == NULL)
		    (void)XawTextSourceRemoveAnchor(w, next);
		entity->next = NULL;

		return (XawTextSourceAddEntity(w, type, flags, data, position,
					       length, property));
	    }
	}
    }

    /* Automatically join sequential entities if possible */
    if (eprev &&
	anchor->position + eprev->offset + eprev->length == position &&
	eprev->property == property && eprev->type == type &&
	eprev->flags == flags && eprev->data == data) {
	eprev->length += length;
	return (eprev);
    }

    entity = XtNew(XawTextEntity);
    entity->type = type;
    entity->flags = flags;
    entity->data = data;
    entity->offset = position - anchor->position;
    entity->length = length;
    entity->property = property;

    if (eprev == NULL) {
	anchor->entities = entity;
	entity->next = NULL;
	anchor->cache = NULL;
    }
    else if (eprev->offset > entity->offset) {
	anchor->cache = NULL;
	anchor->entities = entity;
	entity->next = eprev;
    }
    else {
	anchor->cache = eprev;
	entity->next = eprev->next;
	eprev->next = entity;
    }

    return (entity);
}

void
XawTextSourceClearEntities(Widget w, XawTextPosition left, XawTextPosition right)
{
    XawTextAnchor *anchor = XawTextSourceFindAnchor(w, left);
    XawTextEntity *entity, *eprev, *enext;
    XawTextPosition offset;
    int length;

    while (anchor && anchor->entities == NULL)
	anchor = XawTextSourceRemoveAnchor(w, anchor);

    if (anchor == NULL || left >= right)
	return;

    if (anchor->cache && anchor->position + anchor->cache->offset +
	anchor->cache->length < left)
	eprev = entity = anchor->cache;
    else
	eprev = entity = anchor->entities;

    /* find first entity before left position */
    while (anchor->position + entity->offset + entity->length < left) {
	eprev = entity;
	if ((entity = entity->next) == NULL) {
	    if ((anchor = XawTextSourceNextAnchor(w, anchor)) == NULL)
		return;
	    if ((eprev = entity = anchor->entities) == NULL) {
		fprintf(stderr, "Bad anchor found!\n");
		return;
	    }
	}
    }

    offset = anchor->position + entity->offset;
    if (offset <= left) {
	length = XawMin(entity->length, left - offset);

	if (length <= 0) {
	    enext = entity->next;
	    eprev->next = enext;
	    XtFree((XtPointer)entity);
	    anchor->cache = NULL;
	    if (entity == anchor->entities) {
		eprev = NULL;
		if ((anchor->entities = enext) == NULL) {
		    if ((anchor = XawTextSourceRemoveAnchor(w, anchor)) == NULL)
			return;
		    entity = anchor->entities;
		}
		else
		    entity = enext;
	    }
	    else
		entity = enext;
	}
	else {
	    entity->length = length;
	    eprev = entity;
	    entity = entity->next;
	}
    }

    /* clean everything until right position is reached */
    while (anchor) {
	while (entity) {
	    offset = anchor->position + entity->offset + entity->length;

	    if (offset > right) {
		anchor->cache = NULL;
		entity->offset = XawMax(entity->offset, right - anchor->position);
		entity->length = XawMin(entity->length, offset - right);
		return;
	    }

	    enext = entity->next;
	    if (eprev)
		eprev->next = enext;
	    XtFree((XtPointer)entity);
	    if (entity == anchor->entities) {
		eprev = anchor->cache = NULL;
		if ((anchor->entities = enext) == NULL) {
		    if ((anchor = XawTextSourceRemoveAnchor(w, anchor)) == NULL)
			return;
		    entity = anchor->entities;
		    continue;
		}
	    }
	    entity = enext;
	}
	if (anchor)
	    anchor->cache = NULL;
	if ((anchor = XawTextSourceNextAnchor(w, anchor)) != NULL)
	    entity = anchor->entities;
	eprev = NULL;
    }
}

/* checks the anchors up to position, and create an appropriate anchor
 * at position, if required.
 */
XawTextAnchor *
_XawTextSourceFindAnchor(Widget w, XawTextPosition position)
{
    XawTextAnchor *anchor;

    anchor = XawTextSourceFindAnchor(w, position);

    position -= position % ANCHORS_DIST;

    if (position - anchor->position >= ANCHORS_DIST)
	return (XawTextSourceAddAnchor(w, position));

    return (anchor);
}
#endif


Baltimore 2010 - Erik Larsen has a super weird grip.
Erik Larsen has this really disturbing grip, which I mistakingly call a "Very Bizarre Style" but he was quick to bark back at me and say "Distinctive Grip!" It's really strange. Almost hypnotic, you can't take your eyes off of it. Hell, you even forget for a moment that he's doing a sketch of his character Savage Dragon for the CBLDF charity auction your running.
This was a very funny bit.
Get your Savage Dragon on HERE!
Again, what should I ask Image co-founder? How do you feel about getting closer to Dave and Gerhard's record? Not what was it like leaving Marvel or creating Image - nah, lets talk about doing your book regularly every month. Much more exciting!
Erik Discusses Image United which has come and gone since this interview.
Oh hey - It's Erik Larsen. One of the founders of IMAGE COMICS. What should I ask him? How about when he's going to beat Dave Sim's record for 300 consecutive issues… yeah - that's the best question I could possibly ask one of the founding members of IMAGE COMICS… yeah. Not anything about Leaving Marvel and being one of the six original founder for Image Comics.... Nah, that would be a total waste of air time, right?


There are a variety of easy, exciting events you can host at your home, local bar, or by tailgating as you cheer on your favorite team!
Learn more about getting coverage for your event.
Fraternity and sorority involvement with Coach To Cure MD is a wonderful way for students to demonstrate their commitment to community, their college, and that values that are associated with their organization.
You can reach out to people one of two ways: via an online, email campaign or an old fashioned letter. Either way, we have provided you with the tools you need to get this project started.
Find out now if your team is participating.


text:
Betting for a game has been around for a number of decades. But , it had been from the 20th century that it had been recognized as being a expert game by leading international athletics leagues. It gained popularity in the USA at the late 90s, when professional footballers started initially to engage in the game in international tournaments. Gambling as a game has received a lot of followers as then, especially as the World Cup, held in Germany in 1998.
It's of French origin and features standard credit cards plus a exclusive, specially created table employed for your own betting game just. While traditional players regularly discover it in gambling casinos, then there are some European casinos that still hold the game from their establishments. The principles of this game are usually simple, with every player by means of a hand of five cards, also exactly the same five on the desk. The match also utilizes red and black counters, which could be utilized to signify points onto the match board along with the card table.
Gambling for a game is played on a table with just two seats facing eachother at the gaming table. Two other players sit behind the chairs opposite the two gambling players. The aim of the game is to allow people to find the maximum number of things by using card palms and special chips which can be understood as"trente etquale." Every participant can use any chips that he has at his disposal, but for that banker's chips. All gambling matches, actually card matches, must comply by the laws of the country in which they are being playedwith.
Traditionally, gambling games use four different sorts of card decks: black, crimson, sevens, and also clubs. These will be the forms which are most commonly linked to the term"gambling." However, in Italy there was really a favorite card game named shrub nel Centro nazione. Traditionally the name of the card match would be"centro nazione" but as lots of people have confused the 2 games, today it can be referred to as "nazione."
Traditionally, if there's really a reduce card which reflects either the dealer or the bud. It is thought to be extremely important to own the ideal tone. Black always gets the maximum value, Thus if you gamble on a shameful guarantee, this means that you are gambling the total best quantity of money that you can handle. If you have a high low divide, then your cards that are dealt with you'll be divided that one half is red and one other half is shameful.
Roulette is played with a desk that is coated with thick cloth, usually felt, and it is laid across a wooden frame. The purpose is for that player to make a series of small, even bets by managing a single hand . At an identical time frame that they try going to on the ball, which will eventually stop in a specific location. After the chunk ceases, the other hand of cards are dealt and the approach is repeated. By the end of the guarantee, just one card from every pile can keep on being and it's the player's turn to telephone. If any additional cards have been revealed, the last hands of cards are dealt and the brand new form begins.
After playing this card game at the roulette bars in Italy, players are by and large provided with black and red serving cards to use for their gambling. Players aren't allowed to reveal their cards before last bet has been built. In years past the cards were rarely hand-picked from such Italian betting pubs, but in recent times, quite a few players have started choosing their cards and the dealer can choose the hand that they feel provides them the best likelihood of winning. Hand choice is an integral part of the policies of the card sport. Now, most reputable online casinos have adopted policies similar to those found in montecarlo and so are now offering gamers the opportunity to engage in the traditional game utilizing authentic casino-quality cards in a safe, controlled atmosphere.
A normal guideline is that the trader should deal 10 factors into the left, counting from one to twenty eight. When the flop comes, the trader will probably rely out of the right, a few from left, etc, counting backward. This really is called the flop. The dealer will then offer five cards to the left, then followed closely by 4 cards into the best. If there is a clear bet produced, the dealer could not disclose each one the cards, based on the rules.
[{:section_type=>"rich_text", :content=>"Betting for a game has been around for a number of decades. But , it had been from the 20th century that it had been recognized as being a expert game by leading international athletics leagues. It gained popularity in the USA at the late 90s, when professional footballers started initially to engage in the game in international tournaments. Gambling as a game has received a lot of followers as then, especially as the World Cup, held in Germany in 1998.

It's of French origin and features standard credit cards plus a exclusive, specially created table employed for your own betting game just. While traditional players regularly discover it in gambling casinos, then there are some European casinos that still hold the game from their establishments. The principles of this game are usually simple, with every player by means of a hand of five cards, also exactly the same five on the desk. The match also utilizes red and black counters, which could be utilized to signify points onto the match board along with the card table.

Gambling for a game is played on a table with just two seats facing eachother at the gaming table. Two other players sit behind the chairs opposite the two gambling players. The aim of the game is to allow people to find the maximum number of things by using card palms and special chips which can be understood as\"trente etquale.\" Every participant can use any chips that he has at his disposal, but for that banker's chips. All gambling matches, actually card matches, must comply by the laws of the country in which they are being playedwith.

Traditionally, gambling games use four different sorts of card decks: black, crimson, sevens, and also clubs. These will be the forms which are most commonly linked to the term\"gambling.\" However, in Italy there was really a favorite card game named shrub nel Centro nazione. Traditionally the name of the card match would be\"centro nazione\" but as lots of people have confused the 2 games, today it can be referred to as \"nazione.\"

Traditionally, if there's really a reduce card which reflects either the dealer or the bud. It is thought to be extremely important to own the ideal tone. Black always gets the maximum value, Thus if you gamble on a shameful guarantee, this means that you are gambling the total best quantity of money that you can handle. If you have a high low divide, then your cards that are dealt with you'll be divided that one half is red and one other half is shameful.

Roulette is played with a desk that is coated with thick cloth, usually felt, and it is laid across a wooden frame. The purpose is for that player to make a series of small, even bets by managing a single hand . At an identical time frame that they try going to on the ball, which will eventually stop in a specific location. After the chunk ceases, the other hand of cards are dealt and the approach is repeated. By the end of the guarantee, just one card from every pile can keep on being and it's the player's turn to telephone. If any additional cards have been revealed, the last hands of cards are dealt and the brand new form begins.

After playing this card game at the roulette bars in Italy, players are by and large provided with black and red serving cards to use for their gambling. Players aren't allowed to reveal their cards before last bet has been built. In years past the cards were rarely hand-picked from such Italian betting pubs, but in recent times, quite a few players have started choosing their cards and the dealer can choose the hand that they feel provides them the best likelihood of winning. Hand choice is an integral part of the policies of the card sport. Now, most reputable online casinos have adopted policies similar to those found in montecarlo and so are now offering gamers the opportunity to engage in the traditional game utilizing authentic casino-quality cards in a safe, controlled atmosphere.

A normal guideline is that the trader should deal 10 factors into the left, counting from one to twenty eight. When the flop comes, the trader will probably rely out of the right, a few from left, etc, counting backward. This really is called the flop. The dealer will then offer five cards to the left, then followed closely by 4 cards into the best. If there is a clear bet produced, the dealer could not disclose each one the cards, based on the rules."}]

redpajama_set_name: RedPajamaCommonCrawl


text:
← easter tribbles and subversive peeps
romper room airlines →
Hillary Clinton has no shame
March 24, 2008 by lestro 2 Comments
So apparently Hillary Clinton "misspoke" about the whole running-from-snipers thing in Bosnia. Which I suppose is Clintonspeak for "lied through her ass":
During a speech last Monday, she said of the trip: "I remember landing under sniper fire. There was supposed to be some kind of a greeting ceremony at the airport, but instead we just ran with our heads down to get into the vehicles to get to our base."
According to an AP story at the time, Clinton was placed under no extraordinary risks on that trip. And one of her companions on it, comedian Sinbad, told The Washington Post he has no recollection either of the threat or reality of gunfire.
But wait, there's more. The statements she made last week also contradict what she said in her book:
Clinton wrote: "Due to reports of snipers in the hills around the airstrip, we were forced to cut short an event on the tarmac with local children, though we did have time to meet them and their teachers and to learn how hard they had worked during the war to continue classes in any safe spot they could find."
So, caught in this obvious lie, the Clinton campaign did what they do best and tried to obfuscate and distract:
"That is what she wrote in her book," Wolfson said. "That is what she has said many, many times and on one occasion she misspoke."
yeah, just this once.
except it wasn't.
Another "misspoke," I'm sure, but according to the Washington Post's fact-checker, the Clinton campaign has been developing this little bit of propaganda for some time now:
Last week was not the first time that Clinton talked about sniper fire in Bosnia. She has provided various different versions of the incident along the campaign trail and in her autobiography, Living History.
See, for example, this New York Times account of a campaign rally in Waco, Tex., on February 29, at which Clinton said that the welcoming ceremony had to be "moved inside" a Tuzla airport building "because of sniper fire." She made a similar statement in Dubuque, Iowa, back in December.
No, it was not on purpose to make her seem like she has more experience than she does…
A spokesman for rival Barack Obama's campaign questioned whether Clinton misspoke, saying her comments came in what appeared to be prepared remarks for her speech on Iraq.
The Obama campaign statement contained a link to a text of Clinton's speech that is still posted on her campaign Web site including the account of running to the cars.
So she didn't just misspeak, it was written. It was not her memory, but an obvious plant by the campaign.
and it wasn't just the once or three times. After the event she spoke more about it:
Just after her speech last Monday, she reaffirmed the account of running from the plane to the cars when she was asked about it by reporters at a news conference. She said was moved into the cockpit of the C-17 cargo plane as they were flying into Tuzla Air Base.
"Everyone else was told to sit on their bulletproof vests," Clinton told reporters. "And we came in, in an evasive maneuver. … There was no greeting ceremony, and we basically were told to run to our cars. Now, that is what happened."
"That is what happened"?
Actually, no it's not. Does this look like running to her car to you?
Because unless that's Natalie Portman (and it might be), I am prettty sure that is a little girl and not a sniper.
Let's not forget what Sinbad, one of the celebrities that accompnied the first lady on her trip, had to say about the visit:
Sinbad, who provided entertainment on the trip along with singer Sheryl Crow, said the "scariest" part was deciding where to eat. As he told Mary Ann Akers of washingtonpost.com, "I think the only 'red phone' moment was 'Do we eat here or at the next place?' " He questioned the premise behind the Clinton version of events. "What kind of president would say 'Hey, man, I can't go 'cause I might get shot, so I'm going to send my wife. Oh, and take a guitar player and a comedian with you'?"
He may not be funny, but he's not wrong.
But besides the outright lies and distortions about the trip, here's the real kicker, the real proof that the Clinton Campaign is nothing but a bunch of power-hungry scum sucker screwheads running the Rove playbook page by page:
"This is something that the Obama campaign wants to push cause they have nothing positive to say about their candidate," Wolfson said Monday in the conference call.
Right. Nothing positive at all. How about the endorsement by someone who worked for the Clintons but realized their campaign was destructive and mean? Or that Obama's speech on race is being heralded as one of the best political speeches ever?
Or how about the simple fact that their candidate is kicking your candidate's ass?
If all of this sounds familiar, it is probably because this is exactly what we have seen the Republicans do for the past eight years: claim your opponent is attacking you simply for pointing out your half-truths and lies.
Of course, I suppose that depends on what your definition of the word "lie" is.
Filed under by lestro, clinton mafia, elections, history, video Tagged with 2008 election, Bosnia, clinton campaign, hillary clinton, misspoke, politics, Sinbad, sniper fire
2 Responses to Hillary Clinton has no shame
Jeff Wartman says:
She didn't make a "misstatement", she flat out lied about nearly every single detail of the trip.
John fitness personal new orleans says:
What person would let his wife and 16 year old daughter enter a war zone and be exposed to sniper fire? No one would. You think you would remember running from sniper fire. She said it the first time she misspoke in 12 years; that might come back to haunt Hillary "Mount Everest-Not" Clinton.
There were 4000 armed men, Navy SEALS, Secret Service, 40 tanks, and attack helicopters overhead. As one military man said, "There was nobody coughing the day she showed up". It is insulting to those protecting her.