/* $Header: Src/rcs/Dos.c,v 1.3 1995/02/01 17:49:46 cmh Exp cmh $
 *
 * BindNamesII: Handy assign/path maker.
 * Copyright (C) 1994-95  Magnus Holmgren <cmh@augs.se>
 *
 * 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 2 of the License, 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 the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
#include <exec/types.h>

#ifndef __GNUC__
#include <clib/dos_protos.h>
#include <clib/exec_protos.h>
#include <clib/utility_protos.h>
#endif

#ifdef __GNUC__
#include <inline/dos.h>
#include <inline/exec.h>
#include <inline/utility.h>
#endif

#include <dos/dosextens.h>
#include <exec/memory.h>

#include <string.h>

#define Prototype extern

#include "assignnode.h"	/* Just to keep Gcc silent.. */

#include "proto.h"


Prototype VOID PrintError( STRPTR, ... );
VOID
PrintError( STRPTR header, ... )
{
	LONG	code = IoErr();

	PutStr( "BindNamesII: " );
	VPrintf( header, &header + 1 );
	PutStr( ":\n" );
	PrintFault( code, NULL );
}


Prototype VOID PrintNoMem( VOID );
VOID
PrintNoMem( VOID )
{
	PutStr( "BindNamesII: Not enough memory\n" );
	SetIoErr( ERROR_NO_FREE_STORE );
}


/* Return TRUE if the path refers to a "known" volume. */
Prototype LONG HaveProc( STRPTR );
LONG
HaveProc( STRPTR name )
{
	struct DevProc	*proc;

	if( ( proc = GetDeviceProc( name, NULL ) ) )
	{
		FreeDeviceProc( proc );
	}

	return( ( LONG ) proc );
}


/* Create the specified directory, including any parent directories that
 * might be needed. Doesn't return any lock, rather a success.
 */
Prototype LONG CreateDirPath( STRPTR );
LONG
CreateDirPath( STRPTR path )
{
	if( Test )
	{
		return( TRUE );
	}
	else
	{
		STRPTR	end;
		BPTR	lock;

		end = path + strlen( path ) - 1;

		/* Remove trailing slashes */
		if( *end == '/' )
		{
			*end = 0;
		}

		/* Does the drawer exist? */
		if( !( lock = Lock( path, SHARED_LOCK ) ) )
		{
			/* No, try to create its parent. */
			end = PathPart( path );

			/* Reached the "root"? */
			if( ( end != path ) && *end )
			{
				TEXT    oldChar;

				oldChar = *end;
				*end = 0;

				/* Create the parent(s) */
				if( CreateDirPath( path ) )
				{
					*end = oldChar;
					/* And create the current level */
					lock = CreateDir( path );

					if( lock )
					{
						UnLock( lock );
					}
				}

				*end = oldChar;
			}
		}
		else
		{
			UnLock( lock );
		}

		return( lock );
	}
}


/* Structure the command search list is made of */
struct PathEntry
{
	BPTR	Next;	/* Next path in list */
	BPTR	Lock;	/* Lock to drawer */
};


/* Get a pointer to the current CommandLineInterface struct */
struct CommandLineInterface *GetCLI( VOID )
{
	return( BADDR( ( ( struct Process * ) FindTask( NULL ) )->pr_CLI ) );
}


/* Clear the command search path for the current process */
Prototype VOID ClearProcPath( VOID );
VOID
ClearProcPath( VOID )
{
	struct CommandLineInterface	*cli = GetCLI();
	struct PathEntry		*path;
	BPTR	next = cli->cli_CommandDir;

	cli->cli_CommandDir = NULL;

	while( next )
	{
		path = BADDR( next );
		next = path->Next;

		if( path->Lock )
		{
			UnLock( path->Lock );
		}

		FreeVec( path );
	}
}


/* Add the specified drawer to the current process' command search list */
Prototype BOOL AddNameProcPath( STRPTR );
BOOL
AddNameProcPath( STRPTR name )
{
	struct PathEntry	*path;
	BOOL	ret = FALSE;

	if( ( path = AllocVec( 8, MEMF_ANY | MEMF_CLEAR ) ) )
	{
		if( ( path->Lock = Lock( name, SHARED_LOCK ) ) )
		{
			STATIC struct PathEntry	*last;

			if( !last )
			{
				last = ( struct PathEntry * ) ( &( GetCLI()->cli_CommandDir ) );

				while( last->Next )
				{
					last = BADDR( last->Next );
				}
			}

			last->Next = MKBADDR( path );
			last = path;	/* Cache value */
			ret = TRUE;
		}
		else
		{
			FreeVec( path );
		}
	}

	return( ret );
}
