Mercurial > hg > xemacs-beta
comparison src/dired-msw.c @ 771:943eaba38521
[xemacs-hg @ 2002-03-13 08:51:24 by ben]
The big ben-mule-21-5 check-in!
Various files were added and deleted. See CHANGES-ben-mule.
There are still some test suite failures. No crashes, though.
Many of the failures have to do with problems in the test suite itself
rather than in the actual code. I'll be addressing these in the next
day or so -- none of the test suite failures are at all critical.
Meanwhile I'll be trying to address the biggest issues -- i.e. build
or run failures, which will almost certainly happen on various platforms.
All comments should be sent to ben@xemacs.org -- use a Cc: if necessary
when sending to mailing lists. There will be pre- and post- tags,
something like
pre-ben-mule-21-5-merge-in, and
post-ben-mule-21-5-merge-in.
author | ben |
---|---|
date | Wed, 13 Mar 2002 08:54:06 +0000 |
parents | 11502791fc1c |
children | a5954632b187 |
comparison
equal
deleted
inserted
replaced
770:336a418893b5 | 771:943eaba38521 |
---|---|
1 /* fast dired replacement routines for mswindows. | 1 /* fast dired replacement routines for mswindows. |
2 Copyright (C) 1998 Darryl Okahata | 2 Copyright (C) 1998 Darryl Okahata |
3 Portions Copyright (C) 1992, 1994 by Sebastian Kremer <sk@thp.uni-koeln.de> | 3 Portions Copyright (C) 1992, 1994 by Sebastian Kremer <sk@thp.uni-koeln.de> |
4 Copyright (C) 2000, 2001 Ben Wing. | |
4 | 5 |
5 This file is part of XEmacs. | 6 This file is part of XEmacs. |
6 | 7 |
7 XEmacs is free software; you can redistribute it and/or modify it | 8 XEmacs is free software; you can redistribute it and/or modify it |
8 under the terms of the GNU General Public License as published by the | 9 under the terms of the GNU General Public License as published by the |
18 along with XEmacs; see the file COPYING. If not, write to | 19 along with XEmacs; see the file COPYING. If not, write to |
19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | 20 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
20 Boston, MA 02111-1307, USA. */ | 21 Boston, MA 02111-1307, USA. */ |
21 | 22 |
22 /* Synched up with: Not in FSF. */ | 23 /* Synched up with: Not in FSF. */ |
24 | |
23 | 25 |
24 /* | 26 /* |
25 * Parts of this code (& comments) were taken from ls-lisp.el | 27 * Parts of this code (& comments) were taken from ls-lisp.el |
26 * Author: Sebastian Kremer <sk@thp.uni-koeln.de> | 28 * Author: Sebastian Kremer <sk@thp.uni-koeln.de> |
27 */ | 29 */ |
62 | 64 |
63 /* | 65 /* |
64 * Set INDENT_LISTING to non-zero if the inserted text should be shifted | 66 * Set INDENT_LISTING to non-zero if the inserted text should be shifted |
65 * over by two spaces. | 67 * over by two spaces. |
66 */ | 68 */ |
67 #define INDENT_LISTING 0 | 69 #define INDENT_LISTING 0 |
68 | 70 |
69 #define ROUND_FILE_SIZES 4096 | 71 #define ROUND_FILE_SIZES 4096 |
70 | 72 |
71 | 73 |
72 #include <config.h> | 74 #include <config.h> |
73 #include "lisp.h" | 75 #include "lisp.h" |
74 | 76 |
75 #include "buffer.h" | 77 #include "buffer.h" |
76 #include "nt.h" | |
77 #include "regex.h" | 78 #include "regex.h" |
78 | 79 |
79 #include "sysdir.h" | 80 #include "sysdir.h" |
80 #include "sysproc.h" | |
81 #include "sysfile.h" | 81 #include "sysfile.h" |
82 #include "sysfloat.h" | 82 #include "sysfloat.h" |
83 | 83 #include "sysproc.h" |
84 #include "syspwd.h" | |
85 #include "systime.h" | |
86 #include "syswindows.h" | |
84 | 87 |
85 static int mswindows_ls_sort_case_insensitive; | 88 static int mswindows_ls_sort_case_insensitive; |
86 static Fixnum mswindows_ls_round_file_size; | 89 static Fixnum mswindows_ls_round_file_size; |
87 | 90 |
88 Lisp_Object Qmswindows_insert_directory; | 91 Lisp_Object Qmswindows_insert_directory; |
89 | 92 Lisp_Object Qwildcard_to_regexp; |
90 extern Lisp_Object Vmswindows_downcase_file_names; /* in device-msw.c */ | 93 |
94 extern Lisp_Object Vmswindows_downcase_file_names; /* in device-msw.c */ | |
91 | 95 |
92 enum mswindows_sortby | 96 enum mswindows_sortby |
93 { | 97 { |
94 MSWINDOWS_SORT_BY_NAME, | 98 MSWINDOWS_SORT_BY_NAME, |
95 MSWINDOWS_SORT_BY_NAME_NOCASE, | 99 MSWINDOWS_SORT_BY_NAME_NOCASE, |
96 MSWINDOWS_SORT_BY_MOD_DATE, | 100 MSWINDOWS_SORT_BY_MOD_DATE, |
97 MSWINDOWS_SORT_BY_SIZE | 101 MSWINDOWS_SORT_BY_SIZE |
98 }; | 102 }; |
99 | 103 |
100 | 104 |
101 static enum mswindows_sortby mswindows_sort_method; | 105 static enum mswindows_sortby mswindows_sort_method; |
102 static int mswindows_reverse_sort; | 106 static int mswindows_reverse_sort; |
107 | |
108 /* We create our own structure because the cFileName field in | |
109 WIN32_FIND_DATA is in external format and of fixed size, which we | |
110 may exceed when translating. */ | |
111 | |
112 typedef struct | |
113 { | |
114 DWORD dwFileAttributes; | |
115 FILETIME ftCreationTime; | |
116 FILETIME ftLastAccessTime; | |
117 FILETIME ftLastWriteTime; | |
118 DWORD nFileSizeHigh; | |
119 DWORD nFileSizeLow; | |
120 Intbyte *cFileName; | |
121 } Win32_file; | |
122 | |
123 typedef struct | |
124 { | |
125 Dynarr_declare (Win32_file); | |
126 } Win32_file_dynarr; | |
127 | |
103 | 128 |
104 | 129 |
105 #define CMPDWORDS(t1a, t1b, t2a, t2b) \ | 130 #define CMPDWORDS(t1a, t1b, t2a, t2b) \ |
106 (((t1a) == (t2a)) ? (((t1b) == (t2b)) ? 0 : (((t1b) < (t2b)) ? -1 : 1)) \ | 131 (((t1a) == (t2a)) ? (((t1b) == (t2b)) ? 0 : (((t1b) < (t2b)) ? -1 : 1)) \ |
107 : (((t1a) < (t2a)) ? -1 : 1)) | 132 : (((t1a) < (t2a)) ? -1 : 1)) |
108 | 133 |
109 | 134 |
110 static int | 135 static int |
111 mswindows_ls_sort_fcn (const void *elem1, const void *elem2) | 136 mswindows_ls_sort_fcn (const void *elem1, const void *elem2) |
112 { | 137 { |
113 WIN32_FIND_DATA *e1, *e2; | 138 Win32_file *e1, *e2; |
114 int status; | 139 int status; |
115 | 140 |
116 e1 = *(WIN32_FIND_DATA **)elem1; | 141 e1 = (Win32_file *) elem1; |
117 e2 = *(WIN32_FIND_DATA **)elem2; | 142 e2 = (Win32_file *) elem2; |
143 | |
118 switch (mswindows_sort_method) | 144 switch (mswindows_sort_method) |
119 { | 145 { |
120 case MSWINDOWS_SORT_BY_NAME: | 146 case MSWINDOWS_SORT_BY_NAME: |
121 status = strcmp(e1->cFileName, e2->cFileName); | 147 status = strcmp (e1->cFileName, e2->cFileName); |
122 break; | 148 break; |
123 case MSWINDOWS_SORT_BY_NAME_NOCASE: | 149 case MSWINDOWS_SORT_BY_NAME_NOCASE: |
124 status = _stricmp(e1->cFileName, e2->cFileName); | 150 status = qxestrcasecmp (e1->cFileName, e2->cFileName); |
125 break; | 151 break; |
126 case MSWINDOWS_SORT_BY_MOD_DATE: | 152 case MSWINDOWS_SORT_BY_MOD_DATE: |
127 status = CMPDWORDS(e1->ftLastWriteTime.dwHighDateTime, | 153 status = CMPDWORDS (e1->ftLastWriteTime.dwHighDateTime, |
128 e1->ftLastWriteTime.dwLowDateTime, | 154 e1->ftLastWriteTime.dwLowDateTime, |
129 e2->ftLastWriteTime.dwHighDateTime, | 155 e2->ftLastWriteTime.dwHighDateTime, |
130 e2->ftLastWriteTime.dwLowDateTime); | 156 e2->ftLastWriteTime.dwLowDateTime); |
131 break; | 157 break; |
132 case MSWINDOWS_SORT_BY_SIZE: | 158 case MSWINDOWS_SORT_BY_SIZE: |
133 status = CMPDWORDS(e1->nFileSizeHigh, e1->nFileSizeLow, | 159 status = CMPDWORDS (e1->nFileSizeHigh, e1->nFileSizeLow, |
134 e2->nFileSizeHigh, e2->nFileSizeLow); | 160 e2->nFileSizeHigh, e2->nFileSizeLow); |
135 break; | 161 break; |
136 default: | 162 default: |
137 status = 0; | 163 status = 0; |
138 break; | 164 break; |
139 } | 165 } |
142 status = -status; | 168 status = -status; |
143 } | 169 } |
144 return (status); | 170 return (status); |
145 } | 171 } |
146 | 172 |
147 | |
148 static void | 173 static void |
149 mswindows_sort_files (WIN32_FIND_DATA **files, int nfiles, | 174 mswindows_sort_files (Win32_file_dynarr *files, |
150 enum mswindows_sortby sort_by, int reverse) | 175 enum mswindows_sortby sort_by, int reverse) |
151 { | 176 { |
152 mswindows_sort_method = sort_by; | 177 mswindows_sort_method = sort_by; |
153 mswindows_reverse_sort = reverse; | 178 mswindows_reverse_sort = reverse; |
154 qsort(files, nfiles, sizeof(WIN32_FIND_DATA *), mswindows_ls_sort_fcn); | 179 qsort (Dynarr_atp (files, 0), Dynarr_length (files), |
180 sizeof (Win32_file), mswindows_ls_sort_fcn); | |
155 } | 181 } |
156 | 182 |
157 | 183 static Win32_file_dynarr * |
158 static WIN32_FIND_DATA * | 184 mswindows_get_files (Lisp_Object dirfile, int nowild, Lisp_Object pattern, |
159 mswindows_get_files (char *dirfile, int nowild, Lisp_Object pattern, | 185 int hide_dot, int hide_system) |
160 int hide_dot, int hide_system, int *nfiles) | 186 { |
161 { | 187 Win32_file_dynarr *files = Dynarr_new (Win32_file); |
162 WIN32_FIND_DATA *files; | 188 struct re_pattern_buffer *bufp = NULL; |
163 int array_size; | 189 int findex; |
164 struct re_pattern_buffer *bufp = NULL; | 190 DECLARE_EISTRING (win32pattern); |
165 int findex, len; | 191 HANDLE fh; |
166 char win32pattern[MAXNAMLEN+3]; | 192 |
167 HANDLE fh; | |
168 | |
169 /* | |
170 * Much of the following code and comments were taken from dired.c. | |
171 * Yes, this is something of a waste, but we want speed, speed, SPEED. | |
172 */ | |
173 files = NULL; | |
174 array_size = *nfiles = 0; | |
175 while (1) | 193 while (1) |
176 { | 194 { |
177 if (!NILP(pattern)) | 195 if (!NILP (pattern)) |
178 { | 196 { |
179 /* PATTERN might be a flawed regular expression. Rather than | 197 /* PATTERN might be a flawed regular expression. Rather than |
180 catching and signalling our own errors, we just call | 198 catching and signalling our own errors, we just call |
181 compile_pattern to do the work for us. */ | 199 compile_pattern to do the work for us. */ |
182 bufp = compile_pattern (pattern, 0, Qnil, 0, ERROR_ME); | 200 bufp = compile_pattern (pattern, 0, Qnil, 0, ERROR_ME); |
183 } | 201 } |
184 /* Now *bufp is the compiled form of PATTERN; don't call anything | 202 /* Now *bufp is the compiled form of PATTERN; don't call anything |
185 which might compile a new regexp until we're done with the loop! */ | 203 which might compile a new regexp until we're done with the loop! */ |
186 | 204 |
187 /* Initialize file info array */ | |
188 array_size = 100; /* initial size */ | |
189 files = xmalloc(array_size * sizeof (WIN32_FIND_DATA)); | |
190 | |
191 /* for Win32, we need to insure that the pathname ends with "\*". */ | 205 /* for Win32, we need to insure that the pathname ends with "\*". */ |
192 strcpy (win32pattern, dirfile); | 206 eicpy_lstr (win32pattern, dirfile); |
193 if (!nowild) | 207 if (!nowild) |
194 { | 208 { |
195 len = strlen (win32pattern) - 1; | 209 Charcount len = eicharlen (win32pattern) - 1; |
196 if (!IS_DIRECTORY_SEP (win32pattern[len])) | 210 if (!IS_DIRECTORY_SEP (eigetch_char (win32pattern, len))) |
197 strcat (win32pattern, "\\"); | 211 eicat_c (win32pattern, "\\"); |
198 strcat (win32pattern, "*"); | 212 eicat_c (win32pattern, "*"); |
199 } | 213 } |
214 eito_external (win32pattern, Qmswindows_tstr); | |
200 | 215 |
201 /* | 216 /* |
202 * Here, we use FindFirstFile()/FindNextFile() instead of opendir(), | 217 * Here, we use FindFirstFile()/FindNextFile() instead of opendir(), |
203 * xemacs_stat(), & friends, because xemacs_stat() is VERY expensive in | 218 * qxe_stat(), & friends, because qxe_stat() is VERY expensive in |
204 * terms of time. Hence, we take the time to write complicated | 219 * terms of time. Hence, we take the time to write complicated |
205 * Win32-specific code, instead of simple Unix-style stuff. | 220 * Win32-specific code, instead of simple Unix-style stuff. |
206 */ | 221 */ |
207 findex = 0; | 222 findex = 0; |
208 fh = INVALID_HANDLE_VALUE; | 223 fh = INVALID_HANDLE_VALUE; |
209 | 224 |
210 while (1) | 225 while (1) |
211 { | 226 { |
212 int len; | 227 Bytecount len; |
213 char *filename; | 228 DECLARE_EISTRING (filename); |
214 int result; | 229 int result; |
230 WIN32_FIND_DATAW finddat; | |
231 Win32_file file; | |
215 | 232 |
216 if (fh == INVALID_HANDLE_VALUE) | 233 if (fh == INVALID_HANDLE_VALUE) |
217 { | 234 { |
218 fh = FindFirstFile(win32pattern, &files[findex]); | 235 fh = qxeFindFirstFile (eiextdata (win32pattern), &finddat); |
219 if (fh == INVALID_HANDLE_VALUE) | 236 if (fh == INVALID_HANDLE_VALUE) |
220 { | 237 report_file_error ("Opening directory", dirfile); |
221 report_file_error ("Opening directory", | |
222 build_string (dirfile)); | |
223 } | |
224 } | 238 } |
225 else | 239 else |
226 { | 240 { |
227 if (!FindNextFile(fh, &files[findex])) | 241 if (! qxeFindNextFile (fh, &finddat)) |
228 { | 242 { |
229 if (GetLastError() == ERROR_NO_MORE_FILES) | 243 if (GetLastError () == ERROR_NO_MORE_FILES) |
230 { | 244 break; |
231 break; | 245 FindClose (fh); |
232 } | 246 report_file_error ("Reading directory", dirfile); |
233 FindClose(fh); | |
234 report_file_error ("Reading directory", | |
235 build_string (dirfile)); | |
236 } | 247 } |
237 } | 248 } |
238 | 249 |
239 filename = files[findex].cFileName; | 250 file.dwFileAttributes = finddat.dwFileAttributes; |
240 if (!NILP(Vmswindows_downcase_file_names)) | 251 file.ftCreationTime = finddat.ftCreationTime; |
241 { | 252 file.ftLastAccessTime = finddat.ftLastAccessTime; |
242 strlwr(filename); | 253 file.ftLastWriteTime = finddat.ftLastWriteTime; |
243 } | 254 file.nFileSizeHigh = finddat.nFileSizeHigh; |
244 len = strlen(filename); | 255 file.nFileSizeLow = finddat.nFileSizeLow; |
245 result = (NILP(pattern) | 256 eicpy_ext (filename, (Extbyte *) finddat.cFileName, |
246 || (0 <= re_search (bufp, filename, | 257 Qmswindows_tstr); |
258 | |
259 if (!NILP (Vmswindows_downcase_file_names)) | |
260 eilwr (filename); | |
261 len = eilen (filename); | |
262 result = (NILP (pattern) | |
263 || (0 <= re_search (bufp, eidata (filename), | |
247 len, 0, len, 0))); | 264 len, 0, len, 0))); |
248 if (result) | 265 if (result) |
249 { | 266 { |
250 if ( ! (filename[0] == '.' && | 267 if ( ! (eigetch_char (filename, 0) == '.' && |
251 ((hide_system && (filename[1] == '\0' || | 268 ((hide_system && |
252 (filename[1] == '.' && | 269 (eigetch_char (filename, 1) == '\0' || |
253 filename[2] == '\0'))) || | 270 (eigetch_char (filename, 1) == '.' && |
271 eigetch_char (filename, 2) == '\0'))) || | |
254 hide_dot))) | 272 hide_dot))) |
255 { | 273 { |
256 if (++findex >= array_size) | 274 file.cFileName = |
257 { | 275 (Intbyte *) xmalloc (sizeof (Intbyte) * (1 + len)); |
258 array_size = findex * 2; | 276 memcpy (file.cFileName, eidata (filename), len); |
259 files = xrealloc(files, | 277 file.cFileName[len] = '\0'; |
260 array_size * sizeof(WIN32_FIND_DATA)); | 278 Dynarr_add (files, file); |
261 } | |
262 } | 279 } |
263 } | 280 } |
264 } | 281 } |
265 if (fh != INVALID_HANDLE_VALUE) | 282 if (fh != INVALID_HANDLE_VALUE) |
266 { | 283 FindClose (fh); |
267 FindClose (fh); | |
268 } | |
269 *nfiles = findex; | |
270 break; | 284 break; |
271 } | 285 } |
272 return (files); | 286 return (files); |
273 } | 287 } |
274 | 288 |
275 | 289 static Lisp_Object |
276 static void | 290 mswindows_format_file (Win32_file *file, int display_size, int add_newline) |
277 mswindows_format_file (WIN32_FIND_DATA *file, char *buf, int display_size, | 291 { |
278 int add_newline) | 292 Lisp_Object luser; |
279 { | 293 double file_size; |
280 char *cptr; | 294 DECLARE_EISTRING (puta); |
281 int len; | 295 CIntbyte buf[666]; |
282 Lisp_Object luser; | 296 |
283 double file_size; | |
284 | |
285 len = strlen(file->cFileName); | |
286 file_size = | 297 file_size = |
287 file->nFileSizeHigh * (double)UINT_MAX + file->nFileSizeLow; | 298 file->nFileSizeHigh * (double)UINT_MAX + file->nFileSizeLow; |
288 cptr = buf; | |
289 #if INDENT_LISTING | 299 #if INDENT_LISTING |
290 *cptr++ = ' '; | 300 eicat_c (puta, " "); |
291 *cptr++ = ' '; | |
292 #endif | 301 #endif |
293 if (display_size) | 302 if (display_size) |
294 { | 303 { |
295 sprintf(cptr, "%6d ", (int)((file_size + 1023.) / 1024.)); | 304 sprintf (buf, "%6d ", (int)((file_size + 1023.) / 1024.)); |
296 cptr += 7; | 305 eicat_c (puta, buf); |
297 } | 306 } |
298 if (file->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) | 307 if (file->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) |
299 { | 308 eicat_c (puta, "d"); |
300 *cptr++ = 'd'; | 309 else |
301 } else { | 310 eicat_c (puta, "-"); |
302 *cptr++ = '-'; | 311 buf[0] = buf[3] = buf[6] = 'r'; |
303 } | |
304 cptr[0] = cptr[3] = cptr[6] = 'r'; | |
305 if (file->dwFileAttributes & FILE_ATTRIBUTE_READONLY) | 312 if (file->dwFileAttributes & FILE_ATTRIBUTE_READONLY) |
306 { | 313 buf[1] = buf[4] = buf[7] = '-'; |
307 cptr[1] = cptr[4] = cptr[7] = '-'; | 314 else |
308 } else { | 315 buf[1] = buf[4] = buf[7] = 'w'; |
309 cptr[1] = cptr[4] = cptr[7] = 'w'; | 316 { |
310 } | 317 int is_executable = 0; |
311 if ((file->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) || | 318 |
312 (len > 4 && | 319 if (file->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) |
313 (_stricmp(&file->cFileName[len - 4], ".exe") == 0 | 320 is_executable = 1; |
314 || _stricmp(&file->cFileName[len - 4], ".com") == 0 | 321 else if (qxestrcharlen (file->cFileName) > 4) |
315 || _stricmp(&file->cFileName[len - 4], ".bat") == 0 | 322 { |
323 Intbyte *end = file->cFileName + qxestrlen (file->cFileName); | |
324 DEC_CHARPTR (end); | |
325 DEC_CHARPTR (end); | |
326 DEC_CHARPTR (end); | |
327 DEC_CHARPTR (end); | |
328 if (qxestrcasecmp (end, ".exe") == 0 | |
329 || qxestrcasecmp (end, ".com") == 0 | |
330 || qxestrcasecmp (end, ".bat") == 0 | |
316 #if 0 | 331 #if 0 |
317 || _stricmp(&file->cFileName[len - 4], ".pif") == 0 | 332 || qxestrcasecmp (end, ".pif") == 0 |
318 #endif | 333 #endif |
319 ))) | 334 ) |
320 { | 335 is_executable = 1; |
321 cptr[2] = cptr[5] = cptr[8] = 'x'; | 336 } |
322 } else { | 337 if (is_executable) |
323 cptr[2] = cptr[5] = cptr[8] = '-'; | 338 buf[2] = buf[5] = buf[8] = 'x'; |
324 } | 339 else |
325 cptr += 9; | 340 buf[2] = buf[5] = buf[8] = '-'; |
341 } | |
342 buf[9] = '\0'; | |
343 eicat_c (puta, buf); | |
326 if (file->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) | 344 if (file->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) |
327 { | 345 eicat_c (puta, " 2 "); |
328 strcpy(cptr, " 2 "); | 346 else |
329 } else { | 347 eicat_c (puta, " 1 "); |
330 strcpy(cptr, " 1 "); | 348 luser = Fuser_login_name (Qnil); |
331 } | 349 if (!STRINGP (luser)) |
332 cptr += 5; | 350 sprintf (buf, "%-9d", 0); |
333 luser = Fuser_login_name(Qnil); | 351 else |
334 if (!STRINGP(luser)) | 352 { |
335 { | 353 Intbyte *str; |
336 sprintf(cptr, "%-9d", 0); | 354 |
337 } else { | 355 str = XSTRING_DATA (luser); |
338 char *str; | 356 sprintf (buf, "%-8s ", str); |
339 | 357 } |
340 str = XSTRING_DATA(luser); | 358 eicat_raw (puta, (Intbyte *) buf, strlen (buf)); |
341 sprintf(cptr, "%-8s ", str); | 359 { |
342 } | 360 CIntbyte *cptr = buf; |
343 while (*cptr) | 361 sprintf (buf, "%-8d ", getgid ()); |
344 { | 362 cptr += 9; |
363 if (file_size > 99999999.0) | |
364 { | |
365 file_size = (file_size + 1023.0) / 1024.; | |
366 if (file_size > 999999.0) | |
367 sprintf (cptr, "%6.0fMB ", (file_size + 1023.0) / 1024.); | |
368 else | |
369 sprintf (cptr, "%6.0fKB ", file_size); | |
370 } | |
371 else | |
372 sprintf (cptr, "%8.0f ", file_size); | |
373 while (*cptr) | |
345 ++cptr; | 374 ++cptr; |
346 } | 375 { |
347 sprintf(cptr, "%-8d ", getgid()); | 376 time_t t, now; |
348 cptr += 9; | 377 Intbyte *ctimebuf; |
349 if (file_size > 99999999.0) | 378 |
350 { | 379 if ( |
351 file_size = (file_size + 1023.0) / 1024.; | 380 #if 0 |
352 if (file_size > 999999.0) | 381 /* |
382 * This doesn't work. | |
383 * This code should be correct ... | |
384 */ | |
385 FileTimeToLocalFileTime (&file->ftLastWriteTime, &localtime) && | |
386 ((t = mswindows_convert_time (localtime)) != 0) && | |
387 #else | |
388 /* | |
389 * But this code "works" ... | |
390 */ | |
391 ((t = mswindows_convert_time (file->ftLastWriteTime)) != 0) && | |
392 #endif | |
393 ((ctimebuf = qxe_ctime (&t)) != NULL)) | |
353 { | 394 { |
354 sprintf(cptr, "%6.0fMB ", (file_size + 1023.0) / 1024.); | 395 memcpy (cptr, &ctimebuf[4], 7); |
355 } else { | 396 now = time (NULL); |
356 sprintf(cptr, "%6.0fKB ", file_size); | 397 if (now - t > (365. / 2.0) * 86400.) |
398 { | |
399 /* more than 6 months */ | |
400 cptr[7] = ' '; | |
401 memcpy (&cptr[8], &ctimebuf[20], 4); | |
402 } | |
403 else | |
404 { | |
405 /* less than 6 months */ | |
406 memcpy (&cptr[7], &ctimebuf[11], 5); | |
407 } | |
408 cptr += 12; | |
409 *cptr++ = ' '; | |
410 *cptr++ = '\0'; | |
357 } | 411 } |
358 } else { | 412 } |
359 sprintf(cptr, "%8.0f ", file_size); | |
360 } | |
361 while (*cptr) | |
362 { | |
363 ++cptr; | |
364 } | |
365 { | |
366 time_t t, now; | |
367 char *ctimebuf; | |
368 extern char *sys_ctime(const time_t *t); /* in nt.c */ | |
369 | |
370 if ( | |
371 #if 0 | |
372 /* | |
373 * This doesn't work. | |
374 * This code should be correct ... | |
375 */ | |
376 FileTimeToLocalFileTime(&file->ftLastWriteTime, &localtime) && | |
377 ((t = convert_time(localtime)) != 0) && | |
378 #else | |
379 /* | |
380 * But this code "works" ... | |
381 */ | |
382 ((t = convert_time(file->ftLastWriteTime)) != 0) && | |
383 #endif | |
384 ((ctimebuf = sys_ctime(&t)) != NULL)) | |
385 { | |
386 memcpy(cptr, &ctimebuf[4], 7); | |
387 now = time(NULL); | |
388 if (now - t > (365. / 2.0) * 86400.) | |
389 { | |
390 /* more than 6 months */ | |
391 cptr[7] = ' '; | |
392 memcpy(&cptr[8], &ctimebuf[20], 4); | |
393 } else { | |
394 /* less than 6 months */ | |
395 memcpy(&cptr[7], &ctimebuf[11], 5); | |
396 } | |
397 cptr += 12; | |
398 *cptr++ = ' '; | |
399 } | |
400 } | 413 } |
414 | |
415 eicat_c (puta, buf); | |
416 eicat_raw (puta, file->cFileName, qxestrlen (file->cFileName)); | |
401 if (add_newline) | 417 if (add_newline) |
402 { | 418 eicat_c (puta, "\n"); |
403 sprintf(cptr, "%s\n", file->cFileName); | 419 |
404 } | 420 return eimake_string (puta); |
405 else | |
406 { | |
407 strcpy(cptr, file->cFileName); | |
408 } | |
409 } | 421 } |
410 | 422 |
411 | 423 |
412 DEFUN ("mswindows-insert-directory", Fmswindows_insert_directory, 2, 4, 0, /* | 424 DEFUN ("mswindows-insert-directory", Fmswindows_insert_directory, 2, 4, 0, /* |
413 Insert directory listing for FILE, formatted according to SWITCHES. | 425 Insert directory listing for FILE, formatted according to SWITCHES. |
417 Optional fourth arg FULL-DIRECTORY-P means file is a directory and | 429 Optional fourth arg FULL-DIRECTORY-P means file is a directory and |
418 switches do not contain `d', so that a full listing is expected. | 430 switches do not contain `d', so that a full listing is expected. |
419 */ | 431 */ |
420 (file, switches, wildcard, full_directory_p)) | 432 (file, switches, wildcard, full_directory_p)) |
421 { | 433 { |
422 Lisp_Object result, handler, wildpat, fns, basename; | 434 Lisp_Object handler, wildpat = Qnil, basename = Qnil; |
423 char *switchstr; | 435 int nfiles = 0, i; |
424 int nfiles, i; | 436 int hide_system = 1, hide_dot = 1, reverse = 0, display_size = 0; |
425 int hide_system, hide_dot, reverse, display_size; | 437 Win32_file_dynarr *files; |
426 WIN32_FIND_DATA *files, **sorted_files; | 438 enum mswindows_sortby sort_by = |
427 enum mswindows_sortby sort_by; | 439 (mswindows_ls_sort_case_insensitive ? MSWINDOWS_SORT_BY_NAME_NOCASE |
428 char fmtbuf[MAXNAMLEN+100]; /* larger than necessary */ | 440 : MSWINDOWS_SORT_BY_NAME); |
429 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5; | 441 struct gcpro gcpro1, gcpro2, gcpro3; |
430 | 442 |
431 result = Qnil; | 443 GCPRO3 (file, wildpat, basename); |
432 wildpat = Qnil; | 444 |
433 fns = Qnil; | 445 CHECK_STRING (file); |
434 basename = Qnil; | 446 if (!NILP (wildpat)) |
435 GCPRO5(result, file, wildpat, fns, basename); | 447 CHECK_STRING (wildpat); |
436 sorted_files = NULL; | 448 |
437 switchstr = NULL; | 449 handler = Ffind_file_name_handler (file, Qmswindows_insert_directory); |
438 hide_system = 1; | 450 if (!NILP (handler)) |
439 hide_dot = 1; | 451 { |
440 display_size = 0; | 452 UNGCPRO; |
441 reverse = 0; | 453 return call5 (handler, Qmswindows_insert_directory, file, switches, |
442 sort_by = (mswindows_ls_sort_case_insensitive | 454 wildcard, full_directory_p); |
443 ? MSWINDOWS_SORT_BY_NAME_NOCASE | 455 } |
444 : MSWINDOWS_SORT_BY_NAME); | 456 |
445 nfiles = 0; | 457 if (!NILP (switches)) |
446 while (1) | 458 { |
447 { | 459 Intbyte *cptr, *cptr_end; |
448 handler = Ffind_file_name_handler (file, Qmswindows_insert_directory); | 460 |
449 if (!NILP(handler)) | 461 CHECK_STRING (switches); |
462 cptr = XSTRING_DATA (switches); | |
463 cptr_end = cptr + XSTRING_LENGTH (switches); | |
464 while (cptr < cptr_end) | |
450 { | 465 { |
451 result = call5(handler, Qmswindows_insert_directory, file, switches, | 466 Emchar ch = charptr_emchar (cptr); |
452 wildcard, full_directory_p); | 467 switch (ch) |
453 break; | |
454 } | |
455 CHECK_STRING (file); | |
456 if (!NILP(switches)) | |
457 { | |
458 char *cptr; | |
459 | |
460 CHECK_STRING (switches); | |
461 switchstr = XSTRING_DATA(switches); | |
462 for (cptr = switchstr; *cptr; ++cptr) | |
463 { | 468 { |
464 switch (*cptr) | 469 case 'A': |
465 { | 470 hide_dot = 0; |
466 case 'A': | 471 break; |
467 hide_dot = 0; | 472 case 'a': |
468 break; | 473 hide_system = 0; |
469 case 'a': | 474 hide_dot = 0; |
470 hide_system = 0; | 475 break; |
471 hide_dot = 0; | 476 case 'r': |
472 break; | 477 reverse = 1; |
473 case 'r': | 478 break; |
474 reverse = 1; | 479 case 's': |
475 break; | 480 display_size = 1; |
476 case 's': | 481 break; |
477 display_size = 1; | 482 case 'S': |
478 break; | 483 sort_by = MSWINDOWS_SORT_BY_SIZE; |
479 case 'S': | 484 break; |
480 sort_by = MSWINDOWS_SORT_BY_SIZE; | 485 case 't': |
481 break; | 486 sort_by = MSWINDOWS_SORT_BY_MOD_DATE; |
482 case 't': | |
483 sort_by = MSWINDOWS_SORT_BY_MOD_DATE; | |
484 break; | |
485 } | |
486 } | |
487 } | |
488 | |
489 if (!NILP(wildcard)) | |
490 { | |
491 Lisp_Object newfile; | |
492 | |
493 file = Fdirectory_file_name (file); | |
494 basename = Ffile_name_nondirectory(file); | |
495 fns = intern("wildcard-to-regexp"); | |
496 wildpat = call1(fns, basename); | |
497 newfile = Ffile_name_directory(file); | |
498 if (NILP(newfile)) | |
499 { | |
500 /* Ffile_name_directory() can GC */ | |
501 newfile = Ffile_name_directory(Fexpand_file_name(file, Qnil)); | |
502 } | |
503 file = newfile; | |
504 } | |
505 if (!NILP(wildcard) || !NILP(full_directory_p)) | |
506 { | |
507 CHECK_STRING(file); | |
508 if (!NILP(wildpat)) | |
509 { | |
510 CHECK_STRING(wildpat); | |
511 } | |
512 | |
513 files = mswindows_get_files(XSTRING_DATA(file), FALSE, wildpat, | |
514 hide_dot, hide_system, &nfiles); | |
515 if (files == NULL || nfiles == 0) | |
516 { | |
517 break; | 487 break; |
518 } | 488 } |
489 INC_CHARPTR (cptr); | |
519 } | 490 } |
520 else | 491 } |
492 | |
493 if (!NILP (wildcard)) | |
494 { | |
495 Lisp_Object newfile; | |
496 | |
497 file = Fdirectory_file_name (file); | |
498 basename = Ffile_name_nondirectory (file); | |
499 wildpat = call1 (Qwildcard_to_regexp, basename); | |
500 newfile = Ffile_name_directory (file); | |
501 if (NILP (newfile)) | |
502 newfile = Ffile_name_directory (Fexpand_file_name (file, Qnil)); | |
503 file = newfile; | |
504 } | |
505 | |
506 files = mswindows_get_files (file, | |
507 NILP (wildcard) && NILP (full_directory_p), | |
508 wildpat, hide_dot, hide_system); | |
509 | |
510 if (Dynarr_length (files) > 1) | |
511 mswindows_sort_files (files, sort_by, reverse); | |
512 if (!NILP (wildcard) || !NILP (full_directory_p)) | |
513 { | |
514 /* | |
515 * By using doubles, we can handle files up to 2^53 bytes in | |
516 * size (IEEE doubles have 53 bits of resolution). However, | |
517 * as we divide by 1024 (or 2^10), the total size is | |
518 * accurate up to 2^(53+10) --> 2^63 bytes. | |
519 * | |
520 * Hopefully, we won't have to handle these file sizes anytime | |
521 * soon. | |
522 */ | |
523 double total_size, file_size, block_size; | |
524 | |
525 if ((block_size = mswindows_ls_round_file_size) <= 0) | |
521 { | 526 { |
522 files = mswindows_get_files(XSTRING_DATA(file), TRUE, wildpat, | 527 block_size = 0; |
523 hide_dot, hide_system, &nfiles); | |
524 } | 528 } |
525 if ((sorted_files = xmalloc(nfiles * sizeof(WIN32_FIND_DATA *))) | 529 total_size = 0; |
526 == NULL) | 530 for (i = 0; i < Dynarr_length (files); ++i) |
527 { | 531 { |
528 break; | 532 Win32_file *file = Dynarr_atp (files, i); |
533 file_size = | |
534 file->nFileSizeHigh * (double)UINT_MAX + | |
535 file->nFileSizeLow; | |
536 if (block_size > 0) | |
537 { | |
538 /* | |
539 * Round file_size up to the next nearest block size. | |
540 */ | |
541 file_size = | |
542 floor ((file_size + block_size - 1) / block_size) | |
543 * block_size; | |
544 } | |
545 /* Here, we round to the nearest 1K */ | |
546 total_size += floor ((file_size + 512.) / 1024.); | |
529 } | 547 } |
530 for (i = 0; i < nfiles; ++i) | 548 { |
531 { | 549 Intbyte tempbuf[666]; |
532 sorted_files[i] = &files[i]; | 550 |
533 } | 551 qxesprintf (tempbuf, |
534 if (nfiles > 1) | |
535 { | |
536 mswindows_sort_files(sorted_files, nfiles, sort_by, reverse); | |
537 } | |
538 if (!NILP(wildcard) || !NILP(full_directory_p)) | |
539 { | |
540 /* | |
541 * By using doubles, we can handle files up to 2^53 bytes in | |
542 * size (IEEE doubles have 53 bits of resolution). However, | |
543 * as we divide by 1024 (or 2^10), the total size is | |
544 * accurate up to 2^(53+10) --> 2^63 bytes. | |
545 * | |
546 * Hopefully, we won't have to handle these file sizes anytime | |
547 * soon. | |
548 */ | |
549 double total_size, file_size, block_size; | |
550 | |
551 if ((block_size = mswindows_ls_round_file_size) <= 0) | |
552 { | |
553 block_size = 0; | |
554 } | |
555 total_size = 0; | |
556 for (i = 0; i < nfiles; ++i) | |
557 { | |
558 file_size = | |
559 sorted_files[i]->nFileSizeHigh * (double)UINT_MAX + | |
560 sorted_files[i]->nFileSizeLow; | |
561 if (block_size > 0) | |
562 { | |
563 /* | |
564 * Round file_size up to the next nearest block size. | |
565 */ | |
566 file_size = | |
567 floor((file_size + block_size - 1) / block_size) | |
568 * block_size; | |
569 } | |
570 /* Here, we round to the nearest 1K */ | |
571 total_size += floor((file_size + 512.) / 1024.); | |
572 } | |
573 sprintf(fmtbuf, | |
574 #if INDENT_LISTING | 552 #if INDENT_LISTING |
575 /* ANSI C compilers auto-concatenate adjacent strings */ | 553 /* ANSI C compilers auto-concatenate adjacent strings */ |
576 " " | 554 " " |
577 #endif | 555 #endif |
578 "total %.0f\n", total_size); | 556 "total %.0f\n", total_size); |
579 buffer_insert1(current_buffer, build_string(fmtbuf)); | 557 buffer_insert1 (current_buffer, build_intstring (tempbuf)); |
580 } | 558 } |
581 for (i = 0; i < nfiles; ++i) | 559 } |
582 { | 560 for (i = 0; i < Dynarr_length (files); ++i) |
583 mswindows_format_file(sorted_files[i], fmtbuf, display_size, TRUE); | 561 { |
584 buffer_insert1(current_buffer, build_string(fmtbuf)); | 562 struct gcpro ngcpro1; |
585 } | 563 Lisp_Object fmtfile = |
586 break; | 564 mswindows_format_file (Dynarr_atp (files, i), display_size, TRUE); |
587 } | 565 NGCPRO1 (fmtfile); |
588 if (sorted_files) | 566 buffer_insert1 (current_buffer, fmtfile); |
589 { | 567 NUNGCPRO; |
590 xfree(sorted_files); | 568 } |
591 } | 569 for (i = 0; i < Dynarr_length (files); ++i) |
570 { | |
571 Win32_file *file = Dynarr_atp (files, i); | |
572 xfree (file->cFileName); | |
573 } | |
574 Dynarr_free (files); | |
575 | |
592 UNGCPRO; | 576 UNGCPRO; |
593 return (result); | 577 return Qnil; |
594 } | 578 } |
595 | 579 |
596 | 580 |
597 | 581 |
598 /************************************************************************/ | 582 /************************************************************************/ |
601 | 585 |
602 void | 586 void |
603 syms_of_dired_mswindows (void) | 587 syms_of_dired_mswindows (void) |
604 { | 588 { |
605 DEFSYMBOL (Qmswindows_insert_directory); | 589 DEFSYMBOL (Qmswindows_insert_directory); |
590 DEFSYMBOL (Qwildcard_to_regexp); | |
606 | 591 |
607 DEFSUBR (Fmswindows_insert_directory); | 592 DEFSUBR (Fmswindows_insert_directory); |
608 } | 593 } |
609 | 594 |
610 | 595 |
611 void | 596 void |
612 vars_of_dired_mswindows (void) | 597 vars_of_dired_mswindows (void) |
613 { | 598 { |
614 DEFVAR_BOOL ("mswindows-ls-sort-case-insensitive", &mswindows_ls_sort_case_insensitive /* | 599 DEFVAR_BOOL ("mswindows-ls-sort-case-insensitive", |
600 &mswindows_ls_sort_case_insensitive /* | |
615 *Non-nil means filenames are sorted in a case-insensitive fashion. | 601 *Non-nil means filenames are sorted in a case-insensitive fashion. |
616 Nil means filenames are sorted in a case-sensitive fashion, just like Unix. | 602 Nil means filenames are sorted in a case-sensitive fashion, just like Unix. |
617 */ ); | 603 */ ); |
618 mswindows_ls_sort_case_insensitive = 1; | 604 mswindows_ls_sort_case_insensitive = 1; |
619 | 605 |