ReactOS 0.4.15-dev-7906-g1b85a5f
tree.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS
3 * LICENSE: GNU GPLv2 only as published by the Free Software Foundation
4 * PURPOSE: Implements tree.com command similar to Windows
5 * PROGRAMMERS: Asif Bahrainwala (asif_bahrainwala@hotmail.com)
6 */
7
8#include <stdio.h>
9#include <stdlib.h>
10
11#include <windef.h>
12#include <winbase.h>
13
14#include <conutils.h>
15
16#include "resource.h"
17
18#define STR_MAX 2048
19
20static VOID GetDirectoryStructure(PWSTR strPath, UINT width, PCWSTR prevLine);
21
22/* If this flag is set to true, files will also be listed within the folder structure */
24
25/* If this flag is true, ASCII characters will be used instead of UNICODE ones */
27
37static BOOL HasSubFolder(PCWSTR strPath1)
38{
39 BOOL ret = FALSE;
40 WIN32_FIND_DATAW FindFileData;
41 HANDLE hFind = NULL;
42 static WCHAR strPath[STR_MAX] = L"";
43 ZeroMemory(strPath, sizeof(strPath));
44
45 wcscat(strPath, strPath1);
46 wcscat(strPath, L"\\*.");
47
48 hFind = FindFirstFileW(strPath, &FindFileData);
49 do
50 {
51 if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
52 {
53 if (wcscmp(FindFileData.cFileName, L".") == 0 ||
54 wcscmp(FindFileData.cFileName, L"..") == 0 )
55 {
56 continue;
57 }
58
59 ret = TRUE; // Sub-folder found
60 break;
61 }
62 }
63 while (FindNextFileW(hFind, &FindFileData));
64
65 FindClose(hFind);
66 return ret;
67}
68
88static VOID DrawTree(PCWSTR strPath,
89 const WIN32_FIND_DATAW* arrFolder,
90 const size_t szArr,
91 UINT width,
92 PCWSTR prevLine,
93 BOOL drawfolder)
94{
95 BOOL bHasSubFolder = HasSubFolder(strPath);
96 UINT i = 0;
97
98 /* This will format the spaces required for correct formatting */
99 for (i = 0; i < szArr; ++i)
100 {
101 PWSTR consoleOut = (PWSTR)malloc(STR_MAX * sizeof(WCHAR));
102 UINT j = 0;
103 static WCHAR str[STR_MAX];
104
105 /* As we do not seem to have the _s functions properly set up, use the non-secure version for now */
106 //wcscpy_s(consoleOut, STR_MAX, L"");
107 //wcscpy_s(str, STR_MAX, L"");
108 wcscpy(consoleOut, L"");
109 wcscpy(str, L"");
110
111 for (j = 0; j < width - 1; ++j)
112 {
113 /* If the previous line has '├' or '│' then the current line will
114 add '│' to continue the connecting line */
115 if (prevLine[j] == L'\x251C' || prevLine[j] == L'\x2502' ||
116 prevLine[j] == L'+' || prevLine[j] == L'|')
117 {
118 if (!bUseAscii)
119 {
120 wcscat(consoleOut, L"\x2502");
121 }
122 else
123 {
124 wcscat(consoleOut, L"|");
125 }
126 }
127 else
128 {
129 wcscat(consoleOut, L" ");
130 }
131 }
132
133 if (szArr - 1 != i)
134 {
135 if (drawfolder)
136 {
137 /* Add '├───Folder name' (\xC3\xC4\xC4\xC4 or \x251C\x2500\x2500\x2500) */
138 if (bUseAscii)
139 swprintf(str, L"+---%s", arrFolder[i].cFileName);
140 else
141 swprintf(str, L"\x251C\x2500\x2500\x2500%s", arrFolder[i].cFileName);
142 }
143 else
144 {
145 if (bHasSubFolder)
146 {
147 /* Add '│ FileName' (\xB3 or \x2502) */
148 // This line is added to connect the below-folder sub-structure
149 if (bUseAscii)
150 swprintf(str, L"| %s", arrFolder[i].cFileName);
151 else
152 swprintf(str, L"\x2502 %s", arrFolder[i].cFileName);
153 }
154 else
155 {
156 /* Add ' FileName' */
157 swprintf(str, L" %s", arrFolder[i].cFileName);
158 }
159 }
160 }
161 else
162 {
163 if (drawfolder)
164 {
165 /* '└───Folder name' (\xC0\xC4\xC4\xC4 or \x2514\x2500\x2500\x2500) */
166 if (bUseAscii)
167 swprintf(str, L"\\---%s", arrFolder[i].cFileName);
168 else
169 swprintf(str, L"\x2514\x2500\x2500\x2500%s", arrFolder[i].cFileName);
170 }
171 else
172 {
173 if (bHasSubFolder)
174 {
175 /* '│ FileName' (\xB3 or \x2502) */
176 if (bUseAscii)
177 swprintf(str, L"| %s", arrFolder[i].cFileName);
178 else
179 swprintf(str, L"\x2502 %s", arrFolder[i].cFileName);
180 }
181 else
182 {
183 /* ' FileName' */
184 swprintf(str, L" %s", arrFolder[i].cFileName);
185 }
186 }
187 }
188
189 wcscat(consoleOut, str);
190 ConPrintf(StdOut, L"%s\n", consoleOut);
191
192 if (drawfolder)
193 {
194 PWSTR str = (PWSTR)malloc(STR_MAX * sizeof(WCHAR));
195 ZeroMemory(str, STR_MAX * sizeof(WCHAR));
196
197 wcscat(str, strPath);
198 wcscat(str, L"\\");
199 wcscat(str, arrFolder[i].cFileName);
200 GetDirectoryStructure(str, width + 4, consoleOut);
201
202 free(str);
203 }
204 free(consoleOut);
205 }
206}
207
222static VOID
224{
225 WIN32_FIND_DATAW FindFileData;
226 HANDLE hFind = NULL;
227 //DWORD err = 0;
228 /* Fill up with names of all sub-folders */
229 WIN32_FIND_DATAW *arrFolder = NULL;
230 UINT arrFoldersz = 0;
231 /* Fill up with names of all sub-folders */
232 WIN32_FIND_DATAW *arrFile = NULL;
233 UINT arrFilesz = 0;
234
235 ZeroMemory(&FindFileData, sizeof(FindFileData));
236
237 {
238 static WCHAR tmp[STR_MAX] = L"";
239 ZeroMemory(tmp, sizeof(tmp));
240 wcscat(tmp, strPath);
241 wcscat(tmp, L"\\*.*");
242 hFind = FindFirstFileW(tmp, &FindFileData);
243 //err = GetLastError();
244 }
245
246 if (hFind == INVALID_HANDLE_VALUE)
247 return;
248
249 do
250 {
251 if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
252 {
253 if (wcscmp(FindFileData.cFileName, L".") == 0 ||
254 wcscmp(FindFileData.cFileName, L"..") == 0)
255 continue;
256
257 ++arrFoldersz;
258 arrFolder = (WIN32_FIND_DATAW*)realloc(arrFolder, arrFoldersz * sizeof(FindFileData));
259
260 if (arrFolder == NULL)
261 exit(-1);
262
263 arrFolder[arrFoldersz - 1] = FindFileData;
264
265 }
266 else
267 {
268 ++arrFilesz;
269 arrFile = (WIN32_FIND_DATAW*)realloc(arrFile, arrFilesz * sizeof(FindFileData));
270
271 if(arrFile == NULL)
272 exit(-1);
273
274 arrFile[arrFilesz - 1] = FindFileData;
275 }
276 }
277 while (FindNextFileW(hFind, &FindFileData));
278
279 FindClose(hFind);
280
281 if (bShowFiles)
282 {
283 /* Will free(arrFile) */
284 DrawTree(strPath, arrFile, arrFilesz, width, prevLine, FALSE);
285 }
286
287 /* Will free(arrFile) */
288 DrawTree(strPath, arrFolder, arrFoldersz, width, prevLine, TRUE);
289
290 free(arrFolder);
291 free(arrFile);
292}
293
301int wmain(int argc, WCHAR* argv[])
302{
303 DWORD dwSerial = 0;
304 WCHAR t = 0;
305 PWSTR strPath = NULL;
306 DWORD sz = 0;
307 //PWSTR context = NULL;
308 PWSTR driveLetter = NULL;
309
310 int i;
311
312 /* Initialize the Console Standard Streams */
314
315 /* Parse the command line */
316 for (i = 1; i < argc; ++i)
317 {
318 if (argv[i][0] == L'-' || argv[i][0] == L'/')
319 {
320 switch (towlower(argv[i][1]))
321 {
322 case L'?':
323 /* Print help and exit after */
325 return 0;
326
327 case L'f':
329 break;
330
331 case L'a':
332 bUseAscii = TRUE;
333 break;
334
335 default:
336 break;
337 }
338 }
339 else
340 {
341 /* This must be path to some folder */
342
343 /* Set the current directory for this executable */
345 if (b == FALSE)
346 {
348 return 1;
349 }
350 }
351 }
352
354
355 GetVolumeInformationW(NULL, NULL, 0, &dwSerial, NULL, NULL, NULL, 0);
356 ConResPrintf(StdOut, IDS_VOL_SERIAL, dwSerial >> 16, dwSerial & 0xffff);
357
358 /* get the buffer size */
359 sz = GetCurrentDirectoryW(1, &t);
360 /* must not return before calling delete[] */
361 strPath = (PWSTR)malloc(sz * sizeof(WCHAR));
362
363 /* get the current directory */
364 GetCurrentDirectoryW(sz, strPath);
365
366 /* get the drive letter , must not return before calling delete[] */
367 driveLetter = (PWSTR)malloc(sz * sizeof(WCHAR));
368
369 /* As we do not seem to have the _s functions properly set up, use the non-secure version for now */
370 //wcscpy_s(driveLetter,sz,strPath);
371 //wcstok_s(driveLetter,L":", &context); //parse for the drive letter
372 wcscpy(driveLetter, strPath);
373 wcstok(driveLetter, L":");
374
375 ConPrintf(StdOut, L"%s:.\n", driveLetter);
376
377 free(driveLetter);
378
379 /* get the sub-directories within this current folder */
380 GetDirectoryStructure(strPath, 1, L" ");
381
382 free(strPath);
383 ConPuts(StdOut, L"\n");
384
385 return 0;
386}
static int argc
Definition: ServiceArgs.c:12
#define IDS_USAGE
Definition: resource.h:3
void ConPuts(FILE *fp, LPCWSTR psz)
Definition: fc.c:16
#define ConInitStdStreams()
Definition: fc.c:13
void ConPrintf(FILE *fp, LPCWSTR psz,...)
Definition: fc.c:20
#define StdOut
Definition: fc.c:14
void ConResPrintf(FILE *fp, UINT nID,...)
Definition: fc.c:33
void ConResPuts(FILE *fp, UINT nID)
Definition: fc.c:27
#define IDS_FOLDER_PATH
Definition: resource.h:5
#define IDS_NO_SUBDIRECTORIES
Definition: resource.h:4
#define IDS_VOL_SERIAL
Definition: resource.h:6
static VOID GetDirectoryStructure(PWSTR strPath, UINT width, PCWSTR prevLine)
Definition: tree.c:223
static VOID DrawTree(PCWSTR strPath, const WIN32_FIND_DATAW *arrFolder, const size_t szArr, UINT width, PCWSTR prevLine, BOOL drawfolder)
Definition: tree.c:88
static BOOL HasSubFolder(PCWSTR strPath1)
Definition: tree.c:37
BOOL bUseAscii
Definition: tree.c:26
#define STR_MAX
Definition: tree.c:18
BOOL bShowFiles
Definition: tree.c:23
#define realloc
Definition: debug_ros.c:6
#define free
Definition: debug_ros.c:5
#define malloc
Definition: debug_ros.c:4
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define GetCurrentDirectoryW(x, y)
Definition: compat.h:756
#define INVALID_HANDLE_VALUE
Definition: compat.h:731
HANDLE WINAPI FindFirstFileW(IN LPCWSTR lpFileName, OUT LPWIN32_FIND_DATAW lpFindFileData)
Definition: find.c:320
BOOL WINAPI FindClose(HANDLE hFindFile)
Definition: find.c:502
BOOL WINAPI FindNextFileW(IN HANDLE hFindFile, OUT LPWIN32_FIND_DATAW lpFindFileData)
Definition: find.c:382
BOOL WINAPI GetVolumeInformationW(IN LPCWSTR lpRootPathName, IN LPWSTR lpVolumeNameBuffer, IN DWORD nVolumeNameSize, OUT LPDWORD lpVolumeSerialNumber OPTIONAL, OUT LPDWORD lpMaximumComponentLength OPTIONAL, OUT LPDWORD lpFileSystemFlags OPTIONAL, OUT LPWSTR lpFileSystemNameBuffer OPTIONAL, IN DWORD nFileSystemNameSize)
Definition: volume.c:226
BOOL WINAPI SetCurrentDirectoryW(IN LPCWSTR lpPathName)
Definition: path.c:2249
#define swprintf
Definition: precomp.h:40
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
GLdouble GLdouble t
Definition: gl.h:2047
GLint GLint GLsizei width
Definition: gl.h:1546
GLboolean GLboolean GLboolean b
Definition: glext.h:6204
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint GLint GLint j
Definition: glfuncs.h:250
#define argv
Definition: mplay32.c:18
unsigned int UINT
Definition: ndis.h:50
#define FILE_ATTRIBUTE_DIRECTORY
Definition: nt_native.h:705
#define L(x)
Definition: ntvdm.h:50
int wmain()
const WCHAR * str
_CRTIMP wchar_t *__cdecl wcscpy(_Out_writes_z_(_String_length_(_Source)+1) wchar_t *_Dest, _In_z_ const wchar_t *_Source)
_Check_return_ _CRTIMP int __cdecl wcscmp(_In_z_ const wchar_t *_Str1, _In_z_ const wchar_t *_Str2)
_CRTIMP wchar_t *__cdecl wcscat(_Inout_updates_z_(_String_length_(_Dest)+_String_length_(_Source)+1) wchar_t *_Dest, _In_z_ const wchar_t *_Source)
_Check_return_ _CRTIMP wchar_t *__cdecl wcstok(_Inout_opt_z_ wchar_t *_Str, _In_z_ const wchar_t *_Delim)
#define exit(n)
Definition: config.h:202
#define towlower(c)
Definition: wctype.h:97
uint16_t * PWSTR
Definition: typedefs.h:56
const uint16_t * PCWSTR
Definition: typedefs.h:57
int ret
#define ZeroMemory
Definition: winbase.h:1712
__wchar_t WCHAR
Definition: xmlstorage.h:180