/**FSIO.c****************************************************************
 *									*
 *   SeePix -- by Hank Schafer						*
 *									*
 *   SeePix is an IFF Picture Viewer.  It works with Lo-Res,		*
 *   Med-Res, Hi-Res, HAM, and EHB formats.  I'm working on support     *
 *   for X-Specs, and Anim5 formats.					*
 *									*
 *   SeePix is based on a program by Olaf Barthel, called		*
 *   'LoadImage'.  As released, LoadImage had a couple of bugs. 	*
 *   The Amiga-Key alternatives to menu use didn't all work.  That's	*
 *   been fixed.  There were two separate print functions in LoadImage	*
 *   which behaved exactly the same.  The redundancy was eliminated.	*
 *   LoadImage used the Topaz ROMFONT, and made no allowances for a	*
 *   different system default font (under 2.04).  I added a built-in	*
 *   font.  I've reworked the code considerably from the original       *
 *   release, to allow for optimizations based on time and space.	*
 *									*
 *   SeePix features a palette tool which allows "tweaking" of colors	*
 *   prior to printing, allowing you to modify the color printout to	*
 *   more closely resemble the original graphics (Blue is Blue, not	*
 *   Purple).  SeePix can be Iconified.  SeePix features an ARP 	*
 *   interface.  SeePix now uses the PathMaster File Selector.		*
 *									*
 ************************************************************************
 *                                                                      *
 *   SeePix Copyright © 1992 by Hank Schafer; all rights reserved.      *
 *                                                                      *
 *   This program is free software; you can redistribute it and/or      *
 *   modify it under the terms of the GNU General Public License as     *
 *   published by the Free Software Foundation, either version 1, or    *
 *   (at your option) any later version.                                *
 *                                                                      *
 *   This program is distributed in the hope that it will be useful,    *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of     *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU  *
 *   General Public License for more details.                           *
 *                                                                      *
 *   You should have received a copy of the GNU General Public License  *
 *   along with this program; if not, write to:                         *
 *                 Free Software Foundation, Inc.                       *
 *                 675 Massachusetts Ave.                               *
 *                 Cambridge  MA  02139, USA                            *
 *                                                                      *
 **************** Special Function Copyright Notices ********************
 *									*
 ****LoadImage Copyright Notice:					*
 *									*
 *   LoadImage is © Copyright 1988, 1989, 1990 by MXM, all rights	*
 *   reserved, written by Olaf Barthel.  No guarantees of any kind are	*
 *   made that this program is 100% reliable.  Use this program on	*
 *   your own risk!							*
 *									*
 ****Iconify Copyright Notice:						*
 *									*
 *   Copyright 1987 by Leo L. Schwab.					*
 *   Permission is hereby granted for use in any and all programs,	*
 *   both Public Domain and commercial in nature, provided this 	*
 *   Copyright notice is left intact.					*
 *									*
 ****ColorWindow (Palette) Copyright Notice:				*
 *									*
 * ColorWindow Routine	--  Color Window Routines			*
 *     from Book 1 of the Amiga Programmers' Suite by RJ Mical          *
 *									*
 * Copyright (C) 1986, 1987, Robert J. Mical				*
 * All Rights Reserved. 						*
 *									*
 ****PathMaster Copyright Notice:					*
 *									*
 * -------------------------------------------------------------------- *
 *   Copyright © 1989 Justin V. McCormick.  All Rights Reserved.	*
 * -------------------------------------------------------------------- *
 *									*
 *    The PathMaster name is a trademark of Justin V. McCormick.	*
 *									*
 *   PathMaster File Selector source and documentation written by:	*
 *									*
 *			 Justin V. McCormick.				*
 *	       Copyright © 1989 by Justin V. McCormick. 		*
 *			 All Rights Reserved.				*
 *									*
 * -------------------------------------------------------------------- *
 ************************************************************************
 *									*
 *   Hope this is something you can use and enjoy.			*
 *									*
 ************************************************************************/

#ifdef	PATHMASTER

/*
 * Clean out any pending async IO in a given IORequest type struct.
 */

VOID
AbortAsyncIO(req)
    struct IORequest *req;
{
    if (req->io_Command != 0 && CheckIO(req) == 0) {
	(VOID) AbortIO(req);
	(VOID) WaitIO(req);
    }
}

LONG
FSGrabEntry()
{
    struct file_node *tnode;

    if (fsvirgindir > 0) {	/* Brand new list */
	fstitstatus = 27;	/* Set our windowtitle to Reading */
	FSWinTitle();

	FreeAllFNodes();	/* Clean out old list */
	FSSetKnob();		/* Show full height knob now */
	FSDisableAllFGads();

	if (FSLockDir() == 0)	/* Try to lock the new path */
	    goto CrapOut1;	/* Lock failed */
    }
    if (fnList == 0) {
	if ((fnList = AllocMem((LONG) sizeof(struct MinList), 0L)) == 0)
	    goto CrapOut0;
	NewList(fnList);
    }
    if (FSGetNextFib() <= 0)	/* Try to Examine entry */
	goto CrapOut1;		/* We are done!? */

    /* Initialize new node */

    if ((tnode = AllocFileNode()) == 0)
	goto CrapOut0;

    if (fsvirgindir > 0)	/* New list, needs new head! */
	fsvirgindir = -1;	/* Still TRUE, but avoid relocking dir */

    /* Fill in the info */

    FillFileNode(tnode);
    return (1L);

  CrapOut0:
    FreeFileSelect();
    fstitstatus = 26;
    FSWinTitle();
    return (0L);

  CrapOut1:
    if ((fsflags & FS_DELAYED_SORT) == 0)
	FSUpdateSort();
    if (fsnumentries > 10 && (fsnumentries & 0x01) != 0)
	FSResetKnob();
    fsvirgindir = 0;
    FSClearLock();
    FSWinTitle();
    return (1L);
}

LONG
FSLockDir()
{
    LONG	    namlen;
    struct CommandLineInterface *thiscli;
    struct Process *thisproc;
    struct Window  *oldwin;
    UBYTE	   *tstr;

    /* Inhibit System Requesters */

    thisproc = (struct Process *) FindTask(0L);
    oldwin = (struct Window *) thisproc->pr_WindowPtr;
    thisproc->pr_WindowPtr = (CPTR) - 1L;

    /* Backup last locked pathname and set new pathname */

    (VOID) strcpy(OldFSPathBuf, FSPathBuf);
    (VOID) strcpy(FSPathBuf, FSPathInfo.Buffer);

    /* Make sure we release previous lock */

    FSClearLock();

    /* Allocate a fileinfoblock, if we have to */

    if (AllocFSFib() == 0) {
	fstitstatus = 26;
	goto SNAFUDIR;
    }
    /* Lock new path */

  locknewpath:
    if (FSPathBuf[0] != 0) {	/* Path is named, no guesswork */
	FSPutPath();
	if ((FSLock = (BPTR) Lock(FSPathBuf, (LONG) ACCESS_READ)) == 0) {
	    fstitstatus = ioerrnum(IoErr());
	    goto SNAFUDIR;
	}
	fsdirlocked = 1;	/* Got a live one here! */
    } else {			/* Use current directory */
	if (thisproc->pr_CurrentDir == 0) {
	    fstitstatus = 3;
	    goto SNAFUDIR;
	}
	FSLock = (BPTR) thisproc->pr_CurrentDir;
	fsdirlocked = 0;
    }

    /* Get a FileInfoBlock for this lock */

    if (Examine((BPTR) FSLock, (BPTR) FSFib) == 0) {
	fstitstatus = ioerrnum(IoErr());
	goto SNAFUDIR;
    } else {
	if (FSFib->fib_DirEntryType < 0) {
	    fstitstatus = 2;
	    goto SNAFUDIR;
	}
    }

    /* Copy DateStamp for later comparison */

    FSdirstamp = FSFib->fib_Date;

    if (FSPathBuf[0] == (BYTE) 0) {

	/* Try to extract pathname from AmigaDOS */

	if (thisproc->pr_CLI != 0) {	/* is this a CLI? */
	    thiscli = (struct CommandLineInterface *) ((ULONG) thisproc->pr_CLI << 2L);
	    tstr = (UBYTE *) ((ULONG) thiscli->cli_SetName << 2L);
	    namlen = (LONG) * tstr;
	    safestrcpy(FSPathBuf, (BYTE *) ((ULONG) tstr + 1L), (LONG) namlen);
	} else {		/* must be WorkBench, use Fib name */
	    MakePathString((struct FileLock *) FSLock, FSPathBuf);
	}

	/* Copy path to StringInfo buffer, display */

	(VOID) strcpy(FSPathInfo.Buffer, FSPathBuf);
	FSPutPath();
    }
    thisproc->pr_WindowPtr = (CPTR) oldwin;
    return (1L);

    /* In case of dire directory problem */

  SNAFUDIR:
    thisproc->pr_WindowPtr = (CPTR) oldwin;
    return (0L);
}

/*
 * Called when diskremoved, to see if the disk we are displaying has changed
 * and needs to be re-read.
 */

LONG
FSTestOldLock()
{
    LONG	    locked;
    LONG	    status, oldtitstatus;
    struct FileInfoBlock *fib;
    struct FileLock *flock = 0;
    struct Process *proc;
    struct Window  *oldwin;
    status = 0;
    locked = 0;
    oldtitstatus = fstitstatus;
    proc = (struct Process *) FindTask(0L);
    oldwin = (struct Window *) proc->pr_WindowPtr;
    proc->pr_WindowPtr = (CPTR) - 1L;

    /* Allocate a fileinfoblock */

    if ((fib = (struct FileInfoBlock *) AllocMem((LONG) sizeof(struct FileInfoBlock), MEMF_CLEAR)) == 0) {
	fstitstatus = 26;
	goto BadLock;
    }
    /* Try to lock path */

    if (FSPathBuf[0] != 0) {	/* Path is named, no guesswork */
	if ((flock = (struct FileLock *) Lock(FSPathBuf, (LONG) ACCESS_READ)) == 0) {
	    fstitstatus = ioerrnum(IoErr());
	    goto BadLock;
	}
	locked = 1;
    } else			/* Use current directory */
	flock = (struct FileLock *) proc->pr_CurrentDir;

    /* Examine the root block */

    if (Examine((BPTR) flock, (BPTR) fib) == 0) {
	fstitstatus = ioerrnum(IoErr());
	goto BadLock;
    } else {
	if (fib->fib_DirEntryType < 0) {
	    fstitstatus = 3;
	    goto BadLock;
	}
    }
    if (FSdirstamp.ds_Days == fib->fib_Date.ds_Days && FSdirstamp.ds_Minute == fib->fib_Date.ds_Minute && FSdirstamp.ds_Tick == fib->fib_Date.ds_Tick)
	status = 1;
    else
	status = 0;

    /* In case of dire directory problem */

  BadLock:
    proc->pr_WindowPtr = (CPTR) oldwin;
    if (locked != 0) {
	UnLock((BPTR) flock);
    }
    if (fib != 0) {
	FreeMem(fib, (LONG) sizeof(struct FileInfoBlock));
    }
    if (status == 0) {
	fsvirgindir = 1;
	FSdirstamp.ds_Days = FSdirstamp.ds_Minute = FSdirstamp.ds_Tick = 0;
	if (fstitstatus != oldtitstatus)
	    FSWinTitle();
    }
    return (status);
}

/*
 * Constructs a circular doubly-linked list of device name nodes
 */

LONG
FSGetDevs()
{
    LONG	    blen;
    LONG	    ramflag = 0;/* Flag whether RAM: device found */
    struct DeviceNode *dn;
    struct dev_node *tnode;
    struct DosInfo *di;
    struct RootNode *root;
    UBYTE	   *bstring;

    /* Allocate a MinList for use */

    if (devList == 0) {
	if ((devList = AllocMem((LONG) sizeof(struct MinList), 0L)) == 0)
	    return (0L);
    }
    NewList(devList);

    /* Grab pointer to DosInfo device root */

    root = (struct RootNode *) DOSBase->dl_Root;
    di = (struct DosInfo *) BADDR(root->rn_Info);
    dn = (struct DeviceNode *) BADDR(di->di_DevInfo);

    /* Don't let other processes muck with us during this sneaky stuff */

    Forbid();

    /* Starting with root devinfo, set devnames till out of devices */

    for (; dn != 0; dn = (struct DeviceNode *) BADDR(dn->dn_Next)) {
	/* Found a device? */
	if ((dn->dn_Type == 0) && (dn->dn_Task != 0) && (dn->dn_Name != 0)) {

	    /* Try to allocate a node */

	    if ((tnode = AllocDevNode()) != 0) {
		bstring = (UBYTE *) BADDR(dn->dn_Name);	/* Pointer to BSTR name */
		blen = (LONG) bstring[0];	/* Length of BSTR */
		CopyMem((BYTE *) (bstring + 1), (char *) tnode->name, (LONG) blen);
		bstring = tnode->name;
		bstring[blen] = ':';	/* Append a colon to copy of name */

		if (lstrcmp(bstring, RamDirNameStr) == 0)
		    ramflag = 1;

		AddHead(devList, (struct Node *) tnode);
	    } else {

		/* Can't allocate a node, free 'em all and  crap out */

		Permit();
		FreeAllDNodes();
		return (0L);
	    }
	}
    }
    Permit();

    /* RAM device wasn't out there, add it to list */

    if (ramflag == 0) {
	if ((tnode = AllocDevNode()) == 0) {
	    FreeAllDNodes();
	    return (0L);
	}
	(VOID) strcpy((BYTE *) tnode->name, RamDirNameStr);
	AddHead(devList, (struct Node *) tnode);
    }
    /* This is the first node, start display with this */

    lastdev = tnode;
    return (1L);
}

VOID
CheckFSIDCMP()
{
    BYTE	   *tstr1, *tstr2;
    LONG	    my;
    struct Gadget  *tgadget;
    struct IntuiMessage *imsg;
    ULONG	    class, qualifier;
    ULONG	    code;
    ULONG	    secs, micros;

    while ((imsg = (struct IntuiMessage *) GetMsg(FSWin->UserPort)) != 0) {
	class = imsg->Class;
	qualifier = imsg->Qualifier;
	code = imsg->Code;
	micros = imsg->Micros;
	secs = imsg->Seconds;
	my = imsg->MouseY;

	tgadget = (struct Gadget *) imsg->IAddress;
	ReplyMsg((struct Message *) imsg);

	switch (class) {
	case INTUITICKS:
	    CheckFSArrows();
	    break;
	case RAWKEY:
	    switch (code) {
	    case 0x45:		/* Escape */
		FSDone = 1;
		FSReq->fullname[0] = (BYTE) 0;
		break;
	    case 0x4c:		/* Up cursor 	 */
		FSScrollFileGads(1L);
		break;
	    case 0x4d:		/* Down cursor 	 */
		FSScrollFileGads(0L);
		break;
	    }
	    break;
	case MOUSEBUTTONS:
	    if (code == SELECTDOWN) {
		if (fsstartedstr != 0)
		    FSEndString();
	    } else if (code == MENUUP) {
		if (fsstartedstr != 2)
		    MyActivateGad(&FSPathGad, FSWin);
		else
		    MyActivateGad(&FSFileGad, FSWin);
	    }
	    break;
	case GADGETDOWN:
	    if (fsstartedstr != 0) {
		FSEndString();
	    }
	    code = tgadget->GadgetID;
	    switch (code) {
	    case 10:		/* Alpha */
	    case 11:		/* Size	*/
	    case 12:		/* Time	*/
		FSDoSortGadget((LONG) code - 10);
		break;
	    case 30:		/* FSPatternGad	 */
		fsstartedstr = 3;
		break;
	    case 31:		/* FSFileGad */
		fsstartedstr = 1;
		break;
	    case 32:		/* FSPathGad */
		fsstartedstr = 2;
		break;
	    case 33:		/* SlideGad 	 */
	    case 40:		/* Up Arrow 	 */
	    case 41:		/* Down Arrow	 */
	    case 42:		/* Up Device	 */
	    case 43:		/* Down Device	 */
		FSStartScrollGad(code);
		break;
	    case 50:		/* FSFileGad0	 */
		code = (my - 12) / 11;
		if (FSFileNodes[code] != 0) {
		    fscursecs = secs;
		    fscurmicros = micros;
		    HCompEntry(code);
		    FSVBDelay(5L);
		    HCompEntry(code);
		    FSDoFileGad((LONG) my);
		    fsoldsecs = secs;
		    fsoldmicros = micros;
		}
		break;
	    }
	    break;
	case GADGETUP:
	    code = tgadget->GadgetID;
	    if (fsstartedstr != 0) {
		if ((qualifier & 0x0003) != 0) {
		    if (fsstartedstr == 1) {
			MyActivateGad(&FSPathGad, FSWin);
		    } else {
			MyActivateGad(&FSFileGad, FSWin);
		    }
		    code = 100;
		} else {
		    if (fsstartedstr == 1) {
			if ((tstr1 = myrindex(FSFileInfo.Buffer, (LONG) '/')) != 0) {
			    *tstr1 = '\x0';
			    tstr1++;
			    (VOID) strcpy(FSwstr, tstr1);
			} else {
			    if ((tstr2 = myrindex(FSFileInfo.Buffer, (LONG) ':')) != 0) {
				tstr2++;
				(VOID) strcpy(FSwstr, tstr2);
				*tstr2 = (BYTE) 0;
			    }
			}
			if (tstr1 != 0 || tstr2 != 0) {
			    (VOID) strcpy(FSPathInfo.Buffer, FSFileInfo.Buffer);
			    (VOID) strcpy(FSPathBuf, FSFileInfo.Buffer);
			    (VOID) strcpy(FSFileInfo.Buffer, FSwstr);
			    FSFileInfo.BufferPos = strlen(FSFileInfo.Buffer);
			    RefreshGList(&FSFileGad, FSWin, 0L, 2L);
			    MyActivateGad(&FSFileGad, FSWin);
			    fsvirgindir = 1;
			}
		    }
		}
		fsstartedstr = 0;
	    }
	    FSDoGadget(code);
	    break;
	case DISKREMOVED:
	case DISKINSERTED:

	    /* if disk has stopped spinning... */

	    if (fsvirgindir == 0)
		/* See if we can lock our old place still */

		(VOID) FSTestOldLock();
	    break;
	}
    }
}

#endif	/* PATHMASTER */
