ReactOS  0.4.11-dev-946-g431643b
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 
20 static 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 
37 static 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 
88 static 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 
222 static 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 
301 int 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':
328  bShowFiles = TRUE;
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 */
344  BOOL b = SetCurrentDirectoryW(argv[i]);
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 }
#define realloc
Definition: debug_ros.c:6
BOOL WINAPI FindNextFileW(IN HANDLE hFindFile, OUT LPWIN32_FIND_DATAW lpFindFileData)
Definition: find.c:382
static int argc
Definition: ServiceArgs.c:12
GLint GLint GLsizei width
Definition: gl.h:1546
GLenum GLclampf GLint GLenum GLuint GLenum GLenum GLsizei GLenum const GLvoid GLfloat GLfloat GLfloat GLfloat GLclampd GLint 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 GLboolean GLboolean GLboolean GLint GLenum GLsizei const GLvoid GLenum GLint GLenum GLint GLint GLsizei GLint GLenum GLint GLint GLint GLint GLsizei GLenum GLsizei const GLuint GLboolean GLenum GLenum GLint GLsizei GLenum GLsizei GLenum const GLvoid GLboolean const GLboolean GLenum const GLdouble const GLfloat const GLdouble const GLfloat GLenum GLint GLint GLint GLint GLint GLint j
Definition: glfuncs.h:98
#define TRUE
Definition: types.h:120
__wchar_t WCHAR
Definition: xmlstorage.h:180
uint16_t * PWSTR
Definition: typedefs.h:54
static VOID DrawTree(PCWSTR strPath, const WIN32_FIND_DATAW *arrFolder, const size_t szArr, UINT width, PCWSTR prevLine, BOOL drawfolder)
Definition: tree.c:88
#define free
Definition: debug_ros.c:5
#define GetCurrentDirectoryW(x, y)
Definition: compat.h:413
_Check_return_ _CRTIMP wchar_t *__cdecl wcstok(_Inout_opt_z_ wchar_t *_Str, _In_z_ const wchar_t *_Delim)
GLdouble GLdouble t
Definition: gl.h:2047
#define IDS_NO_SUBDIRECTORIES
Definition: resource.h:4
BOOL bUseAscii
Definition: tree.c:26
#define INVALID_HANDLE_VALUE
Definition: compat.h:391
#define ZeroMemory
Definition: winbase.h:1635
#define IDS_USAGE
Definition: resource.h:3
static char ** argv
Definition: ServiceArgs.c:11
GLenum GLclampf GLint i
Definition: glfuncs.h:14
#define ConInitStdStreams()
Definition: stream.h:122
INT __cdecl ConPrintf(IN PCON_STREAM Stream, IN LPWSTR szStr,...)
Definition: outstream.c:520
static VOID GetDirectoryStructure(PWSTR strPath, UINT width, PCWSTR prevLine)
Definition: tree.c:223
const WCHAR * str
smooth NULL
Definition: ftsmooth.c:416
#define IDS_FOLDER_PATH
Definition: resource.h:5
#define FILE_ATTRIBUTE_DIRECTORY
Definition: nt_native.h:705
INT __cdecl ConResPrintf(IN PCON_STREAM Stream, IN UINT uID,...)
Definition: outstream.c:781
GLboolean GLboolean GLboolean b
Definition: glext.h:6204
unsigned int BOOL
Definition: ntddk_ex.h:94
#define swprintf(buf, format,...)
Definition: sprintf.c:56
unsigned int UINT
Definition: ndis.h:50
unsigned long DWORD
Definition: ntddk_ex.h:95
#define IDS_VOL_SERIAL
Definition: resource.h:6
INT ConResPuts(IN PCON_STREAM Stream, IN UINT uID)
Definition: outstream.c:610
int ret
_CRTIMP wchar_t *__cdecl wcscpy(_Out_writes_z_(_String_length_(_Source)+1) wchar_t *_Dest, _In_z_ const wchar_t *_Source)
static const WCHAR L[]
Definition: oid.c:1087
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
_Check_return_ _CRTIMP int __cdecl wcscmp(_In_z_ const wchar_t *_Str1, _In_z_ const wchar_t *_Str2)
static BOOL HasSubFolder(PCWSTR strPath1)
Definition: tree.c:37
BOOL WINAPI SetCurrentDirectoryW(IN LPCWSTR lpPathName)
Definition: path.c:2248
_CRTIMP wchar_t *__cdecl wcscat(_Inout_updates_z_(_String_length_(_Dest)+_String_length_(_Source)+1) wchar_t *_Dest, _In_z_ const wchar_t *_Source)
INT ConPuts(IN PCON_STREAM Stream, IN LPWSTR szStr)
Definition: outstream.c:427
#define StdOut
Definition: stream.h:76
#define towlower(c)
Definition: wctype.h:97
#define malloc
Definition: debug_ros.c:4
const uint16_t * PCWSTR
Definition: typedefs.h:55
void exit(int exitcode)
Definition: _exit.c:33
BOOL bShowFiles
Definition: tree.c:23
#define STR_MAX
Definition: tree.c:18
int wmain(int argc, WCHAR *argv[])
Definition: tree.c:301
HANDLE WINAPI FindFirstFileW(IN LPCWSTR lpFileName, OUT LPWIN32_FIND_DATAW lpFindFileData)
Definition: find.c:320
BOOL WINAPI FindClose(HANDLE hFindFile)
Definition: find.c:502