Author: zguo Date: Sun Dec 14 00:00:54 2014 New Revision: 65631
URL: http://svn.reactos.org/svn/reactos?rev=65631&view=rev Log: [TREE] Implement directory tree commandline utility. Code by Asif Bahrainwala. Cleanup by Ziliang Guo. CORE-8529
Added: trunk/reactos/base/applications/cmdutils/tree/ (with props) trunk/reactos/base/applications/cmdutils/tree/CMakeLists.txt (with props) trunk/reactos/base/applications/cmdutils/tree/tree.c (with props) Modified: trunk/reactos/base/applications/cmdutils/CMakeLists.txt
Modified: trunk/reactos/base/applications/cmdutils/CMakeLists.txt URL: http://svn.reactos.org/svn/reactos/trunk/reactos/base/applications/cmdutils/... ============================================================================== --- trunk/reactos/base/applications/cmdutils/CMakeLists.txt [iso-8859-1] (original) +++ trunk/reactos/base/applications/cmdutils/CMakeLists.txt [iso-8859-1] Sun Dec 14 00:00:54 2014 @@ -11,6 +11,7 @@ add_subdirectory(reg) add_subdirectory(sort) add_subdirectory(taskkill) +add_subdirectory(tree) add_subdirectory(wmic) add_subdirectory(wscript) add_subdirectory(xcopy)
Propchange: trunk/reactos/base/applications/cmdutils/tree/ ------------------------------------------------------------------------------ --- bugtraq:logregex (added) +++ bugtraq:logregex Sun Dec 14 00:00:54 2014 @@ -0,0 +1,2 @@ +([Ii]ssue|[Bb]ug)s? #?(\d+)(,? ?#?(\d+))*(,? ?(and |or )?#?(\d+))? +(\d+)
Propchange: trunk/reactos/base/applications/cmdutils/tree/ ------------------------------------------------------------------------------ bugtraq:message = See issue #%BUGID% for more details.
Propchange: trunk/reactos/base/applications/cmdutils/tree/ ------------------------------------------------------------------------------ bugtraq:url = http://www.reactos.org/bugzilla/show_bug.cgi?id=%BUGID%
Propchange: trunk/reactos/base/applications/cmdutils/tree/ ------------------------------------------------------------------------------ tsvn:logminsize = 10
Added: trunk/reactos/base/applications/cmdutils/tree/CMakeLists.txt URL: http://svn.reactos.org/svn/reactos/trunk/reactos/base/applications/cmdutils/... ============================================================================== --- trunk/reactos/base/applications/cmdutils/tree/CMakeLists.txt (added) +++ trunk/reactos/base/applications/cmdutils/tree/CMakeLists.txt [iso-8859-1] Sun Dec 14 00:00:54 2014 @@ -0,0 +1,5 @@ + +add_executable(tree tree.c) +set_module_type(tree win32cui UNICODE) +add_importlibs(tree msvcrt kernel32 user32) +add_cd_file(TARGET tree DESTINATION reactos/system32 FOR all)
Propchange: trunk/reactos/base/applications/cmdutils/tree/CMakeLists.txt ------------------------------------------------------------------------------ svn:eol-style = native
Added: trunk/reactos/base/applications/cmdutils/tree/tree.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/base/applications/cmdutils/... ============================================================================== --- trunk/reactos/base/applications/cmdutils/tree/tree.c (added) +++ trunk/reactos/base/applications/cmdutils/tree/tree.c [iso-8859-1] Sun Dec 14 00:00:54 2014 @@ -0,0 +1,332 @@ +/* + * PROJECT: ReactOS + * LICENSE: GNU GPLv2 only as published by the Free Software Foundation + * PURPOSE: Implements tree.com functionality similar to Windows + * PROGRAMMERS: Asif Bahrainwala (asif_bahrainwala@hotmail.com) + */ + +// Tree.cpp : Defines the entry point for the console application. +// +#include <Windows.h> +#include <stdio.h> + +#define STR_MAX 2048 + +const wchar_t *HELP = L"\nGraphically displays the folder structure of a drive or path. \n\nTREE [drive:][path] [/F] [/A]\n\n /F Display the names of the files in each folder.\n\n\n"; +const wchar_t *INVALID = L"No subfolders exist"; + +static void DrawTree(const wchar_t* strPath, const WIN32_FIND_DATA *arrFolder, const size_t szArr, UINT width, const wchar_t *prevLine, BOOL drawfolder); +static void GetDirectoryStructure(wchar_t* strPath, UINT width, const wchar_t* prevLine); + +BOOL bShowFiles = FALSE; //if this flag is set to true, files will also be listed + +/** +* @name: HasSubFolder +* +* @param strPath +* Must specify folder name +* +* @return +* true if folder has sub folders, else will return false +*/ +static BOOL HasSubFolder(const wchar_t *strPath1) +{ + BOOL ret = FALSE; + WIN32_FIND_DATA FindFileData; + HANDLE hFind = NULL; + static wchar_t strPath[STR_MAX]= L""; + ZeroMemory(strPath, sizeof(strPath)); + + wcscat(strPath,strPath1); + wcscat(strPath,L"\*."); + + hFind=FindFirstFile(strPath, &FindFileData); + do + { + if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + if(wcscmp(FindFileData.cFileName, L".")==0 || + wcscmp(FindFileData.cFileName, L"..")==0 ) + { + continue; + } + + ret=TRUE; //found subfolder + break; + } + } + while(FindNextFile(hFind, &FindFileData)); + + FindClose(hFind); + return ret; +} + +/** + * @name: DrawTree + * + * @param strPath + * Must specify folder name + * + * @param arrFolder + * must be a list of folder names to be drawn in tree format + * + * @param width + * specifies drawing distance for correct formatting of tree structure being drawn on console screen + * used internally for adding spaces + * + * @param prevLine + * used internally for formatting reasons + * + * @return + * void + */ +static void DrawTree(const wchar_t* strPath, const WIN32_FIND_DATA *arrFolder, const size_t szArr, UINT width, const wchar_t *prevLine, BOOL drawfolder) +{ + BOOL bHasSubFolder = HasSubFolder(strPath); + UINT i = 0; + + //this will format the spaces required for correct formatting + for(i = 0; i < szArr; ++i) + { + wchar_t *consoleOut = (wchar_t*)malloc(sizeof(wchar_t) * STR_MAX); + UINT j=0; + static wchar_t str[STR_MAX]; + + // 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(str, STR_MAX, L""); + wcscpy(consoleOut, L""); + wcscpy(str, L""); + + for(j=0;j<width-1;++j) + { + //if the previous line has 'â' or 'â' then the current line will add 'â' to continue the connecting line + if((BYTE)prevLine[j] == 195 || (BYTE)prevLine[j] == 179) + { + wchar_t a[]={179,0}; + wcscat(consoleOut,a); + } + else + { + wcscat(consoleOut,L" "); + } + } + + if(szArr - 1 != i) + { + if(drawfolder) + { + // will add 'ââââFolder name + wsprintf(str, L"%c%c%c%c%s", 195, 196, 196, 196, (wchar_t*)arrFolder[i].cFileName); + } + else + { + if(bHasSubFolder) + { + // will add 'â FileNamw' //thie line is added to connect the belowfolder sub structure + wsprintf(str,L"%c %s", 179, (wchar_t*)arrFolder[i].cFileName); + } + else + { + // will add ' FileNamw' + wsprintf(str,L" %s", (wchar_t*)arrFolder[i].cFileName); + } + } + } + else + { + if(drawfolder) + { + // 'ââââFolder name' + wsprintf(str, L"%c%c%c%c%s", 192, 196, 196, 196, (wchar_t*)arrFolder[i].cFileName); + } + else + { + if(bHasSubFolder) + { + // 'â FileName' + wsprintf(str,L"%c %s", 179, (wchar_t*)arrFolder[i].cFileName); + } + else + { + // ' FileName' + wsprintf(str,L" %s", (wchar_t*)arrFolder[i].cFileName); + } + } + } + + wcscat(consoleOut, str); + wprintf(L"%s\n", consoleOut); + + if(drawfolder) + { + wchar_t *str = (wchar_t*)malloc(STR_MAX * sizeof(wchar_t)); + ZeroMemory(str, STR_MAX*sizeof(wchar_t)); + + wcscat(str, strPath); + wcscat(str, L"\"); + wcscat(str, arrFolder[i].cFileName); + GetDirectoryStructure(str, width+4, consoleOut); + + free(str); + } + free(consoleOut); + } +} + +/** + * @name: GetDirectoryStructure + * + * @param strPath + * Must specify folder name + * + * @param width + * specifies drawing distance for correct formatting of tree structure being drawn on console screen + * + * @param prevLine + * specifies the previous line written on console, is used for correct formatting + * @return + * void + */ +static void GetDirectoryStructure(wchar_t* strPath, UINT width, const wchar_t* prevLine) +{ + WIN32_FIND_DATA FindFileData; + HANDLE hFind = NULL; + //DWORD err = 0; + //will fill up with names of all sub folders + WIN32_FIND_DATA *arrFolder = NULL; + UINT arrFoldersz = 0; + //will fill up with names of all sub folders + WIN32_FIND_DATA *arrFile = NULL; + UINT arrFilesz = 0; + + ZeroMemory(&FindFileData,sizeof(FindFileData)); + + { + static wchar_t tmp[STR_MAX]=L""; + ZeroMemory(tmp,sizeof(tmp)); + wcscat(tmp,strPath); + wcscat(tmp,L"\*.*"); + + hFind=FindFirstFile(tmp, &FindFileData); + + //err = GetLastError(); + } + + if(hFind == INVALID_HANDLE_VALUE) + return; + + do + { + if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + if(wcscmp(FindFileData.cFileName, L".")==0 || + wcscmp(FindFileData.cFileName, L"..")==0 ) + continue; + + ++arrFoldersz; + arrFolder=(WIN32_FIND_DATA*)realloc(arrFolder, arrFoldersz * sizeof(FindFileData)); + + if(arrFolder == NULL) + exit(-1); + + arrFolder[arrFoldersz - 1] = FindFileData; + + } + else + { + ++arrFilesz; + arrFile=(WIN32_FIND_DATA*)realloc(arrFile, arrFilesz * sizeof(FindFileData)); + + if(arrFile == NULL) + exit(-1); + + arrFile[arrFilesz - 1] = FindFileData; + } + } + while(FindNextFile(hFind, &FindFileData)); + + FindClose(hFind); + + if(bShowFiles) + { + DrawTree(strPath, arrFile, arrFilesz, width, prevLine, FALSE); //will free(arrFile) + } + + DrawTree(strPath, arrFolder, arrFoldersz, width, prevLine, TRUE); //will free(arrFile) + + free(arrFolder); + free(arrFile); +} + +/** +* @name: main +* standard main functionality as required by C/C++ for application startup +* +* @return +* error /success value +*/ +int wmain( int argc, wchar_t *argv[]) +{ + DWORD dwSerial = 0; + wchar_t t=0; + wchar_t *strPath = NULL; + DWORD sz = 0; + //wchar_t *context = NULL ; + wchar_t *driveLetter = NULL; + + int i; + + for(i = 1; i < argc; ++i) //parse the command line + { + if(wcscmp(argv[i], L"/?") == 0) + { + wprintf(HELP); //will print help and exit after + return 0; + } + else if(wcscmp(argv[i],L"/F")==0 || wcscmp(argv[i],L"/f")==0) + { + bShowFiles=TRUE; //if set to true, will populate all the files within the folder structure + } + else + { + //this must be path to some folder + BOOL b=SetCurrentDirectoryW(argv[i]); //will set the current directory for this executable + if(b==FALSE) + { + wprintf(INVALID); + return 1; + } + } + } + + wprintf(L"Folder PATH listing\n"); + + GetVolumeInformation(NULL, NULL, 0, &dwSerial, NULL, NULL, NULL, 0); + wprintf(L"Volume serial number is %x:%x\n", dwSerial >> 16, dwSerial & 0xffff); + + sz = GetCurrentDirectory(1, &t); //get the buffer size + strPath = (wchar_t*)malloc(sizeof(wchar_t) * sz); //must not return before calling delete[] + + GetCurrentDirectory(sz, strPath); //get the current directory + + + driveLetter = (wchar_t*)malloc(sizeof(wchar_t) * sz); //get the drive letter , must not return before calling delete[] + + // 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); + //wcstok_s(driveLetter,L":", &context); //parse for the drive letter + wcscpy(driveLetter,strPath); + wcstok(driveLetter, L":"); + + wprintf(L"%s:.\n",driveLetter); + + free(driveLetter); + + GetDirectoryStructure(strPath, 1, L" "); //get the sub directories within this current folder + + free(strPath); + wprintf(L"\n"); + + return 0; +}
Propchange: trunk/reactos/base/applications/cmdutils/tree/tree.c ------------------------------------------------------------------------------ svn:eol-style = native