/*
**
** $VER: Aminet2AG.c 2.0 (06.04.95)
**
** Convert AminNet INDEX files in AmigaGuide© documents.
**
** Copyrigth (C) 1995 José Roberto González Rocha.
**
**
**
** Link without any C header (c.o ...)
** Fully resident and reentrant (pure).
**
*/

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

#include <exec/types.h>
#include <exec/nodes.h>
#include <exec/lists.h>
#include <exec/execbase.h>
#include <exec/memory.h>
#include <dos/dos.h>
#include <dos/dosextens.h>
#include <dos/rdargs.h>
#include <dos/stdio.h>
#include <workbench/startup.h>

#include <clib/dos_protos.h>
#include <clib/exec_protos.h>
#include <clib/utility_protos.h>

#include <pragmas/dos_pragmas.h>
#include <pragmas/exec_pragmas.h>
#include <pragmas/utility_pragmas.h>



	/* Shared data and libs                                                */
struct GlobalData
{
	struct ExecBase	   *gd_SysBase;
	struct Library	   *gd_DOSBase;
	struct Library	   *gd_UtilityBase;

	struct Process	   *gd_Process;
	struct WBStartup   *gd_wbMsg;
	LONG 		    	gd_failureLevel;
	LONG 				gd_failureCode;

	ULONG 				mem;
	LONG				ArgArray[11];


	BPTR		   		gd_In; 		   	/* Source INDEX file.              */
	BPTR		   		gd_Out;       	/* Destination AmigaGuidec doc	   */

	UBYTE   	        gd_string[100];

	WORD 				total_pending;

	WORD        		root_count;		/* total file count				   */
	WORD        		root_dircount;	/* number of dirs.                 */
	WORD        		root_subcount;	/* number of subdirs.              */
	LONG        		root_size;		/* total size (incl. all dirs)     */
	BOOL        		root_ignore;	/* ignore same file size.          */
	WORD        		root_pending;	/* filecount of files w/o dirs.    */
	struct Dir 	   	   *root_firstdir;	/* linked list head.               */
	struct Dir 	   	   *root_lastdir;	/* link to the last dir            */

};
#define SysBase			gd->gd_SysBase
#define DOSBase			gd->gd_DOSBase
#define UtilityBase		gd->gd_UtilityBase



	/* SubDir Nodes data                                                   */

struct SubDir
{
	struct SubDir *sub_next;			/* link                            */
	char           sub_name[6];			/* name of this subdir.            */
	WORD		   sub_count;			/* file count in this subdir.      */
	LONG           sub_size;			/* total size of this subdir.      */
	BOOL           sub_ignore;			/* ignore same filesize.           */
};


	/* Dir Nodes data                                                      */

struct Dir
{
	struct Dir    *dir_next;			/* link                            */
	char           dir_name[6];			/* name of this dir.               */
	WORD           dir_subcount;		/* subdir count of this dir.       */
	WORD		   dir_count;			/* total file count of this dir    */
	LONG           dir_size;			/* total size of this subdir.      */
	BOOL           dir_ignore;			/* ignore same filesize            */
	WORD           dir_pending;			/* file count of files w/o sub     */
	struct SubDir *dir_firstsub;		/* linked list head.               */
	struct SubDir *dir_lastsub;			/* link to the last subdir.        */
};


#define isnum(a) ((a >= '0') && (a <= '9'))


/*
 * Function prototipes
 */

BOOL PassOne(struct GlobalData *gd, ULONG Flags);
BOOL PassTwo(struct GlobalData *gd, ULONG Flags);
BOOL PassThree(struct GlobalData *gd, ULONG Flags);
BOOL CheckAbort(struct GlobalData *gd);
VOID PrintSize(struct GlobalData *gd, LONG size, BOOL ignore);




/*
 * Main funcion.
 * Don't use argc/argv, so why use standard main()?.
 */
LONG main(VOID)
{
	/* Version string                                                      */
	char VersionString[] = "$VER: Aminet2AG 2.0 (06.04.95)";

	/* Credits                                                             */
	char CopyRigthString[] = "Copyright (c) 1995 José Roberto González Rocha";

	/* Command template                                                    */
	char Template[] = "FROMFILE/A,TOFILE/A,DC=DIRCOL/K/N,"
					  "NT=NOTOTAL/S,NH=NOHEAD/S,NL=NOTITLE/S,"
					  "TR=TITLEROW/K/N,NS=NOSTATS/S,SC=SIZECOL/K/N,"
					  "P=PLAIN/S,V=VERBOSE/S";


	struct GlobalData gdd = {NULL};
	struct GlobalData *gd = &gdd;

	/* Returned object from template parsing                               */
	struct RDArgs *rdargs;

	/* Position of the argument in the array                               */
#define FROM_FILE 0
#define TO_FILE   1
#define DIRCOL    2
#define NOTOTAL   3
#define NOHEAD    4
#define NOTITLE   5
#define TITLEROW  6
#define NOSTATS   7
#define SIZECOL   8
#define PLAIN     9
#define VERBOSE   10

	/* Quick form of options, used for and'ing and or'ing                  */
	REGISTER ULONG Flags = 0L;
#define F_NODIR		(1L << 0)
#define F_NOSUB		(1L << 1)
#define F_VERBOSE	(1L << 2)
#define F_NOSTATS	(1L << 3)
#define F_NOTITLE	(1L << 4)
#define F_NOHEAD	(1L << 5)
#define F_NOTOTAL	(1L << 6)
#define F_FIXDIR	(1L << 7)
#define F_FIXSUB	(1L << 8)
#define F_POINT   	(1L << 9)
#define F_NOSIZE	(1L << 10)

	gdd.gd_SysBase = *((struct ExecBase **) 4L);
	gdd.gd_failureLevel = RETURN_FAIL;
	gdd.gd_Process = (struct Process *) SysBase->ThisTask;
	/* We only run from CLI												   */
	if(gdd.gd_Process->pr_CLI)
	{

#ifdef _M68020
		/* Make sure we are running with a 68020+ CPU                      */
		if (gdd.gd_SysBase->AttnFlags & AFF_68020)
		{
#endif
			/* Open the ROM libraries                                      */
			if(gdd.gd_DOSBase = OpenLibrary ("dos.library", 37L))
			{
				if(gdd.gd_UtilityBase = OpenLibrary ("utility.library", 37L))
				{

					/* Our process. Really necessary?					   */
					gdd.gd_Process = (struct Process *) FindTask (NULL);
					
					if(rdargs = ReadArgs( Template, gdd.ArgArray, NULL))
					{
						if (gdd.gd_In = Open((STRPTR)(gdd.ArgArray[FROM_FILE]), MODE_OLDFILE))
						{
							if (gdd.gd_Out = Open((STRPTR)(gdd.ArgArray[TO_FILE]), MODE_NEWFILE))
							{
								/* Options processing                      */

								if(gdd.ArgArray[DIRCOL] == 0L)
									gdd.ArgArray[DIRCOL] = 19L;
								else
									gdd.ArgArray[DIRCOL] = *((LONG *)(gdd.ArgArray[DIRCOL]));

								if(gdd.ArgArray[TITLEROW] == 0L)
									gdd.ArgArray[TITLEROW] = 3L;
								else
									gdd.ArgArray[TITLEROW] = *((LONG *)(gdd.ArgArray[TITLEROW]));
	
								if(gdd.ArgArray[SIZECOL] == 0L)
									gdd.ArgArray[SIZECOL] = 30L;
								else
									gdd.ArgArray[SIZECOL] = *((LONG *)(gdd.ArgArray[SIZECOL]));
	
	
								if(gdd.ArgArray[VERBOSE])
									Flags |= F_VERBOSE;
	
								if(gdd.ArgArray[PLAIN])	/* Overrides all the other flags. */
								{
									Flags |= F_NOHEAD | F_NOTITLE | F_NOSTATS | F_NOTOTAL;
								}
								else
								{
									if(gdd.ArgArray[NOHEAD])
										Flags |= F_NOHEAD;
	
									if(gdd.ArgArray[NOTITLE])
										Flags |= F_NOTITLE;
	
									if(gdd.ArgArray[NOSTATS])
										/* If we don't want stats, why put header?       */
										Flags |= F_NOSTATS | F_NOHEAD;
	
									if(gdd.ArgArray[NOTOTAL])
										Flags |= F_NOTOTAL;
								}
	
								if((Flags & (F_NOSTATS | F_NOTOTAL)) == (F_NOSTATS | F_NOTOTAL))
									Flags |= F_NOSIZE;
	
	
								if(!CheckAbort(gd))
								{
									if(PassOne(gd, Flags))
										if(PassTwo(gd, Flags))
											if(PassThree(gd, Flags))
											{
												gdd.gd_failureLevel = RETURN_OK;
												
												if(Flags & F_VERBOSE)
												{
													Printf("\n\n\nAll Done!\n");
													Printf("\nFounds:  %5ld dirs, %5ld subdirs, %5ld files, %5ld KBytes\n",
														   gdd.root_dircount, gdd.root_subcount,
														   gdd.root_count, gdd.root_size);
												}
											}
									{									
										struct Dir 	   *DirNode,*DirNode2;
										struct SubDir  *SubDirNode,*SubDirNode2;
	
	
										if(Flags & F_VERBOSE)
											Printf( "\nUtilized %ld bytes\n", gdd.mem);

										/* Dealocates all memory.		*/
										gdd.mem = 0;
										DirNode2 = gd->root_firstdir;
										while((DirNode = DirNode2) != NULL)
										{
											SubDirNode2 = DirNode->dir_firstsub;
											while((SubDirNode = SubDirNode2) != NULL)
											{
												SubDirNode2 = SubDirNode->sub_next;
												FreeMem(SubDirNode, sizeof(struct SubDir));
												gdd.mem += sizeof(struct SubDir);
											}
											DirNode2 = DirNode->dir_next;
											FreeMem(DirNode, sizeof(struct Dir));
											gdd.mem += sizeof(struct Dir);
										}
		
										if(Flags & F_VERBOSE)
											Printf("Dealocated %ld bytes\n\n", gdd.mem);
									}
								}
	
								Close(gdd.gd_Out);
							}
							else
							{
								Printf("***Error Opening Destination File \'%s\'\n", gdd.ArgArray[FROM_FILE]);
								gdd.gd_failureCode = 201;
							}
	
							Close(gdd.gd_In);
						}
						else
						{
							Printf("***Error Opening Source File \'%s\'\n", gdd.ArgArray[FROM_FILE]);
							gdd.gd_failureCode = 201;
						}
						
						FreeArgs(rdargs);
					}
					else
					{
						if(!CheckAbort(gd))
						{
							Printf("%s\n%s\n", VersionString + 6, CopyRigthString);
						}
						else
							gdd.gd_failureCode = 200;
					}
					CloseLibrary(gdd.gd_UtilityBase);
				}
				else
					gdd.gd_failureCode = 21;
				CloseLibrary(gdd.gd_DOSBase);
			}
			else
				gdd.gd_failureCode = 20;
#ifdef _M68020
		}
		else
			gdd.gd_failureCode = 10;
#endif
	}
	/* If running from WorkBench do nothing	  */
	else
	{
		gdd.gd_failureCode = 1;
		
		WaitPort (&(gdd.gd_Process->pr_MsgPort));
		gdd.gd_wbMsg = (struct WBStartup *) GetMsg (&gdd.gd_Process->pr_MsgPort);

		Forbid();
		ReplyMsg((struct Message *)gdd.gd_wbMsg);
	}
	gdd.gd_Process->pr_Result2 = gdd.gd_failureCode;
	return(gdd.gd_failureLevel);
}

/*
 *
 *
 */
BOOL PassOne(struct GlobalData *gd, ULONG Flags)
{
	REGISTER struct Dir *DirNode;
	REGISTER struct SubDir *SubDirNode;

	REGISTER WORD i = 0;

	char *dir;
	char *subdir;
	char *olddir = "";
	char *oldsubdir = "";
	LONG filesize;

	FPrintf(gd->gd_Out,"@database \"AMINET\"\n");

	if(Flags & F_VERBOSE)
	{
		Printf("[1mPass One[0m\n");
	}

	DirNode = NULL;
	SubDirNode = NULL;

	FPrintf(gd->gd_Out,"@NODE Main \"AmiNet Root Directory\"\n");

	FGets(gd->gd_In, gd->gd_string, 100);
	while(gd->gd_string[0] == '|')
	{
		if(!(Flags & F_NOTITLE))
		{

			if(i < gd->ArgArray[TITLEROW])
			{
				FPuts(gd->gd_Out, gd->gd_string+1);
				i++;
			}
		}
		FGets(gd->gd_In, gd->gd_string, 100);
	}

	if(!(Flags & F_NOTITLE))
		FPuts(gd->gd_Out, "\n");

	do
	{
		if(!(Flags & F_NOSIZE))
		{
			if(gd->gd_string[gd->ArgArray[SIZECOL] + 3] == '?')
				filesize = -1;
			else
			{
				Flags &= ~F_POINT;
				filesize = 0;

				for(i = gd->ArgArray[SIZECOL]; i < gd->ArgArray[SIZECOL] + 3; i++)
					if(isnum(gd->gd_string[i]))
						filesize = SMult32(filesize, 10) + (gd->gd_string[i] - '0');
					else if(gd->gd_string[i] == '.')
						Flags |= F_POINT;

				if(gd->gd_string[i] ==  'M')
				{
					filesize <<= 10;
					if(Flags & F_POINT)
						filesize = SDivMod32(filesize, 10);
				}
			}
		}

		dir = gd->gd_string + gd->ArgArray[DIRCOL];
		dir[10] = 0;
		subdir = FilePart(dir);

		if(dir == subdir)
			Flags |= F_NOSUB;
		else
			Flags &= ~F_NOSUB;

		if(dir[0] == ' ')
			Flags |= F_NODIR;
		else
			Flags &= ~F_NODIR;

		if(!(Flags & F_NODIR))
		{
			if(Flags & F_NOSUB)
			{
				while(subdir[0] != ' ')
				subdir++;
				subdir[0] = 0;
			}
			else
				*(subdir-1) = 0;
			
			if(Strnicmp(olddir, dir, 5L))
			{
				if(DirNode != NULL)
				{
					FPrintf(gd->gd_Out,"@{\"  %-5s  \" link %s}", DirNode->dir_name, DirNode->dir_name);
					if(!(Flags & F_NOSTATS))
					{
						FPrintf(gd->gd_Out, "      %5ld     %5ld     " , DirNode->dir_subcount, DirNode->dir_count);
						PrintSize(gd, DirNode->dir_size, DirNode->dir_ignore);
					}
					else
						FPuts(gd->gd_Out, "\n");
				}
				else
					if(!(Flags & F_NOHEAD))
						FPuts(gd->gd_Out, "                 subdirs    files      size\n"
										  "-------------------------------------------------\n");

				if( (DirNode = (struct Dir *)AllocMem(sizeof(struct Dir), MEMF_CLEAR)) == NULL)
				{
					gd->gd_failureCode = 100;
					return(FALSE);
				}

				gd->mem += sizeof(struct Dir);

				for(i = 0; dir[i], i < 5; i ++)
					DirNode->dir_name[i] =  dir[i];
				DirNode->dir_name[i] =0;

				if(gd->root_firstdir != NULL)
					gd->root_lastdir->dir_next = DirNode;
				else
					gd->root_firstdir = DirNode;
				gd->root_lastdir = DirNode;
				gd->root_dircount++;

				olddir = DirNode->dir_name;
				oldsubdir = "";
			}

			DirNode->dir_count++;
			if(filesize != -1)
				DirNode->dir_size += filesize;
			else
				DirNode->dir_ignore = TRUE;

			if(!(Flags &  F_NOSUB))
			{
				if(Strnicmp(oldsubdir, subdir, 5))
				{
					if(CheckAbort(gd))
						return(FALSE);

					if((SubDirNode = (struct SubDir *)AllocMem(sizeof(struct SubDir), MEMF_CLEAR)) == NULL)
					{
						gd->gd_failureCode = 100;
						return(FALSE);
					}

					gd->mem += sizeof(struct SubDir);

					for(i = 0; dir[i], i < 5; i ++)
						SubDirNode->sub_name[i] =  subdir[i];
					SubDirNode->sub_name[i] =0;

					if(DirNode->dir_firstsub != NULL)
						DirNode->dir_lastsub->sub_next = SubDirNode;
					else
						DirNode->dir_firstsub = SubDirNode;
					DirNode->dir_lastsub = SubDirNode;
					DirNode->dir_subcount++;
					gd->root_subcount++;

					oldsubdir = SubDirNode->sub_name;

					if(Flags & F_VERBOSE)
					{
						Printf("Found Dir    : %s  \n"
							   "Found Sub-Dir: %s  M\r", DirNode->dir_name, SubDirNode->sub_name);
					}
				}

				SubDirNode->sub_count++;
				if(filesize != -1)
					SubDirNode->sub_size += filesize;
				else
					SubDirNode->sub_ignore = TRUE;
			}
			else
			{
				Flags |= F_FIXSUB;
				DirNode->dir_pending++;
				gd->total_pending++;
			}
		}
		else                                           
		{
			Flags |= F_FIXDIR;
			gd->root_pending++;
			gd->total_pending++;
			dir[10] = ' ';
			FPuts(gd->gd_Out, gd->gd_string);
		}

		if(filesize != -1)
			gd->root_size += filesize;
		else
			gd->root_ignore = TRUE;
		gd->root_count++;

	}while(FGets(gd->gd_In, gd->gd_string, 100));

	if(DirNode != NULL)
	{
		FPrintf(gd->gd_Out,"@{\"  %-5s  \" link %s}", DirNode->dir_name, DirNode->dir_name);

		if(!(Flags & F_NOSTATS))
		{
			FPrintf(gd->gd_Out, "      %5ld     %5ld     ", DirNode->dir_subcount, DirNode->dir_count);
			PrintSize(gd, DirNode->dir_size, DirNode->dir_ignore);
		}
		else
			FPuts(gd->gd_Out, "\n");
	}

	if(!(Flags & F_NOTOTAL))
	{
		FPrintf(gd->gd_Out, "\nTotal:  %ld dirs, %ld subdirs, %ld files, size ", gd->root_dircount, gd->root_subcount, gd->root_count);
		PrintSize(gd, gd->root_size, gd->root_ignore);
	}
	FPuts(gd->gd_Out, "@ENDNODE\n\n");


	if( gd->total_pending && (Flags & F_VERBOSE))
	{
		Printf("\n\nFound(s) %ld file(s) without ", gd->total_pending);

		if(Flags & F_FIXDIR)
		{
			Printf("directory");
			if(Flags & F_FIXSUB)
				Printf(" and/or ");
		}
		if(Flags & F_FIXSUB)
			Printf("subdirectory");

		if(gd->root_pending)
			Printf(".\nAdded files to root directory (%ld)", gd->root_pending);

		Printf(".\n\nEntering FIX mode (Pass Two may take a while).M\r");

	}

	return(TRUE);
}

/*
 *
 *
 */
BOOL PassTwo(struct GlobalData *gd, ULONG Flags)
{
	REGISTER struct Dir *DirNode;
	REGISTER struct SubDir *SubDirNode;

	REGISTER WORD i;


	if(Flags & F_VERBOSE)
		Printf("\n\n\n[1mPass Two[0m\n");

	if(gd->total_pending)
	{
		Seek(gd->gd_In, 0, OFFSET_BEGINNING);
		FGets(gd->gd_In, gd->gd_string, 80);

		/* Skip index header.              				   */
		while(gd->gd_string[0] == '|')
			FGets(gd->gd_In, gd->gd_string, 100);

		if((Flags & F_VERBOSE) && gd->root_pending)
			Printf("Skipping root directory files (%ld)\n", gd->root_pending);

		gd->total_pending -= gd->root_pending;

		/* Skip files w/o dir/subdir.      				   */
		for(i = 0; i < gd->root_pending; i++)
			FGets(gd->gd_In, gd->gd_string,100);
	}

	DirNode = gd->root_firstdir;
	while(DirNode != NULL)
	{
		if(Flags & F_VERBOSE)
			Printf("Creating Node: %s  M\n",DirNode->dir_name);

		FPrintf(gd->gd_Out, "@NODE %s \"%s Directory\"\n\n", DirNode->dir_name,DirNode->dir_name);

		if(gd->total_pending)
		{
			if((Flags & F_VERBOSE) && DirNode->dir_pending)
				Printf("Adding directory \"%s\" files (%ld)\n", DirNode->dir_name, DirNode->dir_pending);

			gd->total_pending -=  DirNode->dir_pending;
			for(i = 0; i < DirNode->dir_pending; i++)
			{
				FPuts(gd->gd_Out, gd->gd_string);
				FGets(gd->gd_In, gd->gd_string, 100);
			}
			
			for(; i < DirNode->dir_count; i++)
				FGets(gd->gd_In, gd->gd_string, 100);
		}

		if (CheckAbort(gd))
			return(FALSE);

		if(!(Flags & F_NOHEAD))
			FPuts(gd->gd_Out, "               files       size\n"
							  "-------------------------------------------------\n");

		SubDirNode = DirNode->dir_firstsub;
		while(SubDirNode != NULL)
		{
			FPrintf(gd->gd_Out, "@{\"  %-5s  \" link %s-%s}", SubDirNode->sub_name, DirNode->dir_name, SubDirNode->sub_name);
			if(!(Flags & F_NOSTATS))
			{
				FPrintf(gd->gd_Out, "    %5ld     ", SubDirNode->sub_count);
				PrintSize(gd, SubDirNode->sub_size, SubDirNode->sub_ignore);
			}
			else
				FPuts(gd->gd_Out, "\n");
			SubDirNode = SubDirNode->sub_next;
		}

		if(!(Flags & F_NOTOTAL))
		{
			FPrintf(gd->gd_Out, "\nTotal:  %5ld subdirs, %5ld files, size ", DirNode->dir_subcount, DirNode->dir_count);
			PrintSize(gd, DirNode->dir_size, DirNode->dir_ignore);
		}
		FPuts(gd->gd_Out, "@ENDNODE\n\n");

		DirNode = DirNode->dir_next;
	}

	return(TRUE);
}

/*
 *
 *
 */
BOOL PassThree(struct GlobalData *gd, ULONG Flags)
{
	REGISTER struct Dir *DirNode;
	REGISTER struct SubDir *SubDirNode;

	REGISTER WORD i;


	if(Flags & F_VERBOSE)
		Printf("\n\n[1mPass Three[0m\n");

	Seek(gd->gd_In, 0, OFFSET_BEGINNING);
	FGets(gd->gd_In, gd->gd_string, 80);

	/* Skip index header								   */
	while(gd->gd_string[0] == '|')
		FGets(gd->gd_In, gd->gd_string, 100);

	if((Flags & F_VERBOSE) && gd->root_pending)
		Printf("Skipping root directory files (%ld)\n", gd->root_pending);

	/* Skip files w/o dir/subdir						   */
	for(i = 0; i < gd->root_pending; i++)
		FGets(gd->gd_In, gd->gd_string,100);

	DirNode = gd->root_firstdir;
	while(DirNode != NULL)
	{
		if((Flags & F_VERBOSE) && DirNode->dir_pending)
			Printf("Skipping directory \"%s\" files (%ld)\n", DirNode->dir_name, DirNode->dir_pending);

		/* Skip files with dir and w/o subdir              */
		for(i = 0; i < DirNode->dir_pending; i++)
			FGets(gd->gd_In, gd->gd_string, 100);

		SubDirNode = DirNode->dir_firstsub;
		while(SubDirNode != NULL)
		{
			if(Flags & F_VERBOSE)
			{
				Printf("Working on Node : %s  \n"
					   "Creating Sub-Dir: %s  M\r", DirNode->dir_name, SubDirNode->sub_name);
			}

			if(CheckAbort(gd))
				return(FALSE);

			FPrintf(gd->gd_Out, "@NODE %s-%s \"%s/%s SubDirectory\"\n\n", DirNode->dir_name, SubDirNode->sub_name, DirNode->dir_name, SubDirNode->sub_name);

			for(i = 0; i < SubDirNode->sub_count; i++)
			{
				FPuts(gd->gd_Out, gd->gd_string);
				FGets(gd->gd_In, gd->gd_string, 100);
			}

			if(!(Flags & F_NOTOTAL))
			{
				FPrintf(gd->gd_Out, "\nTotal:  %5ld files, size ", SubDirNode->sub_count);
				PrintSize(gd, SubDirNode->sub_size, SubDirNode->sub_ignore);
			}
			FPuts(gd->gd_Out, "@ENDNODE\n\n");

			SubDirNode = SubDirNode->sub_next;
		}

		DirNode = DirNode->dir_next;

	}

	return(TRUE);
}


/*
 * Function to check for CTRL-C break.
 */
BOOL CheckAbort(struct GlobalData *gd)
{
	if(SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C)
	{
		Printf("\n\n***User Abort\n");
		gd->gd_failureCode = 200;
		return(TRUE);
	}
	return(FALSE);
}

/*
 * Print (write to file) the size of an item (root, dir, subdir, file).
 * Scale format in order to make it smaller and more readable
 * (1024KByte-> 1M, 1024MByte -> 1GByte)
 */
VOID PrintSize(struct GlobalData *gd, LONG size, BOOL ignore)
{
	/* Exact or aproximate size ?									*/
	if(ignore)
		FPutC(gd->gd_Out, '>');
	else
		FPutC(gd->gd_Out, '=');

	if(!(size & 0xFFFFFC00))			/* Size < 1MByte (1024)		*/
		FPrintf(gd->gd_Out, "%5ldK\n", size);
	else if(!(size & 0xFFF00000))		/* Size < 1Gbyte (1048576)	*/
		FPrintf(gd->gd_Out, "%3ld.%01ldM\n", size >> 10, SDivMod32((size & 0x000003FF), 100));
	else
		FPrintf(gd->gd_Out, "%3ld.%-02ldG\n", size >> 20, SDivMod32((size & 0x000FFFFF), 10000));
}
