27-Feb-2005 (Konstantinos Paliouras <squarious@gmail.com>)
Implemented all the switches that were missing, and made the ros dir very similar to windows dir. Major part of the code is rewritten. /p is removed, to be rewriten in the main cmd code.
Modified: trunk/reactos/subsys/system/cmd/dir.c
Modified: trunk/reactos/subsys/system/cmd/precomp.h

Modified: trunk/reactos/subsys/system/cmd/dir.c
--- trunk/reactos/subsys/system/cmd/dir.c	2005-03-08 15:02:41 UTC (rev 13876)
+++ trunk/reactos/subsys/system/cmd/dir.c	2005-03-08 15:08:01 UTC (rev 13877)
@@ -119,6 +119,13 @@
  *
  *    30-Apr-2004 (Filip Navara <xnavara@volny.cz>)
  *        Fix /w to print long names.
+ *
+ *    27-Feb-2005 (Konstantinos Paliouras <squarious@gmail.com>)
+ *        Implemented all the switches that were missing, and made
+ *        the ros dir very similar to windows dir. Major part of
+ *        the code is rewritten. /p is removed, to be rewriten in
+ *        the main cmd code.
+ *        
  */
 
 #include "precomp.h"
@@ -126,21 +133,62 @@
 #ifdef INCLUDE_CMD_DIR
 
 
-/* flag definitions */
-enum
+
+/* Time Field enumeration */
+enum ETimeField
 {
-	DIR_RECURSE = 0x0001,
-	DIR_PAGE    = 0x0002,
-	DIR_WIDE    = 0x0004,        /* Rob Lake */
-	DIR_BARE    = 0x0008,        /* Rob Lake */
-	DIR_ALL     = 0x0010,        /* Rob Lake */
-	DIR_LWR     = 0x0020,        /* Rob Lake */
-	DIR_SORT    = 0x0040,        /* /O sort */
-	DIR_NEW     = 0x0080,        /* /N new style */
-	DIR_FOUR    = 0x0100         /* /4 four digit year */
+	TF_CREATIONDATE		= 0,
+	TF_MODIFIEDDATE		= 1,
+	TF_LASTACCESSEDDATE	= 2
 };
 
+/* Ordered by enumeration */
+enum EOrderBy
+{
+	ORDER_NAME		= 0,
+	ORDER_SIZE		= 1,
+	ORDER_DIRECTORY	= 2,
+	ORDER_EXTENSION	= 3,
+	ORDER_TIME		= 4
+};
 
+/* The struct for holding the switches */
+typedef struct TDirSwitchesFlags
+{
+	BOOL bBareFormat;	/* Bare Format */
+	BOOL bTSeperator;	/* Thousands seperator */
+	BOOL bWideList;		/* Wide list format	*/
+	BOOL bWideListColSort;	/* Wide list format but sorted by column */
+	BOOL bLowerCase;	/* Uses lower case */
+	BOOL bNewLongList;	/* New long list */
+	BOOL bPause;		/* Pause per page */
+	BOOL bUser;			/* Displays the owner of file */
+	BOOL bRecursive;	/* Displays files in specified directory and all sub */
+	BOOL bShortName;	/* Displays the sort name of files if exist	*/
+	BOOL b4Digit;		/* Four digit year	*/
+	struct
+	{
+		DWORD dwAttribVal;	/* The desired state of attribute */
+		DWORD dwAttribMask;	/* Which attributes to check */
+		BOOL bUnSet;		/* A helper flag if "-" was given with the switch */
+		BOOL bParSetted;	/* A helper flag if parameters of switch were given */
+	} stAttribs;		/* Displays files with this attributes only */
+	struct
+	{
+		enum EOrderBy eCriteria[3];	/* Criterias used to order by */
+		BOOL bCriteriaRev[3];		/* If the criteria is in reversed order */
+		short sCriteriaCount;		/* The quantity of criterias */
+		BOOL bUnSet;				/* A helper flag if "-" was given with the switch */
+		BOOL bParSetted;			/* A helper flag if parameters of switch were given */
+	} stOrderBy;		/* Ordered by criterias */
+	struct
+	{
+		enum ETimeField eTimeField;	/* The time field that will be used for */
+		BOOL bUnSet;				/* A helper flag if "-" was given with the switch */
+		BOOL bParSetted;			/* A helper flag if parameters of switch were given */
+	} stTimeField;		/* The time field to display or use for sorting */
+}DIRSWITCHFLAGS, * LPDIRSWITCHFLAGS;
+
 typedef BOOL STDCALL
 (*PGETFREEDISKSPACEEX)(LPCTSTR, PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER);
 
@@ -158,177 +206,382 @@
  * displays help screen for dir
  * Rob Lake
  */
-static VOID Help (VOID)
+static VOID
+	DirHelp (VOID)
 {
-  ConOutPuts(_T("Displays a list of files and subdirectories in a directory.\n"
-       "\n"
-       "DIR [drive:][path][filename] [/A] [/B] [/L] [/N] [/S] [/P] [/W] [/4]\n"
-       "\n"
-       "  [drive:][path][filename]\n"
-       "              Specifies drive, directory, and/or files to list.\n"
-       "\n"
-       "  /A          Displays files with HIDDEN SYSTEM attributes\n"
-       "              default is ARCHIVE and READ ONLY\n"
-       "  /B          Uses bare format (no heading information or summary).\n"
-       "  /L          Uses lowercase.\n"
-       "  /N          New long list format where filenames are on the far right.\n"
-       "  /S          Displays files in specified directory and all subdirectories\n"
-       "  /P          Pauses after each screen full\n"
-       "  /W          Prints in wide format\n"
-       "  /4          Display four digit years.\n"
-       "\n"
-       "Switches may be present in the DIRCMD environment variable.  Use\n"
-       "of the - (hyphen) can turn off defined swtiches.  Ex. /-W would\n"
-       "turn off printing in wide format.\n"
+	ConOutPuts(_T(
+		"DIR [drive:][path][filename] [/A[[:]attributes]] [/B] [/C] [/D] [/L] [/N]\n"
+		"  [/O[[:]sortorder]] [/P] [/Q] [/S] [/T[[:]timefield]] [/W] [/X] [/4]\n"
+		"\n"
+		"  [drive:][path][filename]\n"
+		"              Specifies drive, directory, and/or files to list.\n"
+		"\n"
+		"  /A          Displays files with specified attributes.\n"
+		"  attributes   D  Directories                R  Read-only files\n"
+		"               H  Hidden files               A  Files ready for archiving\n"
+		"               S  System files               -  Prefix meaning not\n"
+		"  /B          Uses bare format (no heading information or summary).\n"
+		"  /C          Display the thousand separator in file sizes.  This is the\n"
+		"              default.  Use /-C to disable display of separator.\n"
+		"  /D          Same as wide but files are list sorted by column.\n"
+		"  /L          Uses lowercase.\n"
+		"  /N          New long list format where filenames are on the far right.\n"
+		"  /O          List by files in sorted order.\n"
+		"  sortorder    N  By name (alphabetic)       S  By size (smallest first)\n"
+		"               E  By extension (alphabetic)  D  By date/time (oldest first)\n"
+		"               G  Group directories first    -  Prefix to reverse order\n"
+		"  /P          Pauses after each screenful of information.\n"
+		"  /Q          Display the owner of the file.\n"
+		"  /S          Displays files in specified directory and all subdirectories.\n"
+		"  /T          Controls which time field displayed or used for sorting\n"
+		"  timefield   C  Creation\n"
+		"              A  Last Access\n"
+		"              W  Last Written\n"
+		"  /W          Uses wide list format.\n"
+		"  /X          This displays the short names generated for non-8dot3 file\n"
+		"              names.  The format is that of /N with the short name inserted\n"
+		"              before the long name. If no short name is present, blanks are\n"
+		"              displayed in its place.\n"
+		"  /4          Displays four-digit years\n"
+		" \n"
+		"Switches may be preset in the DIRCMD environment variable.  Override\n"
+		"preset switches by prefixing any switch with - (hyphen)--for example, /-W.\n"
       ));
 }
 
 
+
 /*
- * DirReadParam
+ * DirReadParameters
  *
- * read the parameters from the command line
+ * Parse the parameters and switches of the command line and exports them
  */
-static BOOL
-DirReadParam (LPTSTR line, LPTSTR *param, LPDWORD lpFlags)
+static BOOL 
+DirReadParam (LPTSTR line,				/* [IN] The line with the parameters & switches */
+			  LPTSTR *param,			/* [OUT] The parameters after parsing */
+			  LPDIRSWITCHFLAGS lpFlags	/* [IN/OUT] The flags after calculating switches */
+			  )
 {
-	INT slash = 0;
+TCHAR cCurSwitch;	/* The current switch */
+TCHAR cCurChar;		/* Current examing character */
+TCHAR cCurUChar;	/* Current upper examing character */
+BOOL bNegative;		/* Negative switch */
+BOOL bPNegative;	/* Negative switch parameter */
+BOOL bIntoQuotes;	/* A flag showing if we are in quotes (") */
+LPTSTR ptrLast;		/* A pointer to the last character of param */
 
-	if (!line)
-		return TRUE;
+	/* Initialize variables; */
+	cCurSwitch = _T(' ');
+	bNegative = FALSE;
+	bPNegative = FALSE;
+	bIntoQuotes = FALSE;
 
+	/* No parameters yet  */
 	*param = NULL;
+	ptrLast = NULL;
+	
+	/* We suppose that switch parameters
+	   were given to avoid setting them to default
+	   if the switch was not given */
+	lpFlags->stAttribs.bParSetted = TRUE;
+	lpFlags->stOrderBy.bParSetted = TRUE;
+	lpFlags->stTimeField.bParSetted = TRUE;
 
-	/* scan the command line, processing switches */
+	/* Main Loop (see README_DIR.txt) */
+	/* scan the command line char per char, and we process its char */
 	while (*line)
 	{
-		/* process switch */
-		if (*line == _T('/') || slash)
+		/* we save current character as it is and its upper case */
+		cCurChar = *line;
+		cCurUChar = _toupper(*line);
+		
+		/* 1st section (see README_DIR.txt) */
+		/* When a switch is expecting */
+		if (cCurSwitch == _T('/'))
 		{
-			if (!slash)
-				line++;
-			slash = 0;
-			if (*line == _T('-'))
-			{
-				line++;
-				if (_totupper (*line) == _T('S'))
-					*lpFlags &= ~DIR_RECURSE;
-				else if (_totupper (*line) == _T('P'))
-					*lpFlags &= ~DIR_PAGE;
-				else if (_totupper (*line) == _T('W'))
-					*lpFlags &= ~DIR_WIDE;
-				else if (_totupper (*line) == _T('B'))
-					*lpFlags &= ~DIR_BARE;
-				else if (_totupper (*line) == _T('A'))
-					*lpFlags &= ~DIR_ALL;
-				else if (_totupper (*line) == _T('L'))
-					*lpFlags &= ~DIR_LWR;
-				else if (_totupper (*line) == _T('N'))
-					*lpFlags &= ~DIR_NEW;
-				else if (_totupper (*line) == _T('O'))
-					*lpFlags &= ~DIR_SORT;
-				else if (_totupper (*line) == _T('4'))
-					*lpFlags &= ~DIR_FOUR;
-				else
+			if ((cCurUChar == _T('A')) ||(cCurUChar == _T('T')) || (cCurUChar == _T('O')))
+			{			
+				cCurSwitch = cCurUChar;
+				switch (cCurUChar)
 				{
-					error_invalid_switch ((TCHAR)_totupper (*line));
-					return FALSE;
+				case _T('A'):
+					lpFlags->stAttribs.bUnSet = bNegative;
+					lpFlags->stAttribs.bParSetted = FALSE;
+					break;
+				case _T('T'):
+					lpFlags->stTimeField.bUnSet = bNegative;
+					lpFlags->stTimeField.bParSetted = FALSE;
+					break;
+				case _T('O'):
+					lpFlags->stOrderBy.bUnSet = bNegative;
+					lpFlags->stOrderBy.bParSetted = FALSE;
+					break;
 				}
-				line++;
-				continue;
 			}
-			else
+			else if (cCurUChar ==  _T('L'))
+				lpFlags->bLowerCase = ! bNegative;
+			else if (cCurUChar ==  _T('B'))			
+				lpFlags->bBareFormat = ! bNegative;
+			else if (cCurUChar ==  _T('C'))
+				lpFlags->bTSeperator = ! bNegative;
+			else if (cCurUChar ==  _T('W'))
+				lpFlags->bWideList = ! bNegative;				
+			else if (cCurUChar ==  _T('D'))
+				lpFlags->bWideListColSort = ! bNegative;				
+			else if (cCurUChar ==  _T('N'))
+				lpFlags->bNewLongList = ! bNegative;
+			else if (cCurUChar ==  _T('P'))
+				lpFlags->bPause = ! bNegative;
+			else if (cCurUChar ==  _T('Q'))
+				lpFlags->bUser = ! bNegative;
+			else if (cCurUChar ==  _T('S'))
+				lpFlags->bRecursive = ! bNegative;
+			else if (cCurUChar ==  _T('X'))
+				lpFlags->bShortName = ! bNegative;
+			else if (cCurChar == _T('4'))
+				lpFlags->b4Digit = ! bNegative;
+			else if (cCurChar ==  _T('?'))
 			{
-				if (_totupper (*line) == _T('S'))
-					*lpFlags |= DIR_RECURSE;
-				else if (_totupper (*line) == _T('P'))
-					*lpFlags |= DIR_PAGE;
-				else if (_totupper (*line) == _T('W'))
-					*lpFlags |= DIR_WIDE;
-				else if (_totupper (*line) == _T('B'))
-					*lpFlags |= DIR_BARE;
-				else if (_totupper (*line) == _T('A'))
-					*lpFlags |= DIR_ALL;
-				else if (_totupper (*line) == _T('L'))
-					*lpFlags |= DIR_LWR;
-				else if (_totupper (*line) == _T('N'))
-					*lpFlags |= DIR_NEW;
-				else if (_totupper (*line) == _T('O'))
-					*lpFlags |= DIR_SORT;
-				else if (_totupper (*line) == _T('4'))
-					*lpFlags |= DIR_FOUR;
-				else if (*line == _T('?'))
+				DirHelp();
+				return FALSE;                
+			}
+			else if (cCurChar ==  _T('-'))
+				bNegative = TRUE;
+			else 
+			{
+				error_invalid_switch ((TCHAR)_totupper (*line));
+				return FALSE;
+			}
+
+			/* We check if we calculated the negative value and realese the flag */
+			if ((cCurChar != _T('-')) && bNegative)
+				bNegative = FALSE;
+
+			/* if not a,o,t or - option then next parameter is not a switch */
+			if ((cCurSwitch == _T('/')) && (!bNegative))
+				cCurSwitch = _T(' ');
+
+		}
+		/* 2nd section (see README_DIR.txt) */
+		/* We are expecting parameter or the unknown */
+		else if ((cCurSwitch == _T(' ')) || (cCurSwitch == _T('P')))
+		{
+			if (cCurChar == _T('/'))
+				cCurSwitch = _T('/');
+
+			/* Process a spacer */
+			else if (cCurChar == _T(' '))
+			{
+				if (!bIntoQuotes)
 				{
-					Help();
-					return FALSE;
-				}
-				else
+					cCurSwitch = _T(' ');
+					if ((*param) && !(ptrLast))
+						ptrLast = line;
+				}				
+					
+			}
+			/* Process a quote */
+			else if (cCurChar == _T('\"'))
+			{
+				bIntoQuotes = !bIntoQuotes;
+				if (!bIntoQuotes) ptrLast = line;
+			}
+			/* Process a character for parameter */
+			else			
+			{
+				if ((cCurSwitch == _T(' ')) && (*param))
 				{
-					error_invalid_switch ((TCHAR)_totupper (*line));
+					error_too_many_parameters(line);
 					return FALSE;
 				}
-				line++;
-				continue;
+				cCurSwitch = _T('P');
+				if (!(*param))
+					*param = line;
 			}
+
 		}
-
-		/* process parameter */
-		if (!_istspace (*line))
+		/* 3rd section (see README_DIR.txt) */
+		/* We are waiting for switch parameters */
+		else
 		{
-			if (*param)
+			/* Check if there are no more switch parameters */
+			if ((cCurChar == _T('/')) || ( cCurChar == _T(' ')))
 			{
-				error_too_many_parameters (line);
-				return FALSE;
+				/* Wrong desicion path, reprocess current character */
+				cCurSwitch = cCurChar;
+				continue;
 			}
+			/* Process parameter switch */
+			switch(cCurSwitch)
+			{
+			case _T('A'):	/* Switch parameters for /A (attributes filter) */
+				/* Ok a switch parameter was given */
+				lpFlags->stAttribs.bParSetted = TRUE;
 
-			*param = line;
+				if (cCurChar == _T(':'))
+					/* =V= dead command, used to make the "if" work */
+					cCurChar = cCurChar;
+				else if(cCurChar == _T('-'))
+					bPNegative = TRUE;
+				else if(cCurUChar == _T('D'))
+				{
+					lpFlags->stAttribs.dwAttribMask |= FILE_ATTRIBUTE_DIRECTORY;
+					if (bPNegative)
+						lpFlags->stAttribs.dwAttribVal &= ~FILE_ATTRIBUTE_DIRECTORY;
+					else
+						lpFlags->stAttribs.dwAttribVal |= FILE_ATTRIBUTE_DIRECTORY;
+				}
+				else if(cCurUChar == _T('R'))
+				{
+					lpFlags->stAttribs.dwAttribMask |= FILE_ATTRIBUTE_READONLY;
+					if (bPNegative)
+						lpFlags->stAttribs.dwAttribVal &= ~FILE_ATTRIBUTE_READONLY;
+					else
+						lpFlags->stAttribs.dwAttribVal |= FILE_ATTRIBUTE_READONLY;
+				}
+				else if(cCurUChar == _T('H'))
+				{
+					lpFlags->stAttribs.dwAttribMask |= FILE_ATTRIBUTE_HIDDEN;
+					if (bPNegative)
+						lpFlags->stAttribs.dwAttribVal &= ~FILE_ATTRIBUTE_HIDDEN;
+					else
+						lpFlags->stAttribs.dwAttribVal |= FILE_ATTRIBUTE_HIDDEN;
+				}
+				else if(cCurUChar == _T('A'))
+				{
+					lpFlags->stAttribs.dwAttribMask |= FILE_ATTRIBUTE_ARCHIVE;
+					if (bPNegative)
+						lpFlags->stAttribs.dwAttribVal &= ~FILE_ATTRIBUTE_ARCHIVE;
+					else
+						lpFlags->stAttribs.dwAttribVal |= FILE_ATTRIBUTE_ARCHIVE;
+				}
+				else if(cCurUChar == _T('S'))
+				{
+					lpFlags->stAttribs.dwAttribMask |= FILE_ATTRIBUTE_SYSTEM;
+					if (bPNegative)
+						lpFlags->stAttribs.dwAttribVal &= ~FILE_ATTRIBUTE_SYSTEM;
+					else
+						lpFlags->stAttribs.dwAttribVal |= FILE_ATTRIBUTE_SYSTEM;
+				}
+				else
+				{
+					error_parameter_format((TCHAR)_totupper (*line));
+					return FALSE;
+				}
+				break;
+			case _T('T'):	/* Switch parameters for /T (time field) */
 
-			/* skip to end of line or next whitespace or next / */
-			if (*line != _T('\"'))
-			{
-				while (*line && !_istspace (*line) && *line != _T('/'))
-					line++;
+				/* Ok a switch parameter was given */
+				lpFlags->stTimeField.bParSetted = TRUE;
 
-				/* if end of line, return */
-				if (!*line)
-					return TRUE;
-			}
-			else
-			{
-				/* skip over the initial quote */
-				(*param)++;
-				line++;
+				if (cCurChar == _T(':'))
+					/* =V= dead command, used to make the "if" work */
+					cCurChar = cCurChar;
+				else if(cCurUChar == _T('C'))
+					lpFlags->stTimeField.eTimeField= TF_CREATIONDATE ;
+				else if(cCurUChar == _T('A'))
+					lpFlags->stTimeField.eTimeField= TF_LASTACCESSEDDATE ;
+				else if(cCurUChar == _T('W'))
+					lpFlags->stTimeField.eTimeField= TF_MODIFIEDDATE  ;
+				else
+				{
+					error_parameter_format((TCHAR)_totupper (*line));
+					return FALSE;
+				}
+				break;
+			case _T('O'):	/* Switch parameters for /O (order) */
+				/* Ok a switch parameter was given */
+				lpFlags->stOrderBy.bParSetted = TRUE;
 
-				while (*line && *line != _T('"'))
-					line++;
+				if (cCurChar == _T(':'))
+					/* <== dead command, used to make the "if" work */
+					cCurChar = cCurChar;
+				else if(cCurChar == _T('-'))
+					bPNegative = TRUE;
+				else if(cCurUChar == _T('N'))
+				{
+					if (lpFlags->stOrderBy.sCriteriaCount < 3) lpFlags->stOrderBy.sCriteriaCount++;
+					lpFlags->stOrderBy.bCriteriaRev[lpFlags->stOrderBy.sCriteriaCount - 1] = bPNegative;
+					lpFlags->stOrderBy.eCriteria[lpFlags->stOrderBy.sCriteriaCount - 1] = ORDER_NAME;
+				}
+				else if(cCurUChar == _T('S'))
+				{
+					if (lpFlags->stOrderBy.sCriteriaCount < 3) lpFlags->stOrderBy.sCriteriaCount++;
+					lpFlags->stOrderBy.bCriteriaRev[lpFlags->stOrderBy.sCriteriaCount - 1] = bPNegative;
+					lpFlags->stOrderBy.eCriteria[lpFlags->stOrderBy.sCriteriaCount - 1] = ORDER_SIZE;
+				}
+				else if(cCurUChar == _T('G'))
+				{
+					if (lpFlags->stOrderBy.sCriteriaCount < 3) lpFlags->stOrderBy.sCriteriaCount++;
+					lpFlags->stOrderBy.bCriteriaRev[lpFlags->stOrderBy.sCriteriaCount - 1] = bPNegative;
+					lpFlags->stOrderBy.eCriteria[lpFlags->stOrderBy.sCriteriaCount - 1] = ORDER_DIRECTORY;
+				}
+				else if(cCurUChar == _T('E'))
+				{
+					if (lpFlags->stOrderBy.sCriteriaCount < 3) lpFlags->stOrderBy.sCriteriaCount++;
+					lpFlags->stOrderBy.bCriteriaRev[lpFlags->stOrderBy.sCriteriaCount - 1] = bPNegative;
+					lpFlags->stOrderBy.eCriteria[lpFlags->stOrderBy.sCriteriaCount - 1] = ORDER_EXTENSION;
+				}
+				else if(cCurUChar == _T('D'))
+				{
+					if (lpFlags->stOrderBy.sCriteriaCount < 3) lpFlags->stOrderBy.sCriteriaCount++;
+					lpFlags->stOrderBy.bCriteriaRev[lpFlags->stOrderBy.sCriteriaCount - 1] = bPNegative;
+					lpFlags->stOrderBy.eCriteria[lpFlags->stOrderBy.sCriteriaCount - 1] = ORDER_TIME;
+				}
 
-				if (*line == _T('"'))
-					*line = 0;
 				else
-					return TRUE;
-			}
+				{
+					error_parameter_format((TCHAR)_totupper (*line));
+					return FALSE;
+				}
 
-			/* if parameter, remember to process it later */
-			if (*line == _T('/'))
-				slash = 1;
 
-			*line++ = 0;
-			continue;
+			}
+			/* We check if we calculated the negative value and realese the flag */
+			if ((cCurChar != _T('-')) && bPNegative)
+				bPNegative = FALSE;
 		}
-
+	
 		line++;
 	}
+	/* Terminate the parameters */
+	if (ptrLast) *ptrLast = 0;
 
-	if (slash)
+	/* Calculate the switches with no switch paramater  */
+	if (!(lpFlags->stAttribs.bParSetted))
 	{
-		error_invalid_switch ((TCHAR)_totupper (*line));
-		return FALSE;
+		lpFlags->stAttribs.dwAttribVal = 0L;
+		lpFlags->stAttribs.dwAttribMask = lpFlags->stAttribs.dwAttribVal;
 	}
+	if (!(lpFlags->stOrderBy.bParSetted))
+	{
+		lpFlags->stOrderBy.sCriteriaCount = 1;
+		lpFlags->stOrderBy.eCriteria[0] = ORDER_NAME;
+		lpFlags->stOrderBy.bCriteriaRev[0] = FALSE;
+	}
+	if (!(lpFlags->stOrderBy.bParSetted))
+		lpFlags->stTimeField.eTimeField = TF_MODIFIEDDATE ;
 
+	/* Calculate the unsetted switches (the "-" prefixed)*/
+	if (lpFlags->stAttribs.bUnSet)
+	{
+		lpFlags->stAttribs.bUnSet = FALSE;
+		lpFlags->stAttribs.dwAttribVal = 0L;
+		lpFlags->stAttribs.dwAttribMask = FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM;
+	}
+	if (lpFlags->stOrderBy.bUnSet)
+	{
+		lpFlags->stOrderBy.bUnSet = FALSE;
+		lpFlags->stOrderBy.sCriteriaCount = 0;
+	}
+	if (lpFlags->stTimeField.bUnSet )
+	{
+		lpFlags->stTimeField.bUnSet = FALSE;
+		lpFlags->stTimeField.eTimeField = TF_MODIFIEDDATE;
+	}
 	return TRUE;
 }
 
-
 /*
  * ExtendFilespec
  *
@@ -507,9 +760,9 @@
  * incline
  *
  * increment our line if paginating, display message at end of screen
- */
+ *//*Maybe needed in future
 static BOOL
-IncLine (LPINT pLine, DWORD dwFlags)
+IncLine (LPINT pLine, LPDIRSWITCHFLAGS lpFlags)
 {
 	BOOL error;
 	CONSOLE_SCREEN_BUFFER_INFO lpConsoleScreenBufferInfo;
@@ -518,16 +771,21 @@
 	
 	WindowHeight= lpConsoleScreenBufferInfo.srWindow.Bottom - lpConsoleScreenBufferInfo.srWindow.Top;
 
-	if (!WindowHeight)  //That prevents bad behave if WindowHeight couln't calc
+	//That prevents bad behave if WindowHeight couln't calc 
+	if (!WindowHeight)  
 	{
 		 WindowHeight= 1000000;
 	}
-	if (!(dwFlags & DIR_PAGE))
+	if (!(lpFlags->bPause))
 		return FALSE;
 
 	(*pLine)++;
 
-	if (*pLine >= (int)maxy - 2 || *pLine >= WindowHeight) //Because I don't know if WindowsHeight work under all cases, perhaps then maxy is the right value
+	// Because I don't know if WindowsHeight
+	   work under all cases, perhaps then maxy
+	   is the right value 
+   
+	if (*pLine >= (int)maxy - 2 || *pLine >= WindowHeight) 
 	{
 		*pLine = 0;
 		return (PagePrompt () == PROMPT_BREAK);
@@ -535,22 +793,22 @@
 
 	return FALSE;
 }
+*/
 
-
 /*
  * PrintDirectoryHeader
  *
  * print the header for the dir command
  */
 static BOOL
-PrintDirectoryHeader (LPTSTR szPath, LPINT pLine, DWORD dwFlags)
+PrintDirectoryHeader (LPTSTR szPath, LPINT pLine, LPDIRSWITCHFLAGS lpFlags)
 {
   TCHAR szRootName[MAX_PATH];
   TCHAR szVolName[80];
   DWORD dwSerialNr;
   LPTSTR p;
 
-  if (dwFlags & DIR_BARE)
+  if (lpFlags->bBareFormat)
     return(TRUE);
 
   /* build usable root path */
@@ -607,15 +865,10 @@
   else
     ConOutPrintf(_T(" has no label\n"));
 
-  if (IncLine(pLine, dwFlags))
-    return(FALSE);
-
   /* print the volume serial number if the return was successful */
   ConOutPrintf(_T(" Volume Serial Number is %04X-%04X\n"),
 	       HIWORD(dwSerialNr),
 	       LOWORD(dwSerialNr));
-  if (IncLine(pLine, dwFlags))
-    return(FALSE);
 
   return(TRUE);
 }
@@ -625,7 +878,7 @@
  * convert
  *
  * insert commas into a number
- */
+ *//* Maybe needed in future
 static INT
 ConvertULong (ULONG num, LPTSTR des, INT len)
 {
@@ -656,10 +909,10 @@
 
 	return n;
 }
+*/
 
-
 static INT
-ConvertULargeInteger (ULARGE_INTEGER num, LPTSTR des, INT len)
+ConvertULargeInteger (ULARGE_INTEGER num, LPTSTR des, INT len, BOOL bPutSeperator)
 {
 	TCHAR temp[32];
 	INT c = 0;
@@ -676,7 +929,7 @@
 		temp[31] = 0;
 		while (num.QuadPart > 0)
 		{
-			if (((c + 1) % (nNumberGroups + 1)) == 0)
+			if ((((c + 1) % (nNumberGroups + 1)) == 0) && (bPutSeperator))
 				temp[30 - c++] = cThousandSeparator;
 			temp[30 - c++] = (TCHAR)(num.QuadPart % 10) + _T('0');
 			num.QuadPart /= 10;
@@ -691,44 +944,80 @@
 
 
 static VOID
-PrintFileDateTime (LPSYSTEMTIME dt, DWORD dwFlags)
+DirPrintFileDateTime (TCHAR * lpDate,
+					  TCHAR * lpTime,
+					  LPWIN32_FIND_DATA lpFile,
+					  LPDIRSWITCHFLAGS lpFlags)
 {
-	WORD wYear = (dwFlags & DIR_FOUR) ? dt->wYear : dt->wYear%100;
+FILETIME ft;
+SYSTEMTIME dt;
+TCHAR szDate[30];
+TCHAR szTime[30];
+WORD wYear;
 
+	/* Select the right time field */
+	switch (lpFlags->stTimeField.eTimeField)
+	{
+	case TF_CREATIONDATE:
+		if (!FileTimeToLocalFileTime(&lpFile->ftCreationTime, &ft))
+			return;
+		FileTimeToSystemTime(&ft, &dt);		
+		break;
+	case TF_LASTACCESSEDDATE :
+		if (!FileTimeToLocalFileTime(&lpFile->ftLastAccessTime, &ft))
+			return;
+		FileTimeToSystemTime(&ft, &dt);		
+		break;
+	case TF_MODIFIEDDATE:
+		if (!FileTimeToLocalFileTime(&lpFile->ftLastWriteTime, &ft))
+			return;
+		FileTimeToSystemTime(&ft, &dt);		
+		break;
+	}
+
+	/* Format date */
+	wYear = (lpFlags->b4Digit) ? dt.wYear : dt.wYear%100;
 	switch (nDateFormat)
 	{
 		case 0: /* mmddyy */
 		default:
-			ConOutPrintf (_T("%.2d%c%.2d%c%d"),
-					dt->wMonth, cDateSeparator, dt->wDay, cDateSeparator, wYear);
+			_stprintf (szDate,_T("%02d%c%02d%c%0*d"),
+					dt.wMonth, cDateSeparator,
+					dt.wDay, cDateSeparator,
+					lpFlags->b4Digit?4:2, wYear);
 			break;
 
 		case 1: /* ddmmyy */
-			ConOutPrintf (_T("%.2d%c%.2d%c%d"),
-					dt->wDay, cDateSeparator, dt->wMonth, cDateSeparator, wYear);
+			_stprintf (szDate, _T("%02d%c%02d%c%0*d"),
+					dt.wDay, cDateSeparator, dt.wMonth,
+					cDateSeparator,lpFlags->b4Digit?4:2, wYear);
 			break;
 
 		case 2: /* yymmdd */
-			ConOutPrintf (_T("%d%c%.2d%c%.2d"),
-					wYear, cDateSeparator, dt->wMonth, cDateSeparator, dt->wDay);
+			_stprintf (szDate, _T("%0*d%c%02d%c%02d"),
+					lpFlags->b4Digit?4:2, wYear, cDateSeparator,
+					dt.wMonth, cDateSeparator, dt.wDay);
 			break;
 	}
-
+	/* Format Time */
 	switch (nTimeFormat)
 	{
 		case 0: /* 12 hour format */
 		default:
-			ConOutPrintf (_T("  %2d%c%.2u%c"),
-					(dt->wHour == 0 ? 12 : (dt->wHour <= 12 ? dt->wHour : dt->wHour - 12)),
+			_stprintf (szTime,_T("  %02d%c%02u%c"),
+					(dt.wHour == 0 ? 12 : (dt.wHour <= 12 ? dt.wHour : dt.wHour - 12)),
 					cTimeSeparator,
-					 dt->wMinute, (dt->wHour <= 11 ? 'a' : 'p'));
+					 dt.wMinute, (dt.wHour <= 11 ? 'a' : 'p'));
 			break;
 
 		case 1: /* 24 hour format */
-			ConOutPrintf (_T("  %2d%c%.2u"),
-					dt->wHour, cTimeSeparator, dt->wMinute);
+			_stprintf (szTime, _T("  %02d%c%02u"),
+					dt.wHour, cTimeSeparator, dt.wMinute);
 			break;
 	}
+	/* Copy results */
+	_tcscpy(lpDate, szDate);
+	_tcscpy(lpTime, szTime);
 }
 
 
@@ -783,457 +1072,734 @@
 PrintSummary(LPTSTR szPath,
 	     ULONG ulFiles,
 	     ULONG ulDirs,
-	     ULARGE_INTEGER bytes,
+	     ULARGE_INTEGER u64Bytes,
 	     LPINT pLine,
-	     DWORD dwFlags)
+	     LPDIRSWITCHFLAGS lpFlags)
 {
-  TCHAR buffer[64];
-  ULARGE_INTEGER uliFree;
-  TCHAR szRoot[] = _T("A:\\");
+TCHAR szBuffer[64];
+ULARGE_INTEGER uliFree;
+TCHAR szRoot[] = _T("A:\\");
 
-  if (dwFlags & DIR_BARE)
-    return(0);
 
-  /* Print number of files and bytes */
-  ConvertULong (ulFiles, buffer, sizeof(buffer));
-  ConOutPrintf (_T("          %6s File%c"),
-                buffer, ulFiles == 1 ? _T(' ') : _T('s'));
+	/* Here we check if we didn't find anything */
+	if (!(ulFiles + ulDirs))
+	{
+		error_file_not_found();
+		return 1;
+	}
+	/* In bare format we don't print results */
+	if (lpFlags->bBareFormat)
+		return 0;
 
-  ConvertULargeInteger (bytes, buffer, sizeof(buffer));
-  ConOutPrintf (_T("  %15s byte%c\n"),
-                buffer, bytes.QuadPart == 1 ? _T(' ') : _T('s'));
+	/* Print recursive specific results */
+	if (lpFlags->bRecursive)
+	{
+		ConvertULargeInteger (u64Bytes, szBuffer, sizeof(szBuffer), lpFlags->bTSeperator);
+		ConOutPrintf (_T("\n     Total Files Listed:\n"));
+		ConOutPrintf(_T("%16i File(s)% 14s bytes\n"),ulFiles, szBuffer);
+    }
 
-  if (IncLine (pLine, dwFlags))
-    return 1;
+	/* Print total  directories and freespace */
+	szRoot[0] = szPath[0];
+	GetUserDiskFreeSpace(szRoot, &uliFree);
+	ConvertULargeInteger (uliFree, szBuffer, sizeof(szBuffer), lpFlags->bTSeperator);
+    ConOutPrintf (_T("%16i Dir(s)% 15s bytes\n"),ulDirs, szBuffer);
 
-  /* Print number of dirs and bytes free */
-  ConvertULong (ulDirs, buffer, sizeof(buffer));
-  ConOutPrintf (_T("          %6s Dir%c"),
-                buffer, ulDirs == 1 ? _T(' ') : _T('s'));
-
-  if (!(dwFlags & DIR_RECURSE))
-    {
-      szRoot[0] = szPath[0];
-      GetUserDiskFreeSpace(szRoot, &uliFree);
-      ConvertULargeInteger (uliFree, buffer, sizeof(buffer));
-      ConOutPrintf (_T("   %15s bytes free\n"), buffer);
-      if (IncLine (pLine, dwFlags))
-        return 1;
-    }
-  else
-    {
-      if ((dwFlags & DIR_BARE) == 0)
-        {
-	  ConOutPrintf (_T("\n"));
-          if (IncLine (pLine, dwFlags))
-            return 1;
-          ConOutPrintf (_T("\n"));
-	}
-      if (IncLine (pLine, dwFlags))
-         return 1;
-    }
-
   return 0;
 }
 
+/*
+ * getExt
+ *
+ * Get the extension of a filename 
+ */
+TCHAR* getExt(const TCHAR* file)
+{
+	
+	TCHAR* tmp = _tcsrchr(file,'.');
+	return tmp?tmp+1:"";
+}
 
 /*
- * dir_list
+ * getName
  *
- * list the files in the directory
+ * Get the name of the file without extension
  */
-static INT
-DirList (LPTSTR szPath, LPTSTR szFilespec, LPINT pLine, DWORD dwFlags)
+TCHAR * getName(const TCHAR* file, TCHAR * dest)
 {
-	TCHAR szFullPath[MAX_PATH];
-	WIN32_FIND_DATA file;
-	ULARGE_INTEGER bytecount;
-	FILETIME   ft;
-	SYSTEMTIME dt;
-	HANDLE hFile;
-	TCHAR  buffer[32];
-	ULONG filecount = 0;
-	ULONG dircount = 0;
-	INT count = 0;
-	SHORT screenwidth;
-	INT longestfname = 0;
+int iLen;
+TCHAR* end;
+	
+	/* Check for "." and ".." folders */
+	if ((_tcscmp(file, _T(".")) == 0)
+		|| (_tcscmp(file, _T("..")) == 0))
+	{
+		_tcscpy(dest,file);
+		return dest;
+	}
 
-	bytecount.QuadPart = 0;
+	end = _tcsrchr(file,'.');
+	if (!end)
+		iLen = _tcslen(file);	
+	else			
+		iLen = (end - file);
+	
 
-	_tcscpy (szFullPath, szPath);
-	if (szFullPath[_tcslen(szFullPath) - 1] != _T('\\'))
-		_tcscat (szFullPath, _T("\\"));
-	_tcscat (szFullPath, szFilespec);
+	_tcsncpy(dest, file, iLen);
+	*(dest + iLen) = _T('\0');
+	
+	return dest;
+}
+/*
+ *  DirPrintNewList
+ *
+ * The function that prints in new style
+ */
+static int
+DirPrintNewList(LPWIN32_FIND_DATA ptrFiles[],	/* [IN]Files' Info */
+				DWORD dwCount,					/* [IN] The quantity of files */
+				TCHAR * szCurPath,				/* [IN] Full path of current directory */
+				LPDIRSWITCHFLAGS lpFlags)		/* [IN] The flags used */
+{
+DWORD i;						/* An indexer for "for"s */
+TCHAR szSize[30];				/* The size of file */
+TCHAR szShortName[15];			/* The sort name */
+TCHAR szDate[20], szTime[20];	/* Date and time strings */
+int iSizeFormat;				/* The format of size field */
+ULARGE_INTEGER u64FileSize;		/* The file size */
 
-	hFile = FindFirstFile (szFullPath, &file);
-	if (hFile == INVALID_HANDLE_VALUE)
+	for(i = 0;i < dwCount;i++)
 	{
-		/* Don't want to print anything if scanning recursively
-		 * for a file. RL
-		 */
-		if ((dwFlags & DIR_RECURSE) == 0)
+
+		/* Calculate size */		
+		if (ptrFiles[i]->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+		/* Directory */
 		{
-			FindClose (hFile);
-			error_file_not_found ();
-			if (IncLine (pLine, dwFlags))
-				return 0;
-			return 1;
+			iSizeFormat = -14;
+			_tcscpy(szSize, _T("<DIR>"));
 		}
-		FindClose (hFile);
-		return 0;
+		else
+		/* File */
+		{
+			iSizeFormat = 14;
+			u64FileSize.HighPart = ptrFiles[i]->nFileSizeHigh;
+			u64FileSize.LowPart = ptrFiles[i]->nFileSizeLow;
+			ConvertULargeInteger(u64FileSize, szSize, 20,lpFlags->bTSeperator);
+		}
+		/* Calculate short name */
[truncated at 1000 lines; 1015 more skipped]