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)
20 static VOID
GetDirectoryStructure(PWSTR strPath
, UINT width
, PCWSTR prevLine
);
22 /* If this flag is set to true, files will also be listed within the folder structure */
23 BOOL bShowFiles
= FALSE
;
25 /* If this flag is true, ASCII characters will be used instead of UNICODE ones */
26 BOOL bUseAscii
= FALSE
;
32 * Must specify folder name
35 * true if folder has sub-folders, else will return false
37 static BOOL
HasSubFolder(PCWSTR strPath1
)
40 WIN32_FIND_DATAW FindFileData
;
42 static WCHAR strPath
[STR_MAX
] = L
"";
43 ZeroMemory(strPath
, sizeof(strPath
));
45 wcscat(strPath
, strPath1
);
46 wcscat(strPath
, L
"\\*.");
48 hFind
= FindFirstFileW(strPath
, &FindFileData
);
51 if (FindFileData
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
53 if (wcscmp(FindFileData
.cFileName
, L
".") == 0 ||
54 wcscmp(FindFileData
.cFileName
, L
"..") == 0 )
59 ret
= TRUE
; // Sub-folder found
63 while (FindNextFileW(hFind
, &FindFileData
));
73 * Must specify folder name
76 * must be a list of folder names to be drawn in tree format
79 * specifies drawing distance for correct formatting of tree structure being drawn on console screen
80 * used internally for adding spaces
83 * used internally for formatting reasons
88 static VOID
DrawTree(PCWSTR strPath
,
89 const WIN32_FIND_DATAW
* arrFolder
,
95 BOOL bHasSubFolder
= HasSubFolder(strPath
);
98 /* This will format the spaces required for correct formatting */
99 for (i
= 0; i
< szArr
; ++i
)
101 PWSTR consoleOut
= (PWSTR
)malloc(STR_MAX
* sizeof(WCHAR
));
103 static WCHAR str
[STR_MAX
];
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
"");
111 for (j
= 0; j
< width
- 1; ++j
)
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
'|')
120 wcscat(consoleOut
, L
"\x2502");
124 wcscat(consoleOut
, L
"|");
129 wcscat(consoleOut
, L
" ");
137 /* Add '├───Folder name' (\xC3\xC4\xC4\xC4 or \x251C\x2500\x2500\x2500) */
139 swprintf(str
, L
"+---%s", arrFolder
[i
].cFileName
);
141 swprintf(str
, L
"\x251C\x2500\x2500\x2500%s", arrFolder
[i
].cFileName
);
147 /* Add '│ FileName' (\xB3 or \x2502) */
148 // This line is added to connect the below-folder sub-structure
150 swprintf(str
, L
"| %s", arrFolder
[i
].cFileName
);
152 swprintf(str
, L
"\x2502 %s", arrFolder
[i
].cFileName
);
156 /* Add ' FileName' */
157 swprintf(str
, L
" %s", arrFolder
[i
].cFileName
);
165 /* '└───Folder name' (\xC0\xC4\xC4\xC4 or \x2514\x2500\x2500\x2500) */
167 swprintf(str
, L
"\\---%s", arrFolder
[i
].cFileName
);
169 swprintf(str
, L
"\x2514\x2500\x2500\x2500%s", arrFolder
[i
].cFileName
);
175 /* '│ FileName' (\xB3 or \x2502) */
177 swprintf(str
, L
"| %s", arrFolder
[i
].cFileName
);
179 swprintf(str
, L
"\x2502 %s", arrFolder
[i
].cFileName
);
184 swprintf(str
, L
" %s", arrFolder
[i
].cFileName
);
189 wcscat(consoleOut
, str
);
190 ConPrintf(StdOut
, L
"%s\n", consoleOut
);
194 PWSTR str
= (PWSTR
)malloc(STR_MAX
* sizeof(WCHAR
));
195 ZeroMemory(str
, STR_MAX
* sizeof(WCHAR
));
197 wcscat(str
, strPath
);
199 wcscat(str
, arrFolder
[i
].cFileName
);
200 GetDirectoryStructure(str
, width
+ 4, consoleOut
);
209 * @name: GetDirectoryStructure
212 * Must specify folder name
215 * specifies drawing distance for correct formatting of tree structure being drawn on console screen
218 * specifies the previous line written on console, is used for correct formatting
223 GetDirectoryStructure(PWSTR strPath
, UINT width
, PCWSTR prevLine
)
225 WIN32_FIND_DATAW FindFileData
;
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
;
235 ZeroMemory(&FindFileData
, sizeof(FindFileData
));
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();
246 if (hFind
== INVALID_HANDLE_VALUE
)
251 if (FindFileData
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
253 if (wcscmp(FindFileData
.cFileName
, L
".") == 0 ||
254 wcscmp(FindFileData
.cFileName
, L
"..") == 0)
258 arrFolder
= (WIN32_FIND_DATAW
*)realloc(arrFolder
, arrFoldersz
* sizeof(FindFileData
));
260 if (arrFolder
== NULL
)
263 arrFolder
[arrFoldersz
- 1] = FindFileData
;
269 arrFile
= (WIN32_FIND_DATAW
*)realloc(arrFile
, arrFilesz
* sizeof(FindFileData
));
274 arrFile
[arrFilesz
- 1] = FindFileData
;
277 while (FindNextFileW(hFind
, &FindFileData
));
283 /* Will free(arrFile) */
284 DrawTree(strPath
, arrFile
, arrFilesz
, width
, prevLine
, FALSE
);
287 /* Will free(arrFile) */
288 DrawTree(strPath
, arrFolder
, arrFoldersz
, width
, prevLine
, TRUE
);
296 * standard main functionality as required by C/C++ for application startup
299 * error /success value
301 int wmain(int argc
, WCHAR
* argv
[])
305 PWSTR strPath
= NULL
;
307 //PWSTR context = NULL;
308 PWSTR driveLetter
= NULL
;
312 /* Initialize the Console Standard Streams */
315 /* Parse the command line */
316 for (i
= 1; i
< argc
; ++i
)
318 if (argv
[i
][0] == L
'-' || argv
[i
][0] == L
'/')
320 switch (towlower(argv
[i
][1]))
323 /* Print help and exit after */
324 ConResPuts(StdOut
, IDS_USAGE
);
341 /* This must be path to some folder */
343 /* Set the current directory for this executable */
344 BOOL b
= SetCurrentDirectoryW(argv
[i
]);
347 ConResPuts(StdOut
, IDS_NO_SUBDIRECTORIES
);
353 ConResPuts(StdOut
, IDS_FOLDER_PATH
);
355 GetVolumeInformationW(NULL
, NULL
, 0, &dwSerial
, NULL
, NULL
, NULL
, 0);
356 ConResPrintf(StdOut
, IDS_VOL_SERIAL
, dwSerial
>> 16, dwSerial
& 0xffff);
358 /* get the buffer size */
359 sz
= GetCurrentDirectoryW(1, &t
);
360 /* must not return before calling delete[] */
361 strPath
= (PWSTR
)malloc(sz
* sizeof(WCHAR
));
363 /* get the current directory */
364 GetCurrentDirectoryW(sz
, strPath
);
366 /* get the drive letter , must not return before calling delete[] */
367 driveLetter
= (PWSTR
)malloc(sz
* sizeof(WCHAR
));
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
":");
375 ConPrintf(StdOut
, L
"%s:.\n", driveLetter
);
379 /* get the sub-directories within this current folder */
380 GetDirectoryStructure(strPath
, 1, L
" ");
383 ConPuts(StdOut
, L
"\n");