2 * WCMD - Wine-compatible command line interface - Directory functions.
4 * Copyright (C) 1999 D A Pickles
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 * On entry, global variables quals, param1, param2 contain
24 * the qualifiers (uppercased and concatenated) and parameters entered, with
25 * environment-variable and batch parameter substitution already done.
30 int WCMD_dir_sort (const void *a
, const void *b
);
31 void WCMD_list_directory (char *path
, int level
);
32 char * WCMD_filesize64 (__int64 free
);
33 char * WCMD_strrev (char *buff
);
37 extern char newline
[];
38 extern char version_string
[];
41 extern char quals
[MAX_PATH
], param1
[MAX_PATH
], param2
[MAX_PATH
];
42 extern DWORD errorlevel
;
44 int file_total
, dir_total
, line_count
, page_mode
, recurse
;
47 /*****************************************************************************
50 * List a file directory.
54 void WCMD_directory () {
56 char path
[MAX_PATH
], drive
[8];
58 ULARGE_INTEGER avail
, total
, free
;
62 file_total
= dir_total
= 0;
63 page_mode
= (strstr(quals
, "/P") != NULL
);
64 recurse
= (strstr(quals
, "/S") != NULL
);
65 if (param1
[0] == '\0') strcpy (param1
, ".");
66 status
= GetFullPathName (param1
, sizeof(path
), path
, NULL
);
71 lstrcpyn (drive
, path
, 3);
72 status
= WCMD_volume (0, drive
);
76 WCMD_list_directory (path
, 0);
77 lstrcpyn (drive
, path
, 4);
78 GetDiskFreeSpaceEx (drive
, &avail
, &total
, &free
);
79 WCMD_output (" %18s bytes free\n\n", WCMD_filesize64 (free
.QuadPart
));
81 WCMD_output ("Total files listed:\n%8d files%25s bytes\n%8d directories\n\n",
82 file_total
, WCMD_filesize64 (byte_total
), dir_total
);
86 /*****************************************************************************
89 * List a single file directory. This function (and those below it) can be called
90 * recursively when the /S switch is used.
92 * FIXME: Entries sorted by name only. Should we support DIRCMD??
93 * FIXME: Assumes 24-line display for the /P qualifier.
94 * FIXME: Other command qualifiers not supported.
95 * FIXME: DIR /S FILENAME fails if at least one matching file is not found in the top level.
98 void WCMD_list_directory (char *search_path
, int level
) {
100 char string
[1024], datestring
[32], timestring
[32];
101 char mem_err
[] = "Memory Allocation Error";
108 int status
, dir_count
, file_count
, entry_count
, i
;
109 ULARGE_INTEGER byte_count
, file_size
;
114 byte_count
.QuadPart
= 0;
117 * If the path supplied does not include a wildcard, and the endpoint of the
118 * path references a directory, we need to list the *contents* of that
119 * directory not the directory file itself.
122 if ((strchr(search_path
, '*') == NULL
) && (strchr(search_path
, '%') == NULL
)) {
123 status
= GetFileAttributes (search_path
);
124 if ((status
!= -1) && (status
& FILE_ATTRIBUTE_DIRECTORY
)) {
125 if (search_path
[strlen(search_path
)-1] == '\\') {
126 strcat (search_path
, "*");
129 strcat (search_path
, "\\*");
134 fd
= malloc (sizeof(WIN32_FIND_DATA
));
135 hff
= FindFirstFile (search_path
, fd
);
136 if (hff
== INVALID_HANDLE_VALUE
) {
137 SetLastError (ERROR_FILE_NOT_FOUND
);
144 fd
= realloc (fd
, (entry_count
+1)*sizeof(WIN32_FIND_DATA
));
147 WCMD_output (mem_err
);
150 } while (FindNextFile(hff
, (fd
+entry_count
)) != 0);
152 qsort (fd
, entry_count
, sizeof(WIN32_FIND_DATA
), WCMD_dir_sort
);
153 if (level
!= 0) WCMD_output ("\n\n");
154 WCMD_output ("Directory of %s\n\n", search_path
);
157 if (line_count
> 23) {
159 WCMD_output (anykey
);
160 ReadFile (GetStdHandle(STD_INPUT_HANDLE
), string
, sizeof(string
), &count
, NULL
);
163 for (i
=0; i
<entry_count
; i
++) {
164 FileTimeToLocalFileTime (&(fd
+i
)->ftLastWriteTime
, &ft
);
165 FileTimeToSystemTime (&ft
, &st
);
166 GetDateFormat (0, DATE_SHORTDATE
, &st
, NULL
, datestring
,
168 GetTimeFormat (0, TIME_NOSECONDS
, &st
,
169 NULL
, timestring
, sizeof(timestring
));
170 if ((fd
+i
)->dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
) {
172 WCMD_output ("%8s %8s <DIR> %s\n",
173 datestring
, timestring
, (fd
+i
)->cFileName
);
177 #ifndef NONAMELESSSTRUCT
178 file_size
.LowPart
= (fd
+i
)->nFileSizeLow
;
179 file_size
.HighPart
= (fd
+i
)->nFileSizeHigh
;
181 file_size
.s
.LowPart
= (fd
+i
)->nFileSizeLow
;
182 file_size
.s
.HighPart
= (fd
+i
)->nFileSizeHigh
;
184 byte_count
.QuadPart
+= file_size
.QuadPart
;
185 WCMD_output ("%8s %8s %10s %s\n",
186 datestring
, timestring
,
187 WCMD_filesize64(file_size
.QuadPart
), (fd
+i
)->cFileName
);
190 if (++line_count
> 23) {
192 WCMD_output (anykey
);
193 ReadFile (GetStdHandle(STD_INPUT_HANDLE
), string
, sizeof(string
), &count
, NULL
);
197 if (file_count
== 1) {
198 WCMD_output (" 1 file %25s bytes\n", WCMD_filesize64 (byte_count
.QuadPart
));
201 WCMD_output ("%8d files %24s bytes\n", file_count
, WCMD_filesize64 (byte_count
.QuadPart
));
204 if (++line_count
> 23) {
206 WCMD_output (anykey
);
207 ReadFile (GetStdHandle(STD_INPUT_HANDLE
), string
, sizeof(string
), &count
, NULL
);
210 byte_total
= byte_total
+ byte_count
.QuadPart
;
211 file_total
= file_total
+ file_count
;
212 dir_total
= dir_total
+ dir_count
;
213 if (dir_count
== 1) WCMD_output ("1 directory ");
214 else WCMD_output ("%8d directories", dir_count
);
216 if (++line_count
> 23) {
218 WCMD_output (anykey
);
219 ReadFile (GetStdHandle(STD_INPUT_HANDLE
), string
, sizeof(string
), &count
, NULL
);
222 for (i
=0; i
<entry_count
; i
++) {
224 ((fd
+i
)->cFileName
[0] != '.') &&
225 ((fd
+i
)->dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)) {
227 GetFullPathName ((fd
+i
)->cFileName
, sizeof(string
), string
, NULL
);
229 p
= strrchr (search_path
, '\\');
230 lstrcpyn (string
, search_path
, (p
-search_path
+2));
231 lstrcat (string
, (fd
+i
)->cFileName
);
233 WCMD_list_directory (string
, 1);
240 /*****************************************************************************
243 * Convert a 64-bit number into a character string, with commas every three digits.
244 * Result is returned in a static string overwritten with each call.
245 * FIXME: There must be a better algorithm!
248 char * WCMD_filesize64 (__int64 n
) {
253 static char buff
[32];
258 if ((++i
)%3 == 1) *p
++ = ',';
269 /*****************************************************************************
272 * Reverse a character string in-place (strrev() is not available under unixen :-( ).
275 char * WCMD_strrev (char *buff
) {
281 for (i
=0; i
<r
/2; i
++) {
283 buff
[i
] = buff
[r
-i
-1];
290 int WCMD_dir_sort (const void *a
, const void *b
) {
292 return (lstrcmpi(((WIN32_FIND_DATA
*)a
)->cFileName
,
293 ((WIN32_FIND_DATA
*)b
)->cFileName
));