Revert, thx Thomas, wasnt sure.
[reactos.git] / reactos / subsys / system / cmd / dir.c
1 /*
2 * DIR.C - dir internal command.
3 *
4 *
5 * History:
6 *
7 * 01/29/97 (Tim Norman)
8 * started.
9 *
10 * 06/13/97 (Tim Norman)
11 * Fixed code.
12 *
13 * 07/12/97 (Tim Norman)
14 * Fixed bug that caused the root directory to be unlistable
15 *
16 * 07/12/97 (Marc Desrochers)
17 * Changed to use maxx, maxy instead of findxy()
18 *
19 * 06/08/98 (Rob Lake)
20 * Added compatibility for /w in dir
21 *
22 * 06/09/98 (Rob Lake)
23 * Compatibility for dir/s started
24 * Tested that program finds directories off root fine
25 *
26 * 06/10/98 (Rob Lake)
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.
31 *
32 * 06/11/98 (Rob Lake)
33 * Found problem that caused COM not to work
34 *
35 * 06/12/98 (Rob Lake)
36 * debugged...
37 * added free mem routine
38 *
39 * 06/13/98 (Rob Lake)
40 * debugged the free mem routine
41 * debugged whole thing some more
42 * Notes:
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
47 * changes throughout
48 *
49 * 06/14/98 (Rob Lake)
50 * Cleaned up code a bit, added comments
51 *
52 * 06/16/98 (Rob Lake)
53 * Added error checking to my previously added routines
54 *
55 * 06/17/98 (Rob Lake)
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
66 * Added help screen
67 *
68 * 06/20/98 (Rob Lake)
69 * Added check for /-(switch) to turn off previously defined
70 * switches.
71 * Added ability to check for DIRCMD in environment and
72 * process it
73 *
74 * 06/21/98 (Rob Lake)
75 * Fixed up /B
76 * Now can dir *.ext/X, no spaces!
77 *
78 * 06/29/98 (Rob Lake)
79 * error message now found in command.h
80 *
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.
85 *
86 * 07/12/98 (Rob Lake)
87 * Changed error messages
88 *
89 * 27-Jul-1998 (John P Price <linux-guru@gcfl.net>)
90 * added config.h include
91 *
92 *
93 * 04-Dec-1998 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
94 * Converted source code to Win32, except recursive dir ("dir /s").
95 *
96 * 10-Dec-1998 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
97 * Fixed recursive dir ("dir /s").
98 *
99 * 14-Dec-1998 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
100 * Converted to Win32 directory functions and
101 * fixed some output bugs. There are still some more ;)
102 *
103 * 10-Jan-1999 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
104 * Added "/N" and "/4" options, "/O" is a dummy.
105 * Added locale support.
106 *
107 * 20-Jan-1999 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
108 * Redirection safe!
109 *
110 * 01-Mar-1999 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
111 * Replaced all runtime io functions by their Win32 counterparts.
112 *
113 * 23-Feb-2001 (Carl Nettelblad <cnettel@hem.passagen.se>)
114 * dir /s now works in deeper trees
115 *
116 * 28-Jan-2004 (Michael Fritscher <michael@fritscher.net>)
117 * Fix for /p, so it is working under Windows in GUI-mode, too.
118 *
119 * 30-Apr-2004 (Filip Navara <xnavara@volny.cz>)
120 * Fix /w to print long names.
121 *
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
126 * the main cmd code.
127 *
128 * 1-Jul-2004 (Brandon Turner <turnerb7@msu.edu>)
129 * Added /p back in using ConOutPrintfPaging
130 */
131
132 #include <precomp.h>
133 #include "resource.h"
134
135 #ifdef INCLUDE_CMD_DIR
136
137
138
139 /* Time Field enumeration */
140 enum ETimeField
141 {
142 TF_CREATIONDATE = 0,
143 TF_MODIFIEDDATE = 1,
144 TF_LASTACCESSEDDATE = 2
145 };
146
147 /* Ordered by enumeration */
148 enum EOrderBy
149 {
150 ORDER_NAME = 0,
151 ORDER_SIZE = 1,
152 ORDER_DIRECTORY = 2,
153 ORDER_EXTENSION = 3,
154 ORDER_TIME = 4
155 };
156
157 /* The struct for holding the switches */
158 typedef struct _DirSwitchesFlags
159 {
160 BOOL bBareFormat; /* Bare Format */
161 BOOL bTSeperator; /* Thousands seperator */
162 BOOL bWideList; /* Wide list format */
163 BOOL bWideListColSort; /* Wide list format but sorted by column */
164 BOOL bLowerCase; /* Uses lower case */
165 BOOL bNewLongList; /* New long list */
166 BOOL bPause; /* Pause per page */
167 BOOL bUser; /* Displays the owner of file */
168 BOOL bRecursive; /* Displays files in specified directory and all sub */
169 BOOL bShortName; /* Displays the sort name of files if exist */
170 BOOL b4Digit; /* Four digit year */
171 struct
172 {
173 DWORD dwAttribVal; /* The desired state of attribute */
174 DWORD dwAttribMask; /* Which attributes to check */
175 BOOL bUnSet; /* A helper flag if "-" was given with the switch */
176 BOOL bParSetted; /* A helper flag if parameters of switch were given */
177 } stAttribs; /* Displays files with this attributes only */
178 struct
179 {
180 enum EOrderBy eCriteria[3]; /* Criterias used to order by */
181 BOOL bCriteriaRev[3]; /* If the criteria is in reversed order */
182 short sCriteriaCount; /* The quantity of criterias */
183 BOOL bUnSet; /* A helper flag if "-" was given with the switch */
184 BOOL bParSetted; /* A helper flag if parameters of switch were given */
185 } stOrderBy; /* Ordered by criterias */
186 struct
187 {
188 enum ETimeField eTimeField; /* The time field that will be used for */
189 BOOL bUnSet; /* A helper flag if "-" was given with the switch */
190 BOOL bParSetted; /* A helper flag if parameters of switch were given */
191 } stTimeField; /* The time field to display or use for sorting */
192 } DIRSWITCHFLAGS, *LPDIRSWITCHFLAGS;
193
194
195 typedef struct _DIRFINDLISTNODE
196 {
197 WIN32_FIND_DATA stFindInfo;
198 struct _DIRFINDLISTNODE *ptrNext;
199 } DIRFINDLISTNODE, *PDIRFINDLISTNODE;
200
201
202 typedef BOOL
203 (WINAPI *PGETFREEDISKSPACEEX)(LPCTSTR, PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER);
204
205
206 /* Globally save the # of dirs, files and bytes,
207 * probabaly later pass them to functions. Rob Lake */
208 static ULONG recurse_dir_cnt;
209 static ULONG recurse_file_cnt;
210 static ULARGE_INTEGER recurse_bytes;
211
212
213 /*
214 * help
215 *
216 * displays help screen for dir
217 * Rob Lake
218 */
219 static VOID
220 DirHelp(VOID)
221 {
222 ConOutResPaging(TRUE, STRING_DIR_HELP1);
223 }
224
225
226
227 /*
228 * DirReadParameters
229 *
230 * Parse the parameters and switches of the command line and exports them
231 */
232 static BOOL
233 DirReadParam(LPTSTR Line, /* [IN] The line with the parameters & switches */
234 LPTSTR** params, /* [OUT] The parameters after parsing */
235 LPINT entries, /* [OUT] The number of parameters after parsing */
236 LPDIRSWITCHFLAGS lpFlags) /* [IN/OUT] The flags after calculating switches */
237 {
238 TCHAR cCurSwitch; /* The current switch */
239 TCHAR cCurChar; /* Current examing character */
240 TCHAR cCurUChar; /* Current upper examing character */
241 BOOL bNegative; /* Negative switch */
242 BOOL bPNegative; /* Negative switch parameter */
243 BOOL bIntoQuotes; /* A flag showing if we are in quotes (") */
244 LPTSTR ptrStart; /* A pointer to the first character of a parameter */
245 LPTSTR ptrEnd; /* A pointer to the last character of a parameter */
246 LPTSTR temp;
247
248 /* Initialize parameter array */
249 *params = malloc(sizeof(LPTSTR));
250 if(!params)
251 return FALSE;
252 *params = NULL;
253 *entries = 0;
254 ptrStart = NULL;
255 ptrEnd = NULL;
256
257 /* Initialize variables; */
258 cCurSwitch = _T(' ');
259 bNegative = FALSE;
260 bPNegative = FALSE;
261 bIntoQuotes = FALSE;
262
263 /* We suppose that switch parameters
264 were given to avoid setting them to default
265 if the switch was not given */
266 lpFlags->stAttribs.bParSetted = TRUE;
267 lpFlags->stOrderBy.bParSetted = TRUE;
268 lpFlags->stTimeField.bParSetted = TRUE;
269
270
271 /* Main Loop (see README_DIR.txt) */
272 /* scan the command line char per char, and we process its char */
273 while (*Line)
274 {
275 /* we save current character as it is and its upper case */
276 cCurChar = *Line;
277 cCurUChar = _totupper(*Line);
278
279 /* 1st section (see README_DIR.txt) */
280 /* When a switch is expecting */
281 if (cCurSwitch == _T('/'))
282 {
283 if ((cCurUChar == _T('A')) ||(cCurUChar == _T('T')) || (cCurUChar == _T('O')))
284 {
285 cCurSwitch = cCurUChar;
286 switch (cCurUChar)
287 {
288 case _T('A'):
289 lpFlags->stAttribs.bUnSet = bNegative;
290 lpFlags->stAttribs.bParSetted = FALSE;
291 break;
292 case _T('T'):
293 lpFlags->stTimeField.bUnSet = bNegative;
294 lpFlags->stTimeField.bParSetted = FALSE;
295 break;
296 case _T('O'):
297 lpFlags->stOrderBy.bUnSet = bNegative;
298 lpFlags->stOrderBy.bParSetted = FALSE;
299 break;
300 }
301 }
302 else if (cCurUChar == _T('L'))
303 lpFlags->bLowerCase = ! bNegative;
304 else if (cCurUChar == _T('B'))
305 lpFlags->bBareFormat = ! bNegative;
306 else if (cCurUChar == _T('C'))
307 lpFlags->bTSeperator = ! bNegative;
308 else if (cCurUChar == _T('W'))
309 lpFlags->bWideList = ! bNegative;
310 else if (cCurUChar == _T('D'))
311 lpFlags->bWideListColSort = ! bNegative;
312 else if (cCurUChar == _T('N'))
313 lpFlags->bNewLongList = ! bNegative;
314 else if (cCurUChar == _T('P'))
315 lpFlags->bPause = ! bNegative;
316 else if (cCurUChar == _T('Q'))
317 lpFlags->bUser = ! bNegative;
318 else if (cCurUChar == _T('S'))
319 lpFlags->bRecursive = ! bNegative;
320 else if (cCurUChar == _T('X'))
321 lpFlags->bShortName = ! bNegative;
322 else if (cCurChar == _T('4'))
323 lpFlags->b4Digit = ! bNegative;
324 else if (cCurChar == _T('?'))
325 {
326 DirHelp();
327 return FALSE;
328 }
329 else if (cCurChar == _T('-'))
330 {
331 bNegative = TRUE;
332 }
333 else
334 {
335 error_invalid_switch ((TCHAR)_totupper (*Line));
336 return FALSE;
337 }
338
339 /* We check if we calculated the negative value and realese the flag */
340 if ((cCurChar != _T('-')) && bNegative)
341 bNegative = FALSE;
342
343 /* if not a,o,t or - option then next parameter is not a switch */
344 if ((cCurSwitch == _T('/')) && (!bNegative))
345 cCurSwitch = _T(' ');
346
347 }
348 else if ((cCurSwitch == _T(' ')) || (cCurSwitch == _T('P')))
349 {
350 /* 2nd section (see README_DIR.txt) */
351 /* We are expecting parameter or the unknown */
352
353 if (cCurChar == _T('/'))
354 cCurSwitch = _T('/');
355
356 /* Process a spacer */
357 else if (cCurChar == _T(' '))
358 {
359 if (!bIntoQuotes)
360 {
361 cCurSwitch = _T(' ');
362 if(ptrStart && ptrEnd)
363 {
364 temp = malloc((ptrEnd - ptrStart) + 2 * sizeof (TCHAR));
365 if(!temp)
366 return FALSE;
367 memcpy(temp, ptrStart, (ptrEnd - ptrStart) + 2 * sizeof (TCHAR));
368 temp[(ptrEnd - ptrStart + 1)] = _T('\0');
369 if(!add_entry(entries, params, temp))
370 {
371 free(temp);
372 freep(*params);
373 return FALSE;
374 }
375
376 free(temp);
377
378 ptrStart = NULL;
379 ptrEnd = NULL;
380 }
381 }
382
383 }
384 else if (cCurChar == _T('\"'))
385 {
386 /* Process a quote */
387 bIntoQuotes = !bIntoQuotes;
388 if(!bIntoQuotes)
389 ptrEnd = Line;
390 }
391 else
392 {
393 /* Process a character for parameter */
394 if ((cCurSwitch == _T(' ')) && ptrStart && ptrEnd)
395 {
396 temp = malloc((ptrEnd - ptrStart) + 2 * sizeof (TCHAR));
397 if(!temp)
398 return FALSE;
399 memcpy(temp, ptrStart, (ptrEnd - ptrStart) + 2 * sizeof (TCHAR));
400 temp[(ptrEnd - ptrStart + 1)] = _T('\0');
401 if(!add_entry(entries, params, temp))
402 {
403 free(temp);
404 freep(*params);
405 return FALSE;
406 }
407
408 free(temp);
409
410 ptrStart = NULL;
411 ptrEnd = NULL;
412 }
413 cCurSwitch = _T('P');
414 if(!ptrStart)
415 ptrStart = ptrEnd = Line;
416 ptrEnd = Line;
417 }
418 }
419 else
420 {
421 /* 3rd section (see README_DIR.txt) */
422 /* We are waiting for switch parameters */
423
424 /* Check if there are no more switch parameters */
425 if ((cCurChar == _T('/')) || ( cCurChar == _T(' ')))
426 {
427 /* Wrong desicion path, reprocess current character */
428 cCurSwitch = cCurChar;
429 continue;
430 }
431 /* Process parameter switch */
432 switch(cCurSwitch)
433 {
434 case _T('A'): /* Switch parameters for /A (attributes filter) */
435 /* Ok a switch parameter was given */
436 lpFlags->stAttribs.bParSetted = TRUE;
437
438 if (cCurChar == _T(':'))
439 /* =V= dead command, used to make the "if" work */
440 cCurChar = cCurChar;
441 else if(cCurChar == _T('-'))
442 bPNegative = TRUE;
443 else if(cCurUChar == _T('D'))
444 {
445 lpFlags->stAttribs.dwAttribMask |= FILE_ATTRIBUTE_DIRECTORY;
446 if (bPNegative)
447 lpFlags->stAttribs.dwAttribVal &= ~FILE_ATTRIBUTE_DIRECTORY;
448 else
449 lpFlags->stAttribs.dwAttribVal |= FILE_ATTRIBUTE_DIRECTORY;
450 }
451 else if(cCurUChar == _T('R'))
452 {
453 lpFlags->stAttribs.dwAttribMask |= FILE_ATTRIBUTE_READONLY;
454 if (bPNegative)
455 lpFlags->stAttribs.dwAttribVal &= ~FILE_ATTRIBUTE_READONLY;
456 else
457 lpFlags->stAttribs.dwAttribVal |= FILE_ATTRIBUTE_READONLY;
458 }
459 else if(cCurUChar == _T('H'))
460 {
461 lpFlags->stAttribs.dwAttribMask |= FILE_ATTRIBUTE_HIDDEN;
462 if (bPNegative)
463 lpFlags->stAttribs.dwAttribVal &= ~FILE_ATTRIBUTE_HIDDEN;
464 else
465 lpFlags->stAttribs.dwAttribVal |= FILE_ATTRIBUTE_HIDDEN;
466 }
467 else if(cCurUChar == _T('A'))
468 {
469 lpFlags->stAttribs.dwAttribMask |= FILE_ATTRIBUTE_ARCHIVE;
470 if (bPNegative)
471 lpFlags->stAttribs.dwAttribVal &= ~FILE_ATTRIBUTE_ARCHIVE;
472 else
473 lpFlags->stAttribs.dwAttribVal |= FILE_ATTRIBUTE_ARCHIVE;
474 }
475 else if(cCurUChar == _T('S'))
476 {
477 lpFlags->stAttribs.dwAttribMask |= FILE_ATTRIBUTE_SYSTEM;
478 if (bPNegative)
479 lpFlags->stAttribs.dwAttribVal &= ~FILE_ATTRIBUTE_SYSTEM;
480 else
481 lpFlags->stAttribs.dwAttribVal |= FILE_ATTRIBUTE_SYSTEM;
482 }
483 else
484 {
485 error_parameter_format((TCHAR)_totupper (*Line));
486 return FALSE;
487 }
488 break;
489 case _T('T'): /* Switch parameters for /T (time field) */
490
491 /* Ok a switch parameter was given */
492 lpFlags->stTimeField.bParSetted = TRUE;
493
494 if (cCurChar == _T(':'))
495 /* =V= dead command, used to make the "if" work */
496 cCurChar = cCurChar;
497 else if(cCurUChar == _T('C'))
498 lpFlags->stTimeField.eTimeField= TF_CREATIONDATE ;
499 else if(cCurUChar == _T('A'))
500 lpFlags->stTimeField.eTimeField= TF_LASTACCESSEDDATE ;
501 else if(cCurUChar == _T('W'))
502 lpFlags->stTimeField.eTimeField= TF_MODIFIEDDATE ;
503 else
504 {
505 error_parameter_format((TCHAR)_totupper (*Line));
506 return FALSE;
507 }
508 break;
509 case _T('O'): /* Switch parameters for /O (order) */
510 /* Ok a switch parameter was given */
511 lpFlags->stOrderBy.bParSetted = TRUE;
512
513 if (cCurChar == _T(':'))
514 /* <== dead command, used to make the "if" work */
515 cCurChar = cCurChar;
516 else if(cCurChar == _T('-'))
517 bPNegative = TRUE;
518 else if(cCurUChar == _T('N'))
519 {
520 if (lpFlags->stOrderBy.sCriteriaCount < 3) lpFlags->stOrderBy.sCriteriaCount++;
521 lpFlags->stOrderBy.bCriteriaRev[lpFlags->stOrderBy.sCriteriaCount - 1] = bPNegative;
522 lpFlags->stOrderBy.eCriteria[lpFlags->stOrderBy.sCriteriaCount - 1] = ORDER_NAME;
523 }
524 else if(cCurUChar == _T('S'))
525 {
526 if (lpFlags->stOrderBy.sCriteriaCount < 3) lpFlags->stOrderBy.sCriteriaCount++;
527 lpFlags->stOrderBy.bCriteriaRev[lpFlags->stOrderBy.sCriteriaCount - 1] = bPNegative;
528 lpFlags->stOrderBy.eCriteria[lpFlags->stOrderBy.sCriteriaCount - 1] = ORDER_SIZE;
529 }
530 else if(cCurUChar == _T('G'))
531 {
532 if (lpFlags->stOrderBy.sCriteriaCount < 3) lpFlags->stOrderBy.sCriteriaCount++;
533 lpFlags->stOrderBy.bCriteriaRev[lpFlags->stOrderBy.sCriteriaCount - 1] = bPNegative;
534 lpFlags->stOrderBy.eCriteria[lpFlags->stOrderBy.sCriteriaCount - 1] = ORDER_DIRECTORY;
535 }
536 else if(cCurUChar == _T('E'))
537 {
538 if (lpFlags->stOrderBy.sCriteriaCount < 3) lpFlags->stOrderBy.sCriteriaCount++;
539 lpFlags->stOrderBy.bCriteriaRev[lpFlags->stOrderBy.sCriteriaCount - 1] = bPNegative;
540 lpFlags->stOrderBy.eCriteria[lpFlags->stOrderBy.sCriteriaCount - 1] = ORDER_EXTENSION;
541 }
542 else if(cCurUChar == _T('D'))
543 {
544 if (lpFlags->stOrderBy.sCriteriaCount < 3) lpFlags->stOrderBy.sCriteriaCount++;
545 lpFlags->stOrderBy.bCriteriaRev[lpFlags->stOrderBy.sCriteriaCount - 1] = bPNegative;
546 lpFlags->stOrderBy.eCriteria[lpFlags->stOrderBy.sCriteriaCount - 1] = ORDER_TIME;
547 }
548
549 else
550 {
551 error_parameter_format((TCHAR)_totupper (*Line));
552 return FALSE;
553 }
554
555
556 }
557 /* We check if we calculated the negative value and realese the flag */
558 if ((cCurChar != _T('-')) && bPNegative)
559 bPNegative = FALSE;
560 }
561
562 Line++;
563 }
564 /* Terminate the parameters */
565 if(ptrStart && ptrEnd)
566 {
567 temp = malloc((ptrEnd - ptrStart) + 2 * sizeof (TCHAR));
568 if(!temp)
569 return FALSE;
570 memcpy(temp, ptrStart, (ptrEnd - ptrStart) + 2 * sizeof (TCHAR));
571 temp[(ptrEnd - ptrStart + 1)] = _T('\0');
572 if(!add_entry(entries, params, temp))
573 {
574 free(temp);
575 freep(*params);
576 return FALSE;
577 }
578
579 free(temp);
580
581 ptrStart = NULL;
582 ptrEnd = NULL;
583 }
584
585 /* Calculate the switches with no switch paramater */
586 if (!(lpFlags->stAttribs.bParSetted))
587 {
588 lpFlags->stAttribs.dwAttribVal = 0L;
589 lpFlags->stAttribs.dwAttribMask = lpFlags->stAttribs.dwAttribVal;
590 }
591 if (!(lpFlags->stOrderBy.bParSetted))
592 {
593 lpFlags->stOrderBy.sCriteriaCount = 1;
594 lpFlags->stOrderBy.eCriteria[0] = ORDER_NAME;
595 lpFlags->stOrderBy.bCriteriaRev[0] = FALSE;
596 }
597 if (!(lpFlags->stOrderBy.bParSetted))
598 lpFlags->stTimeField.eTimeField = TF_MODIFIEDDATE ;
599
600 /* Calculate the unsetted switches (the "-" prefixed)*/
601 if (lpFlags->stAttribs.bUnSet)
602 {
603 lpFlags->stAttribs.bUnSet = FALSE;
604 lpFlags->stAttribs.dwAttribVal = 0L;
605 lpFlags->stAttribs.dwAttribMask = FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM;
606 }
607 if (lpFlags->stOrderBy.bUnSet)
608 {
609 lpFlags->stOrderBy.bUnSet = FALSE;
610 lpFlags->stOrderBy.sCriteriaCount = 0;
611 }
612 if (lpFlags->stTimeField.bUnSet )
613 {
614 lpFlags->stTimeField.bUnSet = FALSE;
615 lpFlags->stTimeField.eTimeField = TF_MODIFIEDDATE;
616 }
617 return TRUE;
618 }
619
620
621 /*
622 * ExtendFilespec
623 *
624 * extend the filespec, possibly adding wildcards
625 */
626 static VOID
627 ExtendFilespec (LPTSTR file)
628 {
629 INT len = 0;
630
631 if (!file)
632 return;
633
634
635 /* if no file spec, change to "*.*" */
636 if (*file == _T('\0'))
637 {
638 _tcscpy (file, _T("*.*"));
639 return;
640 }
641
642 // add support for *.
643 if ((file[0] == _T('*')) && (file[1] == _T('.') ))
644 {
645 return;
646 }
647
648 /* if starts with . add * in front */
649 if (*file == _T('.'))
650 {
651 memmove (&file[1], &file[0], (_tcslen (file) + 1) * sizeof(TCHAR));
652 file[0] = _T('*');
653 }
654
655 /* if no . add .* */
656 if (!_tcschr (file, _T('.')))
657 {
658 _tcscat (file, _T(".*"));
659 return;
660 }
661
662
663
664 /* if last character is '.' add '*' */
665 len = _tcslen (file);
666 if (file[len - 1] == _T('.'))
667 {
668 _tcscat (file, _T("*"));
669 return;
670 }
671 }
672
673
674 /*
675 * dir_parse_pathspec
676 *
677 * split the pathspec into drive, directory, and filespec
678 */
679 static INT
680 DirParsePathspec (LPTSTR szPathspec, LPTSTR szPath, LPTSTR szFilespec)
681 {
682 TCHAR szOrigPath[MAX_PATH];
683 LPTSTR start;
684 LPTSTR tmp;
685 INT i;
686 BOOL bWildcards = FALSE;
687
688 GetCurrentDirectory (MAX_PATH, szOrigPath);
689
690 /* get the drive and change to it */
691 if (szPathspec[1] == _T(':'))
692 {
693 TCHAR szRootPath[] = _T("A:");
694
695 szRootPath[0] = szPathspec[0];
696 start = szPathspec + 2;
697 if (!SetCurrentDirectory (szRootPath))
698 {
699 ErrorMessage (GetLastError(), NULL);
700 return 1;
701 }
702 }
703 else
704 {
705 start = szPathspec;
706 }
707
708
709 /* check for wildcards */
710 for (i = 0; szPathspec[i]; i++)
711 {
712 if (szPathspec[i] == _T('*') || szPathspec[i] == _T('?'))
713 bWildcards = TRUE;
714 }
715
716 /* check if this spec is a directory */
717 if (!bWildcards)
718 {
719 if (SetCurrentDirectory (szPathspec))
720 {
721 _tcscpy (szFilespec, _T("*.*"));
722
723 if (!GetCurrentDirectory (MAX_PATH, szPath))
724 {
725 szFilespec[0] = _T('\0');
726 SetCurrentDirectory (szOrigPath);
727 error_out_of_memory();
728 return 1;
729 }
730
731 SetCurrentDirectory (szOrigPath);
732 return 0;
733 }
734 }
735
736 /* find the file spec */
737 tmp = _tcsrchr (start, _T('\\'));
738
739 /* if no path is specified */
740 if (!tmp)
741 {
742 _tcscpy (szFilespec, start);
743 ExtendFilespec (szFilespec);
744 if (!GetCurrentDirectory (MAX_PATH, szPath))
745 {
746 szFilespec[0] = _T('\0');
747 SetCurrentDirectory (szOrigPath);
748 error_out_of_memory();
749 return 1;
750 }
751
752 SetCurrentDirectory (szOrigPath);
753 return 0;
754 }
755
756 /* get the filename */
757 _tcscpy (szFilespec, tmp+1);
758 ExtendFilespec (szFilespec);
759
760 if (tmp == start)
761 {
762 /* change to the root directory */
763 if (!SetCurrentDirectory (_T("\\")))
764 {
765 szFilespec[0] = _T('\0');
766 SetCurrentDirectory (szOrigPath);
767 error_path_not_found ();
768 return 1;
769 }
770 }
771 else
772 {
773 *tmp = _T('\0');
774
775 /* change to this directory */
776 if (!SetCurrentDirectory (start))
777 {
778 *tmp = _T('\\');
779 szFilespec[0] = _T('\0');
780 SetCurrentDirectory (szOrigPath);
781 error_path_not_found ();
782 return 1;
783 }
784 }
785
786 /* get the full name of the directory */
787 if (!GetCurrentDirectory (MAX_PATH, szPath))
788 {
789 *tmp = _T('\\');
790 szFilespec[0] = _T('\0');
791 SetCurrentDirectory (szOrigPath);
792 error_out_of_memory ();
793 return 1;
794 }
795
796 *tmp = _T('\\');
797
798 SetCurrentDirectory (szOrigPath);
799
800 return 0;
801 }
802
803
804 /*
805 * incline
806 *
807 * increment our line if paginating, display message at end of screen
808 */
809 #if 0
810 static BOOL
811 IncLine (LPINT pLine, LPDIRSWITCHFLAGS lpFlags)
812 {
813 BOOL bError;
814 CONSOLE_SCREEN_BUFFER_INFO lpConsoleScreenBufferInfo;
815 LONG WindowHeight;
816
817 bError = GetConsoleScreenBufferInfo(hConsole, &lpConsoleScreenBufferInfo);
818
819 WindowHeight = lpConsoleScreenBufferInfo.srWindow.Bottom - lpConsoleScreenBufferInfo.srWindow.Top;
820
821 /* That prevents bad behiour if WindowHeight could not be calculated */
822 if (!WindowHeight)
823 {
824 WindowHeight= 1000000;
825 }
826
827 if (!(lpFlags->bPause))
828 return FALSE;
829
830 (*pLine)++;
831
832 /*
833 * Because I don't know if WindowsHeight work in all cases,
834 * perhaps then maxy is the right value
835 */
836 if (*pLine >= (int)maxy - 2 || *pLine >= WindowHeight)
837 {
838 *pLine = 0;
839 return (PagePrompt () == PROMPT_BREAK);
840 }
841
842 return FALSE;
843 }
844 #endif
845
846 /*
847 * PrintDirectoryHeader
848 *
849 * print the header for the dir command
850 */
851 static BOOL
852 PrintDirectoryHeader(LPTSTR szPath, LPINT pLine, LPDIRSWITCHFLAGS lpFlags)
853 {
854 TCHAR szMsg[RC_STRING_MAX_SIZE];
855 TCHAR szRootName[MAX_PATH];
856 TCHAR szVolName[80];
857 DWORD dwSerialNr;
858 LPTSTR p;
859
860 if (lpFlags->bBareFormat)
861 return TRUE;
862
863 /* build usable root path */
864 if (szPath[1] == _T(':') && szPath[2] == _T('\\'))
865 {
866 /* normal path */
867 szRootName[0] = szPath[0];
868 szRootName[1] = _T(':');
869 szRootName[2] = _T('\\');
870 szRootName[3] = 0;
871 }
872 else if (szPath[0] == _T('\\') && szPath[1] == _T('\\'))
873 {
874 /* UNC path */
875 p = _tcschr(&szPath[2], _T('\\'));
876 if (p == NULL)
877 {
878 error_invalid_drive();
879 return(FALSE);
880 }
881 p = _tcschr(p+1, _T('\\'));
882 if (p == NULL)
883 {
884 _tcscpy(szRootName, szPath);
885 _tcscat(szRootName, _T("\\"));
886 }
887 else
888 {
889 *p = 0;
890 _tcscpy(szRootName, szPath);
891 _tcscat(szRootName, _T("\\"));
892 *p = _T('\\');
893 }
894 }
895 else
896 {
897 error_invalid_drive();
898 return(FALSE);
899 }
900
901 /* get the media ID of the drive */
902 if (!GetVolumeInformation(szRootName, szVolName, 80, &dwSerialNr,
903 NULL, NULL, NULL, 0))
904 {
905 error_invalid_drive();
906 return(FALSE);
907 }
908
909 /* print drive info */
910 if (szVolName[0] != _T('\0'))
911 {
912 LoadString(CMD_ModuleHandle, STRING_DIR_HELP2, szMsg, RC_STRING_MAX_SIZE);
913 //needs to have first paramter as TRUE because
914 //this is the first output and need to clear the static
915 if(lpFlags->bPause)
916 ConOutPrintfPaging(TRUE,szMsg, szRootName[0], szVolName);
917 else
918 ConOutPrintf(szMsg, szRootName[0], szVolName);
919
920 }
921 else
922 {
923 LoadString(CMD_ModuleHandle, STRING_DIR_HELP3, szMsg, RC_STRING_MAX_SIZE);
924 if(lpFlags->bPause)
925 ConOutPrintfPaging(TRUE,szMsg, szRootName[0]);
926 else
927 ConOutPrintf(szMsg, szRootName[0]);
928 }
929
930 /* print the volume serial number if the return was successful */
931 LoadString(CMD_ModuleHandle, STRING_DIR_HELP4, (LPTSTR) szMsg, RC_STRING_MAX_SIZE);
932 if(lpFlags->bPause)
933 ConOutPrintfPaging(FALSE,szMsg,
934 HIWORD(dwSerialNr),
935 LOWORD(dwSerialNr));
936 else
937 ConOutPrintf(szMsg,
938 HIWORD(dwSerialNr),
939 LOWORD(dwSerialNr));
940
941
942 return TRUE;
943 }
944
945
946 /*
947 * convert
948 *
949 * insert commas into a number
950 *
951 */
952 #if 0
953 static INT
954 ConvertULong (ULONG num, LPTSTR des, INT len)
955 {
956 TCHAR temp[32];
957 INT c = 0;
958 INT n = 0;
959
960 if (num == 0)
961 {
962 des[0] = _T('0');
963 des[1] = _T('\0');
964 n = 1;
965 }
966 else
967 {
968 temp[31] = 0;
969 while (num > 0)
970 {
971 if (((c + 1) % (nNumberGroups + 1)) == 0)
972 temp[30 - c++] = cThousandSeparator;
973 temp[30 - c++] = (TCHAR)(num % 10) + _T('0');
974 num /= 10;
975 }
976
977 for (n = 0; n <= c; n++)
978 des[n] = temp[31 - c + n];
979 }
980
981 return n;
982 }
983 #endif
984
985 static VOID
986 DirPrintFileDateTime(TCHAR *lpDate,
987 TCHAR *lpTime,
988 LPWIN32_FIND_DATA lpFile,
989 LPDIRSWITCHFLAGS lpFlags)
990 {
991 FILETIME ft;
992 SYSTEMTIME dt;
993 TCHAR szDate[30];
994 TCHAR szTime[30];
995 WORD wYear;
996
997 /* Select the right time field */
998 switch (lpFlags->stTimeField.eTimeField)
999 {
1000 case TF_CREATIONDATE:
1001 if (!FileTimeToLocalFileTime(&lpFile->ftCreationTime, &ft))
1002 return;
1003 FileTimeToSystemTime(&ft, &dt);
1004 break;
1005
1006 case TF_LASTACCESSEDDATE :
1007 if (!FileTimeToLocalFileTime(&lpFile->ftLastAccessTime, &ft))
1008 return;
1009 FileTimeToSystemTime(&ft, &dt);
1010 break;
1011
1012 case TF_MODIFIEDDATE:
1013 if (!FileTimeToLocalFileTime(&lpFile->ftLastWriteTime, &ft))
1014 return;
1015 FileTimeToSystemTime(&ft, &dt);
1016 break;
1017 }
1018
1019 /* Format date */
1020 wYear = (lpFlags->b4Digit) ? dt.wYear : dt.wYear%100;
1021 switch (nDateFormat)
1022 {
1023 case 0: /* mmddyy */
1024 default:
1025 _stprintf (szDate, _T("%02d%c%02d%c%0*d"),
1026 dt.wMonth, cDateSeparator,
1027 dt.wDay, cDateSeparator,
1028 lpFlags->b4Digit?4:2, wYear);
1029 break;
1030
1031 case 1: /* ddmmyy */
1032 _stprintf (szDate, _T("%02d%c%02d%c%0*d"),
1033 dt.wDay, cDateSeparator, dt.wMonth,
1034 cDateSeparator,lpFlags->b4Digit?4:2, wYear);
1035 break;
1036
1037 case 2: /* yymmdd */
1038 _stprintf (szDate, _T("%0*d%c%02d%c%02d"),
1039 lpFlags->b4Digit?4:2, wYear, cDateSeparator,
1040 dt.wMonth, cDateSeparator, dt.wDay);
1041 break;
1042 }
1043 /* Format Time */
1044 switch (nTimeFormat)
1045 {
1046 case 0: /* 12 hour format */
1047 default:
1048 _stprintf (szTime,_T(" %02d%c%02u%c"),
1049 (dt.wHour == 0 ? 12 : (dt.wHour <= 12 ? dt.wHour : dt.wHour - 12)),
1050 cTimeSeparator,
1051 dt.wMinute, (dt.wHour <= 11 ? _T('a') : _T('p')));
1052 break;
1053
1054 case 1: /* 24 hour format */
1055 _stprintf (szTime, _T(" %02d%c%02u"),
1056 dt.wHour, cTimeSeparator, dt.wMinute);
1057 break;
1058 }
1059 /* Copy results */
1060 _tcscpy(lpDate, szDate);
1061 _tcscpy(lpTime, szTime);
1062 }
1063
1064
1065 static VOID
1066 GetUserDiskFreeSpace(LPCTSTR lpRoot,
1067 PULARGE_INTEGER lpFreeSpace)
1068 {
1069 PGETFREEDISKSPACEEX pGetFreeDiskSpaceEx;
1070 HINSTANCE hInstance;
1071 DWORD dwSecPerCl;
1072 DWORD dwBytPerSec;
1073 DWORD dwFreeCl;
1074 DWORD dwTotCl;
1075 ULARGE_INTEGER TotalNumberOfBytes, TotalNumberOfFreeBytes;
1076
1077 lpFreeSpace->QuadPart = 0;
1078
1079 hInstance = LoadLibrary(_T("KERNEL32"));
1080 if (hInstance != NULL)
1081 {
1082 pGetFreeDiskSpaceEx = (PGETFREEDISKSPACEEX)GetProcAddress(hInstance,
1083 #ifdef _UNICODE
1084 "GetDiskFreeSpaceExW");
1085 #else
1086 "GetDiskFreeSpaceExA");
1087 #endif
1088 if (pGetFreeDiskSpaceEx != NULL)
1089 {
1090 if (pGetFreeDiskSpaceEx(lpRoot, lpFreeSpace, &TotalNumberOfBytes, &TotalNumberOfFreeBytes) == TRUE)
1091 return;
1092 }
1093 FreeLibrary(hInstance);
1094 }
1095
1096 GetDiskFreeSpace(lpRoot,
1097 &dwSecPerCl,
1098 &dwBytPerSec,
1099 &dwFreeCl,
1100 &dwTotCl);
1101
1102 lpFreeSpace->QuadPart = dwSecPerCl * dwBytPerSec * dwFreeCl;
1103 }
1104
1105
1106 /*
1107 * print_summary: prints dir summary
1108 * Added by Rob Lake 06/17/98 to compact code
1109 * Just copied Tim's Code and patched it a bit
1110 *
1111 */
1112 static INT
1113 PrintSummary(LPTSTR szPath,
1114 ULONG ulFiles,
1115 ULONG ulDirs,
1116 ULARGE_INTEGER u64Bytes,
1117 LPINT pLine,
1118 LPDIRSWITCHFLAGS lpFlags)
1119 {
1120 TCHAR szMsg[RC_STRING_MAX_SIZE];
1121 TCHAR szBuffer[64];
1122 ULARGE_INTEGER uliFree;
1123 TCHAR szRoot[] = _T("A:\\");
1124
1125
1126 /* Here we check if we didn't find anything */
1127 if (!(ulFiles + ulDirs))
1128 {
1129 error_file_not_found();
1130 return 1;
1131 }
1132
1133
1134 /* In bare format we don't print results */
1135 if (lpFlags->bBareFormat)
1136 return 0;
1137
1138 /* Print recursive specific results */
1139
1140 /* Take this code offline to fix /S does not print duoble info */
1141 if (lpFlags->bRecursive)
1142 {
1143 ConvertULargeInteger(u64Bytes, szBuffer, sizeof(szBuffer), lpFlags->bTSeperator);
1144 LoadString(CMD_ModuleHandle, STRING_DIR_HELP5, szMsg, RC_STRING_MAX_SIZE);
1145 if(lpFlags->bPause)
1146 ConOutPrintfPaging(FALSE,szMsg,ulFiles, szBuffer);
1147 else
1148 ConOutPrintf(szMsg,ulFiles, szBuffer);
1149 }
1150 else
1151 {
1152
1153 /* Print File Summary */
1154 /* Condition to print summary is:
1155 If we are not in bare format and if we have results! */
1156 if (ulFiles > 0)
1157 {
1158 ConvertULargeInteger(u64Bytes, szBuffer, 20, lpFlags->bTSeperator);
1159 LoadString(CMD_ModuleHandle, STRING_DIR_HELP8, szMsg, RC_STRING_MAX_SIZE);
1160 if(lpFlags->bPause)
1161 ConOutPrintfPaging(FALSE,szMsg,ulFiles, szBuffer);
1162 else
1163 ConOutPrintf(szMsg,ulFiles, szBuffer);
1164
1165 }
1166
1167 }
1168 /* Print total directories and freespace */
1169 szRoot[0] = szPath[0];
1170 GetUserDiskFreeSpace(szRoot, &uliFree);
1171 ConvertULargeInteger(uliFree, szBuffer, sizeof(szBuffer), lpFlags->bTSeperator);
1172 LoadString(CMD_ModuleHandle, STRING_DIR_HELP6, (LPTSTR) szMsg, RC_STRING_MAX_SIZE);
1173 if(lpFlags->bPause)
1174 ConOutPrintfPaging(FALSE,szMsg,ulDirs, szBuffer);
1175 else
1176 ConOutPrintf(szMsg,ulDirs, szBuffer);
1177
1178 return 0;
1179 }
1180
1181 /*
1182 * getExt
1183 *
1184 * Get the extension of a filename
1185 */
1186 TCHAR* getExt(const TCHAR* file)
1187 {
1188 static TCHAR *NoExt = _T("");
1189 TCHAR* lastdot = _tcsrchr(file, _T('.'));
1190 return (lastdot != NULL ? lastdot + 1 : NoExt);
1191 }
1192
1193 /*
1194 * getName
1195 *
1196 * Get the name of the file without extension
1197 */
1198 static LPTSTR
1199 getName(const TCHAR* file, TCHAR * dest)
1200 {
1201 int iLen;
1202 LPTSTR end;
1203
1204 /* Check for "." and ".." folders */
1205 if ((_tcscmp(file, _T(".")) == 0) ||
1206 (_tcscmp(file, _T("..")) == 0))
1207 {
1208 _tcscpy(dest,file);
1209 return dest;
1210 }
1211
1212 end = _tcsrchr(file, _T('.'));
1213 if (!end)
1214 iLen = _tcslen(file);
1215 else
1216 iLen = (end - file);
1217
1218
1219 _tcsncpy(dest, file, iLen);
1220 *(dest + iLen) = _T('\0');
1221
1222 return dest;
1223 }
1224
1225
1226 /*
1227 * DirPrintNewList
1228 *
1229 * The function that prints in new style
1230 */
1231 static VOID
1232 DirPrintNewList(LPWIN32_FIND_DATA ptrFiles[], /* [IN]Files' Info */
1233 DWORD dwCount, /* [IN] The quantity of files */
1234 TCHAR *szCurPath, /* [IN] Full path of current directory */
1235 LPDIRSWITCHFLAGS lpFlags) /* [IN] The flags used */
1236 {
1237 DWORD i;
1238 TCHAR szSize[30];
1239 TCHAR szShortName[15];
1240 TCHAR szDate[20];
1241 TCHAR szTime[20];
1242 INT iSizeFormat;
1243 ULARGE_INTEGER u64FileSize;
1244
1245 for (i = 0;i < dwCount;i++)
1246 {
1247 /* Calculate size */
1248 if (ptrFiles[i]->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1249 {
1250 /* Directory */
1251 iSizeFormat = -14;
1252 _tcscpy(szSize, _T("<DIR>"));
1253 }
1254 else
1255 {
1256 /* File */
1257 iSizeFormat = 14;
1258 u64FileSize.HighPart = ptrFiles[i]->nFileSizeHigh;
1259 u64FileSize.LowPart = ptrFiles[i]->nFileSizeLow;
1260 ConvertULargeInteger(u64FileSize, szSize, 20, lpFlags->bTSeperator);
1261 }
1262
1263 /* Calculate short name */
1264 szShortName[0] = _T('\0');
1265 if (lpFlags->bShortName)
1266 _stprintf(szShortName, _T(" %-12s"), ptrFiles[i]->cAlternateFileName);
1267
1268 /* Format date and time */
1269 DirPrintFileDateTime(szDate, szTime, ptrFiles[i], lpFlags);
1270
1271 /* Print the line */
1272 if(lpFlags->bPause)
1273 {
1274 if (ConOutPrintfPaging(FALSE,_T("%10s %-8s %*s%s %s\n"),
1275 szDate,
1276 szTime,
1277 iSizeFormat,
1278 szSize,
1279 szShortName,
1280 ptrFiles[i]->cFileName) == 1)
1281 return ;
1282 }
1283 else
1284 ConOutPrintf(_T("%10s %-8s %*s%s %s\n"),
1285 szDate,
1286 szTime,
1287 iSizeFormat,
1288 szSize,
1289 szShortName,
1290 ptrFiles[i]->cFileName);
1291 }
1292 }
1293
1294
1295 /*
1296 * DirPrintWideList
1297 *
1298 * The function that prints in wide list
1299 */
1300 static VOID
1301 DirPrintWideList(LPWIN32_FIND_DATA ptrFiles[], /* [IN] Files' Info */
1302 DWORD dwCount, /* [IN] The quantity of files */
1303 TCHAR *szCurPath, /* [IN] Full path of current directory */
1304 LPDIRSWITCHFLAGS lpFlags) /* [IN] The flags used */
1305 {
1306 SHORT iScreenWidth;
1307 USHORT iColumns;
1308 USHORT iLines;
1309 UINT iLongestName;
1310 TCHAR szTempFname[MAX_PATH];
1311 DWORD i;
1312 DWORD j;
1313 DWORD temp;
1314
1315 /* Calculate longest name */
1316 iLongestName = 1;
1317 for (i = 0; i < dwCount; i++)
1318 {
1319 if (ptrFiles[i]->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1320 {
1321 /* Directories need 2 additinal characters for brackets */
1322 if ((_tcslen(ptrFiles[i]->cFileName) + 2) > iLongestName)
1323 iLongestName = _tcslen(ptrFiles[i]->cFileName) + 2;
1324 }
1325 else
1326 {
1327 if (_tcslen(ptrFiles[i]->cFileName) > iLongestName)
1328 iLongestName = _tcslen(ptrFiles[i]->cFileName);
1329 }
1330 }
1331
1332 /* Count the highest number of columns */
1333 GetScreenSize(&iScreenWidth, 0);
1334 iColumns = iScreenWidth / iLongestName;
1335
1336 /* Check if there is enough space for spaces between names */
1337 if (((iLongestName * iColumns) + iColumns) >= (UINT)iScreenWidth)
1338 iColumns --;
1339
1340 /* A last check at iColumns to avoid division by zero */
1341 if (!(iColumns))
1342 iColumns = 1;
1343
1344 /* Print Column sorted */
1345 if (lpFlags->bWideListColSort)
1346 {
1347 /* Calculate the lines that will be printed */
1348 // iLines = ceil((float)dwCount/(float)iColumns);
1349 iLines = (USHORT)(dwCount / iColumns);
1350
1351 for (i = 0;i < iLines;i++)
1352 {
1353 for (j = 0; j < iColumns; j++)
1354 {
1355 temp = (j * iLines) + i;
1356 if (temp >= dwCount)
1357 break;
1358
1359 if (ptrFiles[temp]->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1360 _stprintf(szTempFname, _T("[%s]"), ptrFiles[temp]->cFileName);
1361 else
1362 _stprintf(szTempFname, _T("%s"), ptrFiles[temp]->cFileName);
1363
1364 if(lpFlags->bPause)
1365 ConOutPrintfPaging(FALSE,_T("%-*s"), iLongestName + 1 , szTempFname);
1366 else
1367 ConOutPrintf(_T("%-*s"), iLongestName + 1 , szTempFname);
1368 }
1369
1370 if(lpFlags->bPause)
1371 ConOutPrintfPaging(FALSE,_T("\n"));
1372 else
1373 ConOutPrintf(_T("\n"));
1374 }
1375 }
1376 else
1377 {
1378 /* Print Line sorted */
1379 for (i = 0; i < dwCount; i++)
1380 {
1381 if (ptrFiles[i]->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1382 _stprintf(szTempFname, _T("[%s]"), ptrFiles[i]->cFileName);
1383 else
1384 _stprintf(szTempFname, _T("%s"), ptrFiles[i]->cFileName);
1385
1386 if(lpFlags->bPause)
1387 ConOutPrintfPaging(FALSE,_T("%-*s"), iLongestName + 1, szTempFname );
1388 else
1389 ConOutPrintf(_T("%-*s"), iLongestName + 1, szTempFname );
1390
1391 /*
1392 * We print a new line at the end of each column
1393 * except for the case that it is the last item.
1394 */
1395 if (!((i + 1) % iColumns) && (i < (dwCount - 1)))
1396 {
1397 if(lpFlags->bPause)
1398 ConOutPrintfPaging(FALSE,_T("\n"));
1399 else
1400 ConOutPrintf(_T("\n"));
1401 }
1402 }
1403
1404 /* Add a new line after the last item */
1405 if(lpFlags->bPause)
1406 ConOutPrintfPaging(FALSE,_T("\n"));
1407 else
1408 ConOutPrintf(_T("\n"));
1409 }
1410 }
1411
1412
1413 /*
1414 * DirPrintOldList
1415 *
1416 * The function that prints in old style
1417 */
1418 static VOID
1419 DirPrintOldList(LPWIN32_FIND_DATA ptrFiles[], /* [IN] Files' Info */
1420 DWORD dwCount, /* [IN] The quantity of files */
1421 TCHAR * szCurPath, /* [IN] Full path of current directory */
1422 LPDIRSWITCHFLAGS lpFlags) /* [IN] The flags used */
1423 {
1424 DWORD i; /* An indexer for "for"s */
1425 TCHAR szName[10]; /* The name of file */
1426 TCHAR szExt[5]; /* The extension of file */
1427 TCHAR szDate[30],szTime[30]; /* Used to format time and date */
1428 TCHAR szSize[30]; /* The size of file */
1429 int iSizeFormat; /* The format of size field */
1430 ULARGE_INTEGER u64FileSize; /* The file size */
1431
1432 for(i = 0;i < dwCount;i++)
1433 {
1434 /* Broke 8.3 format */
1435 if (*ptrFiles[i]->cAlternateFileName )
1436 {
1437 /* If the file is long named then we read the alter name */
1438 getName( ptrFiles[i]->cAlternateFileName, szName);
1439 _tcscpy(szExt, getExt( ptrFiles[i]->cAlternateFileName));
1440 }
1441 else
1442 {
1443 /* If the file is not long name we read its original name */
1444 getName( ptrFiles[i]->cFileName, szName);
1445 _tcscpy(szExt, getExt( ptrFiles[i]->cFileName));
1446 }
1447
1448 /* Calculate size */
1449 if (ptrFiles[i]->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1450 {
1451 /* Directory, no size it's a directory*/
1452 iSizeFormat = -17;
1453 _tcscpy(szSize, _T("<DIR>"));
1454 }
1455 else
1456 {
1457 /* File */
1458 iSizeFormat = 17;
1459 u64FileSize.HighPart = ptrFiles[i]->nFileSizeHigh;
1460 u64FileSize.LowPart = ptrFiles[i]->nFileSizeLow;
1461 ConvertULargeInteger(u64FileSize, szSize, 20, lpFlags->bTSeperator);
1462 }
1463
1464 /* Format date and time */
1465 DirPrintFileDateTime(szDate,szTime,ptrFiles[i],lpFlags);
1466
1467 /* Print the line */
1468 if(lpFlags->bPause)
1469 {
1470 if (ConOutPrintfPaging(FALSE,_T("%-8s %-3s %*s %s %s\n"),
1471 szName, /* The file's 8.3 name */
1472 szExt, /* The file's 8.3 extension */
1473 iSizeFormat, /* print format for size column */
1474 szSize, /* The size of file or "<DIR>" for dirs */
1475 szDate, /* The date of file/dir */
1476 szTime) == 1) /* The time of file/dir */
1477 {
1478 return ;
1479 }
1480 }
1481 else
1482 ConOutPrintf(_T("%-8s %-3s %*s %s %s\n"),
1483 szName, /* The file's 8.3 name */
1484 szExt, /* The file's 8.3 extension */
1485 iSizeFormat, /* print format for size column */
1486 szSize, /* The size of file or "<DIR>" for dirs */
1487 szDate, /* The date of file/dir */
1488 szTime); /* The time of file/dir */
1489 }
1490 }
1491
1492 /*
1493 * DirPrintBareList
1494 *
1495 * The function that prints in bare format
1496 */
1497 static VOID
1498 DirPrintBareList(LPWIN32_FIND_DATA ptrFiles[], /* [IN] Files' Info */
1499 DWORD dwCount, /* [IN] The number of files */
1500 LPTSTR lpCurPath, /* [IN] Full path of current directory */
1501 LPDIRSWITCHFLAGS lpFlags) /* [IN] The flags used */
1502 {
1503 TCHAR szFullName[MAX_PATH];
1504 DWORD i;
1505
1506 for (i = 0; i < dwCount; i++)
1507 {
1508 if ((_tcscmp(ptrFiles[i]->cFileName, _T(".")) == 0) ||
1509 (_tcscmp(ptrFiles[i]->cFileName, _T("..")) == 0))
1510 {
1511 /* at bare format we don't print "." and ".." folder */
1512 continue;
1513 }
1514 if (lpFlags->bRecursive)
1515 {
1516 /* at recursive mode we print full path of file */
1517 _tcscpy(szFullName, lpCurPath);
1518 _tcscat(szFullName, ptrFiles[i]->cFileName);
1519 if(lpFlags->bPause)
1520 {
1521 if (ConOutPrintfPaging(FALSE,_T("%s\n"), szFullName) == 1)
1522 {
1523 return ;
1524 }
1525 }
1526 else
1527 ConOutPrintf(_T("%s\n"), szFullName);
1528 }
1529 else
1530 {
1531 /* if we are not in recursive mode we print the file names */
1532 if(lpFlags->bPause)
1533 {
1534 if (ConOutPrintfPaging(FALSE,_T("%s\n"),ptrFiles[i]->cFileName) == 1)
1535 {
1536 return ;
1537 }
1538 }
1539 else
1540 ConOutPrintf(_T("%s\n"),ptrFiles[i]->cFileName);
1541 }
1542 }
1543 }
1544
1545
1546 /*
1547 * DirPrintFiles
1548 *
1549 * The functions that prints the files list
1550 */
1551 static VOID
1552 DirPrintFiles(LPWIN32_FIND_DATA ptrFiles[], /* [IN] Files' Info */
1553 DWORD dwCount, /* [IN] The quantity of files */
1554 TCHAR *szCurPath, /* [IN] Full path of current directory */
1555 LPDIRSWITCHFLAGS lpFlags) /* [IN] The flags used */
1556 {
1557 TCHAR szMsg[RC_STRING_MAX_SIZE];
1558 TCHAR szTemp[MAX_PATH]; /* A buffer to format the directory header */
1559
1560 /* Print directory header */
1561 _tcscpy(szTemp, szCurPath);
1562
1563 /* We cut the trailing \ of the full path */
1564 szTemp[_tcslen(szTemp)-1] = _T('\0');
1565
1566 /* Condition to print header:
1567 We are not printing in bare format
1568 and if we are in recursive mode... we must have results */
1569 if (!(lpFlags->bBareFormat ) && !((lpFlags->bRecursive) && (dwCount <= 0)))
1570 {
1571 LoadString(CMD_ModuleHandle, STRING_DIR_HELP7, szMsg, RC_STRING_MAX_SIZE);
1572 if(lpFlags->bPause)
1573 {
1574 if (ConOutPrintfPaging(FALSE,szMsg, szTemp) == 1)
1575 {
1576 return ;
1577 }
1578 }
1579 else
1580 ConOutPrintf(szMsg, szTemp);
1581 }
1582
1583 if (lpFlags->bBareFormat)
1584 {
1585 /* Bare format */
1586 DirPrintBareList(ptrFiles, dwCount, szCurPath, lpFlags);
1587 }
1588 else if(lpFlags->bShortName)
1589 {
1590 /* New list style / Short names */
1591 DirPrintNewList(ptrFiles, dwCount, szCurPath, lpFlags);
1592 }
1593 else if(lpFlags->bWideListColSort || lpFlags->bWideList)
1594 {
1595 /* Wide list */
1596 DirPrintWideList(ptrFiles, dwCount, szCurPath, lpFlags);
1597 }
1598 else if (lpFlags->bNewLongList )
1599 {
1600 /* New list style*/
1601 DirPrintNewList(ptrFiles, dwCount, szCurPath, lpFlags);
1602 }
1603 else
1604 {
1605 /* If nothing is selected old list is the default */
1606 DirPrintOldList(ptrFiles, dwCount, szCurPath, lpFlags);
1607 }
1608 }
1609
1610
1611
1612 /*
1613 * CompareFiles
1614 *
1615 * Compares 2 files based on the order criteria
1616 */
1617 static BOOL
1618 CompareFiles(LPWIN32_FIND_DATA lpFile1, /* [IN] A pointer to WIN32_FIND_DATA of file 1 */
1619 LPWIN32_FIND_DATA lpFile2, /* [IN] A pointer to WIN32_FIND_DATA of file 2 */
1620 LPDIRSWITCHFLAGS lpFlags) /* [IN] The flags that we use to list */
1621 {
1622 ULARGE_INTEGER u64File1;
1623 ULARGE_INTEGER u64File2;
1624 int i;
1625 long iComp = 0; /* The comparison result */
1626
1627 /* Calculate critiries by order given from user */
1628 for (i = 0;i < lpFlags->stOrderBy.sCriteriaCount;i++)
1629 {
1630
1631 /* Calculate criteria */
1632 switch(lpFlags->stOrderBy.eCriteria[i])
1633 {
1634 case ORDER_SIZE: /* Order by size /o:s */
1635 /* concat the 32bit integers to a 64bit */
1636 u64File1.LowPart = lpFile1->nFileSizeLow;
1637 u64File1.HighPart = lpFile1->nFileSizeHigh;
1638 u64File2.LowPart = lpFile2->nFileSizeLow;
1639 u64File2.HighPart = lpFile2->nFileSizeHigh;
1640
1641 /* In case that differnce is too big for a long */
1642 if (u64File1.QuadPart < u64File2.QuadPart)
1643 iComp = -1;
1644 else if (u64File1.QuadPart > u64File2.QuadPart)
1645 iComp = 1;
1646 else
1647 iComp = 0;
1648 break;
1649
1650 case ORDER_DIRECTORY: /* Order by directory attribute /o:g */
1651 iComp = ((lpFile2->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)-
1652 (lpFile1->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY));
1653 break;
1654
1655 case ORDER_EXTENSION: /* Order by extension name /o:e */
1656 iComp = _tcsicmp(getExt(lpFile1->cFileName),getExt(lpFile2->cFileName));
1657 break;
1658
1659 case ORDER_NAME: /* Order by filename /o:n */
1660 iComp = _tcsicmp(lpFile1->cFileName, lpFile2->cFileName);
1661 break;
1662
1663 case ORDER_TIME: /* Order by file's time /o:t */
1664 /* We compare files based on the time field selected by /t */
1665 switch(lpFlags->stTimeField.eTimeField)
1666 {
1667 case TF_CREATIONDATE:
1668 /* concat the 32bit integers to a 64bit */
1669 u64File1.LowPart = lpFile1->ftCreationTime.dwLowDateTime;
1670 u64File1.HighPart = lpFile1->ftCreationTime.dwHighDateTime ;
1671 u64File2.LowPart = lpFile2->ftCreationTime.dwLowDateTime;
1672 u64File2.HighPart = lpFile2->ftCreationTime.dwHighDateTime ;
1673 break;
1674 case TF_LASTACCESSEDDATE :
1675 /* concat the 32bit integers to a 64bit */
1676 u64File1.LowPart = lpFile1->ftLastAccessTime.dwLowDateTime;
1677 u64File1.HighPart = lpFile1->ftLastAccessTime.dwHighDateTime ;
1678 u64File2.LowPart = lpFile2->ftLastAccessTime.dwLowDateTime;
1679 u64File2.HighPart = lpFile2->ftLastAccessTime.dwHighDateTime ;
1680 break;
1681 case TF_MODIFIEDDATE:
1682 /* concat the 32bit integers to a 64bit */
1683 u64File1.LowPart = lpFile1->ftLastWriteTime.dwLowDateTime;
1684 u64File1.HighPart = lpFile1->ftLastWriteTime.dwHighDateTime ;
1685 u64File2.LowPart = lpFile2->ftLastWriteTime.dwLowDateTime;
1686 u64File2.HighPart = lpFile2->ftLastWriteTime.dwHighDateTime ;
1687 break;
1688 }
1689
1690 /* In case that differnce is too big for a long */
1691 if (u64File1.QuadPart < u64File2.QuadPart)
1692 iComp = -1;
1693 else if (u64File1.QuadPart > u64File2.QuadPart)
1694 iComp = 1;
1695 else
1696 iComp = 0;
1697 break;
1698 }
1699
1700 /* Reverse if desired */
1701 if (lpFlags->stOrderBy.bCriteriaRev[i])
1702 iComp *= -1;
1703
1704 /* If that criteria was enough for distinguishing
1705 the files/dirs,there is no need to calculate the others*/
1706 if (iComp != 0) break;
1707 }
1708
1709 /* Translate the value of iComp to boolean */
1710 if (iComp > 0)
1711 return TRUE;
1712 else
1713 return FALSE;
1714 }
1715
1716 /*
1717 * QsortFiles
1718 *
1719 * Sort files by the order criterias using quicksort method
1720 */
1721 static VOID
1722 QsortFiles(LPWIN32_FIND_DATA ptrArray[], /* [IN/OUT] The array with file info pointers */
1723 int i, /* [IN] The index of first item in array */
1724 int j, /* [IN] The index to last item in array */
1725 LPDIRSWITCHFLAGS lpFlags) /* [IN] The flags that we will use to sort */
1726 {
1727 LPWIN32_FIND_DATA lpTemp; /* A temporary pointer */
1728 int First, Last, Temp;
1729 BOOL Way;
1730
1731 if (i < j)
1732 {
1733 First = i;
1734 Last = j;
1735 Way = TRUE;
1736 while (i != j)
1737 {
1738 if (Way == CompareFiles(ptrArray[i], ptrArray[j], lpFlags))
1739 {
1740 /* Swap the pointers of the array */
1741 lpTemp = ptrArray[i];
1742 ptrArray[i]= ptrArray[j];
1743 ptrArray[j] = lpTemp;
1744
1745 /* Swap the indexes for inverting sorting */
1746 Temp = i;
1747 i = j;
1748 j =Temp;
1749
1750 Way = !Way;
1751 }
1752
1753 j += (!Way - Way);
1754 }
1755
1756 QsortFiles(ptrArray,First, i-1, lpFlags);
1757 QsortFiles(ptrArray,i+1,Last, lpFlags);
1758 }
1759 }
1760
1761
1762
1763 /*
1764 * DirList
1765 *
1766 * The functions that does everything except for printing results
1767 */
1768 static INT
1769 DirList(LPTSTR szPath, /* [IN] The path that dir starts */
1770 LPTSTR szFilespec, /* [IN] The type of file that we are looking for */
1771 LPINT pLine, /* FIXME: Maybe used for paginating */
1772 LPDIRSWITCHFLAGS lpFlags) /* [IN] The flags of the listing */
1773 {
1774 HANDLE hSearch; /* The handle of the search */
1775 HANDLE hRecSearch; /* The handle for searching recursivly */
1776 WIN32_FIND_DATA wfdFileInfo; /* The info of file that found */
1777 LPWIN32_FIND_DATA * ptrFileArray; /* An array of pointers with all the files */
1778 PDIRFINDLISTNODE ptrStartNode; /* The pointer to the first node */
1779 PDIRFINDLISTNODE ptrNextNode; /* A pointer used for relatives refernces */
1780 TCHAR szFullPath[MAX_PATH]; /* The full path that we are listing with trailing \ */
1781 TCHAR szFullFileSpec[MAX_PATH]; /* The full path with file specs that we ll request\ */
1782 DWORD dwCount; /* A counter of files found in directory */
1783 DWORD dwCountFiles; /* Counter for files */
1784 DWORD dwCountDirs; /* Counter for directories */
1785 ULARGE_INTEGER u64CountBytes; /* Counter for bytes */
1786 ULARGE_INTEGER u64Temp; /* A temporary counter */
1787
1788 /* Initialize Variables */
1789 ptrStartNode = NULL;
1790 ptrNextNode = NULL;
1791 dwCount = 0;
1792 dwCountFiles = 0;
1793 dwCountDirs = 0;
1794 u64CountBytes.QuadPart = 0;
1795
1796 /* Create szFullPath and szFullFileSpec */
1797 _tcscpy (szFullPath, szPath);
1798 if (szFullPath[_tcslen(szFullPath) - 1] != _T('\\'))
1799 _tcscat (szFullPath, _T("\\"));
1800 _tcscpy (szFullFileSpec, szFullPath);
1801 _tcscat (szFullFileSpec, szFilespec);
1802
1803 /* Prepare the linked list, first node is allocated */
1804 ptrStartNode = malloc(sizeof(DIRFINDLISTNODE));
1805 if (ptrStartNode == NULL)
1806 {
1807 #ifdef _DEBUG
1808 ConErrPrintf(_T("DEBUG: Cannot allocate memory for ptrStartNode!\n"));
1809 #endif
1810 return 1; /* Error cannot allocate memory for 1st object */
1811 }
1812 ptrNextNode = ptrStartNode;
1813
1814 /* Collect the results for the current folder */
1815 hSearch = FindFirstFile(szFullFileSpec, &wfdFileInfo);
1816 do
1817 {
1818 if (hSearch != INVALID_HANDLE_VALUE)
1819 {
1820 /* Here we filter all the specified attributes */
1821 if ((wfdFileInfo.dwFileAttributes & lpFlags->stAttribs.dwAttribMask )
1822 == (lpFlags->stAttribs.dwAttribMask & lpFlags->stAttribs.dwAttribVal ))
1823 {
1824 ptrNextNode->ptrNext = malloc(sizeof(DIRFINDLISTNODE));
1825 if (ptrNextNode->ptrNext == NULL)
1826 {
1827 #ifdef _DEBUG
1828 ConErrPrintf(_T("DEBUG: Cannot allocate memory for ptrNextNode->ptrNext!\n"));
1829 #endif
1830 while (ptrStartNode)
1831 {
1832 ptrNextNode = ptrStartNode->ptrNext;
1833 free(ptrStartNode);
1834 ptrStartNode = ptrNextNode;
1835 dwCount --;
1836 }
1837 return 1;
1838 }
1839
1840 /* If malloc fails we go to next file in hope it works,
1841 without braking the linked list! */
1842 if (ptrNextNode->ptrNext)
1843 {
1844 /* Copy the info of search at linked list */
1845 memcpy(&ptrNextNode->ptrNext->stFindInfo,
1846 &wfdFileInfo,
1847 sizeof(WIN32_FIND_DATA));
1848
1849 /* If lower case is selected do it here */
1850 if (lpFlags->bLowerCase)
1851 {
1852 _tcslwr(ptrNextNode->ptrNext->stFindInfo.cAlternateFileName);
1853 _tcslwr(ptrNextNode->ptrNext->stFindInfo.cFileName);
1854 }
1855
1856 /* Continue at next node at linked list */
1857 ptrNextNode = ptrNextNode->ptrNext;
1858 dwCount ++;
1859
1860 /* Grab statistics */
1861 if (wfdFileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1862 {
1863 /* Directory */
1864 dwCountDirs++;
1865 }
1866 else
1867 {
1868 /* File */
1869 dwCountFiles++;
1870 u64Temp.HighPart = wfdFileInfo.nFileSizeHigh;
1871 u64Temp.LowPart = wfdFileInfo.nFileSizeLow;
1872 u64CountBytes.QuadPart += u64Temp.QuadPart;
1873 }
1874 }
1875 }
1876 }
1877 }while(FindNextFile(hSearch, &wfdFileInfo));
1878 FindClose(hSearch);
1879
1880 /* Terminate list */
1881 ptrNextNode->ptrNext = NULL;
1882
1883 /* Calculate and allocate space need for making an array of pointers */
1884 ptrFileArray = malloc(sizeof(LPWIN32_FIND_DATA) * dwCount);
1885 if (ptrFileArray == NULL)
1886 {
1887 #ifdef _DEBUG
1888 ConErrPrintf(_T("DEBUG: Cannot allocate memory for ptrFileArray!\n"));
1889 #endif
1890 while (ptrStartNode)
1891 {
1892 ptrNextNode = ptrStartNode->ptrNext;
1893 free(ptrStartNode);
1894 ptrStartNode = ptrNextNode;
1895 dwCount --;
1896 }
1897 return 1;
1898 }
1899
1900 /*
1901 * Create an array of pointers from the linked list
1902 * this will be used to sort and print data, rather than the list
1903 */
1904 ptrNextNode = ptrStartNode;
1905 dwCount = 0;
1906 while (ptrNextNode->ptrNext)
1907 {
1908 *(ptrFileArray + dwCount) = &ptrNextNode->ptrNext->stFindInfo;
1909 ptrNextNode = ptrNextNode->ptrNext;
1910 dwCount++;
1911 }
1912
1913 /* Sort Data if requested*/
1914 if (lpFlags->stOrderBy.sCriteriaCount > 0)
1915 QsortFiles(ptrFileArray, 0, dwCount-1,lpFlags);
1916
1917 /* Print Data */
1918 DirPrintFiles(ptrFileArray, dwCount, szFullPath, lpFlags);
1919
1920 /* Free array */
1921 free(ptrFileArray);
1922 if (CheckCtrlBreak(BREAK_INPUT))
1923 return 1;
1924
1925
1926 /* Add statistics to recursive statistics*/
1927 recurse_dir_cnt += dwCountDirs;
1928 recurse_file_cnt += dwCountFiles;
1929 recurse_bytes.QuadPart += u64CountBytes.QuadPart;
1930
1931 /* Do the recursive job if requested
1932 the recursive is be done on ALL(indepent of their attribs)
1933 directoried of the current one.*/
1934 if (lpFlags->bRecursive)
1935 {
1936 /* The new search is involving any *.* file */
1937 _tcscpy(szFullFileSpec, szFullPath);
1938 _tcscat(szFullFileSpec, _T("*.*"));
1939 hRecSearch = FindFirstFile (szFullFileSpec, &wfdFileInfo);
1940 do
1941 {
1942 if (hRecSearch != INVALID_HANDLE_VALUE)
1943 {
1944 /* We search for directories other than "." and ".." */
1945 if ((_tcsicmp(wfdFileInfo.cFileName, _T(".")) != 0) &&
1946 (_tcsicmp(wfdFileInfo.cFileName, _T("..")) != 0 ) &&
1947 (wfdFileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
1948 {
1949 /* Concat the path and the directory to do recursive */
1950 _tcscpy(szFullFileSpec, szFullPath);
1951 _tcscat(szFullFileSpec, wfdFileInfo.cFileName);
1952 /* We do the same for tha folder */
1953 if (DirList(szFullFileSpec, szFilespec, pLine,lpFlags) != 0)
1954 {
1955 return 1;
1956 }
1957 }
1958 }
1959 }while(FindNextFile(hRecSearch,&wfdFileInfo));
1960 FindClose(hRecSearch);
1961 }
1962
1963 /* Free linked list */
1964 while (ptrStartNode)
1965 {
1966 ptrNextNode = ptrStartNode->ptrNext;
1967 free(ptrStartNode);
1968 ptrStartNode = ptrNextNode;
1969 dwCount --;
1970 }
1971
1972 return 0;
1973 }
1974
1975
1976
1977 /*
1978 * dir
1979 *
1980 * internal dir command
1981 */
1982 INT
1983 CommandDir(LPTSTR first, LPTSTR rest)
1984 {
1985 TCHAR dircmd[256]; /* A variable to store the DIRCMD enviroment variable */
1986 TCHAR cDrive;
1987 TCHAR szPath[MAX_PATH];
1988 TCHAR szFilespec[MAX_PATH];
1989 LPTSTR* params;
1990 INT entries = 0;
1991 INT nLine = 0;
1992 UINT loop = 0;
1993 DIRSWITCHFLAGS stFlags;
1994
1995 /* Initialize variables */
1996 cDrive = 0;
1997 recurse_dir_cnt = 0L;
1998 recurse_file_cnt = 0L;
1999 recurse_bytes.QuadPart = 0;
2000
2001 /* Initialize Switch Flags < Default switches are setted here!> */
2002 stFlags.b4Digit = TRUE;
2003 stFlags.bBareFormat = FALSE;
2004 stFlags.bLowerCase = FALSE;
2005 stFlags.bNewLongList = TRUE;
2006 stFlags.bPause = FALSE;
2007 stFlags.bRecursive = FALSE;
2008 stFlags.bShortName = FALSE;
2009 stFlags.bTSeperator = TRUE;
2010 stFlags.bUser = FALSE;
2011 stFlags.bWideList = FALSE;
2012 stFlags.bWideListColSort = FALSE;
2013 stFlags.stTimeField.eTimeField = TF_MODIFIEDDATE;
2014 stFlags.stTimeField.bUnSet = FALSE;
2015 stFlags.stAttribs.dwAttribMask = FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM;
2016 stFlags.stAttribs.dwAttribVal = 0L;
2017 stFlags.stAttribs.bUnSet = FALSE;
2018 stFlags.stOrderBy.sCriteriaCount = 0;
2019 stFlags.stOrderBy.bUnSet = FALSE;
2020
2021 nErrorLevel = 0;
2022
2023 /* read the parameters from the DIRCMD environment variable */
2024 if (GetEnvironmentVariable (_T("DIRCMD"), dircmd, 256))
2025 if (!DirReadParam(dircmd, &params, &entries, &stFlags))
2026 {
2027 nErrorLevel = 1;
2028 return 1;
2029 }
2030
2031 /* read the parameters */
2032 if (!DirReadParam(rest, &params, &entries, &stFlags) || CheckCtrlBreak(BREAK_INPUT))
2033 {
2034 nErrorLevel = 1;
2035 return 1;
2036 }
2037
2038 /* default to current directory */
2039 if(entries == 0) {
2040 if(!add_entry(&entries, &params, _T("."))) {
2041 nErrorLevel = 1;
2042 return 1;
2043 }
2044 }
2045
2046 for(loop = 0; loop < entries; loop++)
2047 {
2048 /* parse the directory info */
2049 if (DirParsePathspec (params[loop], szPath, szFilespec) || CheckCtrlBreak(BREAK_INPUT))
2050 {
2051 nErrorLevel = 1;
2052 return 1;
2053 }
2054
2055 /* <Debug :>
2056 Uncomment this to show the final state of switch flags*/
2057 #ifdef _DEBUG
2058 {
2059 int i;
2060 ConOutPrintf(_T("Attributes mask/value %x/%x\n"),stFlags.stAttribs.dwAttribMask,stFlags.stAttribs.dwAttribVal );
2061 ConOutPrintf(_T("(B) Bare format : %i\n"), stFlags.bBareFormat );
2062 ConOutPrintf(_T("(C) Thousand : %i\n"), stFlags.bTSeperator );
2063 ConOutPrintf(_T("(W) Wide list : %i\n"), stFlags.bWideList );
2064 ConOutPrintf(_T("(D) Wide list sort by column : %i\n"), stFlags.bWideListColSort );
2065 ConOutPrintf(_T("(L) Lowercase : %i\n"), stFlags.bLowerCase );
2066 ConOutPrintf(_T("(N) New : %i\n"), stFlags.bNewLongList );
2067 ConOutPrintf(_T("(O) Order : %i\n"), stFlags.stOrderBy.sCriteriaCount );
2068 for (i =0;i<stFlags.stOrderBy.sCriteriaCount;i++)
2069 ConOutPrintf(_T(" Order Criteria [%i]: %i (Reversed: %i)\n"),i, stFlags.stOrderBy.eCriteria[i], stFlags.stOrderBy.bCriteriaRev[i] );
2070 ConOutPrintf(_T("(P) Pause : %i\n"), stFlags.bPause );
2071 ConOutPrintf(_T("(Q) Owner : %i\n"), stFlags.bUser );
2072 ConOutPrintf(_T("(S) Recursive : %i\n"), stFlags.bRecursive );
2073 ConOutPrintf(_T("(T) Time field : %i\n"), stFlags.stTimeField.eTimeField );
2074 ConOutPrintf(_T("(X) Short names : %i\n"), stFlags.bShortName );
2075 ConOutPrintf(_T("Parameter : %s\n"), params[loop] );
2076 }
2077 #endif
2078
2079 /* Print the drive header if the drive changed */
2080 if(cDrive != szPath[0] && !stFlags.bBareFormat) {
2081 if (!PrintDirectoryHeader (szPath, &nLine, &stFlags)) {
2082 nErrorLevel = 1;
2083 return 1;
2084 }
2085
2086 cDrive = szPath[0];
2087 }
2088
2089
2090 /* do the actual dir */
2091 if (DirList (szPath, szFilespec, &nLine, &stFlags))
2092 {
2093 nErrorLevel = 1;
2094 return 1;
2095 }
2096 }
2097
2098 /* print the footer */
2099 PrintSummary(szPath,
2100 recurse_file_cnt,
2101 recurse_dir_cnt,
2102 recurse_bytes,
2103 &nLine,
2104 &stFlags);
2105
2106 return 0;
2107 }
2108
2109 #endif
2110
2111 /* EOF */