Edit

IABSD.fr/xenocara/lib/libXaw/src/AsciiSrc.c

Branch :

  • Show log

    Commit

  • Author : matthieu
    Date : 2024-07-09 09:37:06
    Hash : 34750499
    Message : update libXaw to version 1.0.16

  • lib/libXaw/src/AsciiSrc.c
  • /*
    
    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.
    
    */
    
    /*
     * AsciiSrc.c - AsciiSrc object. (For use with the text widget).
     *
     */
    
    #ifdef HAVE_CONFIG_H
    #include <config.h>
    #endif
    #include <stdio.h>
    #include <stdlib.h>
    #include <ctype.h>
    #include <errno.h>
    #include <X11/IntrinsicP.h>
    #include <X11/StringDefs.h>
    #include <X11/Xos.h>
    #include <X11/Xfuncs.h>
    #include <X11/Xmu/CharSet.h>
    #include <X11/Xmu/Misc.h>
    #include <X11/Xaw/XawInit.h>
    #include <X11/Xaw/AsciiSrcP.h>
    #include <X11/Xaw/MultiSrcP.h>
    #ifndef OLDXAW
    #include <X11/Xaw/TextSinkP.h>
    #include <X11/Xaw/AsciiSinkP.h>
    #endif
    #include "Private.h"
    
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    
    #ifndef O_CLOEXEC
    #define O_CLOEXEC 0
    #endif
    
    #if (defined(ASCII_STRING) || defined(ASCII_DISK))
    #include <X11/Xaw/AsciiText.h>		/* for Widget Classes */
    #endif
    
    #define MAGIC_VALUE	((XawTextPosition)-1)
    #define streq(a, b)	(strcmp((a), (b)) == 0)
    
    /*
     * Class Methods
     */
    static void XawAsciiSrcClassInitialize(void);
    static void XawAsciiSrcDestroy(Widget);
    static void XawAsciiSrcGetValuesHook(Widget, ArgList, Cardinal*);
    static void XawAsciiSrcInitialize(Widget, Widget, ArgList, Cardinal*);
    static Boolean XawAsciiSrcSetValues(Widget, Widget, Widget,
    				    ArgList, Cardinal*);
    static XawTextPosition ReadText(Widget, XawTextPosition, XawTextBlock*, int);
    static int ReplaceText(Widget, XawTextPosition, XawTextPosition,
    		       XawTextBlock*);
    static XawTextPosition Scan(Widget, XawTextPosition, XawTextScanType,
    			    XawTextScanDirection, int, Bool);
    static XawTextPosition Search(Widget, XawTextPosition, XawTextScanDirection,
    			      XawTextBlock*);
    
    /*
     * Prototypes
     */
    static Piece *AllocNewPiece(AsciiSrcObject, Piece*);
    static void BreakPiece(AsciiSrcObject, Piece*);
    static Boolean CvtAsciiTypeToString(Display*, XrmValuePtr, Cardinal*,
    				    XrmValuePtr, XrmValuePtr, XtPointer*);
    static void CvtStringToAsciiType(XrmValuePtr, Cardinal*,
    				 XrmValuePtr, XrmValuePtr);
    static Piece *FindPiece(AsciiSrcObject, XawTextPosition, XawTextPosition*);
    static void FreeAllPieces(AsciiSrcObject);
    static FILE *InitStringOrFile(AsciiSrcObject, Bool);
    static void LoadPieces(AsciiSrcObject, FILE*, char*);
    static void RemoveOldStringOrFile(AsciiSrcObject, Bool);
    static void RemovePiece(AsciiSrcObject, Piece*);
    static char * StorePiecesInString(AsciiSrcObject);
    static Bool WriteToFile(String, String, unsigned);
    static Bool WritePiecesToFile(AsciiSrcObject, String);
    static void GetDefaultPieceSize(Widget, int, XrmValue*);
    
    /*
     * More Prototypes
     */
    #ifdef ASCII_DISK
    Widget XawAsciiDiskSourceCreate(Widget, ArgList, Cardinal);
    #endif
    #ifdef ASCII_STRING
    Widget XawStringSourceCreate(Widget, ArgList, Cardinal);
    void XawTextSetLastPos(Widget, XawTextPosition);
    #endif
    
    /*
     * Initialization
     */
    #define offset(field) XtOffsetOf(AsciiSrcRec, ascii_src.field)
    static XtResource resources[] = {
      {
        XtNstring,
        XtCString,
        XtRString,
        sizeof(char*),
        offset(string),
        XtRString,
        NULL
      },
      {
        XtNtype,
        XtCType,
        XtRAsciiType,
        sizeof(XawAsciiType),
        offset(type),
        XtRImmediate,
        (XtPointer)XawAsciiString
      },
      {
        XtNdataCompression,
        XtCDataCompression,
        XtRBoolean,
        sizeof(Boolean),
        offset(data_compression),
        XtRImmediate,
        (XtPointer)True
      },
      {
        XtNpieceSize,
        XtCPieceSize,
        XtRInt,
        sizeof(XawTextPosition),
        offset(piece_size),
        XtRCallProc,
        (XtPointer)GetDefaultPieceSize
      },
    #ifdef OLDXAW
      {
        XtNcallback,
        XtCCallback,
        XtRCallback,
        sizeof(XtPointer),
        offset(callback),
        XtRCallback,
        (XtPointer)NULL
      },
    #endif
      {
        XtNuseStringInPlace,
        XtCUseStringInPlace,
        XtRBoolean,
        sizeof(Boolean),
        offset(use_string_in_place),
        XtRImmediate,
        (XtPointer)False
      },
      {
        XtNlength,
        XtCLength,
        XtRInt,
        sizeof(int),
        offset(ascii_length),
        XtRImmediate,
        (XtPointer)MAGIC_VALUE
      },
    #ifdef ASCII_DISK
      {
        XtNfile,
        XtCFile,
        XtRString,
        sizeof(String),
        offset(filename),
        XtRString,
        NULL
      },
    #endif /* ASCII_DISK */
    };
    #undef offset
    
    
    #define Superclass	(&textSrcClassRec)
    AsciiSrcClassRec asciiSrcClassRec = {
      /* object */
      {
        (WidgetClass)Superclass,		/* superclass */
        "AsciiSrc",				/* class_name */
        sizeof(AsciiSrcRec),		/* widget_size */
        XawAsciiSrcClassInitialize,		/* class_initialize */
        NULL,				/* class_part_initialize */
        False,				/* class_inited */
        XawAsciiSrcInitialize,		/* 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 */
        XawAsciiSrcDestroy,			/* destroy */
        NULL,				/* resize */
        NULL,				/* expose */
        XawAsciiSrcSetValues,		/* set_values */
        NULL,				/* set_values_hook */
        NULL,				/* set_values_almost */
        XawAsciiSrcGetValuesHook,		/* get_values_hook */
        NULL,				/* accept_focus */
        XtVersion,				/* version */
        NULL,				/* callback_private */
        NULL,				/* tm_table */
        NULL,				/* query_geometry */
        NULL,				/* display_accelerator */
        NULL,				/* extension */
      },
      /* text_src */
      {
        ReadText,				/* Read */
        ReplaceText,			/* Replace */
        Scan,				/* Scan */
        Search,				/* Search */
        XtInheritSetSelection,		/* SetSelection */
        XtInheritConvertSelection,		/* ConvertSelection */
    #ifndef OLDXAW
        NULL,
    #endif
      },
      /* ascii_src */
      {
        NULL,				/* extension */
      },
    };
    
    WidgetClass asciiSrcObjectClass = (WidgetClass)&asciiSrcClassRec;
    
    static XrmQuark Qstring, Qfile;
    
    /*
     * Implementation
     */
    /*
     * Function:
     *	XawAsciiSrcClassInitialize()
     *
     * Description:
     *	  Initializes the asciiSrcObjectClass and install the converters for
     *	AsciiType <-> String.
     */
    static void
    XawAsciiSrcClassInitialize(void)
    {
        XawInitializeWidgetSet();
        Qstring = XrmPermStringToQuark(XtEstring);
        Qfile = XrmPermStringToQuark(XtEfile);
        XtAddConverter(XtRString, XtRAsciiType, CvtStringToAsciiType, NULL, 0);
        XtSetTypeConverter(XtRAsciiType, XtRString, CvtAsciiTypeToString,
    		       NULL, 0, XtCacheNone, NULL);
    }
    
    /*
     * Function:
     *	XawAsciiSrcInitialize
     *
     * Parameters:
     *	request	 - widget requested by the argument list
     *	cnew	 - new widget with both resource and non resource values
     *	args	 - (unused)
     *	num_args - (unused)
     *
     * Description:
     *	Initializes the ascii src object.
     */
    /*ARGSUSED*/
    static void
    XawAsciiSrcInitialize(Widget request _X_UNUSED, Widget cnew,
    		      ArgList args _X_UNUSED, Cardinal *num_args _X_UNUSED)
    {
        AsciiSrcObject src = (AsciiSrcObject)cnew;
        FILE *file;
    
        /*
         * Set correct flags (override resources) depending upon widget class
         */
        src->text_src.text_format = (XrmQuark)XawFmt8Bit;
    
    #ifdef ASCII_DISK
        if (XtIsSubclass(XtParent(cnew), asciiDiskWidgetClass)) {
    	src->ascii_src.type = XawAsciiFile;
    	src->ascii_src.string = src->ascii_src.filename;
        }
    #endif
    
    #ifdef ASCII_STRING
        if (XtIsSubclass(XtParent(cnew), asciiStringWidgetClass)) {
    	src->ascii_src.use_string_in_place = True;
    	src->ascii_src.type = XawAsciiString;
        }
    #endif
    
    #ifdef OLDXAW
        src->ascii_src.changes = False;
    #else
        src->text_src.changed = False;
    #endif
        src->ascii_src.allocated_string = False;
    
        if (src->ascii_src.use_string_in_place && src->ascii_src.string == NULL)
    	src->ascii_src.use_string_in_place = False;
    
        file = InitStringOrFile(src, src->ascii_src.type == XawAsciiFile);
        LoadPieces(src, file, NULL);
    
        if (file != NULL)
    	fclose(file);
    }
    
    /*
     * Function:
     *	ReadText
     *
     * Parameters:
     *	w	- AsciiSource widget
     *	pos	- position of the text to retrieve.
     *	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.
     */
    static XawTextPosition
    ReadText(Widget w, XawTextPosition pos, XawTextBlock *text, int length)
    {
        AsciiSrcObject src = (AsciiSrcObject)w;
        XawTextPosition count, start;
        Piece *piece;
    #ifndef OLDXAW
        XawTextAnchor *anchor;
        XawTextEntity *entity;
        XawTextPosition offset, end = pos + length;
        Bool state;
    
        end = XawMin(end, src->ascii_src.length);
        while ((state = XawTextSourceAnchorAndEntity(w, pos, &anchor, &entity)) &&
    	(entity->flags & XAW_TENTF_HIDE))
    	pos = anchor->position + entity->offset + entity->length;
        if (state == False ||
    	!(entity->flags & XAW_TENTF_REPLACE)) {
    	while (entity) {
    	    offset = anchor->position + entity->offset;
    	    if (offset >= end)
    		break;
    	    if (offset > pos &&
    		(entity->flags & (XAW_TENTF_HIDE | XAW_TENTF_REPLACE))) {
    		end = XawMin(end, offset);
    		break;
    	    }
    	    if ((entity = entity->next) == NULL &&
    		(anchor = XawTextSourceNextAnchor(w, anchor)) != NULL)
    		entity = anchor->entities;
    	}
        }
        else if (state && (entity->flags & XAW_TENTF_REPLACE) && pos < end) {
    	XawTextBlock *block = (XawTextBlock*)entity->data;
    
    	offset = anchor->position + entity->offset;
    	end = XawMin(end, offset + block->length);
    	if ((length = (int)(end - pos)) < 0)
    	    length = 0;
    	text->length = length;
    	text->format = XawFmt8Bit;
    	if (length == 0) {
    	    text->firstPos = (int)(end = (offset + entity->length));
    	    text->ptr = (char*)"";
    	}
    	else {
    	    text->firstPos = (int)pos;
    	    text->ptr = block->ptr + (pos - offset);
    	    if (pos + length < offset + block->length)
    		end = pos + length;	/* there is data left to be read */
    	    else
    		end = offset + entity->length;
    	}
    
    	return (end);
        }
    
        if ((length = (int)(end - pos)) < 0)
    	length = 0;
    #endif
    
        piece = FindPiece(src, pos, &start);
        text->firstPos = (int)pos;
        text->ptr = piece->text + (pos - start);
        count = piece->used - (pos - start);
        text->length = (int)(Max(0, (length > count) ? count : length));
        text->format = XawFmt8Bit;
    
        return (pos + text->length);
    }
    
    /*
     * Function:
     *	ReplaceText
     *
     * Parameters:
     *	w	 - AsciiSource object
     *	startPos - ends of text that will be replaced
     *	endPos	 - ""
     *	text	 - new text to be inserted into buffer at startPos
     *
     * Description:
     *	Replaces a block of text with new text.
     *
     * Returns:
     *	XawEditDone on success, XawEditError otherwise
     */
    /*ARGSUSED*/
    static int
    ReplaceText(Widget w, XawTextPosition startPos, XawTextPosition endPos,
    	    XawTextBlock *text)
    {
        AsciiSrcObject src = (AsciiSrcObject)w;
        Piece *start_piece, *end_piece, *temp_piece;
        XawTextPosition start_first, end_first;
        int length, firstPos;
    
        /*
         * Editing a read only source is not allowed
         */
        if (src->text_src.edit_mode == XawtextRead)
    	return (XawEditError);
    
        if ((start_piece = FindPiece(src, startPos, &start_first)) == NULL)
    	return XawEditError;
        if ((end_piece = FindPiece(src, endPos, &end_first)) == NULL)
    	return XawEditError;
    
    #ifndef OLDXAW
        /*
         * This is a big hack, but I can't think about a clever way to know
         * if the character being moved forward has a negative lbearing.
         *
         */
        if (start_piece->used) {
    	int i;
    
    	for (i = 0; i < (int)src->text_src.num_text; i++) {
    	    int line;
    	    TextWidget ctx = (TextWidget)src->text_src.text[i];
    
    	    for (line = 0; line < ctx->text.lt.lines; line++)
    		if (startPos < ctx->text.lt.info[line + 1].position)
    		    break;
    	    if (i < ctx->text.lt.lines &&
    		startPos > ctx->text.lt.info[i].position) {
    		AsciiSinkObject sink = (AsciiSinkObject)ctx->text.sink;
    		XawTextAnchor *anchor;
    		XawTextEntity *entity;
    		XawTextProperty *property;
    		XFontStruct *font;
    
    		if (XawTextSourceAnchorAndEntity(w, startPos, &anchor, &entity) &&
    		    (property = XawTextSinkGetProperty(ctx->text.sink,
    						       entity->property)) != NULL &&
    		    (property->mask & XAW_TPROP_FONT))
    		    font = property->font;
    		else
    		    font = sink->ascii_sink.font;
    
    		if (font->min_bounds.lbearing < 0) {
    		    int lbearing = font->min_bounds.lbearing;
    		    unsigned char c = *(unsigned char*)
    			(start_piece->text + (startPos - start_first));
    
    		    if (c == '\t' || c == '\n')
    			c = ' ';
    		    else if ((c & 0177) < XawSP || c == 0177) {
    			if (sink->ascii_sink.display_nonprinting)
    			    c = (unsigned char)(c > 0177 ? '\\' : c + '^');
    			else
    			    c = ' ';
    		    }
    		    if (font->per_char &&
    			(c >= font->min_char_or_byte2 && c <= font->max_char_or_byte2))
    			lbearing = font->per_char[c - font->min_char_or_byte2].lbearing;
    		    if (lbearing < 0)
    			_XawTextNeedsUpdating(ctx, startPos - 1, startPos);
    		}
    	    }
    	}
        }
    
    
    #endif
    
        /*
         * Remove Old Stuff
         */
        if (start_piece != end_piece) {
    	if ((temp_piece = start_piece->next) == NULL)
    	    return XawEditError;
    
    	/*
    	 * If empty and not the only piece then remove it.
    	 */
    	if (((start_piece->used = startPos - start_first) == 0)
    	    && !(start_piece->next == NULL && start_piece->prev == NULL))
    	    RemovePiece(src, start_piece);
    
    	while (temp_piece != end_piece) {
    	    temp_piece = temp_piece->next;
    	    RemovePiece(src, temp_piece->prev);
    	}
    
    	end_piece->used -= endPos - end_first;
    	if (end_piece->used != 0)
    	    memmove(end_piece->text, end_piece->text + endPos - end_first,
    		    (unsigned)end_piece->used);
        }
        else {		    /* We are fully in one piece */
    	if ((start_piece->used -= endPos - startPos) == 0) {
    	    if (!(start_piece->next == NULL && start_piece->prev == NULL))
    		RemovePiece(src, start_piece);
    	}
    	else {
    	    memmove(start_piece->text + (startPos - start_first),
    		    start_piece->text + (endPos - start_first),
    		    (unsigned)(start_piece->used - (startPos - start_first)));
    	    if (src->ascii_src.use_string_in_place
    		&& src->ascii_src.length - (endPos - startPos)
    		< src->ascii_src.piece_size - 1)
    		start_piece->text[src->ascii_src.length - (endPos - startPos)] =
    		    '\0';
    	}
        }
    
        src->ascii_src.length += -(endPos - startPos) + text->length;
    
        if ( text->length != 0) {
    	/*
    	 * Put in the New Stuff
    	 */
    	start_piece = FindPiece(src, startPos, &start_first);
    
    	length = text->length;
    	firstPos = text->firstPos;
    
    	while (length > 0) {
    	    char *ptr;
    	    int fill;
    
    	    if (src->ascii_src.use_string_in_place) {
    		if (start_piece->used == src->ascii_src.piece_size - 1) {
    		    /*
    		     * If we are in ascii string emulation mode. Then the
    		     *	string is not allowed to grow
    		     */
    		    start_piece->used = src->ascii_src.length =
    			src->ascii_src.piece_size - 1;
    		    start_piece->text[src->ascii_src.length] = '\0';
    		    return (XawEditError);
    		}
    	    }
    
    	    if (start_piece->used == src->ascii_src.piece_size) {
    		BreakPiece(src, start_piece);
    		start_piece = FindPiece(src, startPos, &start_first);
    	    }
    
    	    fill = Min((int)(src->ascii_src.piece_size - start_piece->used),
    		       length);
    
    	    ptr = start_piece->text + (startPos - start_first);
    	    memmove(ptr + fill, ptr,
    		    (unsigned)(start_piece->used - (startPos - start_first)));
    	    memcpy(ptr, text->ptr + firstPos, (unsigned)fill);
    
    	    startPos += fill;
    	    firstPos += fill;
    	    start_piece->used += fill;
    	    length -= fill;
    	}
        }
    
        if (src->ascii_src.use_string_in_place)
    	start_piece->text[start_piece->used] = '\0';
    
    #ifdef OLDXAW
        src->ascii_src.changes = True;
        XtCallCallbacks(w, XtNcallback, NULL);
    #endif
    
        return (XawEditDone);
    }
    
    /*
     * Function:
     *	Scan
     *
     * Parameters:
     *	w	 - AsciiSource object
     *	position - position to start scanning
     *	type	 - type of thing to scan for
     *	dir	 - direction to scan
     *		   count - which occurrence 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 item found
     *
     * Note:
     *	  While there are only 'n' characters in the file there are n+1
     *	 possible cursor positions (one before the first character and
     *	one after the last character
     */
    static XawTextPosition
    Scan(Widget w, register XawTextPosition position, XawTextScanType type,
         XawTextScanDirection dir, int count, Bool include)
    {
        AsciiSrcObject src = (AsciiSrcObject)w;
        Piece *piece;
        XawTextPosition first, first_eol_position = 0;
        register char *ptr, *lim;
        register int cnt = count;
        register unsigned char c;
    
        if (dir == XawsdLeft) {
    	if (position <= 0)
    	    return (0);
    	--position;
        }
        else if (position >= src->ascii_src.length)
    	return (src->ascii_src.length);
    
        piece = FindPiece(src, position, &first);
        if (piece->used == 0)
    	return (0);
    
        ptr = (position - first) + piece->text;
    
        if (dir == XawsdRight) {
    	lim = piece->text + piece->used;
    	switch (type) {
    	    case XawstEOL:
    	    case XawstParagraph:
    	    case XawstWhiteSpace:
    	    case XawstAlphaNumeric:
    		for (; cnt > 0; cnt--) {
    		    Bool non_space = False, first_eol = True;
    
    		    /*CONSTCOND*/
    		    while (True) {
    			if (ptr >= lim) {
    			    piece = piece->next;
    			    if (piece == NULL)	/* End of text */
    				return (src->ascii_src.length);
    			    ptr = piece->text;
    			    lim = piece->text + piece->used;
    			}
    
    			c = (unsigned char)*ptr++;
    			++position;
    
    			if (type == XawstEOL) {
    			    if (c == '\n')
    				break;
    			}
    			else if (type == XawstAlphaNumeric) {
    			    if (!isalnum(c)) {
    				if (non_space)
    				    break;
    			    }
    			    else
    				non_space = True;
    			}
    			else if (type == XawstWhiteSpace) {
    			    if (isspace(c)) {
    				if (non_space)
    				    break;
    			    }
    			    else
    				non_space = True;
    			}
    			else {	/* XawstParagraph */
    			    if (first_eol) {
    				if (c == '\n') {
    				    first_eol_position = position;
    				    first_eol = False;
    				}
    			    }
    			    else if (c == '\n')
    				break;
    			    else if (!isspace(c))
    				first_eol = True;
    			}
    		    }
    		}
    		break;
    	    case XawstPositions:
    		position += count;
    		return (position < src->ascii_src.length ?
    			position : src->ascii_src.length);
    	    case XawstAll:
    		return (src->ascii_src.length);
    	    default:
    		break;
    	}
    	if (!include) {
    	    if (type == XawstParagraph)
    		position = first_eol_position;
    	    if (count)
    		--position;
    	}
        }
        else {
    	lim = piece->text;
    	switch (type) {
    	    case XawstEOL:
    	    case XawstParagraph:
    	    case XawstWhiteSpace:
    	    case XawstAlphaNumeric:
    		for (; cnt > 0; cnt--) {
    		    Bool non_space = False, first_eol = True;
    
    		    /*CONSTCOND*/
    		    while (True) {
    			if (ptr < lim) {
    			    piece = piece->prev;
    			    if (piece == NULL)	/* Beginning of text */
    				return (0);
    			    ptr = piece->text + piece->used - 1;
    			    lim = piece->text;
    			}
    
    			c = (unsigned char)*ptr--;
    			--position;
    
    			if (type == XawstEOL) {
    			    if (c == '\n')
    				break;
    			}
    			else if (type == XawstAlphaNumeric) {
    			    if (!isalnum(c)) {
    				if (non_space)
    				    break;
    			    }
    			    else
    				non_space = True;
    			}
    			else if (type == XawstWhiteSpace) {
    			    if (isspace(c)) {
    				if (non_space)
    				    break;
    			    }
    			    else
    				non_space = True;
    			}
    			else {	/* XawstParagraph */
    			    if (first_eol) {
    				if (c == '\n') {
    				    first_eol_position = position;
    				    first_eol = False;
    				}
    			    }
    			    else if (c == '\n')
    				break;
    			    else if (!isspace(c))
    				first_eol = True;
    			}
    		    }
    		}
    		break;
    	    case XawstPositions:
    		position -= count - 1;
    		return (position > 0 ? position : 0);
    	    case XawstAll:
    		return (0);
    	    default:
    		break;
    	}
    	if (!include) {
    	    if (type == XawstParagraph)
    		position = first_eol_position;
    	    if (count)
    		++position;
    	}
    	position++;
        }
    
        return (position);
    }
    
    /*
     * Function:
     *	Search
     *
     * Parameters:
     *	w	 - AsciiSource object
     *	position - the position to start scanning
     *	dir	 - direction to scan
     *	text	 - text block to search for
     *
     * Description:
     *	Searches the text source for the text block passed.
     *
     * Returns:
     *	The position of the item found
     */
    static XawTextPosition
    Search(Widget w, register XawTextPosition position, XawTextScanDirection dir,
           XawTextBlock *text)
    {
        AsciiSrcObject src = (AsciiSrcObject)w;
        register int count = 0;
        register char *ptr, c;
        char *str;
        Piece *piece;
        char *buf;
        XawTextPosition first;
        int cnt, case_sensitive;
    
        if (dir == XawsdLeft) {
    	if (position == 0)
    	    return (XawTextSearchError);
    	position--;
        }
    
        buf = XtMalloc((unsigned)sizeof(unsigned char) * (unsigned)text->length);
        memcpy(buf, text->ptr, (unsigned)text->length);
        piece = FindPiece(src, position, &first);
        ptr = (position - first) + piece->text;
        case_sensitive = text->firstPos;
    
        if (dir == XawsdRight) {
    	str = buf;
    	c = *str;
    	/*CONSTCOND*/
    	while (1) {
    	    if (*ptr++ == c
    		|| (case_sensitive && isalpha((unsigned char)c) && isalpha((unsigned char)ptr[-1])
    		    && toupper((unsigned char)c) == toupper((unsigned char)ptr[-1]))) {
    		if (++count == text->length)
    		    break;
    		c = *++str;
    	    }
    	    else if (count) {
    		ptr -= count;
    		str -= count;
    		position -= count;
    		count = 0;
    		c = *str;
    
    		if (ptr < piece->text) {
    		    do {
    			cnt = (int)(piece->text - ptr);
    			piece = piece->prev;
    			if (piece == NULL) {
    			    XtFree(buf);
    			    return (XawTextSearchError);
    			}
    			ptr = piece->text + piece->used - cnt;
    		    } while (ptr < piece->text);
    		}
    	    }
    	    position++;
    	    if (ptr >= (piece->text + piece->used)) {
    		do {
    		    cnt = (int)(ptr - (piece->text + piece->used));
    		    piece = piece->next;
    		    if (piece == NULL) {
    			XtFree(buf);
    			return (XawTextSearchError);
    		    }
    		    ptr = piece->text + cnt;
    		} while (ptr >= (piece->text + piece->used));
    	    }
    	}
    
    	position -= text->length - 1;
        }
        else {
    	str = buf + text->length - 1;
    	c = *str;
    	/*CONSTCOND*/
    	while (1) {
    	    if (*ptr-- == c
    		|| (case_sensitive && isalpha((unsigned char)c) && isalpha((unsigned char)ptr[1])
    		    && toupper((unsigned char)c) == toupper((unsigned char)ptr[1]))) {
    		if (++count == text->length)
    		    break;
    		c = *--str;
    	    }
    	    else if (count) {
    		ptr += count;
    		str += count;
    		position += count;
    		count = 0;
    		c = *str;
    
    		if (ptr >= (piece->text + piece->used)) {
    		    do {
    			cnt = (int)(ptr - (piece->text + piece->used));
    			piece = piece->next;
    			if (piece == NULL) {
    			    XtFree(buf);
    			    return (XawTextSearchError);
    			}
    			ptr = piece->text + cnt;
    		    } while (ptr >= (piece->text + piece->used));
    		}
    	    }
    	    position--;
    	    if (ptr < piece->text) {
    		do {
    		    cnt = (int)(piece->text - ptr);
    		    piece = piece->prev;
    		    if (piece == NULL) {
    			XtFree(buf);
    			return (XawTextSearchError);
    		    }
    		    ptr = piece->text + piece->used - cnt;
    		} while (ptr < piece->text);
    	    }
    	}
        }
    
        XtFree(buf);
    
        return (position);
    }
    
    /*
     * Function:
     *	XawAsciiSrcSetValues
     *
     * Parameters:
     *	current  - current state of the widget
     *	request  - what was requested
     *	cnew	 - what the widget will become
     *	args	 - representation of changed resources
     *	num_args - number of resources that have changed
     *
     * Description:
     *	Sets the values for the AsciiSource.
     *
     * Returns:
     *	True if redisplay is needed
     */
    static Boolean
    XawAsciiSrcSetValues(Widget current, Widget request _X_UNUSED, Widget cnew,
    		     ArgList args, Cardinal *num_args)
    {
        AsciiSrcObject src = (AsciiSrcObject)cnew;
        AsciiSrcObject old_src = (AsciiSrcObject)current;
        Bool total_reset = False, string_set = False;
        Cardinal i;
    
        if (old_src->ascii_src.use_string_in_place
    	!= src->ascii_src.use_string_in_place) {
    	XtAppWarning(XtWidgetToApplicationContext(cnew),
    		     "AsciiSrc: The XtNuseStringInPlace resource may "
    		     "not be changed.");
    	src->ascii_src.use_string_in_place =
    	    old_src->ascii_src.use_string_in_place;
        }
    
        for (i = 0; i < *num_args ; i++)
    	if (streq(args[i].name, XtNstring)) {
    	    string_set = True;
    	    break;
    	}
    
        if (string_set || (old_src->ascii_src.type != src->ascii_src.type)) {
    	FILE *file;
    
    	RemoveOldStringOrFile(old_src, string_set); /* remove old info */
    	file = InitStringOrFile(src, string_set);   /* Init new info */
    	LoadPieces(src, file, NULL);   /* load new info into internal buffers */
    	if (file != NULL)
    	    fclose(file);
    #ifndef OLDXAW
    	for (i = 0; i < src->text_src.num_text; i++)
    	    /* Tell text widget what happened */
    	    XawTextSetSource(src->text_src.text[i], cnew, 0);
    #else
    	XawTextSetSource(XtParent(cnew), cnew, 0);
    #endif
    	total_reset = True;
        }
    
        if (old_src->ascii_src.ascii_length != src->ascii_src.ascii_length)
    	src->ascii_src.piece_size = src->ascii_src.ascii_length + 1;
    
        if (!total_reset &&
    	old_src->ascii_src.piece_size != src->ascii_src.piece_size) {
    	char * string = StorePiecesInString(old_src);
    
    	FreeAllPieces(old_src);
    	LoadPieces(src, NULL, string);
    	XtFree(string);
        }
    
        return (False);
    }
    
    /*
     * Function:
     *	XawAsciiSrcGetValuesHook
     *
     * Parameters:
     *	w	 - AsciiSource Widget
     *	args	 - argument list
     *	num_args - number of args
     *
     * Description:
     *	  This is a get values hook routine that sets the
     *		     values specific to the ascii source.
     */
    static void
    XawAsciiSrcGetValuesHook(Widget w, ArgList args, Cardinal *num_args)
    {
        AsciiSrcObject src = (AsciiSrcObject)w;
        Cardinal i;
    
        if (src->ascii_src.type == XawAsciiString) {
    	for (i = 0; i < *num_args ; i++)
    	    if (streq(args[i].name, XtNstring)) {
    		if (src->ascii_src.use_string_in_place)
    		    *((char **)args[i].value) = src->ascii_src.first_piece->text;
    		else if (XawAsciiSave(w))   /* If save successful */
    		    *((char **)args[i].value) = src->ascii_src.string;
    		break;
    	    }
    	}
        }
    
    /*
     * Function:
     *	XawAsciiSrcDestroy
     *
     * Parameters:
     *	src - Ascii source object to free
     *
     * Description:
     *	Destroys an ascii source (frees all data)
     */
    static void
    XawAsciiSrcDestroy(Widget w)
    {
        RemoveOldStringOrFile((AsciiSrcObject) w, True);
    }
    
    /*
     * Public routines
     */
    /*
     * Function:
     *	XawAsciiSourceFreeString
     *
     * Parameters:
     *	w - AsciiSrc widget
     *
     * Description:
     *	  Frees the string returned by a get values call
     *		     on the string when the source is of type string.
     */
    void
    XawAsciiSourceFreeString(Widget w)
    {
        AsciiSrcObject src = (AsciiSrcObject)w;
    
        /* If the src is really a multi, call the multi routine */
        if (XtIsSubclass(w, multiSrcObjectClass)) {
    	_XawMultiSourceFreeString(w);
    	return;
        }
        else if (!XtIsSubclass(w, asciiSrcObjectClass)) {
    	XtErrorMsg("bad argument", "asciiSource", "XawError",
    		   "XawAsciiSourceFreeString's parameter must be "
    		   "an asciiSrc or multiSrc.",
    		   NULL, NULL);
        }
    
        if (src->ascii_src.allocated_string && src->ascii_src.type != XawAsciiFile) {
    	src->ascii_src.allocated_string = False;
    	XtFree(src->ascii_src.string);
    	src->ascii_src.string = NULL;
        }
    }
    
    /*
     * Function:
     *	XawAsciiSave
     *
     * Parameters:
     *	w - asciiSrc Widget
     *
     * Description:
     *	Saves all the pieces into a file or string as required.
     *
     * Returns:
     *	True if the save was successful
     */
    Bool
    XawAsciiSave(Widget w)
    {
        AsciiSrcObject src = (AsciiSrcObject)w;
    
        /* If the src is really a multi, call the multi save */
        if (XtIsSubclass(w, multiSrcObjectClass ))
    	return (_XawMultiSave(w));
    
        else if (!XtIsSubclass(w, asciiSrcObjectClass))
    	XtErrorMsg("bad argument", "asciiSource", "XawError",
    		   "XawAsciiSave's parameter must be an asciiSrc or multiSrc.",
    		   NULL, NULL);
    
        /*
         * If using the string in place then there is no need to play games
         * to get the internal info into a readable string.
         */
        if (src->ascii_src.use_string_in_place)
    	return (True);
    
        if (src->ascii_src.type == XawAsciiFile) {
    #ifdef OLDXAW
    	if (!src->ascii_src.changes)
    #else
    	if (!src->text_src.changed) 		/* No changes to save */
    #endif
    	    return (True);
    
    	if (WritePiecesToFile(src, src->ascii_src.string) == False)
    	    return (False);
        }
        else  {
    	if (src->ascii_src.allocated_string == True)
    	    XtFree(src->ascii_src.string);
    	else
    	    src->ascii_src.allocated_string = True;
    
    	src->ascii_src.string = StorePiecesInString(src);
        }
    #ifdef OLDXAW
        src->ascii_src.changes = False;
    #else
        src->text_src.changed = False;
    #endif
    
        return (True);
    }
    
    /*
     * Function:
     *	XawAsciiSaveAsFile
     *
     * Arguments:
     *	w    - AsciiSrc widget
     *	name - name of the file to save this file into
     *
     * Description:
     *	Save the current buffer as a file.
     *
     * Returns:
     *	True if the save was successful
     */
    Bool
    XawAsciiSaveAsFile(Widget w, _Xconst char *name)
    {
        AsciiSrcObject src = (AsciiSrcObject)w;
        Bool ret;
    
        /* If the src is really a multi, call the multi save */
    
        if (XtIsSubclass( w, multiSrcObjectClass))
    	return (_XawMultiSaveAsFile(w, name));
    
        else if (!XtIsSubclass(w, asciiSrcObjectClass))
    	XtErrorMsg("bad argument", "asciiSource", "XawError",
    		   "XawAsciiSaveAsFile's 1st parameter must be an "
    		   "asciiSrc or multiSrc.",
    		   NULL, NULL);
    
        if (src->ascii_src.type == XawAsciiFile)
    	ret = WritePiecesToFile(src, (String)name);
        else {
    	char * string = StorePiecesInString(src);
    
    	ret = WriteToFile(string, (String)name, (unsigned)src->ascii_src.length);
    	XtFree(string);
        }
    
        return (ret);
    }
    
    /*
     * Function:
     *	XawAsciiSourceChanged
     *
     * Parameters:
     *	w - ascii source widget
     *
     * Description:
     *	Returns true if the source has changed since last saved.
     *
     * Returns:
     *	A Boolean (see description).
     */
    Bool
    XawAsciiSourceChanged(Widget w)
    {
    #ifdef OLDXAW
        if (XtIsSubclass(w, multiSrcObjectClass))
    	return (((MultiSrcObject)w)->multi_src.changes);
    
        if (XtIsSubclass(w, asciiSrcObjectClass))
    	return (((AsciiSrcObject)w)->ascii_src.changes);
    #else
        if (XtIsSubclass(w, textSrcObjectClass))
    	return (((TextSrcObject)w)->textSrc.changed);
    #endif
        XtErrorMsg("bad argument", "asciiSource", "XawError",
    	       "XawAsciiSourceChanged parameter must be an "
    	       "asciiSrc or multiSrc.",
    	       NULL, NULL);
    
        return (True);
    }
    
    /*
     * Private Functions
     */
    static void
    RemoveOldStringOrFile(AsciiSrcObject src, Bool checkString)
    {
        FreeAllPieces(src);
    
        if (checkString && src->ascii_src.allocated_string) {
    	XtFree(src->ascii_src.string);
    	src->ascii_src.allocated_string = False;
    	src->ascii_src.string = NULL;
        }
    }
    
    /*
     * Function:
     *	WriteToFile
     *
     * Parameters:
     *	string - string to write
     *	name   - the name of the file
     *
     * Description:
     *	Write the string specified to the beginning of the file specified.
     *
     * Returns:
     *	returns True if successful, False otherwise
     */
    static Bool
    WriteToFile(String string, String name, unsigned length)
    {
        int fd;
    
        if ((fd = open(name, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0666)) == -1)
    	return (False);
    
        if (write(fd, string, length) == -1) {
    	close(fd);
    	return (False);
        }
    
        if (close(fd) == -1)
    	return (False);
    
        return (True);
    }
    
    /*
     * Function:
     *	WritePiecesToFile
     *
     * Parameters:
     *	src  - ascii source object
     *	name - name of the file
     *
     * Description:
     *	  Almost identical to WriteToFile, but only works for ascii src objects
     *	of type XawAsciiFile. This function avoids allocating temporary memory,
     *	what can be useful when editing very large files.
     *
     * Returns:
     *	returns True if successful, False otherwise
     */
    static Bool
    WritePiecesToFile(AsciiSrcObject src, String name)
    {
        Piece *piece;
        int fd;
    
        if (src->ascii_src.data_compression) {
    	piece = src->ascii_src.first_piece;
    	while (piece) {
    	    int bytes = (int)(src->ascii_src.piece_size - piece->used);
    	    Piece *tmp;
    
    	    if (bytes > 0 && (tmp = piece->next) != NULL) {
    		bytes = (int)(XawMin(bytes, tmp->used));
    		memcpy(piece->text + piece->used, tmp->text, (size_t)bytes);
    		memmove(tmp->text, tmp->text + bytes, (size_t)(tmp->used - bytes));
    		piece->used += bytes;
    		if ((tmp->used -= bytes) == 0) {
    		    RemovePiece(src, tmp);
    		    continue;
    		}
    	    }
    	    piece = piece->next;
    	}
        }
    
        if ((fd = open(name, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0666)) == -1)
    	return (False);
    
        for (piece = src->ascii_src.first_piece; piece; piece = piece->next)
    	if (write(fd, piece->text, (size_t)piece->used) == -1) {
    	    close(fd);
    	    return (False);
    	}
    
        if (close(fd) == -1)
    	return (False);
    
        return (True);
    }
    
    /*
     * Function:
     *	StorePiecesInString
     *
     * Parameters:
     *	data - ascii pointer data
     *
     * Description:
     *	Store the pieces in memory into a standard ascii string.
     */
    static char *
    StorePiecesInString(AsciiSrcObject src)
    {
        char * string;
        XawTextPosition first;
        Piece *piece;
    
        string = XtMalloc((unsigned)(src->ascii_src.length + 1));
    
        for (first = 0, piece = src->ascii_src.first_piece ; piece != NULL;
    	 first += piece->used, piece = piece->next)
          memcpy(string + first, piece->text, (unsigned)piece->used);
    
        string[src->ascii_src.length] = '\0';
    
        /*
         * This will refill all pieces to capacity
         */
        if (src->ascii_src.data_compression) {
    	FreeAllPieces(src);
    	LoadPieces(src, NULL, string);
        }
    
        return (string);
    }
    
    /*
     * Function:
     *	InitStringOrFile
     *
     * Parameters:
     *	src - AsciiSource
     *
     * Description:
     *	Initializes the string or file.
     */
    static FILE *
    InitStringOrFile(AsciiSrcObject src, Bool newString)
    {
        mode_t open_mode = 0;
        const char *fdopen_mode = NULL;
    
        if (src->ascii_src.type == XawAsciiString) {
    	if (src->ascii_src.string == NULL)
    	    src->ascii_src.length = 0;
    
    	else if (!src->ascii_src.use_string_in_place) {
    	    src->ascii_src.string = XtNewString(src->ascii_src.string);
    	    src->ascii_src.allocated_string = True;
    	    src->ascii_src.length = (XawTextPosition)strlen(src->ascii_src.string);
    	}
    
    	if (src->ascii_src.use_string_in_place) {
    	    if (src->ascii_src.string != NULL)
    	    src->ascii_src.length = (XawTextPosition)strlen(src->ascii_src.string);
    	    /* In case the length resource is incorrectly set */
    	    if (src->ascii_src.length > src->ascii_src.ascii_length)
    		src->ascii_src.ascii_length = (int)src->ascii_src.length;
    
    	    if (src->ascii_src.ascii_length == MAGIC_VALUE)
    		src->ascii_src.piece_size = src->ascii_src.length;
    	    else
    		src->ascii_src.piece_size = src->ascii_src.ascii_length + 1;
    	}
    
    	return (NULL);
        }
    
        /*
         * type is XawAsciiFile
         */
        src->ascii_src.is_tempfile = False;
    
        switch (src->text_src.edit_mode) {
    	case XawtextRead:
    	    if (src->ascii_src.string == NULL)
    		XtErrorMsg("NoFile", "asciiSourceCreate", "XawError",
    			   "Creating a read only disk widget and no file specified.",
    			   NULL, NULL);
    	    open_mode = O_RDONLY | O_CLOEXEC;
    	    fdopen_mode = "r";
    	    break;
    	case XawtextAppend:
    	case XawtextEdit:
    	    if (src->ascii_src.string == NULL) {
    		src->ascii_src.string = (char*)"*ascii-src*";
    		src->ascii_src.is_tempfile = True;
    	    }
    	    else {
    /* O_NOFOLLOW was a FreeBSD & Linux extension, now adopted by POSIX */
    #ifdef O_NOFOLLOW
    		open_mode = O_RDWR | O_NOFOLLOW | O_CLOEXEC;
    #else
    		open_mode = O_RDWR; /* unsafe; subject to race conditions */
    #endif /* O_NOFOLLOW */
    		fdopen_mode = "r+";
    	    }
    	    break;
    	default:
    	    XtErrorMsg("badMode", "asciiSourceCreate", "XawError",
    		       "Bad editMode for ascii source; must be Read, "
    		       "Append or Edit.",
    		       NULL, NULL);
        }
    
        /* If is_tempfile, allocate a private copy of the text
         * Unlikely to be changed, just to set allocated_string */
        if (newString || src->ascii_src.is_tempfile) {
    	src->ascii_src.string = XtNewString(src->ascii_src.string);
    	src->ascii_src.allocated_string = True;
        }
    
        if (!src->ascii_src.is_tempfile) {
    	int fd = open(src->ascii_src.string, (int)open_mode, 0666);
    
    	if (fd != -1) {
    	    FILE *file = fdopen(fd, fdopen_mode);
    
    	    if (file != NULL) {
    		(void)fseek(file, 0, SEEK_END);
    		src->ascii_src.length = (XawTextPosition)ftell(file);
    		return (file);
    	    }
    	    else
    		close(fd);
    	}
    	{
    	    String params[2];
    	    Cardinal num_params = 2;
    
    	    params[0] = src->ascii_src.string;
    	    params[1] = strerror(errno);
    	    XtAppWarningMsg(XtWidgetToApplicationContext((Widget)src),
    			    "openError", "asciiSourceCreate", "XawWarning",
    			    "Cannot open file %s; %s", params, &num_params);
    	}
        }
        src->ascii_src.length = 0;
        return (NULL);
    }
    
    static void
    LoadPieces(AsciiSrcObject src, FILE *file, char *string)
    {
        char *ptr;
        Piece *piece = NULL;
        XawTextPosition left;
    
        if (string == NULL) {
    	if (src->ascii_src.type == XawAsciiFile) {
    	    if (src->ascii_src.length != 0) {
    		left = 0;
    		fseek(file, 0, SEEK_SET);
    		while (left < src->ascii_src.length) {
    		    int len;
    
    		    ptr = XtMalloc((unsigned)src->ascii_src.piece_size);
    		    if ((len = (int)fread(ptr, sizeof(unsigned char),
    				     (size_t)src->ascii_src.piece_size, file)) < 0)
    			XtErrorMsg("readError", "asciiSourceCreate", "XawError",
    				   "fread returned error.", NULL, NULL);
    		    piece = AllocNewPiece(src, piece);
    		    piece->text = ptr;
    		    piece->used = XawMin(len, src->ascii_src.piece_size);
    		    left += piece->used;
    		}
    	    }
    	    else {
    		piece = AllocNewPiece(src, NULL);
    		piece->text = XtMalloc((unsigned)src->ascii_src.piece_size);
    		piece->used = 0;
    	    }
    	    return;
    	}
    	else
    	    string = src->ascii_src.string;
        }
    
        if (src->ascii_src.use_string_in_place) {
    	piece = AllocNewPiece(src, piece);
    	piece->used = XawMin(src->ascii_src.length, src->ascii_src.piece_size);
    	piece->text = src->ascii_src.string;
    	return;
        }
    
        ptr = string;
        left = src->ascii_src.length;
        do {
    	piece = AllocNewPiece(src, piece);
    
    	piece->text = XtMalloc((unsigned)src->ascii_src.piece_size);
    	piece->used = XawMin(left, src->ascii_src.piece_size);
    	if (piece->used != 0)
    	    memcpy(piece->text, ptr, (unsigned)piece->used);
    
    	left -= piece->used;
    	ptr += piece->used;
        } while (left > 0);
    }
    
    /*
     * Function:
     *	AllocNewPiece
     *
     * Parameters:
     *	src - AsciiSrc Widget
     *	prev - piece just before this one, or NULL
     *
     * Description:
     *	Allocates a new piece of memory.
     *
     * Returns:
     *	The allocated piece
     */
    static Piece *
    AllocNewPiece(AsciiSrcObject src, Piece *prev)
    {
        Piece *piece = XtNew(Piece);
    
        if (prev == NULL) {
    	src->ascii_src.first_piece = piece;
    	piece->next = NULL;
        }
        else  {
    	if (prev->next != NULL)
    	    (prev->next)->prev = piece;
    	piece->next = prev->next;
    	prev->next = piece;
        }
    
        piece->prev = prev;
    
        return (piece);
    }
    
    /*
     * Function:
     *	FreeAllPieces
     *
     * Parameters:
     *	src - AsciiSrc Widget
     *
     * Description:
     *	Frees all the pieces.
     */
    static void
    FreeAllPieces(AsciiSrcObject src)
    {
        Piece *next, * first = src->ascii_src.first_piece;
    
    #ifdef DEBUG
        if (first->prev != NULL)
    	printf("Xaw AsciiSrc Object: possible memory leak in FreeAllPieces().\n");
    #endif
    
        for (; first != NULL ; first = next) {
    	next = first->next;
    	RemovePiece(src, first);
        }
    }
    
    /*
     * Function:
     *	RemovePiece
     *
     * Parameters:
     *	piece - piece to remove
     *
     * Description:
     *	Removes a piece from the list.
     */
    static void
    RemovePiece(AsciiSrcObject src, Piece *piece)
    {
        if (piece->prev == NULL)
    	src->ascii_src.first_piece = piece->next;
        else
    	piece->prev->next = piece->next;
    
        if (piece->next != NULL)
    	piece->next->prev = piece->prev;
    
        if (!src->ascii_src.use_string_in_place)
    	XtFree(piece->text);
    
        XtFree((char *)piece);
    }
    
    /*
     * Function:
     *	FindPiece
     *
     * Parameters:
     *	src	 - AsciiSrc Widget
     *	position - position that we are searching for
     *	first	 - position of the first character in this piece (return)
     *
     * Description:
     *	Finds the piece containing the position indicated.
     *
     * Returns:
     *	the piece that contains this position
     */
    static Piece *
    FindPiece(AsciiSrcObject src, XawTextPosition position, XawTextPosition *first)
    {
        Piece *old_piece, *piece;
        XawTextPosition temp;
    
        for (old_piece = NULL, piece = src->ascii_src.first_piece, temp = 0;
    	piece; old_piece = piece, piece = piece->next)
    	if ((temp += piece->used) > position) {
    	    *first = temp - piece->used;
    	    return (piece);
    	}
    
        *first = temp - (old_piece ? old_piece->used : 0);
    
        return (old_piece);	/* if we run off the end the return the last piece */
    }
    
    /*
     * Function:
     *	BreakPiece
     *
     * Parameters:
     *	src - AsciiSrc Widget
     *	piece - piece to break
     *
     * Description:
     *	Breaks a full piece into two new pieces.
     */
    #define HALF_PIECE (src->ascii_src.piece_size >> 1)
    static void
    BreakPiece(AsciiSrcObject src, Piece *piece)
    {
        Piece *cnew = AllocNewPiece(src, piece);
    
        cnew->text = XtMalloc((unsigned)src->ascii_src.piece_size);
        memcpy(cnew->text, piece->text + HALF_PIECE,
    	   (unsigned)(src->ascii_src.piece_size - HALF_PIECE));
        piece->used = HALF_PIECE;
        cnew->used = src->ascii_src.piece_size - HALF_PIECE;
    }
    
    /*ARGSUSED*/
    static void
    CvtStringToAsciiType(XrmValuePtr args _X_UNUSED, Cardinal *num_args _X_UNUSED,
    		     XrmValuePtr fromVal, XrmValuePtr toVal)
    {
        static XawAsciiType type;
        XrmQuark q;
        char name[7];
    
        XmuNCopyISOLatin1Lowered(name, (char *)fromVal->addr, sizeof(name));
        q = XrmStringToQuark(name);
    
        if (q == Qstring)
    	type = XawAsciiString;
        else if (q == Qfile)
    	type = XawAsciiFile;
        else  {
    	toVal->size = 0;
    	toVal->addr = NULL;
    	XtStringConversionWarning((char *)fromVal->addr, XtRAsciiType);
        }
    
        toVal->size = sizeof(XawAsciiType);
        toVal->addr = (XPointer)&type;
    }
    
    /*ARGSUSED*/
    static Boolean
    CvtAsciiTypeToString(Display *dpy, XrmValuePtr args _X_UNUSED, Cardinal *num_args _X_UNUSED,
    		     XrmValuePtr fromVal, XrmValuePtr toVal,
    		     XtPointer *data _X_UNUSED)
    {
        static String buffer;
        Cardinal size;
    
        switch (*(XawAsciiType *)fromVal->addr) {
    	case XawAsciiFile:
    	    buffer = XtEfile;
    	    break;
    	case XawAsciiString:
    	    buffer = XtEstring;
    	    break;
    	default:
    	    XawTypeToStringWarning(dpy, XtRAsciiType);
    	    toVal->addr = NULL;
    	    toVal->size = 0;
    	    return (False);
        }
    
        size = (Cardinal)(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);
    }
    
    /*ARGSUSED*/
    static void
    GetDefaultPieceSize(Widget w _X_UNUSED, int offset _X_UNUSED, XrmValue *value)
    {
        static XPointer pagesize;
    
        if (pagesize == NULL) {
    	pagesize = (XPointer)((long)_XawGetPageSize());
    	if (pagesize < (XPointer)BUFSIZ)
    	    pagesize = (XPointer)BUFSIZ;
        }
    
        value->addr = (XPointer)&pagesize;
    }
    
    #if (defined(ASCII_STRING) || defined(ASCII_DISK))
    #  include <X11/Xaw/Cardinals.h>
    #endif
    
    #ifdef ASCII_STRING
    /*
     * Compatibility functions.
     */
    /*
     * Function:
     *	AsciiStringSourceCreate
     *
     * Parameters:
     *	parent	 - widget that will own this source
     *	args	 - the argument list
     *	num_args - ""
     *
     * Description:
     *	Creates a string source.
     *
     * Returns:
     *	A pointer to the new text source.
     */
    Widget
    XawStringSourceCreate(Widget parent, ArgList args, Cardinal num_args)
    {
        XawTextSource src;
        ArgList ascii_args;
        Arg temp[2];
    
        XtSetArg(temp[0], XtNtype, XawAsciiString);
        XtSetArg(temp[1], XtNuseStringInPlace, True);
        ascii_args = XtMergeArgLists(temp, TWO, args, num_args);
    
        src = XtCreateWidget("genericAsciiString", asciiSrcObjectClass, parent,
    			 ascii_args, num_args + TWO);
        XtFree((char *)ascii_args);
    
        return (src);
    }
    
    /*
     * This is hacked up to try to emulate old functionality, it
     * may not work, as I have not old code to test it on.
     *
     * Chris D. Peterson  8/31/89.
     */
    void
    XawTextSetLastPos(Widget w, XawTextPosition lastPos)
    {
        AsciiSrcObject src = (AsciiSrcObject)XawTextGetSource(w);
    
        src->ascii_src.piece_size = lastPos;
    }
    #endif /* ASCII_STRING */
    
    #ifdef ASCII_DISK
    /*
     * Function:
     *	AsciiDiskSourceCreate
     *
     * Parameters:
     *	parent	 - widget that will own this source
     *	args	 - argument list
     *	num_args - ""
     *
     * Description:
     *	Creates a disk source.
     *
     * Returns:
     *	A pointer to the new text source
     */
    Widget
    XawDiskSourceCreate(Widget parent, ArgList args, Cardinal num_args)
    {
        XawTextSource src;
        ArgList ascii_args;
        Arg temp[1];
        int i;
    
        XtSetArg(temp[0], XtNtype, XawAsciiFile);
        ascii_args = XtMergeArgLists(temp, ONE, args, num_args);
        num_args++;
    
        for (i = 0; i < num_args; i++)
    	if (streq(ascii_args[i].name, XtNfile)
    	    || streq(ascii_args[i].name, XtCFile))
    	    ascii_args[i].name = XtNstring;
    
        src = XtCreateWidget("genericAsciiDisk", asciiSrcObjectClass, parent,
    			 ascii_args, num_args);
        XtFree((char *)ascii_args);
    
        return (src);
    }
    #endif /* ASCII_DISK */