1 /* $Id: dir.c,v 1.2 2003/05/09 21:58:05 ekohl Exp $
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
120 #ifdef INCLUDE_CMD_DIR
132 (*PGETFREEDISKSPACEEX
)(LPCTSTR
, PULARGE_INTEGER
, PULARGE_INTEGER
, PULARGE_INTEGER
);
135 /* flag definitions */
138 DIR_RECURSE
= 0x0001,
140 DIR_WIDE
= 0x0004, /* Rob Lake */
141 DIR_BARE
= 0x0008, /* Rob Lake */
142 DIR_ALL
= 0x0010, /* Rob Lake */
143 DIR_LWR
= 0x0020, /* Rob Lake */
144 DIR_SORT
= 0x0040, /* /O sort */
145 DIR_NEW
= 0x0080, /* /N new style */
146 DIR_FOUR
= 0x0100 /* /4 four digit year */
150 /* Globally save the # of dirs, files and bytes,
151 * probabaly later pass them to functions. Rob Lake */
152 static ULONG recurse_dir_cnt
;
153 static ULONG recurse_file_cnt
;
154 static ULARGE_INTEGER recurse_bytes
;
160 * displays help screen for dir
163 static VOID
Help (VOID
)
165 ConOutPuts(_T("Displays a list of files and subdirectories in a directory.\n"
167 "DIR [drive:][path][filename] [/A] [/B] [/L] [/N] [/S] [/P] [/W] [/4]\n"
169 " [drive:][path][filename]\n"
170 " Specifies drive, directory, and/or files to list.\n"
172 " /A Displays files with HIDDEN SYSTEM attributes\n"
173 " default is ARCHIVE and READ ONLY\n"
174 " /B Uses bare format (no heading information or summary).\n"
175 " /L Uses lowercase.\n"
176 " /N New long list format where filenames are on the far right.\n"
177 " /S Displays files in specified directory and all subdirectories\n"
178 " /P Pauses after each screen full\n"
179 " /W Prints in wide format\n"
180 " /4 Display four digit years.\n"
182 "Switches may be present in the DIRCMD environment variable. Use\n"
183 "of the - (hyphen) can turn off defined swtiches. Ex. /-W would\n"
184 "turn off printing in wide format.\n"
192 * read the parameters from the command line
195 DirReadParam (LPTSTR line
, LPTSTR
*param
, LPDWORD lpFlags
)
204 /* scan the command line, processing switches */
208 if (*line
== _T('/') || slash
)
213 if (*line
== _T('-'))
216 if (_totupper (*line
) == _T('S'))
217 *lpFlags
&= ~DIR_RECURSE
;
218 else if (_totupper (*line
) == _T('P'))
219 *lpFlags
&= ~DIR_PAGE
;
220 else if (_totupper (*line
) == _T('W'))
221 *lpFlags
&= ~DIR_WIDE
;
222 else if (_totupper (*line
) == _T('B'))
223 *lpFlags
&= ~DIR_BARE
;
224 else if (_totupper (*line
) == _T('A'))
225 *lpFlags
&= ~DIR_ALL
;
226 else if (_totupper (*line
) == _T('L'))
227 *lpFlags
&= ~DIR_LWR
;
228 else if (_totupper (*line
) == _T('N'))
229 *lpFlags
&= ~DIR_NEW
;
230 else if (_totupper (*line
) == _T('O'))
231 *lpFlags
&= ~DIR_SORT
;
232 else if (_totupper (*line
) == _T('4'))
233 *lpFlags
&= ~DIR_FOUR
;
236 error_invalid_switch ((TCHAR
)_totupper (*line
));
244 if (_totupper (*line
) == _T('S'))
245 *lpFlags
|= DIR_RECURSE
;
246 else if (_totupper (*line
) == _T('P'))
247 *lpFlags
|= DIR_PAGE
;
248 else if (_totupper (*line
) == _T('W'))
249 *lpFlags
|= DIR_WIDE
;
250 else if (_totupper (*line
) == _T('B'))
251 *lpFlags
|= DIR_BARE
;
252 else if (_totupper (*line
) == _T('A'))
254 else if (_totupper (*line
) == _T('L'))
256 else if (_totupper (*line
) == _T('N'))
258 else if (_totupper (*line
) == _T('O'))
259 *lpFlags
|= DIR_SORT
;
260 else if (_totupper (*line
) == _T('4'))
261 *lpFlags
|= DIR_FOUR
;
262 else if (*line
== _T('?'))
269 error_invalid_switch ((TCHAR
)_totupper (*line
));
277 /* process parameter */
278 if (!_istspace (*line
))
282 error_too_many_parameters (*param
);
288 /* skip to end of line or next whitespace or next / */
289 while (*line
&& !_istspace (*line
) && *line
!= _T('/'))
292 /* if end of line, return */
296 /* if parameter, remember to process it later */
297 if (*line
== _T('/'))
309 error_invalid_switch ((TCHAR
)_totupper (*line
));
320 * extend the filespec, possibly adding wildcards
323 ExtendFilespec (LPTSTR file
)
330 /* if no file spec, change to "*.*" */
331 if (*file
== _T('\0'))
333 _tcscpy (file
, _T("*.*"));
337 /* if starts with . add * in front */
338 if (*file
== _T('.'))
340 memmove (&file
[1], &file
[0], (_tcslen (file
) + 1) * sizeof(TCHAR
));
345 if (!_tcschr (file
, _T('.')))
347 _tcscat (file
, _T(".*"));
351 /* if last character is '.' add '*' */
352 len
= _tcslen (file
);
353 if (file
[len
- 1] == _T('.'))
355 _tcscat (file
, _T("*"));
364 * split the pathspec into drive, directory, and filespec
367 DirParsePathspec (LPTSTR szPathspec
, LPTSTR szPath
, LPTSTR szFilespec
)
369 TCHAR szOrigPath
[MAX_PATH
];
373 BOOL bWildcards
= FALSE
;
375 GetCurrentDirectory (MAX_PATH
, szOrigPath
);
377 /* get the drive and change to it */
378 if (szPathspec
[1] == _T(':'))
380 TCHAR szRootPath
[] = _T("A:");
382 szRootPath
[0] = szPathspec
[0];
383 start
= szPathspec
+ 2;
384 SetCurrentDirectory (szRootPath
);
392 /* check for wildcards */
393 for (i
= 0; szPathspec
[i
]; i
++)
395 if (szPathspec
[i
] == _T('*') || szPathspec
[i
] == _T('?'))
399 /* check if this spec is a directory */
402 if (SetCurrentDirectory (szPathspec
))
404 _tcscpy (szFilespec
, _T("*.*"));
406 if (!GetCurrentDirectory (MAX_PATH
, szPath
))
408 szFilespec
[0] = _T('\0');
409 SetCurrentDirectory (szOrigPath
);
410 error_out_of_memory();
414 SetCurrentDirectory (szOrigPath
);
419 /* find the file spec */
420 tmp
= _tcsrchr (start
, _T('\\'));
422 /* if no path is specified */
425 _tcscpy (szFilespec
, start
);
426 ExtendFilespec (szFilespec
);
427 if (!GetCurrentDirectory (MAX_PATH
, szPath
))
429 szFilespec
[0] = _T('\0');
430 SetCurrentDirectory (szOrigPath
);
431 error_out_of_memory();
435 SetCurrentDirectory (szOrigPath
);
439 /* get the filename */
440 _tcscpy (szFilespec
, tmp
+1);
441 ExtendFilespec (szFilespec
);
445 /* change to this directory and get its full name */
446 if (!SetCurrentDirectory (start
))
449 szFilespec
[0] = _T('\0');
450 SetCurrentDirectory (szOrigPath
);
451 error_path_not_found ();
455 if (!GetCurrentDirectory (MAX_PATH
, szPath
))
458 szFilespec
[0] = _T('\0');
459 SetCurrentDirectory (szOrigPath
);
460 error_out_of_memory ();
466 SetCurrentDirectory (szOrigPath
);
475 * increment our line if paginating, display message at end of screen
478 IncLine (LPINT pLine
, DWORD dwFlags
)
480 if (!(dwFlags
& DIR_PAGE
))
485 if (*pLine
>= (int)maxy
- 2)
488 return (PagePrompt () == PROMPT_BREAK
);
496 * PrintDirectoryHeader
498 * print the header for the dir command
501 PrintDirectoryHeader (LPTSTR szPath
, LPINT pLine
, DWORD dwFlags
)
503 TCHAR szRootName
[MAX_PATH
];
508 if (dwFlags
& DIR_BARE
)
511 /* build usable root path */
512 if (szPath
[1] == _T(':') && szPath
[2] == _T('\\'))
515 szRootName
[0] = szPath
[0];
516 szRootName
[1] = _T(':');
517 szRootName
[2] = _T('\\');
520 else if (szPath
[0] == _T('\\') && szPath
[1] == _T('\\'))
523 p
= _tcschr(&szPath
[2], _T('\\'));
526 error_invalid_drive();
529 p
= _tcschr(p
+1, _T('\\'));
532 _tcscpy(szRootName
, szPath
);
533 _tcscat(szRootName
, _T("\\"));
538 _tcscpy(szRootName
, szPath
);
539 _tcscat(szRootName
, _T("\\"));
545 error_invalid_drive();
549 /* get the media ID of the drive */
550 if (!GetVolumeInformation(szRootName
, szVolName
, 80, &dwSerialNr
,
551 NULL
, NULL
, NULL
, 0))
553 error_invalid_drive();
557 /* print drive info */
558 ConOutPrintf(_T(" Volume in drive %c"), szRootName
[0]);
560 if (szVolName
[0] != _T('\0'))
561 ConOutPrintf(_T(" is %s\n"), szVolName
);
563 ConOutPrintf(_T(" has no label\n"));
565 if (IncLine(pLine
, dwFlags
))
568 /* print the volume serial number if the return was successful */
569 ConOutPrintf(_T(" Volume Serial Number is %04X-%04X\n"),
572 if (IncLine(pLine
, dwFlags
))
582 * insert commas into a number
585 ConvertULong (ULONG num
, LPTSTR des
, INT len
)
602 if (((c
+ 1) % (nNumberGroups
+ 1)) == 0)
603 temp
[30 - c
++] = cThousandSeparator
;
604 temp
[30 - c
++] = (TCHAR
)(num
% 10) + _T('0');
608 for (n
= 0; n
<= c
; n
++)
609 des
[n
] = temp
[31 - c
+ n
];
617 ConvertULargeInteger (ULARGE_INTEGER num
, LPTSTR des
, INT len
)
623 if (num
.QuadPart
== 0)
632 while (num
.QuadPart
> 0)
634 if (((c
+ 1) % (nNumberGroups
+ 1)) == 0)
635 temp
[30 - c
++] = cThousandSeparator
;
636 temp
[30 - c
++] = (TCHAR
)(num
.QuadPart
% 10) + _T('0');
640 for (n
= 0; n
<= c
; n
++)
641 des
[n
] = temp
[31 - c
+ n
];
649 PrintFileDateTime (LPSYSTEMTIME dt
, DWORD dwFlags
)
651 WORD wYear
= (dwFlags
& DIR_FOUR
) ? dt
->wYear
: dt
->wYear
%100;
657 ConOutPrintf (_T("%.2d%c%.2d%c%d"),
658 dt
->wMonth
, cDateSeparator
, dt
->wDay
, cDateSeparator
, wYear
);
662 ConOutPrintf (_T("%.2d%c%.2d%c%d"),
663 dt
->wDay
, cDateSeparator
, dt
->wMonth
, cDateSeparator
, wYear
);
667 ConOutPrintf (_T("%d%c%.2d%c%.2d"),
668 wYear
, cDateSeparator
, dt
->wMonth
, cDateSeparator
, dt
->wDay
);
674 case 0: /* 12 hour format */
676 ConOutPrintf (_T(" %2d%c%.2u%c"),
677 (dt
->wHour
== 0 ? 12 : (dt
->wHour
<= 12 ? dt
->wHour
: dt
->wHour
- 12)),
679 dt
->wMinute
, (dt
->wHour
<= 11 ? 'a' : 'p'));
682 case 1: /* 24 hour format */
683 ConOutPrintf (_T(" %2d%c%.2u"),
684 dt
->wHour
, cTimeSeparator
, dt
->wMinute
);
691 GetUserDiskFreeSpace(LPCTSTR lpRoot
,
692 PULARGE_INTEGER lpFreeSpace
)
694 PGETFREEDISKSPACEEX pGetFreeDiskSpaceEx
;
701 lpFreeSpace
->QuadPart
= 0;
703 hInstance
= LoadLibrary(_T("KERNEL32"));
704 if (hInstance
!= NULL
)
707 pGetFreeDiskSpaceEx
= GetProcAddress(hInstance
,
708 "GetDiskFreeSpaceExA");
710 pGetFreeDiskSpaceEx
= GetProcAddress(hInstance
,
711 "GetDiskFreeSpaceExW");
713 if (pGetFreeDiskSpaceEx
!= NULL
)
715 if (pGetFreeDiskSpaceEx(lpRoot
, lpFreeSpace
, NULL
, NULL
) == TRUE
)
718 FreeLibrary(hInstance
);
721 GetDiskFreeSpace(lpRoot
,
727 lpFreeSpace
->QuadPart
= dwSecPerCl
* dwBytPerSec
* dwFreeCl
;
732 * print_summary: prints dir summary
733 * Added by Rob Lake 06/17/98 to compact code
734 * Just copied Tim's Code and patched it a bit
738 PrintSummary(LPTSTR szPath
,
741 ULARGE_INTEGER bytes
,
746 ULARGE_INTEGER uliFree
;
747 TCHAR szRoot
[] = _T("A:\\");
749 if (dwFlags
& DIR_BARE
)
752 /* Print number of files and bytes */
753 ConvertULong (ulFiles
, buffer
, sizeof(buffer
));
754 ConOutPrintf (_T(" %6s File%c"),
755 buffer
, ulFiles
== 1 ? _T(' ') : _T('s'));
757 ConvertULargeInteger (bytes
, buffer
, sizeof(buffer
));
758 ConOutPrintf (_T(" %15s byte%c\n"),
759 buffer
, bytes
.QuadPart
== 1 ? _T(' ') : _T('s'));
761 if (IncLine (pLine
, dwFlags
))
764 /* Print number of dirs and bytes free */
765 ConvertULong (ulDirs
, buffer
, sizeof(buffer
));
766 ConOutPrintf (_T(" %6s Dir%c"),
767 buffer
, ulDirs
== 1 ? _T(' ') : _T('s'));
769 if (!(dwFlags
& DIR_RECURSE
))
771 szRoot
[0] = szPath
[0];
772 GetUserDiskFreeSpace(szRoot
, &uliFree
);
773 ConvertULargeInteger (uliFree
, buffer
, sizeof(buffer
));
774 ConOutPrintf (_T(" %15s bytes free\n"), buffer
);
777 if (IncLine (pLine
, dwFlags
))
787 * list the files in the directory
790 DirList (LPTSTR szPath
, LPTSTR szFilespec
, LPINT pLine
, DWORD dwFlags
)
792 TCHAR szFullPath
[MAX_PATH
];
793 WIN32_FIND_DATA file
;
794 ULARGE_INTEGER bytecount
;
803 bytecount
.QuadPart
= 0;
805 _tcscpy (szFullPath
, szPath
);
806 if (szFullPath
[_tcslen(szFullPath
) - 1] != _T('\\'))
807 _tcscat (szFullPath
, _T("\\"));
808 _tcscat (szFullPath
, szFilespec
);
810 hFile
= FindFirstFile (szFullPath
, &file
);
811 if (hFile
== INVALID_HANDLE_VALUE
)
813 /* Don't want to print anything if scanning recursively
816 if ((dwFlags
& DIR_RECURSE
) == 0)
819 error_file_not_found ();
820 if (IncLine (pLine
, dwFlags
))
828 /* moved down here because if we are recursively searching and
829 * don't find any files, we don't want just to print
830 * Directory of C:\SOMEDIR
834 if ((dwFlags
& DIR_BARE
) == 0)
836 ConOutPrintf (_T(" Directory of %s\n"), szPath
);
837 if (IncLine (pLine
, dwFlags
))
839 ConOutPrintf (_T("\n"));
840 if (IncLine (pLine
, dwFlags
))
844 /* For counting columns of output */
849 /* next file, if user doesn't want all files */
850 if (!(dwFlags
& DIR_ALL
) &&
851 ((file
.dwFileAttributes
& FILE_ATTRIBUTE_HIDDEN
) ||
852 (file
.dwFileAttributes
& FILE_ATTRIBUTE_SYSTEM
)))
855 if (dwFlags
& DIR_LWR
)
857 _tcslwr (file
.cAlternateFileName
);
860 if (dwFlags
& DIR_WIDE
&& (dwFlags
& DIR_BARE
) == 0)
862 ULARGE_INTEGER uliSize
;
864 if (file
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
866 if (file
.cAlternateFileName
[0] == _T('\0'))
867 _stprintf (buffer
, _T("[%s]"), file
.cFileName
);
869 _stprintf (buffer
, _T("[%s]"), file
.cAlternateFileName
);
874 if (file
.cAlternateFileName
[0] == _T('\0'))
875 _stprintf (buffer
, _T("%s"), file
.cFileName
);
877 _stprintf (buffer
, _T("%s"), file
.cAlternateFileName
);
881 ConOutPrintf (_T("%-15s"), buffer
);
885 /* output 5 columns */
886 ConOutPrintf (_T("\n"));
887 if (IncLine (pLine
, dwFlags
))
892 uliSize
.LowPart
= file
.nFileSizeLow
;
893 uliSize
.HighPart
= file
.nFileSizeHigh
;
894 bytecount
.QuadPart
+= uliSize
.QuadPart
;
896 else if (dwFlags
& DIR_BARE
)
898 ULARGE_INTEGER uliSize
;
900 if (_tcscmp (file
.cFileName
, _T(".")) == 0 ||
901 _tcscmp (file
.cFileName
, _T("..")) == 0)
904 if (dwFlags
& DIR_RECURSE
)
908 _tcscpy (dir
, szPath
);
909 _tcscat (dir
, _T("\\"));
910 if (dwFlags
& DIR_LWR
)
915 ConOutPrintf (_T("%-13s\n"), file
.cFileName
);
916 if (file
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
920 if (IncLine (pLine
, dwFlags
))
923 uliSize
.LowPart
= file
.nFileSizeLow
;
924 uliSize
.HighPart
= file
.nFileSizeHigh
;
925 bytecount
.QuadPart
+= uliSize
.QuadPart
;
929 if (dwFlags
& DIR_NEW
)
931 /* print file date and time */
932 if (FileTimeToLocalFileTime (&file
.ftLastWriteTime
, &ft
))
934 FileTimeToSystemTime (&ft
, &dt
);
935 PrintFileDateTime (&dt
, dwFlags
);
938 /* print file size */
939 if (file
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
941 ConOutPrintf (_T(" <DIR> "));
946 ULARGE_INTEGER uliSize
;
948 uliSize
.LowPart
= file
.nFileSizeLow
;
949 uliSize
.HighPart
= file
.nFileSizeHigh
;
951 ConvertULargeInteger (uliSize
, buffer
, sizeof(buffer
));
952 ConOutPrintf (_T(" %20s"), buffer
);
954 bytecount
.QuadPart
+= uliSize
.QuadPart
;
958 /* print long filename */
959 ConOutPrintf (_T(" %s\n"), file
.cFileName
);
963 if (file
.cFileName
[0] == _T('.'))
964 ConOutPrintf (_T("%-13s "), file
.cFileName
);
965 else if (file
.cAlternateFileName
[0] == _T('\0'))
967 TCHAR szShortName
[13];
970 _tcsncpy (szShortName
, file
.cFileName
, 13);
971 ext
= _tcschr (szShortName
, _T('.'));
976 ConOutPrintf (_T("%-8s %-3s "), szShortName
, ext
);
982 ext
= _tcschr (file
.cAlternateFileName
, _T('.'));
987 ConOutPrintf (_T("%-8s %-3s "), file
.cAlternateFileName
, ext
);
990 /* print file size */
991 if (file
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
993 ConOutPrintf ("%-14s", "<DIR>");
998 ULARGE_INTEGER uliSize
;
1000 uliSize
.LowPart
= file
.nFileSizeLow
;
1001 uliSize
.HighPart
= file
.nFileSizeHigh
;
1002 ConvertULargeInteger (uliSize
, buffer
, sizeof(buffer
));
1003 ConOutPrintf (_T(" %10s "), buffer
);
1004 bytecount
.QuadPart
+= uliSize
.QuadPart
;
1008 /* print file date and time */
1009 if (FileTimeToLocalFileTime (&file
.ftLastWriteTime
, &ft
))
1011 FileTimeToSystemTime (&ft
, &dt
);
1012 PrintFileDateTime (&dt
, dwFlags
);
1015 /* print long filename */
1016 ConOutPrintf (" %s\n", file
.cFileName
);
1019 if (IncLine (pLine
, dwFlags
))
1023 while (FindNextFile (hFile
, &file
));
1026 /* Rob Lake, need to make clean output */
1027 /* JPP 07/08/1998 added check for count != 0 */
1028 if ((dwFlags
& DIR_WIDE
) && (count
!= 0))
1030 ConOutPrintf (_T("\n"));
1031 if (IncLine (pLine
, dwFlags
))
1035 if (filecount
|| dircount
)
1037 recurse_dir_cnt
+= dircount
;
1038 recurse_file_cnt
+= filecount
;
1039 recurse_bytes
.QuadPart
+= bytecount
.QuadPart
;
1042 if (PrintSummary (szPath
, filecount
, dircount
, bytecount
, pLine
, dwFlags
))
1047 error_file_not_found ();
1056 * _Read_Dir: Actual function that does recursive listing
1059 DirRead (LPTSTR szPath
, LPTSTR szFilespec
, LPINT pLine
, DWORD dwFlags
)
1061 TCHAR szFullPath
[MAX_PATH
];
1062 WIN32_FIND_DATA file
;
1065 _tcscpy (szFullPath
, szPath
);
1066 if (szFullPath
[_tcslen (szFullPath
) - 1] != _T('\\'))
1067 _tcscat (szFullPath
, _T("\\"));
1068 _tcscat (szFullPath
, szFilespec
);
1070 hFile
= FindFirstFile (szFullPath
, &file
);
1071 if (hFile
== INVALID_HANDLE_VALUE
)
1076 /* don't list "." and ".." */
1077 if (_tcscmp (file
.cFileName
, _T(".")) == 0 ||
1078 _tcscmp (file
.cFileName
, _T("..")) == 0)
1081 if (file
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
1083 _tcscpy (szFullPath
, szPath
);
1084 if (szFullPath
[_tcslen (szFullPath
) - 1] != _T('\\'))
1085 _tcscat (szFullPath
, _T("\\"));
1086 _tcscat (szFullPath
, file
.cFileName
);
1088 if (DirList (szFullPath
, szFilespec
, pLine
, dwFlags
))
1094 if ((dwFlags
& DIR_BARE
) == 0)
1096 ConOutPrintf ("\n");
1097 if (IncLine (pLine
, dwFlags
) != 0)
1099 ConOutPrintf ("\n");
1100 if (IncLine (pLine
, dwFlags
) != 0)
1104 if (DirRead (szFullPath
, szFilespec
, pLine
, dwFlags
) == 1)
1111 while (FindNextFile (hFile
, &file
));
1113 if (!FindClose (hFile
))
1121 * do_recurse: Sets up for recursive directory listing
1124 DirRecurse (LPTSTR szPath
, LPTSTR szSpec
, LPINT pLine
, DWORD dwFlags
)
1126 if (!PrintDirectoryHeader (szPath
, pLine
, dwFlags
))
1129 if (DirList (szPath
, szSpec
, pLine
, dwFlags
))
1132 if ((dwFlags
& DIR_BARE
) == 0)
1134 ConOutPrintf (_T("\n"));
1135 if (IncLine (pLine
, dwFlags
))
1139 if (DirRead (szPath
, szSpec
, pLine
, dwFlags
))
1142 if ((dwFlags
& DIR_BARE
) == 0)
1143 ConOutPrintf (_T("Total files listed:\n"));
1145 dwFlags
&= ~DIR_RECURSE
;
1147 if (PrintSummary (szPath
, recurse_file_cnt
,
1148 recurse_dir_cnt
, recurse_bytes
, pLine
, dwFlags
))
1151 if ((dwFlags
& DIR_BARE
) == 0)
1153 ConOutPrintf (_T("\n"));
1154 if (IncLine (pLine
, dwFlags
))
1165 * internal dir command
1167 INT
CommandDir (LPTSTR first
, LPTSTR rest
)
1169 DWORD dwFlags
= DIR_NEW
| DIR_FOUR
;
1171 TCHAR szPath
[MAX_PATH
];
1172 TCHAR szFilespec
[MAX_PATH
];
1177 recurse_dir_cnt
= 0L;
1178 recurse_file_cnt
= 0L;
1179 recurse_bytes
.QuadPart
= 0;
1181 /* read the parameters from the DIRCMD environment variable */
1182 if (GetEnvironmentVariable (_T("DIRCMD"), dircmd
, 256))
1184 if (!DirReadParam (dircmd
, ¶m
, &dwFlags
))
1188 /* read the parameters */
1189 if (!DirReadParam (rest
, ¶m
, &dwFlags
))
1192 /* default to current directory */
1196 /* parse the directory info */
1197 if (DirParsePathspec (param
, szPath
, szFilespec
))
1200 if (dwFlags
& DIR_RECURSE
)
1202 if (IncLine (&nLine
, dwFlags
))
1204 if (DirRecurse (szPath
, szFilespec
, &nLine
, dwFlags
))
1209 /* print the header */
1210 if (!PrintDirectoryHeader (szPath
, &nLine
, dwFlags
))
1213 if (DirList (szPath
, szFilespec
, &nLine
, dwFlags
))