/******************************************************************************\
**	Dir.c					Persistor CF1 directory access example  
**	
**	First release:			Monday, April 26, 1999
**	Update release:			
*****************************************************************************
**	
**	
*****************************************************************************
**	
**	
\******************************************************************************/

#include	<cf1bios.h>		// Persistor CF1 System and I/O Definitions
#include	<cf1pico.h>		// Persistor CF1 PicoDOS Definitions  

#include	<stat.h>		// CF1 POSIX-like File Status Definitions
#include	<fcntl.h>		// CF1 POSIX-like File Access Definitions
#include	<unistd.h>		// CF1 POSIX-like UNIX Function Definitions
#include	<dirent.h>		// CF1 POSIX-like Directory Access Definitions
#include	<termios.h>		// CF1 POSIX-like Terminal I/O Definitions
#include	<dosdrive.h>	// CF1 DOS Drive and Directory Definitions

#include	<assert.h>
#include	<ctype.h>
#include	<errno.h>
#include	<float.h>
#include	<limits.h>
#include	<locale.h>
#include	<math.h>
#include	<setjmp.h>
#include	<signal.h>
#include	<stdarg.h>
#include	<stddef.h>
#include	<stdio.h>
#include	<stdlib.h>
#include	<string.h>
#include	<time.h>

void dir(char *str);

/******************************************************************************\
**	main
\******************************************************************************/
int main(int , char **)
	{
	char	buf[80];
	
	// Identify the program and build
	printf("\nProgram: %s: %s %s \n", __FILE__, __DATE__, __TIME__);
	// Identify the device and its firmware
	printf("Persistor CF1 SN:%ld   BIOS:%d.%d   PicoDOS:%d.%d\n",
		BIOSGVT.CF1SerNum, BIOSGVT.BIOSVersion, BIOSGVT.BIOSRelease, 
		BIOSGVT.PICOVersion, BIOSGVT.PICORelease);

	printf("\nEnter path strings (CTRL-C to exit)\n");
	buf[0] = '\0';
	while (QRstring("\nPath", "%s", true, buf, sizeof(buf)))
		dir(buf);

	return 0;

	}	//____ main() ____//

/******************************************************************************\
**	ULongToCommaDecStr		Convert long decimal number to 14 char string
\******************************************************************************/
char *ULongToCommaDecStr(ulong num);
char *ULongToCommaDecStr(ulong num)
	{
	static char	str[16];	// 4,294,967,295
	csprintf(str, "%,14lu", num);

	return str;
	
	}	//____ ULongToCommaDecStr() ____//


/******************************************************************************\
**	DirCmd		// Displays a list of files and subdirectories in a directory
\******************************************************************************/
void dir(char *str)
	{
	DIRENT	de;
	char	pathstr[80];
	char	matchstr[14];
	char	*p;
	short	err;
	ulong	freespace, usedspace, totalspace;
	char	*volname;
	ulong	volid;
	short	filecount = 0;
	short	dircount = 0;
	ulong	filebytes = 0;
	ulong	allocbytes = 0;
	short	maxcol = 5;
	struct stat stbuf;

	memset(matchstr, 0, sizeof(matchstr));		// guarantee all zeroed
	memset(pathstr, 0, sizeof(pathstr));		// guarantee all zeroed

	if (*str)	// we have a path argument
		strncpy(pathstr, str, sizeof(pathstr) - 1);

	// first test for (and factor out) wildcards
	if ((p = strpbrk(pathstr, "?*")) != 0)
		{
		while (p > pathstr && *p != '\\' && *p != ':')
			p--;
		if (p > pathstr)
			p++;
		strncpy(matchstr, p, sizeof(matchstr) - 1);
		*p = 0;		// chop off wildcard pattern
		}

	// now test if specified path is valid
	if ((err = stat(pathstr, &stbuf)) != 0)	// nothing there
		{
		printf("\nError %d\n", err);
		return;
		}

	pathstr[0] = stbuf.st_dev + 'A';
	pathstr[1] = ':';
	pathstr[2] = '\0';
	strncat(pathstr, stbuf.st_path, sizeof(pathstr) - 3);

	if (stbuf.st_mode == S_IFREG)	// we've got a file (not a directory)
		{
		if ((p = strrchr(pathstr, '\\')) == 0)
			p = strrchr(pathstr, ':');
		strcpy(matchstr, p + 1);		// remainder is now our pattern
		*p = '\0';				// and drive/path is terminated
		}

	if (*matchstr == '\0')		// deal with empty pattern string (force to *.*)
		strcpy(matchstr, "*.*");

	volname = DIRGetVolumeLabel(pathstr);
	volid = DIRSerialNumber(pathstr);

	printf("\n\n Volume in drive %c %s%s", pathstr[0], 
		volname ? "is " : "has no label",
		volname ? volname : "");
	printf("\n Volume Serial Number is %04X-%04X", volid);
	printf("\n Directory of %s", pathstr);

	printf("\nFile Name         Size         Allocated   Modified            Attrib\n\n");

	if ((err = DIRFindFirst(pathstr, &de)) != dsdEndOfDir)
		{
		do	{
			if (err != 0)
				{
				printf("\nError %d\n", err);
				return;
				}

			if (cgetq())		// allow us to abort
				if (cgetc() == 3)	// CTRL-C
					return;
				
		// qualify attributes	
			if (de.d_attr == _A_LONGNM)		// can't deal with Win95 long names
				continue;

			if (DIRMatchName((char *) de.d_name, matchstr))
				{
				char	name[14];
				
				if (de.d_attr & _A_SUBDIR)
					{
					dircount++;
					}
				else
					{
					filecount++;
					filebytes += de.d_size;
					}
				
				strcpy(name, de.d_name);
					
				if (de.d_attr & _A_SUBDIR)
					{
					printf("%-12s", name);
					printf("   <DIR>        ");
					}
				else
					{
					printf("%-12s", name);
					printf("%s  ", ULongToCommaDecStr(de.d_size));
					}

				if (de.d_attr & _A_SUBDIR)
					printf("%-14s", "");
				else
					{
					long	alloc = de.d_size + de.d_clustsize - (de.d_size % de.d_clustsize);
					allocbytes += alloc;
					printf("%s  ", ULongToCommaDecStr(alloc) + 2);
					}

				printf("%02d-%02d-%04d %2d:%02d%c",
					de.d_tm.tm_mon + 1, de.d_tm.tm_mday,
					de.d_tm.tm_year + 1900, 
					de.d_tm.tm_hour == 0 ? 12 :
						de.d_tm.tm_hour > 12 ? de.d_tm.tm_hour - 12 : de.d_tm.tm_hour,
					de.d_tm.tm_min,
					de.d_tm.tm_hour > 11 ? 'p' : 'a'
					);

				printf("  %c%c%c%c%c%c",
					(de.d_attr & _A_RDONLY) ? 'R' : ' ',
					(de.d_attr & _A_HIDDEN) ? 'H' : ' ',
					(de.d_attr & _A_SYSTEM) ? 'S' : ' ',
					(de.d_attr & _A_VOLID) ? 'V' : ' ',
					(de.d_attr & _A_SUBDIR) ? 'D' : ' ',
					(de.d_attr & _A_ARCH) ? 'A' : ' '
					);

				printf("\n");

				}
				
			} while (DIRFindNext(&de) != dsdEndOfDir);
		}
				
		freespace = DIRFreeSpace(pathstr);
		totalspace = DIRTotalSpace(pathstr);
		usedspace = totalspace - freespace;
		
		printf("\n%10d file(s) %s bytes", filecount, ULongToCommaDecStr(filebytes));
		printf("\n%10d dir(s)  %s bytes allocated", dircount, ULongToCommaDecStr(allocbytes));
		printf("\n                   %s bytes free", ULongToCommaDecStr(freespace));

		printf("\n                   %s bytes total disk space,  %lu%% in use",
			ULongToCommaDecStr(totalspace),
			totalspace ? usedspace / (totalspace / 100) : 100);

	printf("\n");

	}	//____ DirCmd() ____//

