take care of Bug#: 1084
[reactos.git] / reactos / subsys / system / cmd / dir.c
index ed559d7..7239811 100644 (file)
@@ -216,7 +216,8 @@ static ULARGE_INTEGER recurse_bytes;
  * displays help screen for dir
  * Rob Lake
  */
-static VOID DirHelp(VOID)
+static VOID 
+DirHelp(VOID)
 {
   ConOutResPaging(TRUE, STRING_DIR_HELP1);
 }
@@ -228,20 +229,30 @@ static VOID DirHelp(VOID)
  *
  * Parse the parameters and switches of the command line and exports them
  */
-static BOOL
+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 */
+                       LPTSTR** params,                        /* [OUT] The parameters after parsing */
+                       LPINT entries,                          /* [OUT] The number of parameters after parsing */
+                       LPDIRSWITCHFLAGS lpFlags)       /* [IN/OUT] The flags after calculating switches */
 {
-  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 */
-
-  
+       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 ptrStart;        /* A pointer to the first character of a parameter */
+       LPTSTR ptrEnd;          /* A pointer to the last character of a parameter */
+       LPTSTR temp;
+
+       /* Initialize parameter array */
+       *params = malloc(sizeof(LPTSTR));
+       if(!params)
+               return FALSE;
+       *params = NULL;
+       *entries = 0;
+       ptrStart = NULL;
+       ptrEnd = NULL;
 
        /* Initialize variables; */
        cCurSwitch = _T(' ');
@@ -249,10 +260,6 @@ DirReadParam(LPTSTR Line,                          /* [IN] The line with the parameters & switches */
        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 */
@@ -352,8 +359,25 @@ DirReadParam(LPTSTR Line,                          /* [IN] The line with the parameters & switches */
                                if (!bIntoQuotes)
                                {
                                        cCurSwitch = _T(' ');
-                                       if ((*param) && !(ptrLast))
-                                               ptrLast = Line;
+                                       if(ptrStart && ptrEnd)
+                                       {               
+                                               temp = malloc((ptrEnd - ptrStart) + 2 * sizeof (TCHAR));
+                                               if(!temp)
+                                                       return FALSE;
+                                               memcpy(temp, ptrStart, (ptrEnd - ptrStart) + 2 * sizeof (TCHAR));
+                                               temp[(ptrEnd - ptrStart + 1)] = _T('\0');
+                                               if(!add_entry(entries, params, temp))
+                                               {
+                                                       free(temp);
+                                                       freep(*params);
+                                                       return FALSE;
+                                               }
+
+                                               free(temp);
+
+                                               ptrStart = NULL;
+                                               ptrEnd = NULL;
+                                       }
                                }
 
                        }
@@ -361,19 +385,35 @@ DirReadParam(LPTSTR Line,                         /* [IN] The line with the parameters & switches */
                        {
                                /* Process a quote */
                                bIntoQuotes = !bIntoQuotes;
-                               if (!bIntoQuotes) ptrLast = Line;
+                               if(!bIntoQuotes)
+                                       ptrEnd = Line;
                        }
                        else
                        {
                                /* Process a character for parameter */
-                               if ((cCurSwitch == _T(' ')) && (*param))
-                               {
-                                       error_too_many_parameters(Line);
-                                       return FALSE;
+                               if ((cCurSwitch == _T(' ')) && ptrStart && ptrEnd)
+                               {               
+                                       temp = malloc((ptrEnd - ptrStart) + 2 * sizeof (TCHAR));
+                                       if(!temp)
+                                               return FALSE;
+                                       memcpy(temp, ptrStart, (ptrEnd - ptrStart) + 2 * sizeof (TCHAR));
+                                       temp[(ptrEnd - ptrStart + 1)] = _T('\0');
+                                       if(!add_entry(entries, params, temp))
+                                       {
+                                               free(temp);
+                                               freep(*params);
+                                               return FALSE;
+                                       }
+
+                                       free(temp);
+
+                                       ptrStart = NULL;
+                                       ptrEnd = NULL;
                                }
                                cCurSwitch = _T('P');
-                               if (!(*param))
-                                       *param = Line;
+                               if(!ptrStart)
+                                       ptrStart = ptrEnd = Line;
+                               ptrEnd = Line;
                        }
                }
                else
@@ -522,7 +562,25 @@ DirReadParam(LPTSTR Line,                          /* [IN] The line with the parameters & switches */
                Line++;
        }
        /* Terminate the parameters */
-       if (ptrLast) *ptrLast = 0;
+       if(ptrStart && ptrEnd)
+       {               
+               temp = malloc((ptrEnd - ptrStart) + 2 * sizeof (TCHAR));
+               if(!temp)
+                       return FALSE;
+               memcpy(temp, ptrStart, (ptrEnd - ptrStart) + 2 * sizeof (TCHAR));
+               temp[(ptrEnd - ptrStart + 1)] = _T('\0');
+               if(!add_entry(entries, params, temp))
+               {
+                       free(temp);
+                       freep(*params);
+                       return FALSE;
+               }
+
+               free(temp);
+
+               ptrStart = NULL;
+               ptrEnd = NULL;
+       }
 
        /* Calculate the switches with no switch paramater  */
        if (!(lpFlags->stAttribs.bParSetted))
@@ -924,38 +982,6 @@ ConvertULong (ULONG num, LPTSTR des, INT len)
 }
 #endif
 
-static INT
-ConvertULargeInteger (ULARGE_INTEGER num, LPTSTR des, INT len, BOOL bPutSeperator)
-{
-       TCHAR temp[32];
-       INT c = 0;
-       INT n = 0;
-
-       if (num.QuadPart == 0)
-       {
-               des[0] = _T('0');
-               des[1] = _T('\0');
-               n = 1;
-       }
-       else
-       {
-               temp[31] = 0;
-               while (num.QuadPart > 0)
-               {
-                       if ((((c + 1) % (nNumberGroups + 1)) == 0) && (bPutSeperator))
-                               temp[30 - c++] = cThousandSeparator;
-   temp[30 - c++] = (TCHAR)(num.QuadPart % 10) + _T('0');
-                       num.QuadPart /= 10;
-               }
-
-               for (n = 0; n <= c; n++)
-                       des[n] = temp[31 - c + n];
-       }
-
-       return n;
-}
-
-
 static VOID
 DirPrintFileDateTime(TCHAR *lpDate,
                      TCHAR *lpTime,
@@ -1104,11 +1130,14 @@ PrintSummary(LPTSTR szPath,
                return 1;
        }
 
+
        /* In bare format we don't print results */
        if (lpFlags->bBareFormat)
                return 0;
 
        /* Print recursive specific results */
+       
+    /* Take this code offline to fix /S does not print duoble info */
        if (lpFlags->bRecursive)
        {
                ConvertULargeInteger(u64Bytes, szBuffer, sizeof(szBuffer), lpFlags->bTSeperator);
@@ -1118,9 +1147,38 @@ PrintSummary(LPTSTR szPath,
                   ConOutPrintfPaging(FALSE,szMsg,ulFiles, szBuffer);
                else
                   ConOutPrintf(szMsg,ulFiles, szBuffer);
+                  
+                  if (ulFiles > 0)
+       {
+               ConvertULargeInteger(u64Bytes, szBuffer, 20, lpFlags->bTSeperator);
+               LoadString(CMD_ModuleHandle, STRING_DIR_HELP8, szMsg, RC_STRING_MAX_SIZE);
+               if(lpFlags->bPause)
+                  ConOutPrintfPaging(FALSE,szMsg,ulFiles, szBuffer);
+               else
+                  ConOutPrintf(szMsg,ulFiles, szBuffer);
+
+       }
+       
        }
+     else
+     {
+     
+       /* Print File Summary */
+       /* Condition to print summary is:
+          If we are not in bare format and if we have results! */
+       if (ulFiles > 0)
+       {
+               ConvertULargeInteger(u64Bytes, szBuffer, 20, lpFlags->bTSeperator);
+               LoadString(CMD_ModuleHandle, STRING_DIR_HELP8, szMsg, RC_STRING_MAX_SIZE);
+               if(lpFlags->bPause)
+                  ConOutPrintfPaging(FALSE,szMsg,ulFiles, szBuffer);
+               else
+                  ConOutPrintf(szMsg,ulFiles, szBuffer);
 
-       /* Print total  directories and freespace */
+       }
+       
+}
+       /* Print total directories and freespace */
        szRoot[0] = szPath[0];
        GetUserDiskFreeSpace(szRoot, &uliFree);
        ConvertULargeInteger(uliFree, szBuffer, sizeof(szBuffer), lpFlags->bTSeperator);
@@ -1150,7 +1208,8 @@ TCHAR* getExt(const TCHAR* file)
  *
  * Get the name of the file without extension
  */
-static LPTSTR getName(const TCHAR* file, TCHAR * dest)
+static LPTSTR 
+getName(const TCHAR* file, TCHAR * dest)
 {
        int iLen;
        LPTSTR end;
@@ -1250,9 +1309,9 @@ DirPrintNewList(LPWIN32_FIND_DATA ptrFiles[],     /* [IN]Files' Info */
  */
 static VOID
 DirPrintWideList(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 dwCount,                 /* [IN] The quantity of files */
+                                TCHAR *szCurPath,              /* [IN] Full path of current directory */
+                                LPDIRSWITCHFLAGS lpFlags)      /* [IN] The flags used */
 {
   SHORT iScreenWidth;
   USHORT iColumns;
@@ -1442,9 +1501,9 @@ ULARGE_INTEGER u64FileSize;               /* The file size */
  */
 static VOID
 DirPrintBareList(LPWIN32_FIND_DATA ptrFiles[], /* [IN] Files' Info */
-                DWORD dwCount,                 /* [IN] The number of files */
-                LPTSTR lpCurPath,              /* [IN] Full path of current directory */
-                LPDIRSWITCHFLAGS lpFlags)      /* [IN] The flags used */
+                                DWORD dwCount,                 /* [IN] The number of files */
+                                LPTSTR lpCurPath,              /* [IN] Full path of current directory */
+                                LPDIRSWITCHFLAGS lpFlags)      /* [IN] The flags used */
 {
        TCHAR szFullName[MAX_PATH];
        DWORD i;
@@ -1486,9 +1545,9 @@ DirPrintBareList(LPWIN32_FIND_DATA ptrFiles[],    /* [IN] Files' Info */
  */
 static VOID
 DirPrintFiles(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 dwCount,                        /* [IN] The quantity of files */
+                         TCHAR *szCurPath,                     /* [IN] Full path of current directory */
+                         LPDIRSWITCHFLAGS lpFlags)             /* [IN] The flags used */
 {
        TCHAR szMsg[RC_STRING_MAX_SIZE];
        TCHAR szTemp[MAX_PATH];                 /* A buffer to format the directory header */
@@ -1547,8 +1606,8 @@ DirPrintFiles(LPWIN32_FIND_DATA ptrFiles[],       /* [IN] Files' Info */
  */
 static BOOL
 CompareFiles(LPWIN32_FIND_DATA lpFile1,        /* [IN] A pointer to WIN32_FIND_DATA of file 1 */
-            LPWIN32_FIND_DATA lpFile2, /* [IN] A pointer to WIN32_FIND_DATA of file 2 */
-            LPDIRSWITCHFLAGS lpFlags)  /* [IN] The flags that we use to list */
+                        LPWIN32_FIND_DATA lpFile2,     /* [IN] A pointer to WIN32_FIND_DATA of file 2 */
+                        LPDIRSWITCHFLAGS lpFlags)      /* [IN] The flags that we use to list */
 {
   ULARGE_INTEGER u64File1;
   ULARGE_INTEGER u64File2;
@@ -1698,9 +1757,9 @@ QsortFiles(LPWIN32_FIND_DATA ptrArray[],  /* [IN/OUT] The array with file info po
  */
 static INT
 DirList(LPTSTR szPath,                 /* [IN] The path that dir starts */
-       LPTSTR szFilespec,              /* [IN] The type of file that we are looking for */
-       LPINT pLine,                    /* FIXME: Maybe used for paginating */
-       LPDIRSWITCHFLAGS lpFlags)       /* [IN] The flags of the listing */
+               LPTSTR szFilespec,              /* [IN] The type of file that we are looking for */
+               LPINT pLine,                    /* FIXME: Maybe used for paginating */
+               LPDIRSWITCHFLAGS lpFlags)       /* [IN] The flags of the listing */
 {
        HANDLE hSearch;                                                 /* The handle of the search */
        HANDLE hRecSearch;                                              /* The handle for searching recursivly */
@@ -1710,13 +1769,11 @@ DirList(LPTSTR szPath,                  /* [IN] The path that dir starts */
        PDIRFINDLISTNODE ptrNextNode;   /* A pointer used for relatives refernces */
 TCHAR szFullPath[MAX_PATH];                            /* The full path that we are listing with trailing \ */
 TCHAR szFullFileSpec[MAX_PATH];                        /* The full path with file specs that we ll request\ */
-TCHAR szBytes[20];                                             /* A string for converting ULARGE integer */
 DWORD dwCount;                                                 /* A counter of files found in directory */
 DWORD dwCountFiles;                                            /* Counter for files */
 DWORD dwCountDirs;                                             /* Counter for directories */
 ULARGE_INTEGER u64CountBytes;                  /* Counter for bytes */
 ULARGE_INTEGER u64Temp;                                        /* A temporary counter */
-TCHAR szMsg[RC_STRING_MAX_SIZE];
 
        /* Initialize Variables */
        ptrStartNode = NULL;
@@ -1853,20 +1910,6 @@ TCHAR szMsg[RC_STRING_MAX_SIZE];
        /* Free array */
        free(ptrFileArray);
 
-       /* Print Directory Summary */
-       /* Condition to print summary is:
-          If we are not in bare format and if we have results! */
-       if (!(lpFlags->bBareFormat) && (dwCount > 0))
-       {
-               ConvertULargeInteger(u64CountBytes, szBytes, 20, lpFlags->bTSeperator);
-               LoadString(CMD_ModuleHandle, STRING_DIR_HELP8, szMsg, RC_STRING_MAX_SIZE);
-               if(lpFlags->bPause)
-                  ConOutPrintfPaging(FALSE,szMsg,dwCountFiles, szBytes);
-               else
-                  ConOutPrintf(szMsg,dwCountFiles, szBytes);
-
-       }
-
        /* Add statistics to recursive statistics*/
        recurse_dir_cnt += dwCountDirs;
        recurse_file_cnt += dwCountFiles;
@@ -1920,16 +1963,21 @@ TCHAR szMsg[RC_STRING_MAX_SIZE];
  *
  * internal dir command
  */
-INT CommandDir(LPTSTR first, LPTSTR rest)
+INT 
+CommandDir(LPTSTR first, LPTSTR rest)
 {
-       TCHAR  dircmd[256];     /* A variable to store the DIRCMD enviroment variable */
-       TCHAR  szPath[MAX_PATH];
-       TCHAR  szFilespec[MAX_PATH];
-       LPTSTR param;
-       INT    nLine = 0;
+       TCHAR   dircmd[256];    /* A variable to store the DIRCMD enviroment variable */
+       TCHAR   cDrive;
+       TCHAR   szPath[MAX_PATH];
+       TCHAR   szFilespec[MAX_PATH];
+       LPTSTR* params;
+       INT             entries = 0;
+       INT             nLine = 0;
+       UINT    loop = 0;
        DIRSWITCHFLAGS stFlags;
 
        /* Initialize variables */
+       cDrive = 0;
        recurse_dir_cnt = 0L;
        recurse_file_cnt = 0L;
        recurse_bytes.QuadPart = 0;
@@ -1958,67 +2006,77 @@ INT CommandDir(LPTSTR first, LPTSTR rest)
        
        /* read the parameters from the DIRCMD environment variable */
        if (GetEnvironmentVariable (_T("DIRCMD"), dircmd, 256))
-               if (!DirReadParam(dircmd, &param, &stFlags))
+               if (!DirReadParam(dircmd, &params, &entries, &stFlags))
                {
                        nErrorLevel = 1;
                        return 1;
                }
 
        /* read the parameters */
-       if (!DirReadParam(rest, &param, &stFlags))
+       if (!DirReadParam(rest, &params, &entries, &stFlags) || CheckCtrlBreak(BREAK_INPUT))
        {
                nErrorLevel = 1;
                return 1;
        }
 
        /* default to current directory */
-       if (!param)
-               param = _T(".");
-
-       /* parse the directory info */
-       if (DirParsePathspec (param, szPath, szFilespec))
-       {
-               nErrorLevel = 1;
-               return 1;
+       if(entries == 0) {
+               if(!add_entry(&entries, &params, _T("."))) {
+                       nErrorLevel = 1;
+                       return 1;
+               }
        }
 
-/* <Debug :>
-   Uncomment this to show the final state of switch flags*/
-#ifdef _DEBUG
+       for(loop = 0; loop < entries; loop++)
        {
-               int i;
-               ConOutPrintf(_T("Attributes mask/value %x/%x\n"),stFlags.stAttribs.dwAttribMask,stFlags.stAttribs.dwAttribVal  );
-               ConOutPrintf(_T("(B) Bare format : %i\n"), stFlags.bBareFormat );
-               ConOutPrintf(_T("(C) Thousand : %i\n"), stFlags.bTSeperator );
-               ConOutPrintf(_T("(W) Wide list : %i\n"), stFlags.bWideList );
-               ConOutPrintf(_T("(D) Wide list sort by column : %i\n"), stFlags.bWideListColSort );
-               ConOutPrintf(_T("(L) Lowercase : %i\n"), stFlags.bLowerCase );
-               ConOutPrintf(_T("(N) New : %i\n"), stFlags.bNewLongList );
-               ConOutPrintf(_T("(O) Order : %i\n"), stFlags.stOrderBy.sCriteriaCount );
-               for (i =0;i<stFlags.stOrderBy.sCriteriaCount;i++)
-                       ConOutPrintf(_T(" Order Criteria [%i]: %i (Reversed: %i)\n"),i, stFlags.stOrderBy.eCriteria[i], stFlags.stOrderBy.bCriteriaRev[i] );
-               ConOutPrintf(_T("(P) Pause : %i\n"), stFlags.bPause  );
-               ConOutPrintf(_T("(Q) Owner : %i\n"), stFlags.bUser );
-               ConOutPrintf(_T("(S) Recursive : %i\n"), stFlags.bRecursive );
-               ConOutPrintf(_T("(T) Time field : %i\n"), stFlags.stTimeField.eTimeField );
-               ConOutPrintf(_T("(X) Short names : %i\n"), stFlags.bShortName );
-               ConOutPrintf(_T("Parameter : %s\n"), param );
-       }
-#endif
-
-       /* print the header  */
-       if (!stFlags.bBareFormat)
-               if (!PrintDirectoryHeader (szPath, &nLine, &stFlags))
+               /* parse the directory info */
+               if (DirParsePathspec (params[loop], szPath, szFilespec) || CheckCtrlBreak(BREAK_INPUT))
                {
                        nErrorLevel = 1;
                        return 1;
                }
 
-       /* do the actual dir */
-       if (DirList (szPath, szFilespec, &nLine, &stFlags))
-       {
-               nErrorLevel = 1;
-               return 1;
+       /* <Debug :>
+          Uncomment this to show the final state of switch flags*/
+       #ifdef _DEBUG
+               {
+                       int i;
+                       ConOutPrintf(_T("Attributes mask/value %x/%x\n"),stFlags.stAttribs.dwAttribMask,stFlags.stAttribs.dwAttribVal  );
+                       ConOutPrintf(_T("(B) Bare format : %i\n"), stFlags.bBareFormat );
+                       ConOutPrintf(_T("(C) Thousand : %i\n"), stFlags.bTSeperator );
+                       ConOutPrintf(_T("(W) Wide list : %i\n"), stFlags.bWideList );
+                       ConOutPrintf(_T("(D) Wide list sort by column : %i\n"), stFlags.bWideListColSort );
+                       ConOutPrintf(_T("(L) Lowercase : %i\n"), stFlags.bLowerCase );
+                       ConOutPrintf(_T("(N) New : %i\n"), stFlags.bNewLongList );
+                       ConOutPrintf(_T("(O) Order : %i\n"), stFlags.stOrderBy.sCriteriaCount );
+                       for (i =0;i<stFlags.stOrderBy.sCriteriaCount;i++)
+                               ConOutPrintf(_T(" Order Criteria [%i]: %i (Reversed: %i)\n"),i, stFlags.stOrderBy.eCriteria[i], stFlags.stOrderBy.bCriteriaRev[i] );
+                       ConOutPrintf(_T("(P) Pause : %i\n"), stFlags.bPause  );
+                       ConOutPrintf(_T("(Q) Owner : %i\n"), stFlags.bUser );
+                       ConOutPrintf(_T("(S) Recursive : %i\n"), stFlags.bRecursive );
+                       ConOutPrintf(_T("(T) Time field : %i\n"), stFlags.stTimeField.eTimeField );
+                       ConOutPrintf(_T("(X) Short names : %i\n"), stFlags.bShortName );
+                       ConOutPrintf(_T("Parameter : %s\n"), params[loop] );
+               }
+       #endif
+
+               /* Print the drive header if the drive changed */
+               if(cDrive != szPath[0] && !stFlags.bBareFormat) {
+                       if (!PrintDirectoryHeader (szPath, &nLine, &stFlags)) {
+                               nErrorLevel = 1;
+                               return 1;
+                       }
+
+                       cDrive = szPath[0];
+               }
+               
+
+               /* do the actual dir */
+               if (DirList (szPath, szFilespec, &nLine, &stFlags))
+               {
+                       nErrorLevel = 1;
+                       return 1;
+               }
        }
 
        /* print the footer */