
/* *** volname.c ************************************************************
 *
 * File IO Suite  --  Volume Name Construction Routines
 *     from Book 1 of the Amiga Programmers' Suite by RJ Mical
 *
 * Copyright (C) 1986, 1987, Robert J. Mical
 * All Rights Reserved.
 *
 * Created for Amiga developers.
 * Any or all of this code can be used in any program as long as this
 * entire copyright notice is retained, ok?  Thanks.
 *
 * HISTORY      NAME            DESCRIPTION
 * -----------  --------------  --------------------------------------------
 * 4 Feb 87     RJ              Real release
 * 12 Aug 86    RJ >:-{)*       Prepare (clean house) for release
 * 3 May 86     =RJ Mical=      Fix prop gadget for both 1.1 and 1.2
 * 1 Feb 86     =RJ Mical=      Created this file.
 *
 * *********************************************************************** */


#define FILEIO_SOURCEFILE
#include "fileio.h"
#include <libraries\dosextens.h>


/* Lattice doesn't accept the ID_DOS_DISK which looks like this:
 * #define ID_DOS_DISK ('DOS\0')
 * so I make up my own.
 */
#define X_ID_DOS_DISK (((LONG)'D'<<24)|((LONG)'O'<<16)|('S'<<8)|('\0'))


BOOL DOSDisk(device)
struct DeviceList *device;
/* This little routine dips its gnarled toes directly into the 
 * scary murky depths of AmigaDOS interior.
 * If it survives, it returns TRUE or FALSE depending on whether or
 * the specified device is a DOS disk.
 * Jeez, Look at the structure names in this routine!  Whew!  You almost
 * gotta be a computer scientist to understand this stuff.
 */
{
    struct MsgPort *port;
    BOOL result;
    struct InfoData *info;
    struct StandardPacket *packet;


    result = FALSE;

    /* Allocate the data structures required to communicate with AmigaDOS */
    info = (struct InfoData *)AllocMem(sizeof(struct InfoData), MEMF_CLEAR);
    packet = (struct StandardPacket *)AllocMem(sizeof(struct StandardPacket),
            MEMF_CLEAR);

    /* Grab us a message port for the reply from DOS */
    port = CreatePort(NULL, 0);

    if (port && info && packet)
        {
        /* OK, everything is set so here we go! */

        /* Set up the StandardPacket's Exec message */
        packet->sp_Msg.mn_Node.ln_Type = NT_MESSAGE;
        packet->sp_Msg.mn_Node.ln_Name = (char *)&packet->sp_Pkt;
        packet->sp_Msg.mn_ReplyPort = port;

        /* Set up the StandardPacket's DOS data */
        packet->sp_Pkt.dp_Link = &packet->sp_Msg;
        packet->sp_Pkt.dp_Type = ACTION_DISK_INFO;
        packet->sp_Pkt.dp_Arg1 = ((LONG)info >> 2);
        packet->sp_Pkt.dp_Port = port;

        /* Now, ask the device whether or not it's a DOS disk */
        PutMsg(device->dl_Task, &packet->sp_Msg);
        /* zzz */
        WaitPort(port);

        /* Well? */
        if (info->id_DiskType == X_ID_DOS_DISK) result = TRUE;
        }

    if (port) DeletePort(port);
    if (info) FreeMem(info, sizeof(struct InfoData));
    if (packet) FreeMem(packet, sizeof(struct StandardPacket));

    return(result);
}



VOID BuildVolumeTable(fileio)
struct FileIOSupport *fileio;
/* This routine builds an alphabetically-sorted list of all active volumes.
 * The names can be either the device names or the volume names, depending
 * on whether you set USE_VOLUME_NAMES.
 */
{
    struct DosInfo *dosinfo;
    struct DeviceList *masterlist, *devlist, *worklist;
    struct MsgPort *handler;
    LONG yuck;
    UBYTE *nameptr, *textptr;
    UBYTE len;
    SHORT i;
    struct Remember **key, *localkey;


    if (DosBase == NULL) return;

    key = &fileio->VolumeKey;
    FreeRemember(key, TRUE);
    localkey = NULL;

    fileio->VolumeCount = fileio->VolumeIndex = 0;

    /* First, feel through from DosBase down to the device list, dancing
     * all the while with the bcpl pointers.
     */
    yuck = (LONG)((struct RootNode *)DosBase->dl_Root)->rn_Info;
    dosinfo = (struct DosInfo *)(yuck << 2);    /* reality pointer */
    yuck = (LONG)dosinfo->di_DevInfo;
    masterlist = (struct DeviceList *)(yuck << 2);  /* reality pointer */

    devlist = masterlist;


    while (devlist)
        {
        /* First, find each device that's active (dl_Task is not NULL) */
        if ((devlist->dl_Type == DLT_DEVICE) && (devlist->dl_Task))
            {
            /* OK, got a device.  Now ask it if it's a DOS disk. */
            if (NOT DOSDisk(devlist)) goto NEXT_DEVICE;

            /* OK, got a device that's a DOS disk.  Now find the name.
             * If USE_VOLUME_NAMES is clear, use the device name,
             * else look up the volume name.
             */
            nameptr = (UBYTE *)devlist->dl_Name;
            if (FlagIsSet(fileio->Flags, USE_VOLUME_NAMES))
                {
                /* Use the handler for this volume to find the matching device */
                handler = (struct MsgPort *)devlist->dl_Task;

                worklist = masterlist;
                while (worklist)
                    {
                    if ((worklist->dl_Type == DLT_VOLUME)
                            && (worklist->dl_Task == handler))
                        {
                        nameptr = (UBYTE *)worklist->dl_Name;
                        goto GOT_NAME;
                        }

                    yuck = worklist->dl_Next;
                    worklist = (struct DeviceList *)(yuck << 2);
                    }
                /* If we get to the end of this loop and fall out, then what?  
                 * Got an active device but no matching volume?  OK.
                 */
                }

GOT_NAME:
            yuck = (LONG)nameptr;
            nameptr = (UBYTE *)(yuck << 2);
            len = *nameptr++;

            if ((textptr = AllocRemember(&localkey, len + 2, NULL)) == NULL)
                {
                Alert(ALERT_OUTOFMEM, NULL);
                goto DEVICES_DONE;
                }

            fileio->VolumeCount++;
            for (i = 0; i < len; i++) *textptr++ = *nameptr++;
            *textptr++ = ':';
            *textptr = '\0';
            MakeEntry(localkey->Memory, &fileio->VolumeKey, NULL);
            }

NEXT_DEVICE:
        yuck = devlist->dl_Next;
        devlist = (struct DeviceList *)(yuck << 2);
        }


DEVICES_DONE:

    FreeRemember(&localkey, TRUE);
}


UBYTE *CurrentVolumeName()
/* This routine returns a pointer the name of the current volume */
{
    SHORT i;
    struct Remember *remember;

    /* If there's no active volumes then return the "safe" volume name */
    if (OpenReqFileIO->VolumeCount < 1)
        return(&CurrentDiskString[0]);

    /* Safety measure */
    if (OpenReqFileIO->VolumeIndex >= OpenReqFileIO->VolumeCount)
        OpenReqFileIO->VolumeIndex = 0;

    /* Finally, look up the name */
    remember = OpenReqFileIO->VolumeKey;
    for (i = 0; i < OpenReqFileIO->VolumeIndex; i++)
        remember = remember->NextRemember;
    return(remember->Memory);
}

