/*
**	Misc.c
**
**	Copyright (C) 1993,94,95,96 Bernardo Innocenti
**
**	Parts of this file are:
**
**	Copyright © 1990-1993 by Olaf `Olsen' Barthel & MXM
**		All Rights Reserved
**
**	Miscellaneus useful functions
*/

#include <exec/ports.h>
#include <workbench/startup.h>

#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/icon.h>
#include <proto/graphics.h>

#include "XModulePriv.h"
#include "Gui.h"


#if 0 /* --- This part has been removed --- */

/* Function pointers to Kickstart-sensitive RastPort query code */
ULONG (*ReadAPen)(struct RastPort *RPort);
ULONG (*ReadBPen)(struct RastPort *RPort);
ULONG (*ReadDrMd)(struct RastPort *RPort);



/* Local function prototypes */
static ULONG OldGetAPen (struct RastPort *RPort);
static ULONG OldGetBPen (struct RastPort *RPort);
static ULONG OldGetDrMd (struct RastPort *RPort);
static ULONG NewGetAPen (struct RastPort *RPort);
static ULONG NewGetBPen (struct RastPort *RPort);
static ULONG NewGetDrMd (struct RastPort *RPort);

#endif /* --- This part has been removed --- */



GLOBALCALL struct DiskObject *GetProgramIcon (void)

/* Get program associated icon.
 * This function will fail if we are not a son of Workbench.
 * The returned DiskObject must be freed by FreeDiskObject().
 */
{
	struct DiskObject *dobj;
	BPTR olddir;

	if (!WBenchMsg) return NULL;

	olddir = CurrentDir (WBenchMsg->sm_ArgList->wa_Lock);
	dobj = GetDiskObject (WBenchMsg->sm_ArgList->wa_Name);
	CurrentDir (olddir);

	return dobj;
}



GLOBALCALL struct Library *MyOpenLibrary (CONST_STRPTR name, ULONG ver)
{
	struct Library *lib;
	BPTR progdir = NULL;

	while (!(lib = OpenLibrary (name, ver)))
	{
		UBYTE path[PATHNAME_MAX];


		/* Search the library file in "PROGDIR:"... */

		strcpy (path, "PROGDIR:");
		AddPart (path, name, PATHNAME_MAX);
		if (lib = OpenLibrary (path, ver))
			break;

		strcpy (path, "PROGDIR:Libs");
		AddPart (path, name, PATHNAME_MAX);
		if (lib = OpenLibrary (path, ver))
			break;

		/* Tell the user we can't find this library anywhere... */
		if (!ShowRequest (MSG_OPENLIB_FAIL, MSG_RETRY_OR_CANCEL, name, ver))
			break;
	}

	if (progdir) UnLock (progdir);

	return lib;
}



GLOBALCALL void CantOpenLib (CONST_STRPTR name, LONG ver)

/* Notify the user that a library didn't open */
{
	if (ver)
		ShowRequest (MSG_OPENLIB_VER_FAIL, MSG_CONTINUE, name, ver);
	else
		ShowRequest (MSG_OPENLIB_FAIL, MSG_CONTINUE, name);
}



GLOBALCALL void KillMsgPort (struct MsgPort *mp)

/* Reply all pending messages and call DeletePort() */
{
	struct Message *msg;

	Forbid();	/* is this really useful? */

	/* Reply all pending Messages */
	while (msg = GetMsg (mp))
		ReplyMsg (msg);

	DeleteMsgPort (mp);

	Permit();
}



GLOBALCALL struct TextAttr *CopyTextAttrPooled (void *pool, const struct TextAttr *source, struct TextAttr *dest)

/* Copy <source> textattr structure over <dest>, allocating and copying
 * the ta_Name field.  <dest>->ta_Name if FreeVec()ed before
 * allocating the new one.
 *
 * Returns: <dest> if everything was ok, NULL for failure.
 */

{
	FreeVecPooled (pool, dest->ta_Name);

	memcpy (dest, source, sizeof (struct TextAttr));

	if (dest->ta_Name = AllocVecPooled (pool, strlen (source->ta_Name) + 1))
	{
		strcpy (dest->ta_Name, source->ta_Name);
		return dest;
	}
	return NULL;
}



GLOBALCALL UWORD CmpTextAttr (const struct TextAttr *ta1, const struct TextAttr *ta2)

/* Compares two TextAttr structures and returns 0 if they refer to
 * the same font, a non-zero value otherwise.
 */
{
	if (ta1->ta_YSize == ta2->ta_YSize && ta1->ta_Style == ta2->ta_Style)
	{
		if (!ta1->ta_Name && !ta2->ta_Name)
				return 0;

		if (!ta1->ta_Name || !ta2->ta_Name)
				return 1;

		if (!strcmp (ta1->ta_Name, ta2->ta_Name))
			return 0;
	}

	return 1;
}



/* More memory pools support */

#ifdef PORTABLE

GLOBCALL void *AllocVecPooled (void *pool, ULONG size)
{
    void *mem;

	size += 4;

#ifdef OS30_ONLY
	if (mem = AllocPooled (pool, size))
#else
	if (mem = AsmAllocPooled (pool, size))
#endif
		*((ULONG *)mem)++ = size;

    return mem;
}



GLOBCALL void FreeVecPooled (void *pool, void *memory)
{
    if (mem)
    {
		--(((ULONG *)mem);
#ifdef OS30_ONLY
		FreePooled (pool, mem, *((ULONG *)mem));
#else
		AsmFreePooled (pool, mem, *((ULONG *)mem));
#endif
    }
}



GLOBCALL void *CAllocVecPooled (void *pool, ULONG size)

{
    void *mem;

	size += 4;

#ifdef OS30_ONLY
	if (mem = AllocPooled (pool, size))
#else
	if (mem = AsmAllocPooled (pool, size))
#endif
	{
		memset (mem, size, 0);
		*((ULONG *)mem)++ = size;
	}

    return mem;
}

#endif /* PORTABLE */



GLOBALCALL STRPTR DupStringPooled (void *pool, CONST_STRPTR source, STRPTR *dest)

/* Allocates a buffer big enough to fit the <source> string
 * using AllocVecPooled() and then copies the contents of <source>
 * there.  If the buffer pointed by <dest> is not NULL,
 * DupStringPooled() will first check to see if <source> and
 * <dest> are identical, in which case no new buffer will be
 * allocated and the result will be FALSE.  Otherwise, <dest> will
 * be deallocated and a new buffer will be allocated. Both <source> and <*dest>
 * can be NULL.
 *
 * RESULT
 *	Non-zero if <dest> has been reallocated, FALSE otherwise.
 */
{
	if (*dest)
	{
		if (source)
		{
			if (!(strcmp (*dest, source)))
				return NULL;
		}

		FreeVecPooled (pool, *dest);
	}

	if (source)
	{
		if (*dest = AllocVecPooled (pool, strlen (source) + 1))
			strcpy (*dest, source);
	}

	return *dest;
}



GLOBALCALL void FilterName (STRPTR name)

/* Finds and blanks out invalid characters in a string.
 * Will also strip blanks at the end.  Passing NULL is safe.
 */
{
	UWORD i = 0;

	if (!name) return;

	while (name[i])
	{
		if (name[i] < ' ' ||
			(name[i] >'~' && name[i] < '¡'))
			name[i] = ' ';

		i++;
	}

	/* Kill blanks at the end of the string */
	for (--i; i > 0 ; i--)
		if (name[i] == ' ') name[i] = '\0';
		else break;
}



GLOBALCALL LONG PutIcon (CONST_STRPTR source, CONST_STRPTR dest)

/* Add the <source> icon to <dest> file */
{
	struct DiskObject *dobj;
	UBYTE buf[PATHNAME_MAX];

	/* We do not alter existing icons */
	if (dobj = GetDiskObject (dest))
	{
		FreeDiskObject (dobj);
		return RETURN_WARN;
	}

	/* Get source icon */

	strcpy (buf, "PROGDIR:Icons");
	AddPart (buf, source, PATHNAME_MAX);
	if (!(dobj = GetDiskObject (buf)))
	{
		strcpy (buf, "ENV:Sys");
		AddPart (buf, source, PATHNAME_MAX);
		if (!(dobj = GetDiskObject (buf)))
		{
			/* Get default project icon */
			dobj = GetDefDiskObject (WBPROJECT);
		}
	}

	if (dobj)
	{
		dobj->do_CurrentX = dobj->do_CurrentY = NO_ICON_POSITION;

		if (!(dobj->do_DefaultTool[0]))
		{
			/* Get program path and store in icon's Default Tool */

			BPTR progdir;

			dobj->do_DefaultTool = NULL;

			if (WBenchMsg)	/* WB */
				progdir = WBenchMsg->sm_ArgList->wa_Lock;
			else			/* CLI */
				progdir = GetProgramDir();

			if (progdir)
			{
				if (NameFromLock (progdir, buf, PATHNAME_MAX))
				{
					UBYTE progname[32];

					if (WBenchMsg)	/* WB */
						strncpy (progname, WBenchMsg->sm_ArgList->wa_Name, 32);
					else			/* CLI*/
						GetProgramName (progname, 32);

					if(AddPart (buf, progname, PATHNAME_MAX))
						dobj->do_DefaultTool = buf;
				}
			}
		}

		if (!dobj->do_DefaultTool) dobj->do_DefaultTool = BaseName;
		PutDiskObject (dest, dobj);
		FreeDiskObject (dobj);
		return RETURN_OK;
	}

	return RETURN_FAIL;
}



static ULONG MakeBackupName (STRPTR buf, CONST_STRPTR s, CONST_STRPTR tmpl, ULONG n)

/* DESCRIPTION
 *	Subfunction for BackupFile() - Constructs a file name for the backup.
 *	<tmpl> is the template to build the backup name.
 *	Each occurence of the '#' character in the template is replaced with
 *	an ASCII decimal representation of <n>. The '*' character is replaced
 *	with the original filename <s>.
 *
 * RESULT
 *	The result is stored in <buf>. Returns TRUE if at least one occurrence
 *	of the '#' wildcard has been replaced, otherwise returns FALSE.
 *
 * BUGS
 *	Does not check for buffer overflow.
 *
 */
{
	BOOL wild_done = FALSE;
	BOOL num_done = FALSE;

	do
	{
		if ((*tmpl == '*') && (!wild_done))
		{
			/* Copy file name */

			s = FilePart (s);
			while (*buf++ = *s++);
			--buf;

			wild_done = TRUE;
		}
		else if (*tmpl == '#')
		{
			/* Insert backup number */

			if (n > 9)
				*buf++ = (n / 10) + '0';
			*buf++ = (n % 10) + '0';

			num_done = TRUE;
		}
		else if (*tmpl == '\\')
			/* Handle escape character */
			*buf++ = *++tmpl;
		else
			*buf++ = *tmpl;
	}
	while (*tmpl++);

	return num_done;
}



GLOBALCALL LONG BackupFile (CONST_STRPTR src, CONST_STRPTR template, ULONG versions)

/* Creates backups of the given file */
{
	UBYTE buf[PATHNAME_MAX], oldbuf[PATHNAME_MAX];
	ULONG i;
	BPTR lock, dir, olddir;

	if (!(lock = Lock (src, ACCESS_READ)))
		return IoErr();

	/* CD to source directory: needed for relative paths */
	dir = ParentDir (lock);
	olddir = CurrentDir (dir);


	if (!MakeBackupName (buf, src, template, 1))
	{
		/* Simple backup */
		DeleteFile (buf);
	}
	else
	{
		/* Delete oldest backup if exists */

		MakeBackupName (buf, src, template, versions);
		DeleteFile (buf);

		/* Shift all others ahead... */

		for (i = versions; i > 0; --i)
		{
			strcpy (oldbuf, buf);
			MakeBackupName (buf, src, template, i);
			Rename (buf, oldbuf);

			DB (kprintf ("Backup name is: %s\n", buf));
		}
	}

	/* And finally move file to its backup location */
	Rename (src, buf);

	/* Restore old current directory */
	CurrentDir (olddir);
	UnLock (dir);
	UnLock (lock);

	return RETURN_OK;
}



#if 0 /* --- This part has been removed --- */

GLOBALCALL void InstallGfxFunctions (void)

/* Install the correct routines to query
 * the rendering colours and drawing mode.
 */
{
	if(GfxBase->lib_Version >= 39)
	{
		ReadAPen = NewGetAPen;
		ReadBPen = NewGetBPen;
		ReadDrMd = NewGetDrMd;
	}
	else
	{
		ReadAPen = OldGetAPen;
		ReadBPen = OldGetBPen;
		ReadDrMd = OldGetDrMd;
	}
}



/* OldGetAPen(struct RastPort *RPort):
 *
 *	Query the current primary rendering colour (old style).
 */

static ULONG OldGetAPen (struct RastPort *RPort)
{
	return((ULONG)RPort->FgPen);
}



/* OldGetBPen(struct RastPort *RPort):
 *
 *	Query the current seconary rendering colour (old style).
 */

static ULONG OldGetBPen (struct RastPort *RPort)
{
	return((ULONG)RPort->BgPen);
}



/* OldGetDrMd(struct RastPort *RPort):
 *
 *	Query the current drawing mode (old style).
 */

static ULONG OldGetDrMd (struct RastPort *RPort)
{
	return((ULONG)RPort->DrawMode);
}



/* NewGetAPen(struct RastPort *RPort):
 *
 *	Query the current primary rendering colour (new style).
 */

static ULONG NewGetAPen (struct RastPort *RPort)
{
	return(GetAPen (RPort));
}



/* NewGetBPen(struct RastPort *RPort):
 *
 *	Query the current seconary rendering colour (new style).
 */

static ULONG NewGetBPen (struct RastPort *RPort)
{
	return (GetBPen (RPort));
}



/* NewGetDrMd(struct RastPort *RPort):
 *
 *	Query the current drawing mode (new style).
 */

static ULONG NewGetDrMd (struct RastPort *RPort)
{
	return(GetDrMd (RPort));
}

#endif /* --- This part has been removed --- */

