
/*
 *  SUBS.C
 *
 *	(C)Copyright 1987 by Matthew Dillon, All Rights Reserved
 *
 *  Subroutines.
 */
/*
 *  + all that was in MODS.C
 *
 *  Additional DME commands written by Kevin T. Seghetti fixed up and
 *  incorporated by Matt Dillon 17 April 1988.
 */

#include "defs.h"
#include <clib/macros.h>

Prototype void	 makemygadget	 (struct Gadget *);
Prototype int	 firstns	 (char *);
Prototype int	 lastns 	 (char *);
Prototype int	 wordlen	 (char *);
Prototype int	 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 int	 DeadKeyConvert  (struct IntuiMessage *, UBYTE *, int, struct KeyMap *);
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, ushort, ushort, ushort, ushort);
Prototype char * skip_whitespace (char *);

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

typedef struct FileInfoBlock FIB;


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

void makemygadget (struct Gadget *gad)
{
    static unsigned long ga[] = {
	0xFFFFFFFF,	/* 32 pixels across */
	0x80FDCBFD,
	0xFFFDDFFD,
	0x80000001,
	0x80DFDDDF,
	0x80000001,
	0xBC0EF00B,
	0x80000001,
	0xBFC00CDD,
	0x80000001,
	0xA00DF00F,
	0x80000001,
	0x80000001,

	0x80000001,
	0x80FDCBFD,
	0xFFFDDFFD,
	0x80000001,
	0x80DFDDDF,
	0x80000001,
	0xBC0EF00B,
	0x80000001,
	0xBFC00CDD,
	0x80000001,
	0xA00DF00F,
	0x80000001,
	0xFFFFFFFF
    };
    static struct Image image = {
	0, 0, 20, 16, 2, (unsigned short *)ga, 3, 0, NULL
    };

    clrmem(gad, sizeof(struct Gadget));

    gad->Width	      = 20;
    gad->Height       = 17;
    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;

    for (i = strlen(str) - 1; i > 0 && str[i] == ' '; i --);

    if (i < 0)
	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.
 */

int getpathto (BPTR lock, char * arg0, char * buf)
{
    FIB * fib;
    BPTR  parLock = 0L;
    int   r	  = 0;
    short lastDir = 0;

    buf[0] = 0;

    if (fib = malloc (sizeof(FIB))) {
	r = 1;

	while (lock) {
	    fib->fib_FileName[0] = 0;

	    if (Examine (lock, fib) == 0)
		return (0);

	    if (parLock) {
		parLock = ParentDir (lock);
		UnLock (lock);
	    } else {
		parLock = ParentDir (lock);
		if (fib->fib_DirEntryType > 0)
		    lastDir = 1;
	    }

	    if (parLock == 0L)
		if (*buf == '/')
		    *buf = ':';
		else {
		    *buf = ':';
		    buf[1] = 0;
		}

	    strins (buf, fib->fib_FileName);

	    if (parLock)
		strins (buf, "/");

	    lock = parLock;
	} /* while (lock) */

	free (fib);

	if (lastDir == 1) {
	    short len;
	    if ((len = strlen (buf)) && buf[len-1] != ':')
		strcat (buf, "/");
	    strcat (buf, arg0);
	} /* if (lastDir == 1) */
    } /* if malloc */

    return (r);
} /* getpathto */


/*
 *  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 *)DBase.mlh_Head; ed->Node.mln_Succ;
	    ed = (ED *)ed->Node.mln_Succ) {
	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 > 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 */


/*
 *  DEAD.C
 */

int DeadKeyConvert (struct IntuiMessage * msg, UBYTE * buf, int bufsize, struct KeyMap * keymap)
{
    static struct InputEvent ievent = {
	NULL, IECLASS_RAWKEY
    };

    if (msg->Class != RAWKEY)
	return(-2);

    ievent.ie_Code	       = msg->Code;
    ievent.ie_Qualifier        = msg->Qualifier;
    ievent.ie_position.ie_addr = *((APTR *)msg->IAddress);

    return (RawKeyConvert (&ievent, (char *)buf, bufsize, keymap));
} /* DeadKeyConvert */


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 + Rows)
	flags = LINE_VISIBLE;
    else
	flags = LINE_BELOW;

    return (flags);
} /* lineflags */


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

/*printf ("dx %d  dy %d\n", dx, dy);*/

    if (Ep->iconmode) return;

    if (bl < Ep->Topline || tl > Ep->Topline+Rows || rc < Ep->Topcolumn ||
	lc > Ep->Topcolumn + Columns) return;

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

    if (tl < Ep->Topline) tl = Ep->Topline;
    if (bl > Ep->Topline+Rows) bl = Ep->Topline + Rows;
    if (lc < Ep->Topcolumn) lc = Ep->Topcolumn;
    if (rc > Ep->Topcolumn+Columns) rc = Ep->Topcolumn + Columns;

    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;
    }

    x1 = lc - Ep->Topcolumn;
    x2 = rc - Ep->Topcolumn;
    y1 = tl - Ep->Topline;
    y2 = bl - Ep->Topline;

    if (y2 == y1) y2 = y1+1;
    if (x2 == x1) x2 = x1+1;

    t = y1;

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

    rp = Ep->Win->RPort;

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

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

	if (dx) {
	    text_displayseg (t, height);
	} else {
	    if (dy < 0) {
		text_displayseg (t, lines);
	    } else {
		text_displayseg (t+rest, lines);
	    }
	}
    } else {
	SetAPen (rp, Ep->BGPen);
	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 */
