/******************************************************************************

    MODUL
	subs.c

    DESCRIPTION
	General subroutines.

    NOTES

    BUGS

    TODO

    EXAMPLES

    SEE ALSO

    INDEX

    HISTORY
	16. Jan 1993	ada created

******************************************************************************/

/**************************************
		Includes
**************************************/
#include "defs.h"
#include <clib/macros.h>
#include <graphics/display.h>


/**************************************
	    Globale Variable
**************************************/
Prototype void	 makemygadget	 (struct Gadget *);
Prototype int	 firstns	 (char *);
Prototype int	 lastns 	 (char *);
Prototype int	 wordlen	 (char *);
Prototype Bool	 getpathto	 (BPTR, char *, char *);
Prototype void * allocline	 (long);
Prototype int	 detab		 (char *, char *, int);
Prototype int	 xefgets	 (FILE *, char *, int);
Prototype ED   * finded 	 (char *, int);
Prototype void	 mountrequest	 (int);
Prototype FONT * GetFont	 (char *, short);
Prototype void	 freeline	 (LINE);
Prototype void	 movetocursor	 (void);
Prototype int	 extend 	 (ED *, int);
Prototype int	 makeroom	 (int);
Prototype void	 freelist	 (LINE *, int);
Prototype long	 lineflags	 (int);
Prototype void	 scroll_display  (short, short, Column, Line, Column, Line);
Prototype char * skip_whitespace (char *);
Prototype char	 is_number	 (char *);
Prototype char * getnextcomline  (FILE *, int *);
Prototype char * fname		 (char *);
Prototype Bool	 switch_ed	 (ED *);
Prototype void	 MakeRectVisible (WIN *, USHORT, USHORT, USHORT, USHORT);
Prototype int	 LINELEN	 (ED *, Line);

/* Assembler */
Prototype void swapmem (void *, void *, ULONG);


/**************************************
      Interne Defines & Strukturen
**************************************/
typedef struct FileInfoBlock FIB;


/**************************************
	    Interne Variable
**************************************/


/**************************************
	   Interne Prototypes
**************************************/


/*
 *  Create XDME's text icon.
 */

void makemygadget (struct Gadget *gad)
{
    const static unsigned short ga[] =
    {
     /* Plane 0 */
     0x0000,0x0000,0x0000,0x0400,0x0000,0x0000,0x0000,0x0C00,
     0x0000,0x0000,0x0000,0x0C00,0x0FFF,0xFFFF,0xFFFF,0x8C00,
     0x0C00,0x0000,0x0000,0x0C00,0x0C1F,0xFFFF,0xFFE0,0x0C00,
     0x0C17,0xFFFF,0xFFA0,0x0C00,0x0C1E,0x08BF,0xFFE0,0x0C00,
     0x0C17,0xFFFF,0xFFA0,0x0C00,0x0C1F,0x25FF,0xFFE0,0x0C00,
     0x0C17,0xFFFF,0xFFA0,0x0C00,0x0C1F,0x0BFF,0xFFE0,0x0C00,
     0x0C17,0xFFFF,0xFFA0,0x0C00,0x0C1E,0x1FFF,0xFFE0,0x0C00,
     0x0C16,0xFFFF,0xFFA0,0x0C00,0x0C1E,0x7FFF,0xFFE0,0x0C00,
     0x0C17,0xFFFF,0xFFA0,0x0C00,0x0800,0x0000,0x0000,0x0C00,
     0x0000,0x0000,0x0000,0x0C00,0x007B,0xFF9E,0x7FF8,0x0C00,
     0x0031,0x98CE,0x7318,0x0C00,0x001B,0x186F,0xF318,0x0C00,
     0x001B,0x186F,0xF360,0x0C00,0x000E,0x186D,0xB3E0,0x0C00,
     0x001B,0x186D,0xB360,0x0C00,0x001B,0x186C,0x3318,0x0C00,
     0x0031,0x98CC,0x3318,0x0C00,0x007B,0xFF9E,0x7FF8,0x0C00,
     0x0000,0x0000,0x0000,0x0C00,0x7FFF,0xFFFF,0xFFFF,0xFC00,
     /* Plane 1 */
     0xFFFF,0xFFFF,0xFFFF,0xF800,0xD555,0x5555,0x5555,0x5000,
     0xD555,0x5555,0x5555,0x5000,0xD000,0x0000,0x0000,0x5000,
     0xD000,0x0000,0x0000,0xD000,0xD000,0x0000,0x0000,0xD000,
     0xD003,0xFFFF,0xFF00,0xD000,0xD003,0xFFFF,0xFF00,0xD000,
     0xD003,0xFFFF,0xFF00,0xD000,0xD003,0xFFFF,0xFF00,0xD000,
     0xD003,0xFFFF,0xFF00,0xD000,0xD003,0xFFFF,0xFF00,0xD000,
     0xD003,0xFFFF,0xFF00,0xD000,0xD003,0xFFFF,0xFF00,0xD000,
     0xD003,0xFFFF,0xFF00,0xD000,0xD003,0xFFFF,0xFF00,0xD000,
     0xD003,0xFFFF,0xFF00,0xD000,0xD7FF,0xFFFF,0xFFFF,0xD000,
     0xD555,0x5555,0x5555,0x5000,0xD504,0x0041,0x0005,0x5000,
     0xD544,0x4511,0x0445,0x5000,0xD544,0x4510,0x0445,0x5000,
     0xD544,0x4510,0x0415,0x5000,0xD551,0x4510,0x4415,0x5000,
     0xD544,0x4510,0x4415,0x5000,0xD544,0x4511,0x4445,0x5000,
     0xD544,0x4511,0x4445,0x5000,0xD504,0x0041,0x0005,0x5000,
     0xD555,0x5555,0x5555,0x5000,0x8000,0x0000,0x0000,0x0000
    };
    const static struct Image image =
    {
     0, 0, 54, 30, 2, (unsigned short *)ga, 3, 0, NULL
    };

    clrmem (gad, sizeof(struct Gadget));

    gad->Width	      = 54;
    gad->Height       = 31; /* Blank line between Image and Text ! */
    gad->Flags	      = GADGIMAGE|GADGHCOMP;
    gad->GadgetType   = BOOLGADGET;
    gad->Activation   = RELVERIFY|GADGIMMEDIATE;
    gad->GadgetRender = (APTR)&image;
} /* makemygadget */


/*
 * return index of first non space.  Returns 0 if no spaces found.
 */

int firstns (char * str)
{
    short i;

    for (i = 0; str[i] && str[i] == ' '; i ++);

    if (str[i] == 0)
	i = 0;

    return (i);
} /* firstns */


/*
 *  Return index of last non-space, 0 if no spaces.
 */

int lastns (char * str)
{
    short i;

    /* get last char of string (i might be -1 after that !).
       now walk left until a char != ' ' is found or i == 0. */
    for (i = strlen(str) - 1; i > 0 && str[i] == ' '; i --);

    if (i < 0)  /* string empty */
	i = 0;

    return (i);
} /* lastns */


/*
 *  Return length of word under cursor
 */

int wordlen (char * str)
{
    short i;

    for (i = 0; *str && *str != ' '; ++i, ++str);

    return(i);
} /* wordlen */


/*
 *  Backtracks the program lock, 0 on failure, 1 on success.
 *  The filename is appended to the lock, if it exists.
 */

Bool getpathto (BPTR lock, char * filename, char * buf)
{
    Bool success;

    if (!NameFromLock (lock, buf, PATHSIZE))
	return (FALSE);

    if (filename)
	AddPart (buf, filename, PATHSIZE);

    return (TRUE);
}


/*
 *  Allocation routines and other shortcuts
 */

static LINE empty_line = "";

void * allocline (long size)
{
     if (size <= 1) return (empty_line);     /* no more tiny empty blocks */

     /* Make sure we always get a padded block */
     size += 7;
     size &= ~7;

     return (AllocMem (size, 0));
} /* allocline */


void freeline (LINE line)
{
    short size;

    if (line && line != empty_line)
    {
	size = strlen (line) + 8;
	size &= ~7;

	FreeMem (line, size);
    }
} /* freeline */


/*
 *  Remove tabs in a buffer
 */

int detab (char * ibuf, char * obuf, int maxlen)
{
    short i, j;

    maxlen -= 1;

    for (i = j = 0; ibuf[i] && j < maxlen; ++i)
    {
	if (ibuf[i] == 9)
	{
	    do
	    {
		obuf[j++] = ' ';
	    } while ((j & 7) && j < maxlen);
	} else
	{
	    obuf[j++] = ibuf[i];
	}
    }

    if (j && obuf[j-1] == '\n')
	--j;

    while (j && obuf[j-1] == ' ')
	--j;

    obuf[j] = 0;

    return (j);
} /* detab */


int xefgets (FILE * fi, char * buf, int max)
{
    char ebuf[MAXLINELEN];

    if (fgets (ebuf, max, fi))
	return (detab (ebuf, buf, max));

    return (-1);
} /* xefgets */


ED * finded (char * str, int doff)

{
    ED *ed;

    for (ed = (ED *)GetHead(&DBase); ed; ed=(ED *)GetSucc((struct Node *)ed))
    {
	if (strlen (ed->name) >= doff && stricmp (str, ed->name+doff) == 0)
	    return (ed);
    }

    return (NULL);
} /* finded */


void mountrequest (int bool)
{
    static APTR     original_pr_WindowPtr = NULL;
    register PROC * proc;

    proc = (PROC *)FindTask (0);

    if (!bool && proc->pr_WindowPtr != (APTR)-1)
    {
	original_pr_WindowPtr = proc->pr_WindowPtr;
	proc->pr_WindowPtr    = (APTR)-1;
    }

    if (bool && proc->pr_WindowPtr == (APTR)-1)
	proc->pr_WindowPtr = original_pr_WindowPtr;
} /* mountrequest */


/*
 *  GETFONT()
 *
 *  This function properly searches resident and disk fonts for the
 *  font.
 */

struct Library * DiskfontBase;

FONT * GetFont (char * name, short size)
{
    FONT * font1;
    TA	   Ta;
    USHORT pos;

    strcpy (tmp_buffer, name);
    pos = strlen (tmp_buffer);

    if (pos < 6 || (pos > 5 && stricmp (tmp_buffer + pos - 5, ".font")))
	strcpy (tmp_buffer + pos, ".font");

    Ta.ta_Name	= (UBYTE *)tmp_buffer;
    Ta.ta_YSize = size;
    Ta.ta_Style = 0;
    Ta.ta_Flags = 0;

    font1 = OpenFont (&Ta);

    if (!font1 || font1->tf_YSize != Ta.ta_YSize)
    {
	FONT * font2;

	if (DiskfontBase = OpenLibrary ("diskfont.library", 0L))
	{
	    if (font2 = OpenDiskFont (&Ta))
	    {
		if (font1)
		    CloseFont (font1);

		font1 = font2;

		CloseLibrary (DiskfontBase);
	    }
	}
    } /* if !font1 || Wrong_Font_Size */

    return (font1);
} /* GetFont */


void movetocursor (void)
{
    Move (Ep->win->RPort, COLT(Ep->column - Ep->topcolumn),
	  ROWT(Ep->line - Ep->topline));
} /* movetocursor */


int extend (ED * ep, int lines)
{
    long   extra = ep->maxlines - ep->lines;
    LINE * list;

    if (lines > extra)
    {
	lines += ep->lines;

	if (list = (LINE *)alloclptr(lines))
	{
	    bmovl (ep->list, list, ep->lines);
	    FreeMem (ep->list, sizeof(LINE) * ep->maxlines);

	    ep->maxlines = lines;
	    ep->list	 = list;

	    return (1);
	}

	nomemory ();
	return (0);
    }

    return (1);
} /* extend */


int makeroom (int n)
{
    ED * ep = Ep;

    if (ep->lines >= ep->maxlines)
	return (extend (ep, n));

    return (1);
} /* makeroom */


void freelist (LINE * list, int n)
{
    while (n)
    {
	freeline (list[0]);
	list ++;
	n --;
    }
} /* freelist */


void do_undo (void)
{
    text_load ();
    text_redisplaycurrline ();
} /* do_undo */


long lineflags (int line)
{
    long flags;

    if (line < Ep->topline)
	flags = LINE_ABOVE;
    else if (line < Ep->topline + Lines)
	flags = LINE_VISIBLE;
    else
	flags = LINE_BELOW;

    return (flags);
} /* lineflags */


void scroll_display (short dx, short dy, Column lc, Line tl, Column rc, Line bl)
{
    ushort width, height;
    Line lines, rest;
    ushort x1, y1, x2, y2, t;
    Line bottom;
    Column right;
    RP * rp;

    if (Ep->iconmode || Nsu) return;

    if (bl < Ep->topline || tl >= Ep->topline+Lines || rc < Ep->topcolumn ||
	lc >= Ep->topcolumn + Columns) return;

    if (!(dx || dy) ) return;

    if (tl < Ep->topline) tl = Ep->topline;
    if (bl >= Ep->topline+Lines) bl = Ep->topline + Lines - 1;
    if (lc < Ep->topcolumn) lc = Ep->topcolumn;
    if (rc >= Ep->topcolumn+Columns) rc = Ep->topcolumn + Columns - 1;

    if (bl > Ep->lines)
    {
	bottom = bl - Ep->lines;
    } else
    {
	bottom = 0;
    }

    if (rc > MAXLINELEN)
    {
	right = rc - MAXLINELEN;
    } else
    {
	right = 0;
    }

    width = rc - lc - right;
    height = bl - tl - bottom;

    if (dx)
    {
	lines = ABS(dx);
	if (lines >= width) rest = 0;
	else rest = width - lines;

	dx *= Xsize;
    } else
    {
	lines = ABS(dy);
	if (lines >= height) rest = 0;
	else rest = height - lines;

	dy *= Ysize;
    }

    rest ++;

    x1 = lc - Ep->topcolumn;
    x2 = rc - Ep->topcolumn;
    y1 = tl - Ep->topline;
    y2 = bl - Ep->topline;

    t = y1;

    x1 = COL(x1);
    x2 = COL(x2+1)-1;
    y1 = ROW(y1);
    y2 = ROW(y2+1)-1;

    rp = Ep->win->RPort;

#ifdef DEBUG
    D(bug("scroll_display: rest %d  lines %d  t %d (%d,%d)-(%d,%d)\n",
	  rest, lines, t, x1, y1, x2, y2));
#endif

    SetWrMsk (rp, -1);
    SetBPen (rp, TEXT_BPEN);

    if (rest)
    {
	ScrollRaster (rp, dx, dy, x1, y1, x2, y2);

	if (dx)
	{
	    Line   line;
	    Column col;

	    line = tl;
	    col  = lc;

	    if (dx > 0)
		col += rest;

	    redraw_block (TRUE, line, col, line + height, col + lines - 1);
	} else
	{
	    if (dy < 0)
	    {
		text_displayseg (t, lines);
	    } else
	    {
		text_displayseg (t+rest, lines);
	    }
	}
    } else
    {
	SetAPen (rp, TEXT_BPEN);
	RectFill (rp, x1, y1, x2, y2);

	text_displayseg (t, height);
    }
} /* scroll_display */


char * skip_whitespace (char * ptr)
{
    while (isspace (*ptr)) ptr ++;

    return (ptr);
} /* skip_whitespace */


#ifdef PATCH_NULL
/*
 *  IS_NUMBER
 *  tests if a string represents a valid number, i.e.
 *  if there are only numbers in it ( what about spaces around,
 *  and + before a number, do they disturb atol??? )
 */

char is_number (char * str)           /* represents a string a number? */
{
    while (*str==' ')           /* ignore leading spaces */
    {
	str++;
    } /* while */

    if ((*str=='-')||(*str=='+'))  /* dont worry about +/- */
    {
	str++;
    } /* if */

    while (isdigit(*str))     /* if there are only numbers in str: ok */
    {
	str++;
    } /* while */

    while (*str==' ')          /* ignore ending spaces */
    {
	str++;
    } /* while */

    return (!*str);
} /* is_number */


char * getnextcomline (FILE* fi, int * lineno)
{
    /* skipps comments and emptylines */
    char* buf;
    char* ptr;
    do
    {
	if (lineno)
	{
	    (*lineno)++; /* Welches hat Priortaet?? */
	} /* if */

	buf = tmp_buffer;
	if ((xefgets(fi, tmp_buffer, LINE_LENGTH))<0)
	/* buf = fgets(tmp_buffer, LINE_LENGTH, fi); */
	if (!buf)
	{
	    error ("%s:\nUnexpected End Of File Encountered", av[0]);
	    return(NULL);
	} /* if */
	buf[255] = 0; /* marker for eol */
	while (*buf<33 && *buf)
	{
	    buf++;
	} /* while */
    } while (buf[0] == 0 || buf[0] == '#');
    for (ptr = buf; *ptr;ptr++)
    {
	if (*ptr == 10)
	{
	    *ptr = 0;
	} /* if */
    } /* for */
    return(buf);
} /* getnextcomline */


/*
 *  fname
 *
 *  instead of a macro: sets a ptr to the filename of a full path&filename
 *  (returniert einen Zeiger auf den namensteil eines pfades)
 *
 * SHOULD BE PUT INTO SUBS.C
 */

char * fname (char * fullpath)
{
    return (FilePart (fullpath));
} /* fname */

#endif /* PATCH_NULL */


Bool switch_ed (ED * newed)
{
    Bool success;

    if (newed)
    {
	if (Ep)
	    text_sync ();

	Ep = newed;

	text_load ();

	if (!Ep->iconmode)
	{
	    set_window_params ();
	    window_title ();
	}

	text_cursor (1);

	success = TRUE;
    } else
	success = FALSE;

    return (success);
} /* switch_ed */


void MakeRectVisible (WIN * win, USHORT minx, USHORT miny, USHORT maxx,
								   USHORT maxy)
{
    struct DimensionInfo diminfo;
    struct Screen      * screen        = win->WScreen;
    ULONG		 Width, Height;
    WORD		 dx, dy;

    GetDisplayInfoData (NULL,
			(UBYTE *)&diminfo,
			sizeof(diminfo),
			DTAG_DIMS,
			GetVPModeID (&screen->ViewPort)
    );

    Width  = diminfo.TxtOScan.MaxX - diminfo.TxtOScan.MinX;
    Height = diminfo.TxtOScan.MaxY - diminfo.TxtOScan.MinY;

    if (Width > screen->Width)
	Width = screen->Width;

    if (Height > screen->Height)
	Height = screen->Height;

    if (minx < win->LeftEdge)
	minx = win->LeftEdge;

    if (miny < win->TopEdge)
	miny = win->TopEdge;

    if (maxx > win->LeftEdge + win->Width)
	maxx = win->LeftEdge + win->Width;

    if (maxy > win->TopEdge + win->Height)
	maxy = win->TopEdge + win->Height;

    dx = (Width - screen->LeftEdge) - maxx + 1;

    if (dx > 0)
    {
	dx = minx + screen->LeftEdge;

	if (dx > 0)
	    dx = 0;
	else
	    dx = -dx;
    }

    dy = (Height - screen->TopEdge) - maxy + 1;

    if (dy > 0)
    {
	dy = miny + screen->TopEdge;

	if (dy >= 0)
	    dy = 0;
	else
	    dy = -dy;
    }

    MoveScreen (screen, dx, dy);
} /* MakeRectVisible */


int LINELEN (ED * ep, Line nr)
{
    int len;

    if (nr == ep->line)
    {
	/* line is in Current */

	if ((len = lastns ((char *)Current)) || (*Current && *Current != ' '))
	    len ++;
    }
    else
	len = strlen (GETTEXT(ep,nr));

    return (len);
} /* LINELEN */


/******************************************************************************
*****  ENDE subs.c
******************************************************************************/
