/*
	Testdir.c

	Display a 'tree' of the directory structure for a given drive.
	Include drive name as a command line argument to specify drive. If
	not specified, the current logged drive is mapped. This was written
	to develop and test the techniques to display a graphic tree
	structure for a commercial product, the KYSS!(tm) System Organizer.
	A number which indicates the nesting level is printed on each line.

	Written for Microsoft C V5.1

	Compile as follows:

		cl testdir.c /link /STACK:4096

	Use a larger value for stack if you run into 'Stack overflow' errors.

	The DisplayDirectories() function is recursive. A maximum of 32 levels
	of sub-directory nesting can be displayed, assuming that recursion
	does not eat all the memory...I've tested to 7 levels deep.

	This code is placed into the public domain by the author:
	Gene McManus
	The Information People
	358 Grandview Rd.
	Newark, OH 43055
	(614) 349-8644

	It may be used for any purpose whatsoever, with no claims or
	warranties made.
*/

#include <stdio.h>
#include <dos.h>

#define TRUE	1
#define FALSE	0

typedef struct find_t FILEINFO;

main(int argc, char *argv[])
	{
	int indent = 0;
	char drive[20];
	void DisplayDirectories();

	if(argc > 1)
		strcpy(drive, argv[1]);
	else
		drive[0] = '\0';

	DisplayDirectories(indent, drive, 0);
	}

/*
	DisplayDirectories() - Display all subdirectories in the current
	directory. If a sub-directory has sub-directories, display them.
	This function is recursive.
*/

static unsigned char map[32];

void 
DisplayDirectories(int indent, char *path, int sw)
	{
   static char indent_char[][4] = { " ³ ", " ÃÄ", " ÀÄ" };
	static first = 1;
	int done, empty_dir, i, must_close, shift;
	char display[80];
	char this_dir[65];
	char full_path[65];
	char *p;
	FILEINFO FileInfo1, FileInfo2;
	char *printPaths();

	if(first)
		{
		first = 0;
		printf("0 %s\\ (Root)\n", path);
		strcpy(this_dir, path);
		strcat(this_dir, "\\");
		strcpy(full_path, this_dir);
		strcat(full_path, "*.*");
		for(i = 0; i < 32; i++)
			map[i] = '\0';
		}
	else
		{
		strcpy(this_dir, path);
		strcpy(full_path,path);
		if(full_path[strlen(full_path) - 1] != '\\')
			strcat(full_path,"\\*.*");
		else
			strcat(full_path,"*.*");
		}

	shift = indent;
	must_close = FALSE;
	empty_dir = TRUE;

	done = _dos_findfirst(full_path, _A_SUBDIR, &FileInfo2);
	++shift;
	display[0] = '\0';

	while(!done)
		{
		if((FileInfo2.attrib & _A_SUBDIR) &&
			 FileInfo2.name[0] != '.')
		/* do this only for sub-directories */
			{
			empty_dir = FALSE;
			must_close = TRUE; 
			display[0] = '\0';

			if(sw)		/* previous level ended branch */
				map[shift-1] = 0xff;

			for(i = 1; i < shift; i++)
				if(map[i] != 0xff)
					strcat(display, indent_char[0]);
				else
					strcat(display, "   ");


			memcpy((char *)&FileInfo1, (char *)&FileInfo2, sizeof(FILEINFO));
			done = _dos_findnext(&FileInfo2);
			if(!done)		/* another file found in this directory */
				{
				while(!done)
					{
					if(FileInfo2.attrib & _A_SUBDIR)
						{
						must_close = FALSE;
						break;
						}
					done = _dos_findnext(&FileInfo2);
					} /* while(!done &&.. */

				if(must_close)
				/* there are no more sub-directories */
					p = indent_char[2];
				else
				/* there is at least one more sub-directory */
					p = indent_char[1];

				strcpy(full_path,
						 printPaths(display, p, FileInfo1.name, this_dir, shift));
				DisplayDirectories(shift, full_path, must_close); 
				}
			else
				{
				strcpy(full_path,
						 printPaths(display, indent_char[2], FileInfo1.name, this_dir, shift));
				DisplayDirectories(shift, full_path, must_close); 
				return;
				}
			}
		else
			{
			if(must_close)
				{
				strcpy(full_path,
					printPaths(display, indent_char[2], FileInfo1.name, this_dir, shift));
				DisplayDirectories(shift, full_path, must_close); 
				return;
				}

			done = _dos_findnext(&FileInfo2);
			}
		}	/* while (done == 0) */
	map[shift] = '\0';
	}

char
*printPaths(char *display, char *indent_char, char *name, char *path, int shift)
	{
	char full_path[65];

	strcat(display, indent_char);
	strcat(display, name);
	strcpy(full_path, path);
	if(full_path[strlen(full_path) - 1] != '\\')
		strcat(full_path, "\\");
	strcat(full_path, name);
	printf("%d %s \n", shift, display);
	return(full_path);
	}
