3 * DIR.C - dir internal command.
8 * 01/29/97 (Tim Norman)
11 * 06/13/97 (Tim Norman)
14 * 07/12/97 (Tim Norman)
15 * Fixed bug that caused the root directory to be unlistable
17 * 07/12/97 (Marc Desrochers)
18 * Changed to use maxx, maxy instead of findxy()
21 * Added compatibility for /w in dir
24 * Compatibility for dir/s started
25 * Tested that program finds directories off root fine
28 * do_recurse saves the cwd and also stores it in Root
29 * build_tree adds the cwd to the beginning of its' entries
30 * Program runs fine, added print_tree -- works fine.. as EXE,
31 * program won't work properly as COM.
34 * Found problem that caused COM not to work
38 * added free mem routine
41 * debugged the free mem routine
42 * debugged whole thing some more
44 * ReadDir stores Root name and _Read_Dir does the hard work
45 * PrintDir prints Root and _Print_Dir does the hard work
46 * KillDir kills Root _after_ _Kill_Dir does the hard work
47 * Integrated program into DIR.C(this file) and made some same
51 * Cleaned up code a bit, added comments
54 * Added error checking to my previously added routines
57 * Rewrote recursive functions, again! Most other recursive
58 * functions are now obsolete -- ReadDir, PrintDir, _Print_Dir,
59 * KillDir and _Kill_Dir. do_recurse does what PrintDir did
60 * and _Read_Dir did what it did before along with what _Print_Dir
61 * did. Makes /s a lot faster!
62 * Reports 2 more files/dirs that MS-DOS actually reports
63 * when used in root directory(is this because dir defaults
64 * to look for read only files?)
65 * Added support for /b, /a and /l
66 * Made error message similar to DOS error messages
70 * Added check for /-(switch) to turn off previously defined
72 * Added ability to check for DIRCMD in environment and
77 * Now can dir *.ext/X, no spaces!
80 * error message now found in command.h
82 * 07/08/1998 (John P. Price)
83 * removed extra returns; closer to MSDOS
84 * fixed wide display so that an extra return is not displayed
85 * when there is five filenames in the last line.
88 * Changed error messages
90 * 27-Jul-1998 (John P Price <linux-guru@gcfl.net>)
91 * added config.h include
94 * 04-Dec-1998 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
95 * Converted source code to Win32, except recursive dir ("dir /s").
97 * 10-Dec-1998 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
98 * Fixed recursive dir ("dir /s").
100 * 14-Dec-1998 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
101 * Converted to Win32 directory functions and
102 * fixed some output bugs. There are still some more ;)
104 * 10-Jan-1999 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
105 * Added "/N" and "/4" options, "/O" is a dummy.
106 * Added locale support.
108 * 20-Jan-1999 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
111 * 01-Mar-1999 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
112 * Replaced all runtime io functions by their Win32 counterparts.
114 * 23-Feb-2001 (Carl Nettelblad <cnettel@hem.passagen.se>)
115 * dir /s now works in deeper trees
117 * 28-Jan-2004 (Michael Fritscher <michael@fritscher.net>)
118 * Fix for /p, so it is working under Windows in GUI-mode, too.
120 * 30-Apr-2004 (Filip Navara <xnavara@volny.cz>)
121 * Fix /w to print long names.
126 #ifdef INCLUDE_CMD_DIR
129 /* flag definitions */
132 DIR_RECURSE
= 0x0001,
134 DIR_WIDE
= 0x0004, /* Rob Lake */
135 DIR_BARE
= 0x0008, /* Rob Lake */
136 DIR_ALL
= 0x0010, /* Rob Lake */
137 DIR_LWR
= 0x0020, /* Rob Lake */
138 DIR_SORT
= 0x0040, /* /O sort */
139 DIR_NEW
= 0x0080, /* /N new style */
140 DIR_FOUR
= 0x0100 /* /4 four digit year */
145 (*PGETFREEDISKSPACEEX
)(LPCTSTR
, PULARGE_INTEGER
, PULARGE_INTEGER
, PULARGE_INTEGER
);
148 /* Globally save the # of dirs, files and bytes,
149 * probabaly later pass them to functions. Rob Lake */
150 static ULONG recurse_dir_cnt
;
151 static ULONG recurse_file_cnt
;
152 static ULARGE_INTEGER recurse_bytes
;
158 * displays help screen for dir
161 static VOID
Help (VOID
)
163 ConOutPuts(_T("Displays a list of files and subdirectories in a directory.\n"
165 "DIR [drive:][path][filename] [/A] [/B] [/L] [/N] [/S] [/P] [/W] [/4]\n"
167 " [drive:][path][filename]\n"
168 " Specifies drive, directory, and/or files to list.\n"
170 " /A Displays files with HIDDEN SYSTEM attributes\n"
171 " default is ARCHIVE and READ ONLY\n"
172 " /B Uses bare format (no heading information or summary).\n"
173 " /L Uses lowercase.\n"
174 " /N New long list format where filenames are on the far right.\n"
175 " /S Displays files in specified directory and all subdirectories\n"
176 " /P Pauses after each screen full\n"
177 " /W Prints in wide format\n"
178 " /4 Display four digit years.\n"
180 "Switches may be present in the DIRCMD environment variable. Use\n"
181 "of the - (hyphen) can turn off defined swtiches. Ex. /-W would\n"
182 "turn off printing in wide format.\n"
190 * read the parameters from the command line
193 DirReadParam (LPTSTR line
, LPTSTR
*param
, LPDWORD lpFlags
)
202 /* scan the command line, processing switches */
206 if (*line
== _T('/') || slash
)
211 if (*line
== _T('-'))
214 if (_totupper (*line
) == _T('S'))
215 *lpFlags
&= ~DIR_RECURSE
;
216 else if (_totupper (*line
) == _T('P'))
217 *lpFlags
&= ~DIR_PAGE
;
218 else if (_totupper (*line
) == _T('W'))
219 *lpFlags
&= ~DIR_WIDE
;
220 else if (_totupper (*line
) == _T('B'))
221 *lpFlags
&= ~DIR_BARE
;
222 else if (_totupper (*line
) == _T('A'))
223 *lpFlags
&= ~DIR_ALL
;
224 else if (_totupper (*line
) == _T('L'))
225 *lpFlags
&= ~DIR_LWR
;
226 else if (_totupper (*line
) == _T('N'))
227 *lpFlags
&= ~DIR_NEW
;
228 else if (_totupper (*line
) == _T('O'))
229 *lpFlags
&= ~DIR_SORT
;
230 else if (_totupper (*line
) == _T('4'))
231 *lpFlags
&= ~DIR_FOUR
;
234 error_invalid_switch ((TCHAR
)_totupper (*line
));
242 if (_totupper (*line
) == _T('S'))
243 *lpFlags
|= DIR_RECURSE
;
244 else if (_totupper (*line
) == _T('P'))
245 *lpFlags
|= DIR_PAGE
;
246 else if (_totupper (*line
) == _T('W'))
247 *lpFlags
|= DIR_WIDE
;
248 else if (_totupper (*line
) == _T('B'))
249 *lpFlags
|= DIR_BARE
;
250 else if (_totupper (*line
) == _T('A'))
252 else if (_totupper (*line
) == _T('L'))
254 else if (_totupper (*line
) == _T('N'))
256 else if (_totupper (*line
) == _T('O'))
257 *lpFlags
|= DIR_SORT
;
258 else if (_totupper (*line
) == _T('4'))
259 *lpFlags
|= DIR_FOUR
;
260 else if (*line
== _T('?'))
267 error_invalid_switch ((TCHAR
)_totupper (*line
));
275 /* process parameter */
276 if (!_istspace (*line
))
280 error_too_many_parameters (line
);
286 /* skip to end of line or next whitespace or next / */
287 if (*line
!= _T('\"'))
289 while (*line
&& !_istspace (*line
) && *line
!= _T('/'))
292 /* if end of line, return */
298 /* skip over the initial quote */
302 while (*line
&& *line
!= _T('"'))
305 if (*line
== _T('"'))
311 /* if parameter, remember to process it later */
312 if (*line
== _T('/'))
324 error_invalid_switch ((TCHAR
)_totupper (*line
));
335 * extend the filespec, possibly adding wildcards
338 ExtendFilespec (LPTSTR file
)
345 /* if no file spec, change to "*.*" */
346 if (*file
== _T('\0'))
348 _tcscpy (file
, _T("*.*"));
352 /* if starts with . add * in front */
353 if (*file
== _T('.'))
355 memmove (&file
[1], &file
[0], (_tcslen (file
) + 1) * sizeof(TCHAR
));
360 if (!_tcschr (file
, _T('.')))
362 _tcscat (file
, _T(".*"));
366 /* if last character is '.' add '*' */
367 len
= _tcslen (file
);
368 if (file
[len
- 1] == _T('.'))
370 _tcscat (file
, _T("*"));
379 * split the pathspec into drive, directory, and filespec
382 DirParsePathspec (LPTSTR szPathspec
, LPTSTR szPath
, LPTSTR szFilespec
)
384 TCHAR szOrigPath
[MAX_PATH
];
388 BOOL bWildcards
= FALSE
;
390 GetCurrentDirectory (MAX_PATH
, szOrigPath
);
392 /* get the drive and change to it */
393 if (szPathspec
[1] == _T(':'))
395 TCHAR szRootPath
[] = _T("A:");
397 szRootPath
[0] = szPathspec
[0];
398 start
= szPathspec
+ 2;
399 if (!SetCurrentDirectory (szRootPath
))
401 ErrorMessage (GetLastError(), NULL
);
411 /* check for wildcards */
412 for (i
= 0; szPathspec
[i
]; i
++)
414 if (szPathspec
[i
] == _T('*') || szPathspec
[i
] == _T('?'))
418 /* check if this spec is a directory */
421 if (SetCurrentDirectory (szPathspec
))
423 _tcscpy (szFilespec
, _T("*.*"));
425 if (!GetCurrentDirectory (MAX_PATH
, szPath
))
427 szFilespec
[0] = _T('\0');
428 SetCurrentDirectory (szOrigPath
);
429 error_out_of_memory();
433 SetCurrentDirectory (szOrigPath
);
438 /* find the file spec */
439 tmp
= _tcsrchr (start
, _T('\\'));
441 /* if no path is specified */
444 _tcscpy (szFilespec
, start
);
445 ExtendFilespec (szFilespec
);
446 if (!GetCurrentDirectory (MAX_PATH
, szPath
))
448 szFilespec
[0] = _T('\0');
449 SetCurrentDirectory (szOrigPath
);
450 error_out_of_memory();
454 SetCurrentDirectory (szOrigPath
);
458 /* get the filename */
459 _tcscpy (szFilespec
, tmp
+1);
460 ExtendFilespec (szFilespec
);
464 /* change to the root directory */
465 if (!SetCurrentDirectory (_T("\\")))
467 szFilespec
[0] = _T('\0');
468 SetCurrentDirectory (szOrigPath
);
469 error_path_not_found ();
478 /* change to this directory */
479 if (!SetCurrentDirectory (start
))
482 szFilespec
[0] = _T('\0');
483 SetCurrentDirectory (szOrigPath
);
484 error_path_not_found ();
488 /* get the full name of the directory */
489 if (!GetCurrentDirectory (MAX_PATH
, szPath
))
492 szFilespec
[0] = _T('\0');
493 SetCurrentDirectory (szOrigPath
);
494 error_out_of_memory ();
500 SetCurrentDirectory (szOrigPath
);
509 * increment our line if paginating, display message at end of screen
512 IncLine (LPINT pLine
, DWORD dwFlags
)
515 CONSOLE_SCREEN_BUFFER_INFO lpConsoleScreenBufferInfo
;
517 error
= GetConsoleScreenBufferInfo(hConsole
, &lpConsoleScreenBufferInfo
);
519 WindowHeight
= lpConsoleScreenBufferInfo
.srWindow
.Bottom
- lpConsoleScreenBufferInfo
.srWindow
.Top
;
521 if (!WindowHeight
) //That prevents bad behave if WindowHeight couln't calc
523 WindowHeight
= 1000000;
525 if (!(dwFlags
& DIR_PAGE
))
530 if (*pLine
>= (int)maxy
- 2 || *pLine
>= WindowHeight
) //Because I don't know if WindowsHeight work under all cases, perhaps then maxy is the right value
533 return (PagePrompt () == PROMPT_BREAK
);
541 * PrintDirectoryHeader
543 * print the header for the dir command
546 PrintDirectoryHeader (LPTSTR szPath
, LPINT pLine
, DWORD dwFlags
)
548 TCHAR szRootName
[MAX_PATH
];
553 if (dwFlags
& DIR_BARE
)
556 /* build usable root path */
557 if (szPath
[1] == _T(':') && szPath
[2] == _T('\\'))
560 szRootName
[0] = szPath
[0];
561 szRootName
[1] = _T(':');
562 szRootName
[2] = _T('\\');
565 else if (szPath
[0] == _T('\\') && szPath
[1] == _T('\\'))
568 p
= _tcschr(&szPath
[2], _T('\\'));
571 error_invalid_drive();
574 p
= _tcschr(p
+1, _T('\\'));
577 _tcscpy(szRootName
, szPath
);
578 _tcscat(szRootName
, _T("\\"));
583 _tcscpy(szRootName
, szPath
);
584 _tcscat(szRootName
, _T("\\"));
590 error_invalid_drive();
594 /* get the media ID of the drive */
595 if (!GetVolumeInformation(szRootName
, szVolName
, 80, &dwSerialNr
,
596 NULL
, NULL
, NULL
, 0))
598 error_invalid_drive();
602 /* print drive info */
603 ConOutPrintf(_T(" Volume in drive %c"), szRootName
[0]);
605 if (szVolName
[0] != _T('\0'))
606 ConOutPrintf(_T(" is %s\n"), szVolName
);
608 ConOutPrintf(_T(" has no label\n"));
610 if (IncLine(pLine
, dwFlags
))
613 /* print the volume serial number if the return was successful */
614 ConOutPrintf(_T(" Volume Serial Number is %04X-%04X\n"),
617 if (IncLine(pLine
, dwFlags
))
627 * insert commas into a number
630 ConvertULong (ULONG num
, LPTSTR des
, INT len
)
647 if (((c
+ 1) % (nNumberGroups
+ 1)) == 0)
648 temp
[30 - c
++] = cThousandSeparator
;
649 temp
[30 - c
++] = (TCHAR
)(num
% 10) + _T('0');
653 for (n
= 0; n
<= c
; n
++)
654 des
[n
] = temp
[31 - c
+ n
];
662 ConvertULargeInteger (ULARGE_INTEGER num
, LPTSTR des
, INT len
)
668 if (num
.QuadPart
== 0)
677 while (num
.QuadPart
> 0)
679 if (((c
+ 1) % (nNumberGroups
+ 1)) == 0)
680 temp
[30 - c
++] = cThousandSeparator
;
681 temp
[30 - c
++] = (TCHAR
)(num
.QuadPart
% 10) + _T('0');
685 for (n
= 0; n
<= c
; n
++)
686 des
[n
] = temp
[31 - c
+ n
];
694 PrintFileDateTime (LPSYSTEMTIME dt
, DWORD dwFlags
)
696 WORD wYear
= (dwFlags
& DIR_FOUR
) ? dt
->wYear
: dt
->wYear
%100;
702 ConOutPrintf (_T("%.2d%c%.2d%c%d"),
703 dt
->wMonth
, cDateSeparator
, dt
->wDay
, cDateSeparator
, wYear
);
707 ConOutPrintf (_T("%.2d%c%.2d%c%d"),
708 dt
->wDay
, cDateSeparator
, dt
->wMonth
, cDateSeparator
, wYear
);
712 ConOutPrintf (_T("%d%c%.2d%c%.2d"),
713 wYear
, cDateSeparator
, dt
->wMonth
, cDateSeparator
, dt
->wDay
);
719 case 0: /* 12 hour format */
721 ConOutPrintf (_T(" %2d%c%.2u%c"),
722 (dt
->wHour
== 0 ? 12 : (dt
->wHour
<= 12 ? dt
->wHour
: dt
->wHour
- 12)),
724 dt
->wMinute
, (dt
->wHour
<= 11 ? 'a' : 'p'));
727 case 1: /* 24 hour format */
728 ConOutPrintf (_T(" %2d%c%.2u"),
729 dt
->wHour
, cTimeSeparator
, dt
->wMinute
);
736 GetUserDiskFreeSpace(LPCTSTR lpRoot
,
737 PULARGE_INTEGER lpFreeSpace
)
739 PGETFREEDISKSPACEEX pGetFreeDiskSpaceEx
;
745 ULARGE_INTEGER TotalNumberOfBytes
, TotalNumberOfFreeBytes
;
747 lpFreeSpace
->QuadPart
= 0;
749 hInstance
= LoadLibrary(_T("KERNEL32"));
750 if (hInstance
!= NULL
)
752 pGetFreeDiskSpaceEx
= (PGETFREEDISKSPACEEX
)GetProcAddress(hInstance
,
754 "GetDiskFreeSpaceExW");
756 "GetDiskFreeSpaceExA");
758 if (pGetFreeDiskSpaceEx
!= NULL
)
760 if (pGetFreeDiskSpaceEx(lpRoot
, lpFreeSpace
, &TotalNumberOfBytes
, &TotalNumberOfFreeBytes
) == TRUE
)
763 FreeLibrary(hInstance
);
766 GetDiskFreeSpace(lpRoot
,
772 lpFreeSpace
->QuadPart
= dwSecPerCl
* dwBytPerSec
* dwFreeCl
;
777 * print_summary: prints dir summary
778 * Added by Rob Lake 06/17/98 to compact code
779 * Just copied Tim's Code and patched it a bit
783 PrintSummary(LPTSTR szPath
,
786 ULARGE_INTEGER bytes
,
791 ULARGE_INTEGER uliFree
;
792 TCHAR szRoot
[] = _T("A:\\");
794 if (dwFlags
& DIR_BARE
)
797 /* Print number of files and bytes */
798 ConvertULong (ulFiles
, buffer
, sizeof(buffer
));
799 ConOutPrintf (_T(" %6s File%c"),
800 buffer
, ulFiles
== 1 ? _T(' ') : _T('s'));
802 ConvertULargeInteger (bytes
, buffer
, sizeof(buffer
));
803 ConOutPrintf (_T(" %15s byte%c\n"),
804 buffer
, bytes
.QuadPart
== 1 ? _T(' ') : _T('s'));
806 if (IncLine (pLine
, dwFlags
))
809 /* Print number of dirs and bytes free */
810 ConvertULong (ulDirs
, buffer
, sizeof(buffer
));
811 ConOutPrintf (_T(" %6s Dir%c"),
812 buffer
, ulDirs
== 1 ? _T(' ') : _T('s'));
814 if (!(dwFlags
& DIR_RECURSE
))
816 szRoot
[0] = szPath
[0];
817 GetUserDiskFreeSpace(szRoot
, &uliFree
);
818 ConvertULargeInteger (uliFree
, buffer
, sizeof(buffer
));
819 ConOutPrintf (_T(" %15s bytes free\n"), buffer
);
820 if (IncLine (pLine
, dwFlags
))
825 if ((dwFlags
& DIR_BARE
) == 0)
827 ConOutPrintf (_T("\n"));
828 if (IncLine (pLine
, dwFlags
))
830 ConOutPrintf (_T("\n"));
832 if (IncLine (pLine
, dwFlags
))
843 * list the files in the directory
846 DirList (LPTSTR szPath
, LPTSTR szFilespec
, LPINT pLine
, DWORD dwFlags
)
848 TCHAR szFullPath
[MAX_PATH
];
849 WIN32_FIND_DATA file
;
850 ULARGE_INTEGER bytecount
;
859 INT longestfname
= 0;
861 bytecount
.QuadPart
= 0;
863 _tcscpy (szFullPath
, szPath
);
864 if (szFullPath
[_tcslen(szFullPath
) - 1] != _T('\\'))
865 _tcscat (szFullPath
, _T("\\"));
866 _tcscat (szFullPath
, szFilespec
);
868 hFile
= FindFirstFile (szFullPath
, &file
);
869 if (hFile
== INVALID_HANDLE_VALUE
)
871 /* Don't want to print anything if scanning recursively
874 if ((dwFlags
& DIR_RECURSE
) == 0)
877 error_file_not_found ();
878 if (IncLine (pLine
, dwFlags
))
886 /* Get the size of longest filename for wide listing. FN */
887 if (dwFlags
& DIR_WIDE
&& (dwFlags
& DIR_BARE
) == 0)
891 if (_tcslen(file
.cFileName
) > longestfname
)
893 longestfname
= _tcslen(file
.cFileName
);
894 /* Directories get extra brackets around them. */
895 if (file
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
899 while (FindNextFile (hFile
, &file
));
902 hFile
= FindFirstFile (szFullPath
, &file
);
904 /* Count the highest number of columns */
905 GetScreenSize(&screenwidth
, 0);
907 /* For counting columns of output */
910 /* Increase by the number of spaces behind file name */
914 /* moved down here because if we are recursively searching and
915 * don't find any files, we don't want just to print
916 * Directory of C:\SOMEDIR
920 if ((dwFlags
& DIR_BARE
) == 0)
922 ConOutPrintf (_T(" Directory of %s\n"), szPath
);
923 if (IncLine (pLine
, dwFlags
))
925 ConOutPrintf (_T("\n"));
926 if (IncLine (pLine
, dwFlags
))
932 /* next file, if user doesn't want all files */
933 if (!(dwFlags
& DIR_ALL
) &&
934 ((file
.dwFileAttributes
& FILE_ATTRIBUTE_HIDDEN
) ||
935 (file
.dwFileAttributes
& FILE_ATTRIBUTE_SYSTEM
)))
938 if (dwFlags
& DIR_LWR
)
940 _tcslwr (file
.cAlternateFileName
);
943 if (dwFlags
& DIR_WIDE
&& (dwFlags
& DIR_BARE
) == 0)
945 ULARGE_INTEGER uliSize
;
947 if (file
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
949 _stprintf (buffer
, _T("[%s]"), file
.cFileName
);
954 _stprintf (buffer
, _T("%s"), file
.cFileName
);
958 ConOutPrintf (_T("%*s"), - longestfname
, buffer
);
960 /* output as much columns as fits on the screen */
961 if (count
>= (screenwidth
/ longestfname
))
963 /* print the new line only if we aren't on the
964 * last column, in this case it wraps anyway */
965 if (count
* longestfname
!= screenwidth
)
966 ConOutPrintf (_T("\n"));
967 if (IncLine (pLine
, dwFlags
))
972 uliSize
.LowPart
= file
.nFileSizeLow
;
973 uliSize
.HighPart
= file
.nFileSizeHigh
;
974 bytecount
.QuadPart
+= uliSize
.QuadPart
;
976 else if (dwFlags
& DIR_BARE
)
978 ULARGE_INTEGER uliSize
;
980 if (_tcscmp (file
.cFileName
, _T(".")) == 0 ||
981 _tcscmp (file
.cFileName
, _T("..")) == 0)
984 if (dwFlags
& DIR_RECURSE
)
988 _tcscpy (dir
, szPath
);
989 _tcscat (dir
, _T("\\"));
990 if (dwFlags
& DIR_LWR
)
995 ConOutPrintf (_T("%-13s\n"), file
.cFileName
);
996 if (file
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
1000 if (IncLine (pLine
, dwFlags
))
1003 uliSize
.LowPart
= file
.nFileSizeLow
;
1004 uliSize
.HighPart
= file
.nFileSizeHigh
;
1005 bytecount
.QuadPart
+= uliSize
.QuadPart
;
1009 if (dwFlags
& DIR_NEW
)
1011 /* print file date and time */
1012 if (FileTimeToLocalFileTime (&file
.ftLastWriteTime
, &ft
))
1014 FileTimeToSystemTime (&ft
, &dt
);
1015 PrintFileDateTime (&dt
, dwFlags
);
1018 /* print file size */
1019 if (file
.dwFileAttributes
& FILE_ATTRIBUTE_REPARSE_POINT
)
1021 ConOutPrintf (_T(" <JUNCTION> "));
1022 if (file
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
1025 else if (file
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
1027 ConOutPrintf (_T(" <DIR> "));
1032 ULARGE_INTEGER uliSize
;
1034 uliSize
.LowPart
= file
.nFileSizeLow
;
1035 uliSize
.HighPart
= file
.nFileSizeHigh
;
1037 ConvertULargeInteger (uliSize
, buffer
, sizeof(buffer
));
1038 ConOutPrintf (_T(" %20s"), buffer
);
1040 bytecount
.QuadPart
+= uliSize
.QuadPart
;
1044 /* print long filename */
1045 ConOutPrintf (_T(" %s\n"), file
.cFileName
);
1049 if (file
.cFileName
[0] == _T('.'))
1050 ConOutPrintf (_T("%-13s "), file
.cFileName
);
1051 else if (file
.cAlternateFileName
[0] == _T('\0'))
1053 TCHAR szShortName
[13];
1056 _tcsncpy (szShortName
, file
.cFileName
, 13);
1057 ext
= _tcschr (szShortName
, _T('.'));
1062 ConOutPrintf (_T("%-8s %-3s "), szShortName
, ext
);
1068 ext
= _tcschr (file
.cAlternateFileName
, _T('.'));
1073 ConOutPrintf (_T("%-8s %-3s "), file
.cAlternateFileName
, ext
);
1076 /* print file size */
1077 if (file
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
1079 ConOutPrintf (_T("%-14s"), _T("<DIR>"));
1084 ULARGE_INTEGER uliSize
;
1086 uliSize
.LowPart
= file
.nFileSizeLow
;
1087 uliSize
.HighPart
= file
.nFileSizeHigh
;
1088 ConvertULargeInteger (uliSize
, buffer
, sizeof(buffer
));
1089 ConOutPrintf (_T(" %10s "), buffer
);
1090 bytecount
.QuadPart
+= uliSize
.QuadPart
;
1094 /* print file date and time */
1095 if (FileTimeToLocalFileTime (&file
.ftLastWriteTime
, &ft
))
1097 FileTimeToSystemTime (&ft
, &dt
);
1098 PrintFileDateTime (&dt
, dwFlags
);
1101 /* print long filename */
1102 ConOutPrintf (_T(" %s\n"), file
.cFileName
);
1105 if (IncLine (pLine
, dwFlags
))
1109 while (FindNextFile (hFile
, &file
));
1112 /* Rob Lake, need to make clean output */
1113 /* JPP 07/08/1998 added check for count != 0 */
1114 if ((dwFlags
& DIR_WIDE
) && (count
!= 0))
1116 ConOutPrintf (_T("\n"));
1117 if (IncLine (pLine
, dwFlags
))
1121 if (filecount
|| dircount
)
1123 recurse_dir_cnt
+= dircount
;
1124 recurse_file_cnt
+= filecount
;
1125 recurse_bytes
.QuadPart
+= bytecount
.QuadPart
;
1128 if (PrintSummary (szPath
, filecount
, dircount
, bytecount
, pLine
, dwFlags
))
1133 error_file_not_found ();
1142 * _Read_Dir: Actual function that does recursive listing
1145 DirRead (LPTSTR szPath
, LPTSTR szFilespec
, LPINT pLine
, DWORD dwFlags
)
1147 TCHAR szFullPath
[MAX_PATH
];
1148 WIN32_FIND_DATA file
;
1151 _tcscpy (szFullPath
, szPath
);
1152 if (szFullPath
[_tcslen (szFullPath
) - 1] != _T('\\'))
1153 _tcscat (szFullPath
, _T("\\"));
1154 _tcscat (szFullPath
, _T("*"));
1156 hFile
= FindFirstFile (szFullPath
, &file
);
1157 if (hFile
== INVALID_HANDLE_VALUE
)
1162 /* don't list "." and ".." */
1163 if (_tcscmp (file
.cFileName
, _T(".")) == 0 ||
1164 _tcscmp (file
.cFileName
, _T("..")) == 0)
1167 if (file
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
1169 _tcscpy (szFullPath
, szPath
);
1170 if (szFullPath
[_tcslen (szFullPath
) - 1] != _T('\\'))
1171 _tcscat (szFullPath
, _T("\\"));
1172 _tcscat (szFullPath
, file
.cFileName
);
1174 if (DirList (szFullPath
, szFilespec
, pLine
, dwFlags
))
1179 if (DirRead (szFullPath
, szFilespec
, pLine
, dwFlags
) == 1)
1186 while (FindNextFile (hFile
, &file
));
1188 if (!FindClose (hFile
))
1196 * do_recurse: Sets up for recursive directory listing
1199 DirRecurse (LPTSTR szPath
, LPTSTR szSpec
, LPINT pLine
, DWORD dwFlags
)
1201 if (!PrintDirectoryHeader (szPath
, pLine
, dwFlags
))
1204 if (DirList (szPath
, szSpec
, pLine
, dwFlags
))
1207 if ((dwFlags
& DIR_BARE
) == 0)
1209 ConOutPrintf (_T("\n"));
1210 if (IncLine (pLine
, dwFlags
))
1214 if (DirRead (szPath
, szSpec
, pLine
, dwFlags
))
1217 if ((dwFlags
& DIR_BARE
) == 0)
1218 ConOutPrintf (_T("Total files listed:\n"));
1220 dwFlags
&= ~DIR_RECURSE
;
1222 if (PrintSummary (szPath
, recurse_file_cnt
,
1223 recurse_dir_cnt
, recurse_bytes
, pLine
, dwFlags
))
1226 if ((dwFlags
& DIR_BARE
) == 0)
1228 ConOutPrintf (_T("\n"));
1229 if (IncLine (pLine
, dwFlags
))
1240 * internal dir command
1242 INT
CommandDir (LPTSTR first
, LPTSTR rest
)
1244 DWORD dwFlags
= DIR_NEW
| DIR_FOUR
;
1246 TCHAR szPath
[MAX_PATH
];
1247 TCHAR szFilespec
[MAX_PATH
];
1252 recurse_dir_cnt
= 0L;
1253 recurse_file_cnt
= 0L;
1254 recurse_bytes
.QuadPart
= 0;
1256 /* read the parameters from the DIRCMD environment variable */
1257 if (GetEnvironmentVariable (_T("DIRCMD"), dircmd
, 256))
1259 if (!DirReadParam (dircmd
, ¶m
, &dwFlags
))
1263 /* read the parameters */
1264 if (!DirReadParam (rest
, ¶m
, &dwFlags
))
1267 /* default to current directory */
1271 /* parse the directory info */
1272 if (DirParsePathspec (param
, szPath
, szFilespec
))
1275 if (dwFlags
& DIR_RECURSE
)
1277 if (IncLine (&nLine
, dwFlags
))
1279 if (DirRecurse (szPath
, szFilespec
, &nLine
, dwFlags
))
1284 /* print the header */
1285 if (!PrintDirectoryHeader (szPath
, &nLine
, dwFlags
))
1288 if (DirList (szPath
, szFilespec
, &nLine
, dwFlags
))