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'));
760 ConOutPrintf (_T(" %I64u byte%c\n"),
761 bytes.QuadPart, bytes.QuadPart == 1 ? _T(' ') : _T('s'));
763 if (IncLine (pLine, dwFlags))
766 /* Print number of dirs and bytes free */
767 ConvertULong (ulDirs, buffer, sizeof(buffer));
768 ConOutPrintf (_T(" %6s Dir%c"),
769 buffer, ulDirs == 1 ? _T(' ') : _T('s'));
771 if (!(dwFlags & DIR_RECURSE))
773 szRoot[0] = szPath[0];
774 GetUserDiskFreeSpace(szRoot, &uliFree);
775 ConvertULargeInteger (uliFree, buffer, sizeof(buffer));
776 ConOutPrintf (_T(" %15s bytes free\n"), buffer);
779 if (IncLine (pLine, dwFlags))
789 * list the files in the directory
792 DirList (LPTSTR szPath, LPTSTR szFilespec, LPINT pLine, DWORD dwFlags)
794 TCHAR szFullPath[MAX_PATH];
795 WIN32_FIND_DATA file;
796 ULARGE_INTEGER bytecount;
805 bytecount.QuadPart = 0;
807 _tcscpy (szFullPath, szPath);
808 if (szFullPath[_tcslen(szFullPath) - 1] != _T('\\'))
809 _tcscat (szFullPath, _T("\\"));
810 _tcscat (szFullPath, szFilespec);
812 hFile = FindFirstFile (szFullPath, &file);
813 if (hFile == INVALID_HANDLE_VALUE)
815 /* Don't want to print anything if scanning recursively
818 if ((dwFlags & DIR_RECURSE) == 0)
821 error_file_not_found ();
822 if (IncLine (pLine, dwFlags))
830 /* moved down here because if we are recursively searching and
831 * don't find any files, we don't want just to print
832 * Directory of C:\SOMEDIR
836 if ((dwFlags & DIR_BARE) == 0)
838 ConOutPrintf (_T(" Directory of %s\n"), szPath);
839 if (IncLine (pLine, dwFlags))
841 ConOutPrintf (_T("\n"));
842 if (IncLine (pLine, dwFlags))
846 /* For counting columns of output */
851 /* next file, if user doesn't want all files */
852 if (!(dwFlags & DIR_ALL) &&
853 ((file.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) ||
854 (file.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)))
857 if (dwFlags & DIR_LWR)
859 _tcslwr (file.cAlternateFileName);
862 if (dwFlags & DIR_WIDE && (dwFlags & DIR_BARE) == 0)
864 ULARGE_INTEGER uliSize;
866 if (file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
868 if (file.cAlternateFileName[0] == _T('\0'))
869 _stprintf (buffer, _T("[%s]"), file.cFileName);
871 _stprintf (buffer, _T("[%s]"), file.cAlternateFileName);
876 if (file.cAlternateFileName[0] == _T('\0'))
877 _stprintf (buffer, _T("%s"), file.cFileName);
879 _stprintf (buffer, _T("%s"), file.cAlternateFileName);
883 ConOutPrintf (_T("%-15s"), buffer);
887 /* output 5 columns */
888 ConOutPrintf (_T("\n"));
889 if (IncLine (pLine, dwFlags))
894 uliSize.LowPart = file.nFileSizeLow;
895 uliSize.HighPart = file.nFileSizeHigh;
896 bytecount.QuadPart += uliSize.QuadPart;
898 else if (dwFlags & DIR_BARE)
900 ULARGE_INTEGER uliSize;
902 if (_tcscmp (file.cFileName, _T(".")) == 0 ||
903 _tcscmp (file.cFileName, _T("..")) == 0)
906 if (dwFlags & DIR_RECURSE)
910 _tcscpy (dir, szPath);
911 _tcscat (dir, _T("\\"));
912 if (dwFlags & DIR_LWR)
917 ConOutPrintf (_T("%-13s\n"), file.cFileName);
918 if (file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
922 if (IncLine (pLine, dwFlags))
925 uliSize.LowPart = file.nFileSizeLow;
926 uliSize.HighPart = file.nFileSizeHigh;
927 bytecount.QuadPart += uliSize.QuadPart;
931 if (dwFlags & DIR_NEW)
933 /* print file date and time */
934 if (FileTimeToLocalFileTime (&file.ftLastWriteTime, &ft))
936 FileTimeToSystemTime (&ft, &dt);
937 PrintFileDateTime (&dt, dwFlags);
940 /* print file size */
941 if (file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
943 ConOutPrintf (_T(" <DIR> "));
948 ULARGE_INTEGER uliSize;
950 uliSize.LowPart = file.nFileSizeLow;
951 uliSize.HighPart = file.nFileSizeHigh;
953 ConvertULargeInteger (uliSize, buffer, sizeof(buffer));
954 ConOutPrintf (_T(" %20s"), buffer);
956 bytecount.QuadPart += uliSize.QuadPart;
960 /* print long filename */
961 ConOutPrintf (_T(" %s\n"), file.cFileName);
965 if (file.cFileName[0] == _T('.'))
966 ConOutPrintf (_T("%-13s "), file.cFileName);
967 else if (file.cAlternateFileName[0] == _T('\0'))
969 TCHAR szShortName[13];
972 _tcsncpy (szShortName, file.cFileName, 13);
973 ext = _tcschr (szShortName, _T('.'));
978 ConOutPrintf (_T("%-8s %-3s "), szShortName, ext);
984 ext = _tcschr (file.cAlternateFileName, _T('.'));
989 ConOutPrintf (_T("%-8s %-3s "), file.cAlternateFileName, ext);
992 /* print file size */
993 if (file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
995 ConOutPrintf ("%-14s", "<DIR>");
1000 ULARGE_INTEGER uliSize;
1002 uliSize.LowPart = file.nFileSizeLow;
1003 uliSize.HighPart = file.nFileSizeHigh;
1004 ConvertULargeInteger (uliSize, buffer, sizeof(buffer));
1005 ConOutPrintf (_T(" %10s "), buffer);
1006 bytecount.QuadPart += uliSize.QuadPart;
1010 /* print file date and time */
1011 if (FileTimeToLocalFileTime (&file.ftLastWriteTime, &ft))
1013 FileTimeToSystemTime (&ft, &dt);
1014 PrintFileDateTime (&dt, dwFlags);
1017 /* print long filename */
1018 ConOutPrintf (" %s\n", file.cFileName);
1021 if (IncLine (pLine, dwFlags))
1025 while (FindNextFile (hFile, &file));
1028 /* Rob Lake, need to make clean output */
1029 /* JPP 07/08/1998 added check for count != 0 */
1030 if ((dwFlags & DIR_WIDE) && (count != 0))
1032 ConOutPrintf (_T("\n"));
1033 if (IncLine (pLine, dwFlags))
1037 if (filecount || dircount)
1039 recurse_dir_cnt += dircount;
1040 recurse_file_cnt += filecount;
1041 recurse_bytes.QuadPart += bytecount.QuadPart;
1044 if (PrintSummary (szPath, filecount, dircount, bytecount, pLine, dwFlags))
1049 error_file_not_found ();
1058 * _Read_Dir: Actual function that does recursive listing
1061 DirRead (LPTSTR szPath, LPTSTR szFilespec, LPINT pLine, DWORD dwFlags)
1063 TCHAR szFullPath[MAX_PATH];
1064 WIN32_FIND_DATA file;
1067 _tcscpy (szFullPath, szPath);
1068 if (szFullPath[_tcslen (szFullPath) - 1] != _T('\\'))
1069 _tcscat (szFullPath, _T("\\"));
1070 _tcscat (szFullPath, szFilespec);
1072 hFile = FindFirstFile (szFullPath, &file);
1073 if (hFile == INVALID_HANDLE_VALUE)
1078 /* don't list "." and ".." */
1079 if (_tcscmp (file.cFileName, _T(".")) == 0 ||
1080 _tcscmp (file.cFileName, _T("..")) == 0)
1083 if (file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1085 _tcscpy (szFullPath, szPath);
1086 if (szFullPath[_tcslen (szFullPath) - 1] != _T('\\'))
1087 _tcscat (szFullPath, _T("\\"));
1088 _tcscat (szFullPath, file.cFileName);
1090 if (DirList (szFullPath, szFilespec, pLine, dwFlags))
1096 if ((dwFlags & DIR_BARE) == 0)
1098 ConOutPrintf ("\n");
1099 if (IncLine (pLine, dwFlags) != 0)
1101 ConOutPrintf ("\n");
1102 if (IncLine (pLine, dwFlags) != 0)
1106 if (DirRead (szFullPath, szFilespec, pLine, dwFlags) == 1)
1113 while (FindNextFile (hFile, &file));
1115 if (!FindClose (hFile))
1123 * do_recurse: Sets up for recursive directory listing
1126 DirRecurse (LPTSTR szPath, LPTSTR szSpec, LPINT pLine, DWORD dwFlags)
1128 if (!PrintDirectoryHeader (szPath, pLine, dwFlags))
1131 if (DirList (szPath, szSpec, pLine, dwFlags))
1134 if ((dwFlags & DIR_BARE) == 0)
1136 ConOutPrintf (_T("\n"));
1137 if (IncLine (pLine, dwFlags))
1141 if (DirRead (szPath, szSpec, pLine, dwFlags))
1144 if ((dwFlags & DIR_BARE) == 0)
1145 ConOutPrintf (_T("Total files listed:\n"));
1147 dwFlags &= ~DIR_RECURSE;
1149 if (PrintSummary (szPath, recurse_file_cnt,
1150 recurse_dir_cnt, recurse_bytes, pLine, dwFlags))
1153 if ((dwFlags & DIR_BARE) == 0)
1155 ConOutPrintf (_T("\n"));
1156 if (IncLine (pLine, dwFlags))
1167 * internal dir command
1169 INT CommandDir (LPTSTR first, LPTSTR rest)
1171 DWORD dwFlags = DIR_NEW | DIR_FOUR;
1173 TCHAR szPath[MAX_PATH];
1174 TCHAR szFilespec[MAX_PATH];
1179 recurse_dir_cnt = 0L;
1180 recurse_file_cnt = 0L;
1181 recurse_bytes.QuadPart = 0;
1183 /* read the parameters from the DIRCMD environment variable */
1184 if (GetEnvironmentVariable (_T("DIRCMD"), dircmd, 256))
1186 if (!DirReadParam (dircmd, ¶m, &dwFlags))
1190 /* read the parameters */
1191 if (!DirReadParam (rest, ¶m, &dwFlags))
1194 /* default to current directory */
1198 /* parse the directory info */
1199 if (DirParsePathspec (param, szPath, szFilespec))
1202 if (dwFlags & DIR_RECURSE)
1204 if (IncLine (&nLine, dwFlags))
1206 if (DirRecurse (szPath, szFilespec, &nLine, dwFlags))
1211 /* print the header */
1212 if (!PrintDirectoryHeader (szPath, &nLine, dwFlags))
1215 if (DirList (szPath, szFilespec, &nLine, dwFlags))