/*
 *	$Source: /u1/X/DECToolkit/src/RCS/StringSource.c,v $
 *	$Header: StringSource.c,v 1.1 86/12/17 09:02:48 swick Exp $
 */

#ifndef lint
static char *rcsid_StringSource_c = "$Header: StringSource.c,v 1.1 86/12/17 09:02:48 swick Exp $";
#endif	lint

#ifndef lint
static  char    *sccsid = "@(#)StringSource.c	1.6          12/11/86";
#endif lint
/*
 *			  COPYRIGHT 1986
 *		   DIGITAL EQUIPMENT CORPORATION
 *		       MAYNARD, MASSACHUSETTS
 *			ALL RIGHTS RESERVED.
 *
 * THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE AND
 * SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL EQUIPMENT CORPORATION.
 * DIGITAL MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE FOR
 * ANY PURPOSE.  IT IS SUPPLIED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
 *
 * IF THE SOFTWARE IS MODIFIED IN A MANNER CREATING DERIVATIVE COPYRIGHT RIGHTS,
 * APPROPRIATE LEGENDS MAY BE PLACED ON THE DERIVATIVE WORK IN ADDITION TO THAT
 * SET FORTH ABOVE.
 *
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose and without fee is hereby granted, provided
 * that the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting documentation,
 * and that the name of Digital Equipment Corporation not be used in advertising
 * or publicity pertaining to distribution of the software without specific, 
 * written prior permission.
 */


/* File: StringSource.c */

#include <X/Xlib.h>
#include <strings.h>
#include "Toolkit.h"		/** included in all toolkit files **/
#include "TextDisplay.h"	/** included in all text subwindow files **/

/* Private StringSource Definitions */

typedef struct _StringSourceData {
    char *str;			/** pointer to buffer in memory with source **/
    TTextPosition length, 	/** length of stuff in buffer **/
		  maxLength;	/** max length of buffer **/
} StringSourceData, *StringSourcePtr;


#define Increment(data, position, direction)\
{\
    if (direction == left) {\
	if (position > 0) \
	    position -= 1;\
    }\
    else {\
	if (position < data->length)\
	    position += 1;\
    }\
}

static char Look(data, position, direction)
  StringSourcePtr data;
  TTextPosition position;
  enum ScanDirection direction;
{
/* Looking left at pos 0 or right at position data->length returns newline */
    if (direction == left) {
	if (position == 0)
	    return('\n');
	else
	    return(data->str[position-1]);
    }
    else {
	if (position == data->length)
	    return('\n');
	else
	    return(data->str[position]);
    }
}

/***
 *** this routine will read source into "text", starting at "pos", for	
 *** "maxRead" characters or end.
 *** NOTE: since this is a string source, no actually reading takes place
 ***       because the source is already all in memory.
 ***/
static int StringReadText (src, pos, text, maxRead)
  TTextSource *src;
  int pos;		/* starting position */
  TTextBlock *text; 	/* RETURNED: text read in */
  int maxRead;
{
    int     charsLeft;
    StringSourcePtr data;

    data = (StringSourcePtr) src->data;
    text->ptr = data->str + pos;
    charsLeft = data->length - pos;
    text->length = (maxRead > charsLeft) ? charsLeft : maxRead;
    return pos + text->length;
}

/***
 *** Given a starting and ending position, this routine will replace the
 *** source text with "text".  Depending on the startPos and endPos, the
 *** text may be inserted instead of replaced.
 ***/
static int StringReplaceText (src, startPos, endPos, text)
  TTextSource *src;
  TTextPosition startPos, endPos;
  TTextBlock *text;
{
    StringSourcePtr data;
    int     i, delta, length;

    length = endPos - startPos;
    data = (StringSourcePtr) src->data;

    if (text->length < 0) 	/* delete key was hit */
	delta = -1;
    else			/* any other key was hit */
        delta = text->length - length;

    if (delta < 0)		/* insert shorter than delete, text getting
				   shorter */
	for (i = startPos; i < data->length + delta; ++i)
	    data->str[i] = data->str[i - delta];
    else
	if (delta > 0)		/* insert longer than delete, text getting
				   longer */
	    for (i = data->length; i >= startPos + delta - 1; --i)
		data->str[i + delta] = data->str[i];

    /** do the insert **/
    if (text->length > 0)
	for (i = 0; i < text->length; ++i)
	    data->str[startPos + i] = text->ptr[i];
    data->length = data->length + delta;
    return delta;
}

/***
 *** function to get length of source.
 ***/
static TTextPosition StringGetLastPos (src)
  TTextSource *src;
{
    return(((StringSourceData *) (src->data))->length);
}


/***
 *** fuction to change lenght of source.
 ***/
static StringSetLastPos (src, lastPos)
  TTextSource *src;
  TTextPosition lastPos;
{
    ((StringSourceData *) (src->data))->length = lastPos;
}


/***
 *** what time of text insertion is allowed for this source.
 ***/
static enum InsertionType StringEditType()
{
 return(edit);
}


/***
 *** This routine will start at
 *** the "pos" position of the source and scan in the appropriate
 *** direction until it finds something of the right sType.  It returns 
 *** the new position.
 ***/
static TTextPosition StringScan (src, pos, sType, dir, word_break_symbols)
  TTextSource *src;
  TTextPosition pos;
  enum SelectionType sType;
  enum ScanDirection dir;
  char *word_break_symbols;
{
    StringSourcePtr data;
    TTextPosition  position;
    int whiteSpace;
    char c;

    data = (StringSourcePtr) src->data;
    position = pos;
    switch (sType) {
	case charSelection: 
	    Increment(data, position, dir);
	    break;
	case wordSelection:
	    whiteSpace = 0; 
	    while (position > 0 && position < data->length) {
		c = Look(data, position, dir);
		whiteSpace = (c == ' ') || (c == '\t') || (c == '\n');
		if (whiteSpace)
		    break;
		else
		   if (index(word_break_symbols, c) != 0)
			break;
		Increment(data, position, dir);
	    }
	    break;
	case lineSelection: 
	    while (position > 0 && position < data->length) {
		if (Look(data, position, dir) == '\n')
		    break;
		Increment(data, position, dir);
	    }
	    break;
	case allSelection: 
	    if (dir == left)
		position = 0;
	    else
		position = data->length;
    }
    return(position);
}

/* Public routines */

int *TCreateStringSource (str, maxLength)
  char *str;
  int maxLength;
{
    TTextSource *src;
    StringSourcePtr data;
    int     i;

    src = (TTextSource *) Tmalloc(sizeof(TTextSource));
    src->read = StringReadText;
    src->replace = StringReplaceText;
    src->getLastPos = StringGetLastPos;
    src->setLastPos = StringSetLastPos;
    src->getEditType = StringEditType;
    src->scan = StringScan;
    src->data = (int *) (Tmalloc(sizeof(StringSourceData)));
    data = (StringSourcePtr) src->data;
    i = 0;
    while (str[i] != 0)
	++i;
    data->str = str;
    data->length = i;
    data->maxLength = maxLength;
    src->data = (int *) (data);
    return(int *) src;
}

void TDestroyStringSource (src)
  TTextSource *src;
{
    free(src->data);
    free(src);
}
