[TREE]: Rework the utility (use explicit UNICODE, use WIN32 types, remove useless dependency to user32...), and add support for console ConUtils streams.

CORE-12677 #resolve

svn path=/trunk/; revision=73622
This commit is contained in:
Hermès Bélusca-Maïto 2017-01-29 16:51:23 +00:00
parent ff5f825f59
commit c8a8975faf
2 changed files with 94 additions and 102 deletions

View file

@ -1,6 +1,9 @@
include_directories(${REACTOS_SOURCE_DIR}/sdk/lib/conutils)
add_executable(tree tree.c tree.rc) add_executable(tree tree.c tree.rc)
set_module_type(tree win32cui UNICODE) set_module_type(tree win32cui UNICODE)
target_link_libraries(tree conutils ${PSEH_LIB})
add_importlibs(tree msvcrt kernel32)
set_target_properties(tree PROPERTIES SUFFIX ".com") set_target_properties(tree PROPERTIES SUFFIX ".com")
add_importlibs(tree user32 msvcrt kernel32)
add_cd_file(TARGET tree DESTINATION reactos/system32 FOR all) add_cd_file(TARGET tree DESTINATION reactos/system32 FOR all)

View file

@ -1,45 +1,30 @@
/* /*
* PROJECT: ReactOS * PROJECT: ReactOS
* LICENSE: GNU GPLv2 only as published by the Free Software Foundation * LICENSE: GNU GPLv2 only as published by the Free Software Foundation
* PURPOSE: Implements tree.com functionality similar to Windows * PURPOSE: Implements tree.com command similar to Windows
* PROGRAMMERS: Asif Bahrainwala (asif_bahrainwala@hotmail.com) * PROGRAMMERS: Asif Bahrainwala (asif_bahrainwala@hotmail.com)
*/ */
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <windef.h> #include <windef.h>
#include <winbase.h> #include <winbase.h>
#include <winuser.h>
#include <conutils.h>
#include "resource.h" #include "resource.h"
#define STR_MAX 2048 #define STR_MAX 2048
static void GetDirectoryStructure(wchar_t* strPath, UINT width, const wchar_t* prevLine); static VOID GetDirectoryStructure(PWSTR strPath, UINT width, PCWSTR prevLine);
/* if this flag is set to true, files will also be listed */ /* If this flag is set to true, files will also be listed within the folder structure */
BOOL bShowFiles = FALSE; BOOL bShowFiles = FALSE;
/* if this flag is true, ASCII characters will be used instead of UNICODE ones */ /* If this flag is true, ASCII characters will be used instead of UNICODE ones */
BOOL bUseAscii = FALSE; BOOL bUseAscii = FALSE;
/*
* This takes strings from a resource string table
* and outputs it to the console.
*/
VOID PrintResourceString(INT resID, ...)
{
WCHAR tmpBuffer[STR_MAX];
CHAR tmpBufferA[STR_MAX];
va_list arg_ptr;
va_start(arg_ptr, resID);
LoadStringW(GetModuleHandle(NULL), resID, tmpBuffer, STR_MAX);
CharToOemW(tmpBuffer, tmpBufferA);
vfprintf(stdout, tmpBufferA, arg_ptr);
va_end(arg_ptr);
}
/** /**
* @name: HasSubFolder * @name: HasSubFolder
* *
@ -47,20 +32,20 @@ VOID PrintResourceString(INT resID, ...)
* Must specify folder name * Must specify folder name
* *
* @return * @return
* true if folder has sub folders, else will return false * true if folder has sub-folders, else will return false
*/ */
static BOOL HasSubFolder(const wchar_t *strPath1) static BOOL HasSubFolder(PCWSTR strPath1)
{ {
BOOL ret = FALSE; BOOL ret = FALSE;
WIN32_FIND_DATA FindFileData; WIN32_FIND_DATAW FindFileData;
HANDLE hFind = NULL; HANDLE hFind = NULL;
static wchar_t strPath[STR_MAX] = L""; static WCHAR strPath[STR_MAX] = L"";
ZeroMemory(strPath, sizeof(strPath)); ZeroMemory(strPath, sizeof(strPath));
wcscat(strPath, strPath1); wcscat(strPath, strPath1);
wcscat(strPath, L"\\*."); wcscat(strPath, L"\\*.");
hFind = FindFirstFile(strPath, &FindFileData); hFind = FindFirstFileW(strPath, &FindFileData);
do do
{ {
if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
@ -71,11 +56,11 @@ static BOOL HasSubFolder(const wchar_t *strPath1)
continue; continue;
} }
ret = TRUE; //found subfolder ret = TRUE; // Sub-folder found
break; break;
} }
} }
while (FindNextFile(hFind, &FindFileData)); while (FindNextFileW(hFind, &FindFileData));
FindClose(hFind); FindClose(hFind);
return ret; return ret;
@ -100,22 +85,22 @@ static BOOL HasSubFolder(const wchar_t *strPath1)
* @return * @return
* void * void
*/ */
static void DrawTree(const wchar_t* strPath, static VOID DrawTree(PCWSTR strPath,
const WIN32_FIND_DATA *arrFolder, const WIN32_FIND_DATAW* arrFolder,
const size_t szArr, const size_t szArr,
UINT width, UINT width,
const wchar_t *prevLine, PCWSTR prevLine,
BOOL drawfolder) BOOL drawfolder)
{ {
BOOL bHasSubFolder = HasSubFolder(strPath); BOOL bHasSubFolder = HasSubFolder(strPath);
UINT i = 0; UINT i = 0;
/* this will format the spaces required for correct formatting */ /* This will format the spaces required for correct formatting */
for (i = 0; i < szArr; ++i) for (i = 0; i < szArr; ++i)
{ {
wchar_t *consoleOut = (wchar_t*)malloc(sizeof(wchar_t) * STR_MAX); PWSTR consoleOut = (PWSTR)malloc(STR_MAX * sizeof(WCHAR));
UINT j = 0; UINT j = 0;
static wchar_t str[STR_MAX]; static WCHAR str[STR_MAX];
/* As we do not seem to have the _s functions properly set up, use the non-secure version for now */ /* As we do not seem to have the _s functions properly set up, use the non-secure version for now */
//wcscpy_s(consoleOut, STR_MAX, L""); //wcscpy_s(consoleOut, STR_MAX, L"");
@ -125,15 +110,14 @@ static void DrawTree(const wchar_t* strPath,
for (j = 0; j < width - 1; ++j) for (j = 0; j < width - 1; ++j)
{ {
/* if the previous line has '├' or '│' then the current line will /* If the previous line has '├' or '│' then the current line will
add '' to continue the connecting line */ add '' to continue the connecting line */
if ((BYTE)prevLine[j] == 195 || (BYTE)prevLine[j] == 179 || if (prevLine[j] == L'\x251C' || prevLine[j] == L'\x2502' ||
(BYTE)prevLine[j] == L'+' || (BYTE)prevLine[j] == L'|') prevLine[j] == L'+' || prevLine[j] == L'|')
{ {
if (!bUseAscii) if (!bUseAscii)
{ {
wchar_t a[] = {179, 0}; wcscat(consoleOut, L"\x2502");
wcscat(consoleOut, a);
} }
else else
{ {
@ -150,27 +134,27 @@ static void DrawTree(const wchar_t* strPath,
{ {
if (drawfolder) if (drawfolder)
{ {
/* will add '├───Folder name */ /* Add '├───Folder name' (\xC3\xC4\xC4\xC4 or \x251C\x2500\x2500\x2500) */
if (bUseAscii) if (bUseAscii)
wsprintf(str, L"+---%s", (wchar_t*)arrFolder[i].cFileName); swprintf(str, L"+---%s", arrFolder[i].cFileName);
else else
wsprintf(str, L"%c%c%c%c%s", 195, 196, 196, 196, (wchar_t*)arrFolder[i].cFileName); swprintf(str, L"\x251C\x2500\x2500\x2500%s", arrFolder[i].cFileName);
} }
else else
{ {
if (bHasSubFolder) if (bHasSubFolder)
{ {
/* will add '│ FileNamw' //thie line is added to connect /* Add '│ FileName' (\xB3 or \x2502) */
the belowfolder sub structure */ // This line is added to connect the below-folder sub-structure
if (bUseAscii) if (bUseAscii)
wsprintf(str,L"| %s", (wchar_t*)arrFolder[i].cFileName); swprintf(str, L"| %s", arrFolder[i].cFileName);
else else
wsprintf(str,L"%c %s", 179, (wchar_t*)arrFolder[i].cFileName); swprintf(str, L"\x2502 %s", arrFolder[i].cFileName);
} }
else else
{ {
/* will add ' FileNamw' */ /* Add ' FileName' */
wsprintf(str,L" %s", (wchar_t*)arrFolder[i].cFileName); swprintf(str, L" %s", arrFolder[i].cFileName);
} }
} }
} }
@ -178,44 +162,44 @@ static void DrawTree(const wchar_t* strPath,
{ {
if (drawfolder) if (drawfolder)
{ {
/* '└───Folder name' */ /* '└───Folder name' (\xC0\xC4\xC4\xC4 or \x2514\x2500\x2500\x2500) */
if (bUseAscii) if (bUseAscii)
wsprintf(str, L"\\---%s", (wchar_t*)arrFolder[i].cFileName); swprintf(str, L"\\---%s", arrFolder[i].cFileName);
else else
wsprintf(str, L"%c%c%c%c%s", 192, 196, 196, 196, (wchar_t*)arrFolder[i].cFileName); swprintf(str, L"\x2514\x2500\x2500\x2500%s", arrFolder[i].cFileName);
} }
else else
{ {
if (bHasSubFolder) if (bHasSubFolder)
{ {
/* '│ FileName' */ /* '│ FileName' (\xB3 or \x2502) */
if (bUseAscii) if (bUseAscii)
wsprintf(str, L"| %s", (wchar_t*)arrFolder[i].cFileName); swprintf(str, L"| %s", arrFolder[i].cFileName);
else else
wsprintf(str, L"%c %s", 179, (wchar_t*)arrFolder[i].cFileName); swprintf(str, L"\x2502 %s", arrFolder[i].cFileName);
} }
else else
{ {
/* ' FileName' */ /* ' FileName' */
wsprintf(str, L" %s", (wchar_t*)arrFolder[i].cFileName); swprintf(str, L" %s", arrFolder[i].cFileName);
} }
} }
} }
wcscat(consoleOut, str); wcscat(consoleOut, str);
wprintf(L"%s\n", consoleOut); ConPrintf(StdOut, L"%s\n", consoleOut);
if (drawfolder) if (drawfolder)
{ {
wchar_t *str = (wchar_t*)malloc(STR_MAX * sizeof(wchar_t)); PWSTR str = (PWSTR)malloc(STR_MAX * sizeof(WCHAR));
ZeroMemory(str, STR_MAX * sizeof(wchar_t)); ZeroMemory(str, STR_MAX * sizeof(WCHAR));
wcscat(str, strPath); wcscat(str, strPath);
wcscat(str, L"\\"); wcscat(str, L"\\");
wcscat(str, arrFolder[i].cFileName); wcscat(str, arrFolder[i].cFileName);
GetDirectoryStructure(str, width + 4, consoleOut); GetDirectoryStructure(str, width + 4, consoleOut);
free(str); free(str);
} }
free(consoleOut); free(consoleOut);
} }
@ -235,27 +219,27 @@ static void DrawTree(const wchar_t* strPath,
* @return * @return
* void * void
*/ */
static void static VOID
GetDirectoryStructure(wchar_t* strPath, UINT width, const wchar_t* prevLine) GetDirectoryStructure(PWSTR strPath, UINT width, PCWSTR prevLine)
{ {
WIN32_FIND_DATA FindFileData; WIN32_FIND_DATAW FindFileData;
HANDLE hFind = NULL; HANDLE hFind = NULL;
//DWORD err = 0; //DWORD err = 0;
/* will fill up with names of all sub folders */ /* Fill up with names of all sub-folders */
WIN32_FIND_DATA *arrFolder = NULL; WIN32_FIND_DATAW *arrFolder = NULL;
UINT arrFoldersz = 0; UINT arrFoldersz = 0;
/* will fill up with names of all sub folders */ /* Fill up with names of all sub-folders */
WIN32_FIND_DATA *arrFile = NULL; WIN32_FIND_DATAW *arrFile = NULL;
UINT arrFilesz = 0; UINT arrFilesz = 0;
ZeroMemory(&FindFileData, sizeof(FindFileData)); ZeroMemory(&FindFileData, sizeof(FindFileData));
{ {
static wchar_t tmp[STR_MAX] = L""; static WCHAR tmp[STR_MAX] = L"";
ZeroMemory(tmp, sizeof(tmp)); ZeroMemory(tmp, sizeof(tmp));
wcscat(tmp, strPath); wcscat(tmp, strPath);
wcscat(tmp, L"\\*.*"); wcscat(tmp, L"\\*.*");
hFind = FindFirstFile(tmp, &FindFileData); hFind = FindFirstFileW(tmp, &FindFileData);
//err = GetLastError(); //err = GetLastError();
} }
@ -271,7 +255,7 @@ GetDirectoryStructure(wchar_t* strPath, UINT width, const wchar_t* prevLine)
continue; continue;
++arrFoldersz; ++arrFoldersz;
arrFolder = (WIN32_FIND_DATA*)realloc(arrFolder, arrFoldersz * sizeof(FindFileData)); arrFolder = (WIN32_FIND_DATAW*)realloc(arrFolder, arrFoldersz * sizeof(FindFileData));
if (arrFolder == NULL) if (arrFolder == NULL)
exit(-1); exit(-1);
@ -282,7 +266,7 @@ GetDirectoryStructure(wchar_t* strPath, UINT width, const wchar_t* prevLine)
else else
{ {
++arrFilesz; ++arrFilesz;
arrFile = (WIN32_FIND_DATA*)realloc(arrFile, arrFilesz * sizeof(FindFileData)); arrFile = (WIN32_FIND_DATAW*)realloc(arrFile, arrFilesz * sizeof(FindFileData));
if(arrFile == NULL) if(arrFile == NULL)
exit(-1); exit(-1);
@ -290,17 +274,17 @@ GetDirectoryStructure(wchar_t* strPath, UINT width, const wchar_t* prevLine)
arrFile[arrFilesz - 1] = FindFileData; arrFile[arrFilesz - 1] = FindFileData;
} }
} }
while (FindNextFile(hFind, &FindFileData)); while (FindNextFileW(hFind, &FindFileData));
FindClose(hFind); FindClose(hFind);
if (bShowFiles) if (bShowFiles)
{ {
/* will free(arrFile) */ /* Will free(arrFile) */
DrawTree(strPath, arrFile, arrFilesz, width, prevLine, FALSE); DrawTree(strPath, arrFile, arrFilesz, width, prevLine, FALSE);
} }
/* will free(arrFile) */ /* Will free(arrFile) */
DrawTree(strPath, arrFolder, arrFoldersz, width, prevLine, TRUE); DrawTree(strPath, arrFolder, arrFoldersz, width, prevLine, TRUE);
free(arrFolder); free(arrFolder);
@ -314,18 +298,21 @@ GetDirectoryStructure(wchar_t* strPath, UINT width, const wchar_t* prevLine)
* @return * @return
* error /success value * error /success value
*/ */
int wmain( int argc, wchar_t *argv[]) int wmain(int argc, WCHAR* argv[])
{ {
DWORD dwSerial = 0; DWORD dwSerial = 0;
wchar_t t = 0; WCHAR t = 0;
wchar_t *strPath = NULL; PWSTR strPath = NULL;
DWORD sz = 0; DWORD sz = 0;
//wchar_t *context = NULL; //PWSTR context = NULL;
wchar_t *driveLetter = NULL; PWSTR driveLetter = NULL;
int i; int i;
/* parse the command line */ /* Initialize the Console Standard Streams */
ConInitStdStreams();
/* Parse the command line */
for (i = 1; i < argc; ++i) for (i = 1; i < argc; ++i)
{ {
if (argv[i][0] == L'-' || argv[i][0] == L'/') if (argv[i][0] == L'-' || argv[i][0] == L'/')
@ -333,49 +320,51 @@ int wmain( int argc, wchar_t *argv[])
switch (towlower(argv[i][1])) switch (towlower(argv[i][1]))
{ {
case L'?': case L'?':
/* will print help and exit after */ /* Print help and exit after */
PrintResourceString(IDS_USAGE); ConResPuts(StdOut, IDS_USAGE);
return 0; return 0;
case L'f': case L'f':
/* if set to true, will populate all the files within the folder structure */
bShowFiles = TRUE; bShowFiles = TRUE;
break; break;
case L'a': case L'a':
bUseAscii = TRUE; bUseAscii = TRUE;
break; break;
default: default:
break; break;
} }
} }
else else
{ {
/* this must be path to some folder */ /* This must be path to some folder */
/* will set the current directory for this executable */ /* Set the current directory for this executable */
BOOL b = SetCurrentDirectoryW(argv[i]); BOOL b = SetCurrentDirectoryW(argv[i]);
if (b == FALSE) if (b == FALSE)
{ {
PrintResourceString(IDS_NO_SUBDIRECTORIES); ConResPuts(StdOut, IDS_NO_SUBDIRECTORIES);
return 1; return 1;
} }
} }
} }
PrintResourceString(IDS_FOLDER_PATH); ConResPuts(StdOut, IDS_FOLDER_PATH);
GetVolumeInformation(NULL, NULL, 0, &dwSerial, NULL, NULL, NULL, 0); GetVolumeInformationW(NULL, NULL, 0, &dwSerial, NULL, NULL, NULL, 0);
PrintResourceString(IDS_VOL_SERIAL, dwSerial >> 16, dwSerial & 0xffff); ConResPrintf(StdOut, IDS_VOL_SERIAL, dwSerial >> 16, dwSerial & 0xffff);
/* get the buffer size */ /* get the buffer size */
sz = GetCurrentDirectory(1, &t); sz = GetCurrentDirectoryW(1, &t);
/* must not return before calling delete[] */ /* must not return before calling delete[] */
strPath = (wchar_t*)malloc(sizeof(wchar_t) * sz); strPath = (PWSTR)malloc(sz * sizeof(WCHAR));
/* get the current directory */ /* get the current directory */
GetCurrentDirectory(sz, strPath); GetCurrentDirectoryW(sz, strPath);
/* get the drive letter , must not return before calling delete[] */ /* get the drive letter , must not return before calling delete[] */
driveLetter = (wchar_t*)malloc(sizeof(wchar_t) * sz); driveLetter = (PWSTR)malloc(sz * sizeof(WCHAR));
/* As we do not seem to have the _s functions properly set up, use the non-secure version for now */ /* As we do not seem to have the _s functions properly set up, use the non-secure version for now */
//wcscpy_s(driveLetter,sz,strPath); //wcscpy_s(driveLetter,sz,strPath);
@ -383,15 +372,15 @@ int wmain( int argc, wchar_t *argv[])
wcscpy(driveLetter, strPath); wcscpy(driveLetter, strPath);
wcstok(driveLetter, L":"); wcstok(driveLetter, L":");
wprintf(L"%s:.\n", driveLetter); ConPrintf(StdOut, L"%s:.\n", driveLetter);
free(driveLetter); free(driveLetter);
/* get the sub directories within this current folder */ /* get the sub-directories within this current folder */
GetDirectoryStructure(strPath, 1, L" "); GetDirectoryStructure(strPath, 1, L" ");
free(strPath); free(strPath);
wprintf(L"\n"); ConPuts(StdOut, L"\n");
return 0; return 0;
} }