2 * DIR.C - dir internal command.
7 * 01/29/97 (Tim Norman)
10 * 06/13/97 (Tim Norman)
13 * 07/12/97 (Tim Norman)
14 * Fixed bug that caused the root directory to be unlistable
16 * 07/12/97 (Marc Desrochers)
17 * Changed to use maxx, maxy instead of findxy()
20 * Added compatibility for /w in dir
23 * Compatibility for dir/s started
24 * Tested that program finds directories off root fine
27 * do_recurse saves the cwd and also stores it in Root
28 * build_tree adds the cwd to the beginning of its' entries
29 * Program runs fine, added print_tree -- works fine.. as EXE,
30 * program won't work properly as COM.
33 * Found problem that caused COM not to work
37 * added free mem routine
40 * debugged the free mem routine
41 * debugged whole thing some more
43 * ReadDir stores Root name and _Read_Dir does the hard work
44 * PrintDir prints Root and _Print_Dir does the hard work
45 * KillDir kills Root _after_ _Kill_Dir does the hard work
46 * Integrated program into DIR.C(this file) and made some same
50 * Cleaned up code a bit, added comments
53 * Added error checking to my previously added routines
56 * Rewrote recursive functions, again! Most other recursive
57 * functions are now obsolete -- ReadDir, PrintDir, _Print_Dir,
58 * KillDir and _Kill_Dir. do_recurse does what PrintDir did
59 * and _Read_Dir did what it did before along with what _Print_Dir
60 * did. Makes /s a lot faster!
61 * Reports 2 more files/dirs that MS-DOS actually reports
62 * when used in root directory(is this because dir defaults
63 * to look for read only files?)
64 * Added support for /b, /a and /l
65 * Made error message similar to DOS error messages
69 * Added check for /-(switch) to turn off previously defined
71 * Added ability to check for DIRCMD in environment and
76 * Now can dir *.ext/X, no spaces!
79 * error message now found in command.h
81 * 07/08/1998 (John P. Price)
82 * removed extra returns; closer to MSDOS
83 * fixed wide display so that an extra return is not displayed
84 * when there is five filenames in the last line.
87 * Changed error messages
89 * 27-Jul-1998 (John P Price <linux-guru@gcfl.net>)
90 * added config.h include
93 * 04-Dec-1998 (Eric Kohl)
94 * Converted source code to Win32, except recursive dir ("dir /s").
96 * 10-Dec-1998 (Eric Kohl)
97 * Fixed recursive dir ("dir /s").
99 * 14-Dec-1998 (Eric Kohl)
100 * Converted to Win32 directory functions and
101 * fixed some output bugs. There are still some more ;)
103 * 10-Jan-1999 (Eric Kohl)
104 * Added "/N" and "/4" options, "/O" is a dummy.
105 * Added locale support.
107 * 20-Jan-1999 (Eric Kohl)
110 * 01-Mar-1999 (Eric Kohl)
111 * Replaced all runtime io functions by their Win32 counterparts.
113 * 23-Feb-2001 (Carl Nettelblad <cnettel@hem.passagen.se>)
114 * dir /s now works in deeper trees
116 * 28-Jan-2004 (Michael Fritscher <michael@fritscher.net>)
117 * Fix for /p, so it is working under Windows in GUI-mode, too.
119 * 30-Apr-2004 (Filip Navara <xnavara@volny.cz>)
120 * Fix /w to print long names.
122 * 27-Feb-2005 (Konstantinos Paliouras <squarious@gmail.com>)
123 * Implemented all the switches that were missing, and made
124 * the ros dir very similar to windows dir. Major part of
125 * the code is rewritten. /p is removed, to be rewriten in
128 * 1-Jul-2004 (Brandon Turner <turnerb7@msu.edu>)
129 * Added /p back in using ConOutPrintfPaging
131 * 3-feb-2007 (Paolo Devoti devotip at gmail)
132 * Removed variables formerly in use to handle pagination
133 * Pagination belongs to ConOutPrintfPaging
134 * Removed already commented out code of old pagination
139 #ifdef INCLUDE_CMD_DIR
143 /* Time Field enumeration */
148 TF_LASTACCESSEDDATE
= 2
151 /* Ordered by enumeration */
161 /* The struct for holding the switches */
162 typedef struct _DirSwitchesFlags
164 BOOL bBareFormat
; /* Bare Format */
165 BOOL bTSeperator
; /* Thousands seperator */
166 BOOL bWideList
; /* Wide list format */
167 BOOL bWideListColSort
; /* Wide list format but sorted by column */
168 BOOL bLowerCase
; /* Uses lower case */
169 BOOL bNewLongList
; /* New long list */
170 BOOL bPause
; /* Pause per page */
171 BOOL bUser
; /* Displays the owner of file */
172 BOOL bRecursive
; /* Displays files in specified directory and all sub */
173 BOOL bShortName
; /* Displays the sort name of files if exist */
174 BOOL b4Digit
; /* Four digit year */
177 DWORD dwAttribVal
; /* The desired state of attribute */
178 DWORD dwAttribMask
; /* Which attributes to check */
179 } stAttribs
; /* Displays files with this attributes only */
182 enum EOrderBy eCriteria
[3]; /* Criterias used to order by */
183 BOOL bCriteriaRev
[3]; /* If the criteria is in reversed order */
184 short sCriteriaCount
; /* The quantity of criterias */
185 } stOrderBy
; /* Ordered by criterias */
188 enum ETimeField eTimeField
; /* The time field that will be used for */
189 } stTimeField
; /* The time field to display or use for sorting */
190 } DIRSWITCHFLAGS
, *LPDIRSWITCHFLAGS
;
193 typedef struct _DIRFINDLISTNODE
195 WIN32_FIND_DATA stFindInfo
;
196 struct _DIRFINDLISTNODE
*ptrNext
;
197 } DIRFINDLISTNODE
, *PDIRFINDLISTNODE
;
201 (WINAPI
*PGETFREEDISKSPACEEX
)(LPCTSTR
, PULARGE_INTEGER
, PULARGE_INTEGER
, PULARGE_INTEGER
);
204 /* Globally save the # of dirs, files and bytes,
205 * probabaly later pass them to functions. Rob Lake */
206 static ULONG recurse_dir_cnt
;
207 static ULONG recurse_file_cnt
;
208 static ULONGLONG recurse_bytes
;
214 * displays help screen for dir
220 ConOutResPaging(TRUE
, STRING_DIR_HELP1
);
228 * Parse the parameters and switches of the command line and exports them
231 DirReadParam(LPTSTR Line
, /* [IN] The line with the parameters & switches */
232 LPTSTR
** params
, /* [OUT] The parameters after parsing */
233 LPINT entries
, /* [OUT] The number of parameters after parsing */
234 LPDIRSWITCHFLAGS lpFlags
) /* [IN/OUT] The flags after calculating switches */
236 TCHAR cCurSwitch
; /* The current switch */
237 TCHAR cCurChar
; /* Current examing character */
238 TCHAR cCurUChar
; /* Current upper examing character */
239 BOOL bNegative
; /* Negative switch */
240 BOOL bPNegative
; /* Negative switch parameter */
241 BOOL bIntoQuotes
; /* A flag showing if we are in quotes (") */
242 LPTSTR ptrStart
; /* A pointer to the first character of a parameter */
243 LPTSTR ptrEnd
; /* A pointer to the last character of a parameter */
244 BOOL bOrderByNoPar
; /* A flag to indicate /O with no switch parameter */
247 /* Initialize parameter array */
251 /* Initialize variables; */
252 cCurSwitch
= _T(' ');
256 /* We suppose that switch parameters
257 were given to avoid setting them to default
258 if the switch was not given */
259 bOrderByNoPar
= FALSE
;
261 /* Main Loop (see README_DIR.txt) */
262 /* scan the command line char per char, and we process its char */
265 /* we save current character as it is and its upper case */
267 cCurUChar
= _totupper(*Line
);
269 /* 1st section (see README_DIR.txt) */
270 /* When a switch is expecting */
271 if (cCurSwitch
== _T('/'))
273 while (*Line
== _T(' '))
276 bNegative
= (*Line
== _T('-'));
280 cCurUChar
= _totupper(*Line
);
282 if ((cCurUChar
== _T('A')) ||(cCurUChar
== _T('T')) || (cCurUChar
== _T('O')))
284 /* If positive, prepare for parameters... if negative, reset to defaults */
288 lpFlags
->stAttribs
.dwAttribVal
= 0L;
289 lpFlags
->stAttribs
.dwAttribMask
= 0L;
291 lpFlags
->stAttribs
.dwAttribMask
= FILE_ATTRIBUTE_HIDDEN
| FILE_ATTRIBUTE_SYSTEM
;
295 lpFlags
->stTimeField
.eTimeField
= TF_MODIFIEDDATE
;
298 bOrderByNoPar
= !bNegative
;
299 lpFlags
->stOrderBy
.sCriteriaCount
= 0;
305 /* Positive switch, so it can take parameters. */
306 cCurSwitch
= cCurUChar
;
308 /* Skip optional leading colon */
309 if (*Line
== _T(':'))
314 else if (cCurUChar
== _T('L'))
315 lpFlags
->bLowerCase
= ! bNegative
;
316 else if (cCurUChar
== _T('B'))
317 lpFlags
->bBareFormat
= ! bNegative
;
318 else if (cCurUChar
== _T('C'))
319 lpFlags
->bTSeperator
= ! bNegative
;
320 else if (cCurUChar
== _T('W'))
321 lpFlags
->bWideList
= ! bNegative
;
322 else if (cCurUChar
== _T('D'))
323 lpFlags
->bWideListColSort
= ! bNegative
;
324 else if (cCurUChar
== _T('N'))
325 lpFlags
->bNewLongList
= ! bNegative
;
326 else if (cCurUChar
== _T('P'))
327 lpFlags
->bPause
= ! bNegative
;
328 else if (cCurUChar
== _T('Q'))
329 lpFlags
->bUser
= ! bNegative
;
330 else if (cCurUChar
== _T('S'))
331 lpFlags
->bRecursive
= ! bNegative
;
332 else if (cCurUChar
== _T('X'))
333 lpFlags
->bShortName
= ! bNegative
;
334 else if (cCurChar
== _T('4'))
335 lpFlags
->b4Digit
= ! bNegative
;
336 else if (cCurChar
== _T('?'))
343 error_invalid_switch ((TCHAR
)_totupper (*Line
));
347 /* Make sure there's no extra characters at the end of the switch */
348 if (Line
[1] && Line
[1] != _T('/') && Line
[1] != _T(' '))
350 error_parameter_format(Line
[1]);
354 cCurSwitch
= _T(' ');
356 else if (cCurSwitch
== _T(' '))
358 /* 2nd section (see README_DIR.txt) */
359 /* We are expecting parameter or the unknown */
361 if (cCurChar
== _T('/'))
362 cCurSwitch
= _T('/');
363 else if (cCurChar
== _T(' '))
367 /* This is a file/directory name parameter. Find its end */
372 if (!bIntoQuotes
&& (*Line
== _T('/') || *Line
== _T(' ')))
374 bIntoQuotes
^= (*Line
== _T('"'));
379 /* Copy it to the entries list */
380 temp
= cmd_alloc((ptrEnd
- ptrStart
+ 1) * sizeof (TCHAR
));
383 memcpy(temp
, ptrStart
, (ptrEnd
- ptrStart
) * sizeof (TCHAR
));
384 temp
[ptrEnd
- ptrStart
] = _T('\0');
386 if(!add_entry(entries
, params
, temp
))
399 /* 3rd section (see README_DIR.txt) */
400 /* We are waiting for switch parameters */
402 /* Check if there are no more switch parameters */
403 if ((cCurChar
== _T('/')) || ( cCurChar
== _T(' ')))
405 /* Wrong desicion path, reprocess current character */
406 cCurSwitch
= _T(' ');
409 /* Process parameter switch */
412 case _T('A'): /* Switch parameters for /A (attributes filter) */
413 if(cCurChar
== _T('-'))
415 else if(cCurUChar
== _T('D'))
417 lpFlags
->stAttribs
.dwAttribMask
|= FILE_ATTRIBUTE_DIRECTORY
;
419 lpFlags
->stAttribs
.dwAttribVal
&= ~FILE_ATTRIBUTE_DIRECTORY
;
421 lpFlags
->stAttribs
.dwAttribVal
|= FILE_ATTRIBUTE_DIRECTORY
;
423 else if(cCurUChar
== _T('R'))
425 lpFlags
->stAttribs
.dwAttribMask
|= FILE_ATTRIBUTE_READONLY
;
427 lpFlags
->stAttribs
.dwAttribVal
&= ~FILE_ATTRIBUTE_READONLY
;
429 lpFlags
->stAttribs
.dwAttribVal
|= FILE_ATTRIBUTE_READONLY
;
431 else if(cCurUChar
== _T('H'))
433 lpFlags
->stAttribs
.dwAttribMask
|= FILE_ATTRIBUTE_HIDDEN
;
435 lpFlags
->stAttribs
.dwAttribVal
&= ~FILE_ATTRIBUTE_HIDDEN
;
437 lpFlags
->stAttribs
.dwAttribVal
|= FILE_ATTRIBUTE_HIDDEN
;
439 else if(cCurUChar
== _T('A'))
441 lpFlags
->stAttribs
.dwAttribMask
|= FILE_ATTRIBUTE_ARCHIVE
;
443 lpFlags
->stAttribs
.dwAttribVal
&= ~FILE_ATTRIBUTE_ARCHIVE
;
445 lpFlags
->stAttribs
.dwAttribVal
|= FILE_ATTRIBUTE_ARCHIVE
;
447 else if(cCurUChar
== _T('S'))
449 lpFlags
->stAttribs
.dwAttribMask
|= FILE_ATTRIBUTE_SYSTEM
;
451 lpFlags
->stAttribs
.dwAttribVal
&= ~FILE_ATTRIBUTE_SYSTEM
;
453 lpFlags
->stAttribs
.dwAttribVal
|= FILE_ATTRIBUTE_SYSTEM
;
457 error_parameter_format((TCHAR
)_totupper (*Line
));
461 case _T('T'): /* Switch parameters for /T (time field) */
462 if(cCurUChar
== _T('C'))
463 lpFlags
->stTimeField
.eTimeField
= TF_CREATIONDATE
;
464 else if(cCurUChar
== _T('A'))
465 lpFlags
->stTimeField
.eTimeField
= TF_LASTACCESSEDDATE
;
466 else if(cCurUChar
== _T('W'))
467 lpFlags
->stTimeField
.eTimeField
= TF_MODIFIEDDATE
;
470 error_parameter_format((TCHAR
)_totupper (*Line
));
474 case _T('O'): /* Switch parameters for /O (order) */
475 /* Ok a switch parameter was given */
476 bOrderByNoPar
= FALSE
;
478 if(cCurChar
== _T('-'))
480 else if(cCurUChar
== _T('N'))
482 if (lpFlags
->stOrderBy
.sCriteriaCount
< 3) lpFlags
->stOrderBy
.sCriteriaCount
++;
483 lpFlags
->stOrderBy
.bCriteriaRev
[lpFlags
->stOrderBy
.sCriteriaCount
- 1] = bPNegative
;
484 lpFlags
->stOrderBy
.eCriteria
[lpFlags
->stOrderBy
.sCriteriaCount
- 1] = ORDER_NAME
;
486 else if(cCurUChar
== _T('S'))
488 if (lpFlags
->stOrderBy
.sCriteriaCount
< 3) lpFlags
->stOrderBy
.sCriteriaCount
++;
489 lpFlags
->stOrderBy
.bCriteriaRev
[lpFlags
->stOrderBy
.sCriteriaCount
- 1] = bPNegative
;
490 lpFlags
->stOrderBy
.eCriteria
[lpFlags
->stOrderBy
.sCriteriaCount
- 1] = ORDER_SIZE
;
492 else if(cCurUChar
== _T('G'))
494 if (lpFlags
->stOrderBy
.sCriteriaCount
< 3) lpFlags
->stOrderBy
.sCriteriaCount
++;
495 lpFlags
->stOrderBy
.bCriteriaRev
[lpFlags
->stOrderBy
.sCriteriaCount
- 1] = bPNegative
;
496 lpFlags
->stOrderBy
.eCriteria
[lpFlags
->stOrderBy
.sCriteriaCount
- 1] = ORDER_DIRECTORY
;
498 else if(cCurUChar
== _T('E'))
500 if (lpFlags
->stOrderBy
.sCriteriaCount
< 3) lpFlags
->stOrderBy
.sCriteriaCount
++;
501 lpFlags
->stOrderBy
.bCriteriaRev
[lpFlags
->stOrderBy
.sCriteriaCount
- 1] = bPNegative
;
502 lpFlags
->stOrderBy
.eCriteria
[lpFlags
->stOrderBy
.sCriteriaCount
- 1] = ORDER_EXTENSION
;
504 else if(cCurUChar
== _T('D'))
506 if (lpFlags
->stOrderBy
.sCriteriaCount
< 3) lpFlags
->stOrderBy
.sCriteriaCount
++;
507 lpFlags
->stOrderBy
.bCriteriaRev
[lpFlags
->stOrderBy
.sCriteriaCount
- 1] = bPNegative
;
508 lpFlags
->stOrderBy
.eCriteria
[lpFlags
->stOrderBy
.sCriteriaCount
- 1] = ORDER_TIME
;
513 error_parameter_format((TCHAR
)_totupper (*Line
));
519 /* We check if we calculated the negative value and realese the flag */
520 if ((cCurChar
!= _T('-')) && bPNegative
)
527 /* /O with no switch parameters acts like /O:GN */
530 lpFlags
->stOrderBy
.sCriteriaCount
= 2;
531 lpFlags
->stOrderBy
.eCriteria
[0] = ORDER_DIRECTORY
;
532 lpFlags
->stOrderBy
.bCriteriaRev
[0] = FALSE
;
533 lpFlags
->stOrderBy
.eCriteria
[1] = ORDER_NAME
;
534 lpFlags
->stOrderBy
.bCriteriaRev
[1] = FALSE
;
540 /* Print either with or without paging, depending on /P switch */
542 DirPrintf(LPDIRSWITCHFLAGS lpFlags
, LPTSTR szFormat
, ...)
546 va_start(arg_ptr
, szFormat
);
548 iReturn
= ConPrintfPaging(FALSE
, szFormat
, arg_ptr
, STD_OUTPUT_HANDLE
);
550 ConPrintf(szFormat
, arg_ptr
, STD_OUTPUT_HANDLE
);
557 * PrintDirectoryHeader
559 * print the header for the dir command
562 PrintDirectoryHeader(LPTSTR szPath
, LPDIRSWITCHFLAGS lpFlags
)
564 TCHAR szMsg
[RC_STRING_MAX_SIZE
];
565 TCHAR szFullDir
[MAX_PATH
];
566 TCHAR szRootName
[MAX_PATH
];
571 if (lpFlags
->bBareFormat
)
574 if (GetFullPathName(szPath
, sizeof(szFullDir
) / sizeof(TCHAR
), szFullDir
, &pszFilePart
) == 0)
576 ErrorMessage(GetLastError(), _T("Failed to build full directory path"));
580 if (pszFilePart
!= NULL
)
581 *pszFilePart
= _T('\0');
583 /* get the media ID of the drive */
584 if (!GetVolumePathName(szFullDir
, szRootName
, sizeof(szRootName
) / sizeof(TCHAR
)) ||
585 !GetVolumeInformation(szRootName
, szVolName
, 80, &dwSerialNr
,
586 NULL
, NULL
, NULL
, 0))
591 /* print drive info */
592 if (szVolName
[0] != _T('\0'))
594 LoadString(CMD_ModuleHandle
, STRING_DIR_HELP2
, szMsg
, RC_STRING_MAX_SIZE
);
595 DirPrintf(lpFlags
, szMsg
, szRootName
[0], szVolName
);
599 LoadString(CMD_ModuleHandle
, STRING_DIR_HELP3
, szMsg
, RC_STRING_MAX_SIZE
);
600 DirPrintf(lpFlags
, szMsg
, szRootName
[0]);
603 /* print the volume serial number if the return was successful */
604 LoadString(CMD_ModuleHandle
, STRING_DIR_HELP4
, (LPTSTR
) szMsg
, RC_STRING_MAX_SIZE
);
605 DirPrintf(lpFlags
, szMsg
, HIWORD(dwSerialNr
), LOWORD(dwSerialNr
));
612 DirPrintFileDateTime(TCHAR
*lpDate
,
614 LPWIN32_FIND_DATA lpFile
,
615 LPDIRSWITCHFLAGS lpFlags
)
620 /* Select the right time field */
621 switch (lpFlags
->stTimeField
.eTimeField
)
623 case TF_CREATIONDATE
:
624 if (!FileTimeToLocalFileTime(&lpFile
->ftCreationTime
, &ft
))
626 FileTimeToSystemTime(&ft
, &dt
);
629 case TF_LASTACCESSEDDATE
:
630 if (!FileTimeToLocalFileTime(&lpFile
->ftLastAccessTime
, &ft
))
632 FileTimeToSystemTime(&ft
, &dt
);
635 case TF_MODIFIEDDATE
:
636 if (!FileTimeToLocalFileTime(&lpFile
->ftLastWriteTime
, &ft
))
638 FileTimeToSystemTime(&ft
, &dt
);
642 FormatDate(lpDate
, &dt
, lpFlags
->b4Digit
);
643 FormatTime(lpTime
, &dt
);
647 FormatDate(TCHAR
*lpDate
, LPSYSTEMTIME dt
, BOOL b4Digit
)
650 WORD wYear
= b4Digit
? dt
->wYear
: dt
->wYear
%100;
655 return _stprintf(lpDate
, _T("%02d%c%02d%c%0*d"),
656 dt
->wMonth
, cDateSeparator
,
657 dt
->wDay
, cDateSeparator
,
662 return _stprintf(lpDate
, _T("%02d%c%02d%c%0*d"),
663 dt
->wDay
, cDateSeparator
, dt
->wMonth
,
664 cDateSeparator
, b4Digit
?4:2, wYear
);
668 return _stprintf(lpDate
, _T("%0*d%c%02d%c%02d"),
669 b4Digit
?4:2, wYear
, cDateSeparator
,
670 dt
->wMonth
, cDateSeparator
, dt
->wDay
);
676 FormatTime(TCHAR
*lpTime
, LPSYSTEMTIME dt
)
681 case 0: /* 12 hour format */
683 return _stprintf(lpTime
,_T("%02d%c%02u%c"),
684 (dt
->wHour
== 0 ? 12 : (dt
->wHour
<= 12 ? dt
->wHour
: dt
->wHour
- 12)),
686 dt
->wMinute
, (dt
->wHour
<= 11 ? _T('a') : _T('p')));
689 case 1: /* 24 hour format */
690 return _stprintf(lpTime
, _T("%02d%c%02u"),
691 dt
->wHour
, cTimeSeparator
, dt
->wMinute
);
698 GetUserDiskFreeSpace(LPCTSTR lpRoot
,
699 PULARGE_INTEGER lpFreeSpace
)
701 PGETFREEDISKSPACEEX pGetFreeDiskSpaceEx
;
707 ULARGE_INTEGER TotalNumberOfBytes
, TotalNumberOfFreeBytes
;
709 lpFreeSpace
->QuadPart
= 0;
711 hInstance
= GetModuleHandle(_T("KERNEL32"));
712 if (hInstance
!= NULL
)
714 pGetFreeDiskSpaceEx
= (PGETFREEDISKSPACEEX
)GetProcAddress(hInstance
,
716 "GetDiskFreeSpaceExW");
718 "GetDiskFreeSpaceExA");
720 if (pGetFreeDiskSpaceEx
!= NULL
)
722 if (pGetFreeDiskSpaceEx(lpRoot
, lpFreeSpace
, &TotalNumberOfBytes
, &TotalNumberOfFreeBytes
) == TRUE
)
727 GetDiskFreeSpace(lpRoot
,
733 lpFreeSpace
->QuadPart
= dwSecPerCl
* dwBytPerSec
* dwFreeCl
;
738 * print_summary: prints dir summary
739 * Added by Rob Lake 06/17/98 to compact code
740 * Just copied Tim's Code and patched it a bit
744 PrintSummary(LPTSTR szPath
,
748 LPDIRSWITCHFLAGS lpFlags
,
751 TCHAR szMsg
[RC_STRING_MAX_SIZE
];
753 ULARGE_INTEGER uliFree
;
756 /* Here we check if we didn't find anything */
757 if (!(ulFiles
+ ulDirs
))
759 if (!lpFlags
->bRecursive
|| (TotalSummary
&& lpFlags
->bRecursive
))
760 error_file_not_found();
765 /* In bare format we don't print results */
766 if (lpFlags
->bBareFormat
)
769 /* Print recursive specific results */
771 /* Take this code offline to fix /S does not print duoble info */
772 if (TotalSummary
&& lpFlags
->bRecursive
)
774 ConvertULargeInteger(u64Bytes
, szBuffer
, sizeof(szBuffer
), lpFlags
->bTSeperator
);
775 LoadString(CMD_ModuleHandle
, STRING_DIR_HELP5
, szMsg
, RC_STRING_MAX_SIZE
);
776 DirPrintf(lpFlags
, szMsg
, ulFiles
, szBuffer
);
780 /* Print File Summary */
781 /* Condition to print summary is:
782 If we are not in bare format and if we have results! */
783 ConvertULargeInteger(u64Bytes
, szBuffer
, 20, lpFlags
->bTSeperator
);
784 LoadString(CMD_ModuleHandle
, STRING_DIR_HELP8
, szMsg
, RC_STRING_MAX_SIZE
);
785 DirPrintf(lpFlags
, szMsg
, ulFiles
, szBuffer
);
788 /* Print total directories and freespace */
789 if (!lpFlags
->bRecursive
|| TotalSummary
)
791 GetUserDiskFreeSpace(szPath
, &uliFree
);
792 ConvertULargeInteger(uliFree
.QuadPart
, szBuffer
, sizeof(szBuffer
), lpFlags
->bTSeperator
);
793 LoadString(CMD_ModuleHandle
, STRING_DIR_HELP6
, (LPTSTR
) szMsg
, RC_STRING_MAX_SIZE
);
794 DirPrintf(lpFlags
, szMsg
, ulDirs
, szBuffer
);
803 * Get the extension of a filename
805 TCHAR
* getExt(const TCHAR
* file
)
807 static TCHAR
*NoExt
= _T("");
808 TCHAR
* lastdot
= _tcsrchr(file
, _T('.'));
809 return (lastdot
!= NULL
? lastdot
+ 1 : NoExt
);
815 * Get the name of the file without extension
818 getName(const TCHAR
* file
, TCHAR
* dest
)
823 /* Check for "." and ".." folders */
824 if ((_tcscmp(file
, _T(".")) == 0) ||
825 (_tcscmp(file
, _T("..")) == 0))
831 end
= _tcsrchr(file
, _T('.'));
833 iLen
= _tcslen(file
);
838 _tcsncpy(dest
, file
, iLen
);
839 *(dest
+ iLen
) = _T('\0');
848 * The function that prints in new style
851 DirPrintNewList(LPWIN32_FIND_DATA ptrFiles
[], /* [IN]Files' Info */
852 DWORD dwCount
, /* [IN] The quantity of files */
853 TCHAR
*szCurPath
, /* [IN] Full path of current directory */
854 LPDIRSWITCHFLAGS lpFlags
) /* [IN] The flags used */
858 TCHAR szShortName
[15];
862 ULARGE_INTEGER u64FileSize
;
864 for (i
= 0; i
< dwCount
&& !bCtrlBreak
; i
++)
867 if (ptrFiles
[i
]->dwFileAttributes
& FILE_ATTRIBUTE_REPARSE_POINT
)
871 _tcscpy(szSize
, _T("<JUNCTION>"));
873 else if (ptrFiles
[i
]->dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
877 _tcscpy(szSize
, _T("<DIR>"));
883 u64FileSize
.HighPart
= ptrFiles
[i
]->nFileSizeHigh
;
884 u64FileSize
.LowPart
= ptrFiles
[i
]->nFileSizeLow
;
885 ConvertULargeInteger(u64FileSize
.QuadPart
, szSize
, 20, lpFlags
->bTSeperator
);
888 /* Calculate short name */
889 szShortName
[0] = _T('\0');
890 if (lpFlags
->bShortName
)
891 _stprintf(szShortName
, _T(" %-12s"), ptrFiles
[i
]->cAlternateFileName
);
893 /* Format date and time */
894 DirPrintFileDateTime(szDate
, szTime
, ptrFiles
[i
], lpFlags
);
897 DirPrintf(lpFlags
, _T("%10s %-6s %*s%s %s\n"),
903 ptrFiles
[i
]->cFileName
);
911 * The function that prints in wide list
914 DirPrintWideList(LPWIN32_FIND_DATA ptrFiles
[], /* [IN] Files' Info */
915 DWORD dwCount
, /* [IN] The quantity of files */
916 TCHAR
*szCurPath
, /* [IN] Full path of current directory */
917 LPDIRSWITCHFLAGS lpFlags
) /* [IN] The flags used */
923 TCHAR szTempFname
[MAX_PATH
];
928 /* Calculate longest name */
930 for (i
= 0; i
< dwCount
; i
++)
932 if (ptrFiles
[i
]->dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
934 /* Directories need 2 additinal characters for brackets */
935 if ((_tcslen(ptrFiles
[i
]->cFileName
) + 2) > iLongestName
)
936 iLongestName
= _tcslen(ptrFiles
[i
]->cFileName
) + 2;
940 if (_tcslen(ptrFiles
[i
]->cFileName
) > iLongestName
)
941 iLongestName
= _tcslen(ptrFiles
[i
]->cFileName
);
945 /* Count the highest number of columns */
946 GetScreenSize(&iScreenWidth
, 0);
947 iColumns
= iScreenWidth
/ iLongestName
;
949 /* Check if there is enough space for spaces between names */
950 if (((iLongestName
* iColumns
) + iColumns
) >= (UINT
)iScreenWidth
)
953 /* A last check at iColumns to avoid division by zero */
957 /* Calculate the lines that will be printed */
958 iLines
= (USHORT
)((dwCount
+ iColumns
- 1) / iColumns
);
960 for (i
= 0; i
< iLines
&& !bCtrlBreak
; i
++)
962 for (j
= 0; j
< iColumns
; j
++)
964 if (lpFlags
->bWideListColSort
)
966 /* Print Column sorted */
967 temp
= (j
* iLines
) + i
;
971 /* Print Line sorted */
972 temp
= (i
* iColumns
) + j
;
978 if (ptrFiles
[temp
]->dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
979 _stprintf(szTempFname
, _T("[%s]"), ptrFiles
[temp
]->cFileName
);
981 _stprintf(szTempFname
, _T("%s"), ptrFiles
[temp
]->cFileName
);
983 DirPrintf(lpFlags
, _T("%-*s"), iLongestName
+ 1, szTempFname
);
986 /* Add a new line after the last item in the column */
987 DirPrintf(lpFlags
, _T("\n"));
995 * The function that prints in old style
998 DirPrintOldList(LPWIN32_FIND_DATA ptrFiles
[], /* [IN] Files' Info */
999 DWORD dwCount
, /* [IN] The quantity of files */
1000 TCHAR
* szCurPath
, /* [IN] Full path of current directory */
1001 LPDIRSWITCHFLAGS lpFlags
) /* [IN] The flags used */
1003 DWORD i
; /* An indexer for "for"s */
1004 TCHAR szName
[10]; /* The name of file */
1005 TCHAR szExt
[5]; /* The extension of file */
1006 TCHAR szDate
[30],szTime
[30]; /* Used to format time and date */
1007 TCHAR szSize
[30]; /* The size of file */
1008 int iSizeFormat
; /* The format of size field */
1009 ULARGE_INTEGER u64FileSize
; /* The file size */
1011 for (i
= 0; i
< dwCount
&& !bCtrlBreak
; i
++)
1013 /* Broke 8.3 format */
1014 if (*ptrFiles
[i
]->cAlternateFileName
)
1016 /* If the file is long named then we read the alter name */
1017 getName( ptrFiles
[i
]->cAlternateFileName
, szName
);
1018 _tcscpy(szExt
, getExt( ptrFiles
[i
]->cAlternateFileName
));
1022 /* If the file is not long name we read its original name */
1023 getName( ptrFiles
[i
]->cFileName
, szName
);
1024 _tcscpy(szExt
, getExt( ptrFiles
[i
]->cFileName
));
1027 /* Calculate size */
1028 if (ptrFiles
[i
]->dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
1030 /* Directory, no size it's a directory*/
1032 _tcscpy(szSize
, _T("<DIR>"));
1038 u64FileSize
.HighPart
= ptrFiles
[i
]->nFileSizeHigh
;
1039 u64FileSize
.LowPart
= ptrFiles
[i
]->nFileSizeLow
;
1040 ConvertULargeInteger(u64FileSize
.QuadPart
, szSize
, 20, lpFlags
->bTSeperator
);
1043 /* Format date and time */
1044 DirPrintFileDateTime(szDate
,szTime
,ptrFiles
[i
],lpFlags
);
1046 /* Print the line */
1047 DirPrintf(lpFlags
, _T("%-8s %-3s %*s %s %s\n"),
1048 szName
, /* The file's 8.3 name */
1049 szExt
, /* The file's 8.3 extension */
1050 iSizeFormat
, /* print format for size column */
1051 szSize
, /* The size of file or "<DIR>" for dirs */
1052 szDate
, /* The date of file/dir */
1053 szTime
); /* The time of file/dir */
1060 * The function that prints in bare format
1063 DirPrintBareList(LPWIN32_FIND_DATA ptrFiles
[], /* [IN] Files' Info */
1064 DWORD dwCount
, /* [IN] The number of files */
1065 LPTSTR lpCurPath
, /* [IN] Full path of current directory */
1066 LPDIRSWITCHFLAGS lpFlags
) /* [IN] The flags used */
1070 for (i
= 0; i
< dwCount
&& !bCtrlBreak
; i
++)
1072 if ((_tcscmp(ptrFiles
[i
]->cFileName
, _T(".")) == 0) ||
1073 (_tcscmp(ptrFiles
[i
]->cFileName
, _T("..")) == 0))
1075 /* at bare format we don't print "." and ".." folder */
1078 if (lpFlags
->bRecursive
)
1080 /* at recursive mode we print full path of file */
1081 DirPrintf(lpFlags
, _T("%s\\%s\n"), lpCurPath
, ptrFiles
[i
]->cFileName
);
1085 /* if we are not in recursive mode we print the file names */
1086 DirPrintf(lpFlags
, _T("%s\n"), ptrFiles
[i
]->cFileName
);
1095 * The functions that prints the files list
1098 DirPrintFiles(LPWIN32_FIND_DATA ptrFiles
[], /* [IN] Files' Info */
1099 DWORD dwCount
, /* [IN] The quantity of files */
1100 TCHAR
*szCurPath
, /* [IN] Full path of current directory */
1101 LPDIRSWITCHFLAGS lpFlags
) /* [IN] The flags used */
1103 TCHAR szMsg
[RC_STRING_MAX_SIZE
];
1104 TCHAR szTemp
[MAX_PATH
]; /* A buffer to format the directory header */
1106 /* Print trailing backslash for root directory of drive */
1107 _tcscpy(szTemp
, szCurPath
);
1108 if (_tcslen(szTemp
) == 2 && szTemp
[1] == _T(':'))
1109 _tcscat(szTemp
, _T("\\"));
1111 /* Condition to print header:
1112 We are not printing in bare format
1113 and if we are in recursive mode... we must have results */
1114 if (!(lpFlags
->bBareFormat
) && !((lpFlags
->bRecursive
) && (dwCount
<= 0)))
1116 LoadString(CMD_ModuleHandle
, STRING_DIR_HELP7
, szMsg
, RC_STRING_MAX_SIZE
);
1117 if (DirPrintf(lpFlags
, szMsg
, szTemp
))
1121 if (lpFlags
->bBareFormat
)
1124 DirPrintBareList(ptrFiles
, dwCount
, szCurPath
, lpFlags
);
1126 else if(lpFlags
->bShortName
)
1128 /* New list style / Short names */
1129 DirPrintNewList(ptrFiles
, dwCount
, szCurPath
, lpFlags
);
1131 else if(lpFlags
->bWideListColSort
|| lpFlags
->bWideList
)
1134 DirPrintWideList(ptrFiles
, dwCount
, szCurPath
, lpFlags
);
1136 else if (lpFlags
->bNewLongList
)
1139 DirPrintNewList(ptrFiles
, dwCount
, szCurPath
, lpFlags
);
1143 /* If nothing is selected old list is the default */
1144 DirPrintOldList(ptrFiles
, dwCount
, szCurPath
, lpFlags
);
1153 * Compares 2 files based on the order criteria
1156 CompareFiles(LPWIN32_FIND_DATA lpFile1
, /* [IN] A pointer to WIN32_FIND_DATA of file 1 */
1157 LPWIN32_FIND_DATA lpFile2
, /* [IN] A pointer to WIN32_FIND_DATA of file 2 */
1158 LPDIRSWITCHFLAGS lpFlags
) /* [IN] The flags that we use to list */
1160 ULARGE_INTEGER u64File1
;
1161 ULARGE_INTEGER u64File2
;
1163 long iComp
= 0; /* The comparison result */
1165 /* Calculate critiries by order given from user */
1166 for (i
= 0;i
< lpFlags
->stOrderBy
.sCriteriaCount
;i
++)
1169 /* Calculate criteria */
1170 switch(lpFlags
->stOrderBy
.eCriteria
[i
])
1172 case ORDER_SIZE
: /* Order by size /o:s */
1173 /* concat the 32bit integers to a 64bit */
1174 u64File1
.LowPart
= lpFile1
->nFileSizeLow
;
1175 u64File1
.HighPart
= lpFile1
->nFileSizeHigh
;
1176 u64File2
.LowPart
= lpFile2
->nFileSizeLow
;
1177 u64File2
.HighPart
= lpFile2
->nFileSizeHigh
;
1179 /* In case that differnce is too big for a long */
1180 if (u64File1
.QuadPart
< u64File2
.QuadPart
)
1182 else if (u64File1
.QuadPart
> u64File2
.QuadPart
)
1188 case ORDER_DIRECTORY
: /* Order by directory attribute /o:g */
1189 iComp
= ((lpFile2
->dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)-
1190 (lpFile1
->dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
));
1193 case ORDER_EXTENSION
: /* Order by extension name /o:e */
1194 iComp
= _tcsicmp(getExt(lpFile1
->cFileName
),getExt(lpFile2
->cFileName
));
1197 case ORDER_NAME
: /* Order by filename /o:n */
1198 iComp
= _tcsicmp(lpFile1
->cFileName
, lpFile2
->cFileName
);
1201 case ORDER_TIME
: /* Order by file's time /o:t */
1202 /* We compare files based on the time field selected by /t */
1203 switch(lpFlags
->stTimeField
.eTimeField
)
1205 case TF_CREATIONDATE
:
1206 /* concat the 32bit integers to a 64bit */
1207 u64File1
.LowPart
= lpFile1
->ftCreationTime
.dwLowDateTime
;
1208 u64File1
.HighPart
= lpFile1
->ftCreationTime
.dwHighDateTime
;
1209 u64File2
.LowPart
= lpFile2
->ftCreationTime
.dwLowDateTime
;
1210 u64File2
.HighPart
= lpFile2
->ftCreationTime
.dwHighDateTime
;
1212 case TF_LASTACCESSEDDATE
:
1213 /* concat the 32bit integers to a 64bit */
1214 u64File1
.LowPart
= lpFile1
->ftLastAccessTime
.dwLowDateTime
;
1215 u64File1
.HighPart
= lpFile1
->ftLastAccessTime
.dwHighDateTime
;
1216 u64File2
.LowPart
= lpFile2
->ftLastAccessTime
.dwLowDateTime
;
1217 u64File2
.HighPart
= lpFile2
->ftLastAccessTime
.dwHighDateTime
;
1219 case TF_MODIFIEDDATE
:
1220 /* concat the 32bit integers to a 64bit */
1221 u64File1
.LowPart
= lpFile1
->ftLastWriteTime
.dwLowDateTime
;
1222 u64File1
.HighPart
= lpFile1
->ftLastWriteTime
.dwHighDateTime
;
1223 u64File2
.LowPart
= lpFile2
->ftLastWriteTime
.dwLowDateTime
;
1224 u64File2
.HighPart
= lpFile2
->ftLastWriteTime
.dwHighDateTime
;
1228 /* In case that differnce is too big for a long */
1229 if (u64File1
.QuadPart
< u64File2
.QuadPart
)
1231 else if (u64File1
.QuadPart
> u64File2
.QuadPart
)
1238 /* Reverse if desired */
1239 if (lpFlags
->stOrderBy
.bCriteriaRev
[i
])
1242 /* If that criteria was enough for distinguishing
1243 the files/dirs,there is no need to calculate the others*/
1244 if (iComp
!= 0) break;
1247 /* Translate the value of iComp to boolean */
1254 * Sort files by the order criterias using quicksort method
1257 QsortFiles(LPWIN32_FIND_DATA ptrArray
[], /* [IN/OUT] The array with file info pointers */
1258 int i
, /* [IN] The index of first item in array */
1259 int j
, /* [IN] The index to last item in array */
1260 LPDIRSWITCHFLAGS lpFlags
) /* [IN] The flags that we will use to sort */
1262 LPWIN32_FIND_DATA lpTemp
; /* A temporary pointer */
1263 int First
, Last
, Temp
;
1273 if (Way
== CompareFiles(ptrArray
[i
], ptrArray
[j
], lpFlags
))
1275 /* Swap the pointers of the array */
1276 lpTemp
= ptrArray
[i
];
1277 ptrArray
[i
]= ptrArray
[j
];
1278 ptrArray
[j
] = lpTemp
;
1280 /* Swap the indexes for inverting sorting */
1291 QsortFiles(ptrArray
,First
, i
-1, lpFlags
);
1292 QsortFiles(ptrArray
,i
+1,Last
, lpFlags
);
1301 * The functions that does everything except for printing results
1304 DirList(LPTSTR szPath
, /* [IN] The path that dir starts */
1305 LPDIRSWITCHFLAGS lpFlags
) /* [IN] The flags of the listing */
1307 BOOL fPoint
; /* If szPath is a file with extension fPoint will be True*/
1308 HANDLE hSearch
; /* The handle of the search */
1309 HANDLE hRecSearch
; /* The handle for searching recursivly */
1310 WIN32_FIND_DATA wfdFileInfo
; /* The info of file that found */
1311 LPWIN32_FIND_DATA
* ptrFileArray
; /* An array of pointers with all the files */
1312 PDIRFINDLISTNODE ptrStartNode
; /* The pointer to the first node */
1313 PDIRFINDLISTNODE ptrNextNode
; /* A pointer used for relatives refernces */
1314 TCHAR szFullPath
[MAX_PATH
]; /* The full path that we are listing with trailing \ */
1315 TCHAR szSubPath
[MAX_PATH
];
1317 DWORD dwCount
; /* A counter of files found in directory */
1318 DWORD dwCountFiles
; /* Counter for files */
1319 DWORD dwCountDirs
; /* Counter for directories */
1320 ULONGLONG u64CountBytes
; /* Counter for bytes */
1321 ULARGE_INTEGER u64Temp
; /* A temporary counter */
1323 /* Initialize Variables */
1324 ptrStartNode
= NULL
;
1332 /* Create szFullPath */
1333 if (GetFullPathName(szPath
, sizeof(szFullPath
) / sizeof(TCHAR
), szFullPath
, &pszFilePart
) == 0)
1335 _tcscpy (szFullPath
, szPath
);
1339 /* If no wildcard or file was specified and this is a directory, then
1340 display all files in it */
1341 if (pszFilePart
== NULL
|| IsExistingDirectory(szFullPath
))
1343 pszFilePart
= &szFullPath
[_tcslen(szFullPath
)];
1344 if (pszFilePart
[-1] != _T('\\'))
1345 *pszFilePart
++ = _T('\\');
1346 _tcscpy(pszFilePart
, _T("*"));
1349 /* Prepare the linked list, first node is allocated */
1350 ptrStartNode
= cmd_alloc(sizeof(DIRFINDLISTNODE
));
1351 if (ptrStartNode
== NULL
)
1353 WARN("DEBUG: Cannot allocate memory for ptrStartNode!\n");
1354 return 1; /* Error cannot allocate memory for 1st object */
1356 ptrNextNode
= ptrStartNode
;
1358 /*Checking ir szPath is a File with/wout extension*/
1359 if (szPath
[_tcslen(szPath
) - 1] == _T('.'))
1362 /* Collect the results for the current folder */
1363 hSearch
= FindFirstFile(szFullPath
, &wfdFileInfo
);
1364 if (hSearch
!= INVALID_HANDLE_VALUE
)
1368 /*If retrieved FileName has extension,and szPath doesnt have extension then JUMP the retrieved FileName*/
1369 if(_tcschr(wfdFileInfo
.cFileName
,_T('.'))&&(fPoint
==TRUE
))
1372 /* Here we filter all the specified attributes */
1373 }else if ((wfdFileInfo
.dwFileAttributes
& lpFlags
->stAttribs
.dwAttribMask
)
1374 == (lpFlags
->stAttribs
.dwAttribMask
& lpFlags
->stAttribs
.dwAttribVal
))
1376 ptrNextNode
->ptrNext
= cmd_alloc(sizeof(DIRFINDLISTNODE
));
1377 if (ptrNextNode
->ptrNext
== NULL
)
1379 WARN("DEBUG: Cannot allocate memory for ptrNextNode->ptrNext!\n");
1380 while (ptrStartNode
)
1382 ptrNextNode
= ptrStartNode
->ptrNext
;
1383 cmd_free(ptrStartNode
);
1384 ptrStartNode
= ptrNextNode
;
1391 /* If cmd_alloc fails we go to next file in hope it works,
1392 without braking the linked list! */
1393 if (ptrNextNode
->ptrNext
)
1395 /* Copy the info of search at linked list */
1396 memcpy(&ptrNextNode
->ptrNext
->stFindInfo
,
1398 sizeof(WIN32_FIND_DATA
));
1400 /* If lower case is selected do it here */
1401 if (lpFlags
->bLowerCase
)
1403 _tcslwr(ptrNextNode
->ptrNext
->stFindInfo
.cAlternateFileName
);
1404 _tcslwr(ptrNextNode
->ptrNext
->stFindInfo
.cFileName
);
1407 /* Continue at next node at linked list */
1408 ptrNextNode
= ptrNextNode
->ptrNext
;
1411 /* Grab statistics */
1412 if (wfdFileInfo
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
1421 u64Temp
.HighPart
= wfdFileInfo
.nFileSizeHigh
;
1422 u64Temp
.LowPart
= wfdFileInfo
.nFileSizeLow
;
1423 u64CountBytes
+= u64Temp
.QuadPart
;
1427 } while (FindNextFile(hSearch
, &wfdFileInfo
));
1431 /* Terminate list */
1432 ptrNextNode
->ptrNext
= NULL
;
1434 /* Calculate and allocate space need for making an array of pointers */
1435 ptrFileArray
= cmd_alloc(sizeof(LPWIN32_FIND_DATA
) * dwCount
);
1436 if (ptrFileArray
== NULL
)
1438 WARN("DEBUG: Cannot allocate memory for ptrFileArray!\n");
1439 while (ptrStartNode
)
1441 ptrNextNode
= ptrStartNode
->ptrNext
;
1442 cmd_free(ptrStartNode
);
1443 ptrStartNode
= ptrNextNode
;
1450 * Create an array of pointers from the linked list
1451 * this will be used to sort and print data, rather than the list
1453 ptrNextNode
= ptrStartNode
;
1455 while (ptrNextNode
->ptrNext
)
1457 *(ptrFileArray
+ dwCount
) = &ptrNextNode
->ptrNext
->stFindInfo
;
1458 ptrNextNode
= ptrNextNode
->ptrNext
;
1462 /* Sort Data if requested*/
1463 if (lpFlags
->stOrderBy
.sCriteriaCount
> 0)
1464 QsortFiles(ptrFileArray
, 0, dwCount
-1, lpFlags
);
1467 pszFilePart
[-1] = _T('\0'); /* truncate to directory name only */
1468 DirPrintFiles(ptrFileArray
, dwCount
, szFullPath
, lpFlags
);
1469 pszFilePart
[-1] = _T('\\');
1471 if (lpFlags
->bRecursive
)
1473 PrintSummary(szFullPath
,
1482 cmd_free(ptrFileArray
);
1483 /* Free linked list */
1484 while (ptrStartNode
)
1486 ptrNextNode
= ptrStartNode
->ptrNext
;
1487 cmd_free(ptrStartNode
);
1488 ptrStartNode
= ptrNextNode
;
1492 if (CheckCtrlBreak(BREAK_INPUT
))
1496 /* Add statistics to recursive statistics*/
1497 recurse_dir_cnt
+= dwCountDirs
;
1498 recurse_file_cnt
+= dwCountFiles
;
1499 recurse_bytes
+= u64CountBytes
;
1501 /* Do the recursive job if requested
1502 the recursive is be done on ALL(indepent of their attribs)
1503 directoried of the current one.*/
1504 if (lpFlags
->bRecursive
)
1506 /* The new search is involving any *.* file */
1507 memcpy(szSubPath
, szFullPath
, (pszFilePart
- szFullPath
) * sizeof(TCHAR
));
1508 _tcscpy(&szSubPath
[pszFilePart
- szFullPath
], _T("*.*"));
1510 hRecSearch
= FindFirstFile (szSubPath
, &wfdFileInfo
);
1511 if (hRecSearch
!= INVALID_HANDLE_VALUE
)
1515 /* We search for directories other than "." and ".." */
1516 if ((_tcsicmp(wfdFileInfo
.cFileName
, _T(".")) != 0) &&
1517 (_tcsicmp(wfdFileInfo
.cFileName
, _T("..")) != 0 ) &&
1518 (wfdFileInfo
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
))
1520 /* Concat the path and the directory to do recursive */
1521 memcpy(szSubPath
, szFullPath
, (pszFilePart
- szFullPath
) * sizeof(TCHAR
));
1522 _tcscpy(&szSubPath
[pszFilePart
- szFullPath
], wfdFileInfo
.cFileName
);
1523 _tcscat(szSubPath
, _T("\\"));
1524 _tcscat(szSubPath
, pszFilePart
);
1526 /* We do the same for the folder */
1527 if (DirList(szSubPath
, lpFlags
) != 0)
1529 FindClose(hRecSearch
);
1533 } while(FindNextFile(hRecSearch
, &wfdFileInfo
));
1535 FindClose(hRecSearch
);
1546 * internal dir command
1549 CommandDir(LPTSTR rest
)
1551 TCHAR dircmd
[256]; /* A variable to store the DIRCMD enviroment variable */
1552 TCHAR path
[MAX_PATH
];
1553 TCHAR prev_volume
[MAX_PATH
];
1554 LPTSTR
* params
= NULL
;
1558 DIRSWITCHFLAGS stFlags
;
1562 /* Initialize Switch Flags < Default switches are setted here!> */
1563 stFlags
.b4Digit
= TRUE
;
1564 stFlags
.bBareFormat
= FALSE
;
1565 stFlags
.bLowerCase
= FALSE
;
1566 stFlags
.bNewLongList
= TRUE
;
1567 stFlags
.bPause
= FALSE
;
1568 stFlags
.bRecursive
= FALSE
;
1569 stFlags
.bShortName
= FALSE
;
1570 stFlags
.bTSeperator
= TRUE
;
1571 stFlags
.bUser
= FALSE
;
1572 stFlags
.bWideList
= FALSE
;
1573 stFlags
.bWideListColSort
= FALSE
;
1574 stFlags
.stTimeField
.eTimeField
= TF_MODIFIEDDATE
;
1575 stFlags
.stAttribs
.dwAttribMask
= FILE_ATTRIBUTE_HIDDEN
| FILE_ATTRIBUTE_SYSTEM
;
1576 stFlags
.stAttribs
.dwAttribVal
= 0L;
1577 stFlags
.stOrderBy
.sCriteriaCount
= 0;
1581 /* read the parameters from the DIRCMD environment variable */
1582 if (GetEnvironmentVariable (_T("DIRCMD"), dircmd
, 256))
1583 if (!DirReadParam(dircmd
, ¶ms
, &entries
, &stFlags
))
1589 /* read the parameters */
1590 if (!DirReadParam(rest
, ¶ms
, &entries
, &stFlags
) || CheckCtrlBreak(BREAK_INPUT
))
1596 /* default to current directory */
1598 if(!add_entry(&entries
, ¶ms
, _T("*"))) {
1604 prev_volume
[0] = _T('\0');
1606 /* Reset paging state */
1608 ConOutPrintfPaging(TRUE
, _T(""));
1610 for(loop
= 0; loop
< (UINT
)entries
; loop
++)
1612 if (CheckCtrlBreak(BREAK_INPUT
))
1618 recurse_dir_cnt
= 0L;
1619 recurse_file_cnt
= 0L;
1623 Uncomment this to show the final state of switch flags*/
1626 TRACE("Attributes mask/value %x/%x\n",stFlags
.stAttribs
.dwAttribMask
,stFlags
.stAttribs
.dwAttribVal
);
1627 TRACE("(B) Bare format : %i\n", stFlags
.bBareFormat
);
1628 TRACE("(C) Thousand : %i\n", stFlags
.bTSeperator
);
1629 TRACE("(W) Wide list : %i\n", stFlags
.bWideList
);
1630 TRACE("(D) Wide list sort by column : %i\n", stFlags
.bWideListColSort
);
1631 TRACE("(L) Lowercase : %i\n", stFlags
.bLowerCase
);
1632 TRACE("(N) New : %i\n", stFlags
.bNewLongList
);
1633 TRACE("(O) Order : %i\n", stFlags
.stOrderBy
.sCriteriaCount
);
1634 for (i
=0;i
<stFlags
.stOrderBy
.sCriteriaCount
;i
++)
1635 TRACE(" Order Criteria [%i]: %i (Reversed: %i)\n",i
, stFlags
.stOrderBy
.eCriteria
[i
], stFlags
.stOrderBy
.bCriteriaRev
[i
] );
1636 TRACE("(P) Pause : %i\n", stFlags
.bPause
);
1637 TRACE("(Q) Owner : %i\n", stFlags
.bUser
);
1638 TRACE("(S) Recursive : %i\n", stFlags
.bRecursive
);
1639 TRACE("(T) Time field : %i\n", stFlags
.stTimeField
.eTimeField
);
1640 TRACE("(X) Short names : %i\n", stFlags
.bShortName
);
1641 TRACE("Parameter : %s\n", debugstr_aw(params
[loop
]) );
1644 /* Print the drive header if the volume changed */
1645 ChangedVolume
= TRUE
;
1647 if (!stFlags
.bBareFormat
&&
1648 GetVolumePathName(params
[loop
], path
, sizeof(path
) / sizeof(TCHAR
)))
1650 if (!_tcscmp(path
, prev_volume
))
1651 ChangedVolume
= FALSE
;
1653 _tcscpy(prev_volume
, path
);
1655 else if (GetFullPathName(params
[loop
], sizeof(path
) / sizeof(TCHAR
), path
, &pszFilePart
) != 0)
1657 if (pszFilePart
!= NULL
)
1658 *pszFilePart
= _T('\0');
1661 _tcscpy(path
, params
[loop
]);
1663 if (ChangedVolume
&& !stFlags
.bBareFormat
) {
1664 if (!PrintDirectoryHeader (params
[loop
], &stFlags
)) {
1670 /* do the actual dir */
1671 if (DirList (params
[loop
], &stFlags
))
1677 /* print the footer */