/*---------------------------------------------------------------------------*
  Project:  NitroSDK - FS - libraries
  File:     util.h

  Copyright 2003-2004 Nintendo.  All rights reserved.

  These coded instructions, statements, and computer programs contain
  proprietary information of Nintendo of America Inc. and/or Nintendo
  Company Ltd., and are protected by Federal copyright law.  They may
  not be disclosed to third parties or copied or duplicated in any form,
  in whole or in part, without the prior written consent of Nintendo.

  $Log: util.h,v $
  Revision 1.12  2004/07/23 08:30:17  yosizaki
  add some macro.

  Revision 1.11  2004/07/19 13:20:35  yosizaki
  add some functions.

  Revision 1.10  2004/07/08 13:40:26  yosizaki
  add some function FSi_Is*()

  Revision 1.9  2004/06/30 04:38:50  yosizaki
  delete FSi_InitArchiveThread.

  Revision 1.8  2004/06/07 10:26:28  yosizaki
  fix around archive asynchronous operation.

  Revision 1.7  2004/06/03 13:33:13  yosizaki
  fix around archive asynchronous operation.

  Revision 1.6  2004/06/01 10:18:04  yosizaki
  change around assertion code.

  Revision 1.5  2004/05/31 02:56:20  yosizaki
  change FSi_ASSERT_ARG() to FS_ASSERT_ARG().

  Revision 1.4  2004/05/20 06:49:27  yosizaki
  small fix.

  Revision 1.3  2004/05/17 08:32:31  yosizaki
  add comment.
  add assertion of each interface function.

  Revision 1.2  2004/05/12 05:22:41  yosizaki
  prepare a option "SDK_ARM7FS".

  Revision 1.1  2004/05/11 04:28:47  yosizaki
  (none)

  $NoKeywords: $
 *---------------------------------------------------------------------------*/


#if	!defined(NITRO_FS_UTIL_H_)
#define NITRO_FS_UTIL_H_

#include <nitro/misc.h>
#include <nitro/types.h>
#include <nitro/fs/file.h>


#ifdef __cplusplus
extern "C" {
#endif


/*
 * SDK_ARM7FS
 * Enable this definition when you want to use the file system from the ARM7.
 */
/*
#define	SDK_ARM7FS
*/

/*
 * FS_IMPLEMENT
 * Defines only the environment that includes the full file system.
 */
#if	!defined(SDK_ARM7) || defined(SDK_ARM7FS)
#define	FS_IMPLEMENT
#endif


/*
 * FS_TODO
 * Macro for TODO memo.
 * Make the storage locations easier to search later. 
 */
#define	FS_TODO(comment)


/* Bit and alignment macro */
#define	BIT_MASK(n)	((1 << (n)) - 1)
#define	ALIGN_MASK(a)	((a) - 1)
#define	ALIGN_BYTE(n, a)	(((u32)(n) + ALIGN_MASK(a)) & ~ALIGN_MASK(a))


/*
 * Determine the validity of function call.  
 * Include return value in macro arguments just in case.  
 */
#if	!defined(SDK_FINALROM)

/* assertion failure message string */
extern	const char	*fsi_assert_fs_format;
extern	const char	*fsi_assert_is_init;
extern	const char	*fsi_assert_is_valid_arg;
extern	const char	*fsi_assert_is_empty;
extern	const char	*fsi_assert_is_handle;
extern	const char	*fsi_assert_is_file;
extern	const char	*fsi_assert_is_dir;
extern	const char	*fsi_assert_is_idle;
extern	const char	*fsi_assert_arc_free;
extern	const char	*fsi_assert_arc_unloaded;
extern	const char	*fsi_assert_arc_not_rom;

/* global assertion */
#define	FS_ASSERT_INIT(ret)	\
	if(!FS_IsAvailable())	OS_Panic(fsi_assert_fs_format, fsi_assert_is_init);

#define	FS_ASSERT_ARG(e, ret)	\
	if(!(e))	OS_Panic(fsi_assert_fs_format, fsi_assert_is_valid_arg);

/* file and directory assertion */
#define	FS_ASSERT_EMPTY(p_file, ret)	\
	if(FS_IsFile(p_file))	OS_Panic(fsi_assert_fs_format, fsi_assert_is_empty);

#define	FS_ASSERT_HANDLE(p_file, ret)	\
	if(!FS_IsFile(p_file) && !FS_IsDir(p_file))	OS_Panic(fsi_assert_fs_format, fsi_assert_is_handle);

#define	FS_ASSERT_FILE(p_file, ret)	\
	if(!FS_IsFile(p_file))	OS_Panic(fsi_assert_fs_format, fsi_assert_is_file);

#define	FS_ASSERT_DIR(p_file, ret)	\
	if(!FS_IsDir(p_file))	OS_Panic(fsi_assert_fs_format, fsi_assert_is_dir);

#define	FS_ASSERT_IDLE(p_file, ret)	\
	if(FS_IsBusy(p_file))	OS_Panic(fsi_assert_fs_format, fsi_assert_is_idle);

/* archive assertion */
#define	FS_ASSERT_ARC_FREE(p_arc, ret)	\
	if(p_arc->name.pack)	OS_Panic(fsi_assert_fs_format, fsi_assert_arc_free);

#define	FS_ASSERT_ARC_UNLOADED(p_arc, ret)	\
	if(FS_IsArchiveLoaded(p_arc))	OS_Panic(fsi_assert_fs_format, fsi_assert_arc_unloaded);

#define	FS_ASSERT_ARC_NOT_ROM(p_arc, ret)	\
	if(p_arc == arc_list)	OS_Panic(fsi_assert_fs_format, fsi_assert_arc_not_rom);

#else

#define	FS_ASSERT_INIT(ret)	
#define	FS_ASSERT_ARG(e, ret)	

#define	FS_ASSERT_EMPTY(p_file, ret)	
#define	FS_ASSERT_HANDLE(p_file, ret)	
#define	FS_ASSERT_FILE(p_file, ret)	
#define	FS_ASSERT_DIR(p_file, ret)	
#define	FS_ASSERT_IDLE(p_file, ret)	

#define	FS_ASSERT_ARC_FREE(p_file, ret)	
#define	FS_ASSERT_ARC_UNLOADED(p_file, ret)	
#define	FS_ASSERT_ARC_NOT_ROM(p_file, ret)	

#endif


/* file list function */

// Get the element after the specified element.
static inline FSFile*	FS_GetNextFile(const FSFile *elem)
{
	return	elem->link.next;
}

// Get the element before the specified element. 
static inline FSFile*	FS_GetPrevFile(const FSFile *elem)
{
	return	elem->link.prev;
}

// Cut the element from the its current queue.
void	FS_CutFromList(FSFile *elem);

// Cut the processing element and insert before specified element. 
void	FS_InsertToList(FSFile *elem, FSFile *list);

// Cut the processing element and insert after specified element. 
void	FS_AddToList(FSFile *elem, FSFile *list);

//  Cut the processing element and add to end of specified list. 
void	FS_AppendToList(FSFile *elem, FSFile *list);


// Internal function. Determine if character is directory delimiter. 
static inline BOOL	is_slash(u32 c)
{
	return	(c == '/') || (c == '\\');
}


/* internal archive function */

// Determine if archive is currently running. 
static inline BOOL	FSi_IsArchiveRunning(const volatile FSArchive *p)
{
	return	(p->flag & FS_ARCHIVE_FLAG_RUNNING) ? TRUE : FALSE;
}

// Determine if file under archive management is being cancelled. 
static inline BOOL	FSi_IsArchiveCanceling(const volatile FSArchive *p)
{
	return	(p->flag & FS_ARCHIVE_FLAG_CANCELING) ? TRUE : FALSE;
}

// Determine if archive is shifting suspension.
static inline BOOL	FSi_IsArchiveSuspending(const volatile FSArchive *p)
{
	return	(p->flag & FS_ARCHIVE_FLAG_SUSPENDING) ? TRUE : FALSE;
}

// Determine if archive is currently processing an async command. 
static inline BOOL	FSi_IsArchiveAsync(const volatile FSArchive *p)
{
	return	(p->flag & FS_ARCHIVE_FLAG_IS_ASYNC) ? TRUE : FALSE;
}

// Determine if archive is blocking a sync command. 
static inline BOOL	FSi_IsArchiveSync(const volatile FSArchive *p)
{
	return	(p->flag & FS_ARCHIVE_FLAG_IS_SYNC) ? TRUE : FALSE;
}


/********************************************************************/


#ifdef __cplusplus
} /* extern "C" */
#endif


#endif	/* NITRO_FS_UTIL_H_ */
