Mercurial > hg > xemacs-beta
annotate src/dired-msw.c @ 5857:6ec4964c1687
Be more careful about echo_buf arithmetic, event-stream.c.
src/ChangeLog addition:
2015-03-12 Aidan Kehoe <kehoea@parhasard.net>
* event-stream.c (lookup_command_event):
Check whether echo_buf_fill_pointer is negative before using it in
arithmetic, avoiding a crash in GC.
Oddly the old code didn't do this check and didn't crash, but its
echo_buf was from malloced memory, not from our string data, so
there may have been more room to manoeuvre.
| author | Aidan Kehoe <kehoea@parhasard.net> |
|---|---|
| date | Thu, 12 Mar 2015 23:31:42 +0000 |
| parents | 2aa9cd456ae7 |
| children |
| rev | line source |
|---|---|
| 428 | 1 /* fast dired replacement routines for mswindows. |
| 2 Copyright (C) 1998 Darryl Okahata | |
| 3 Portions Copyright (C) 1992, 1994 by Sebastian Kremer <sk@thp.uni-koeln.de> | |
| 800 | 4 Copyright (C) 2000, 2001, 2002 Ben Wing. |
| 428 | 5 |
| 6 This file is part of XEmacs. | |
| 7 | |
|
5405
2aa9cd456ae7
Move src/ to GPLv3.
Mike Sperber <sperber@deinprogramm.de>
parents:
4976
diff
changeset
|
8 XEmacs is free software: you can redistribute it and/or modify it |
| 428 | 9 under the terms of the GNU General Public License as published by the |
|
5405
2aa9cd456ae7
Move src/ to GPLv3.
Mike Sperber <sperber@deinprogramm.de>
parents:
4976
diff
changeset
|
10 Free Software Foundation, either version 3 of the License, or (at your |
|
2aa9cd456ae7
Move src/ to GPLv3.
Mike Sperber <sperber@deinprogramm.de>
parents:
4976
diff
changeset
|
11 option) any later version. |
| 428 | 12 |
| 13 XEmacs is distributed in the hope that it will be useful, but WITHOUT | |
| 14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 16 for more details. | |
| 17 | |
| 18 You should have received a copy of the GNU General Public License | |
|
5405
2aa9cd456ae7
Move src/ to GPLv3.
Mike Sperber <sperber@deinprogramm.de>
parents:
4976
diff
changeset
|
19 along with XEmacs. If not, see <http://www.gnu.org/licenses/>. */ |
| 428 | 20 |
| 21 /* Synched up with: Not in FSF. */ | |
| 22 | |
| 771 | 23 |
| 428 | 24 /* |
| 25 * Parts of this code (& comments) were taken from ls-lisp.el | |
| 26 * Author: Sebastian Kremer <sk@thp.uni-koeln.de> | |
| 27 */ | |
| 28 | |
| 29 /* | |
| 30 * insert-directory | |
| 31 * - must insert _exactly_one_line_ describing FILE if WILDCARD and | |
| 32 * FULL-DIRECTORY-P is nil. | |
| 33 * The single line of output must display FILE's name as it was | |
| 34 * given, namely, an absolute path name. | |
| 35 * - must insert exactly one line for each file if WILDCARD or | |
| 36 * FULL-DIRECTORY-P is t, plus one optional "total" line | |
| 37 * before the file lines, plus optional text after the file lines. | |
| 38 * Lines are delimited by "\n", so filenames containing "\n" are not | |
| 39 * allowed. | |
| 40 * File lines should display the basename. | |
| 41 * - must be consistent with | |
| 42 * - functions dired-move-to-filename, (these two define what a file line is) | |
| 43 * dired-move-to-end-of-filename, | |
| 44 * dired-between-files, (shortcut for (not (dired-move-to-filename))) | |
| 45 * dired-insert-headerline | |
| 46 * dired-after-subdir-garbage (defines what a "total" line is) | |
| 47 * - variable dired-subdir-regexp | |
| 48 */ | |
| 49 | |
| 50 /* | |
| 51 * Insert directory listing for FILE, formatted according to SWITCHES. | |
| 52 * Leaves point after the inserted text. | |
| 53 * SWITCHES may be a string of options, or a list of strings. | |
| 54 * Optional third arg WILDCARD means treat FILE as shell wildcard. | |
| 55 * Optional fourth arg FULL-DIRECTORY-P means file is a directory and | |
| 56 * switches do not contain `d', so that a full listing is expected. | |
| 57 * | |
| 58 * This works by running a directory listing program | |
| 59 * whose name is in the variable `insert-directory-program'. | |
| 60 * If WILDCARD, it also runs the shell specified by `shell-file-name'." | |
| 61 */ | |
| 62 | |
| 63 /* | |
| 64 * Set INDENT_LISTING to non-zero if the inserted text should be shifted | |
| 65 * over by two spaces. | |
| 66 */ | |
| 771 | 67 #define INDENT_LISTING 0 |
| 428 | 68 |
| 771 | 69 #define ROUND_FILE_SIZES 4096 |
| 428 | 70 |
| 71 | |
| 72 #include <config.h> | |
| 73 #include "lisp.h" | |
| 74 | |
| 75 #include "buffer.h" | |
| 76 #include "regex.h" | |
| 826 | 77 #include "syntax.h" |
| 428 | 78 |
| 872 | 79 #include "console-msw.h" |
| 80 | |
| 428 | 81 #include "sysdir.h" |
| 442 | 82 #include "sysfile.h" |
| 558 | 83 #include "sysfloat.h" |
| 771 | 84 #include "sysproc.h" |
| 85 #include "syspwd.h" | |
| 86 #include "systime.h" | |
| 872 | 87 |
| 428 | 88 |
| 89 static int mswindows_ls_sort_case_insensitive; | |
| 458 | 90 static Fixnum mswindows_ls_round_file_size; |
| 428 | 91 |
| 771 | 92 Lisp_Object Qmswindows_insert_directory; |
| 93 Lisp_Object Qwildcard_to_regexp; | |
| 428 | 94 |
| 771 | 95 extern Lisp_Object Vmswindows_downcase_file_names; /* in device-msw.c */ |
| 428 | 96 |
| 558 | 97 enum mswindows_sortby |
| 98 { | |
| 428 | 99 MSWINDOWS_SORT_BY_NAME, |
| 100 MSWINDOWS_SORT_BY_NAME_NOCASE, | |
| 101 MSWINDOWS_SORT_BY_MOD_DATE, | |
| 102 MSWINDOWS_SORT_BY_SIZE | |
| 103 }; | |
| 104 | |
| 105 | |
| 771 | 106 static enum mswindows_sortby mswindows_sort_method; |
| 107 static int mswindows_reverse_sort; | |
| 108 | |
| 109 /* We create our own structure because the cFileName field in | |
| 110 WIN32_FIND_DATA is in external format and of fixed size, which we | |
| 111 may exceed when translating. */ | |
| 112 | |
| 113 typedef struct | |
| 114 { | |
| 115 DWORD dwFileAttributes; | |
| 116 FILETIME ftCreationTime; | |
| 117 FILETIME ftLastAccessTime; | |
| 118 FILETIME ftLastWriteTime; | |
| 119 DWORD nFileSizeHigh; | |
| 120 DWORD nFileSizeLow; | |
| 867 | 121 Ibyte *cFileName; |
| 771 | 122 } Win32_file; |
| 123 | |
| 124 typedef struct | |
| 125 { | |
| 126 Dynarr_declare (Win32_file); | |
| 127 } Win32_file_dynarr; | |
| 128 | |
| 428 | 129 |
| 130 | |
| 131 #define CMPDWORDS(t1a, t1b, t2a, t2b) \ | |
| 132 (((t1a) == (t2a)) ? (((t1b) == (t2b)) ? 0 : (((t1b) < (t2b)) ? -1 : 1)) \ | |
| 133 : (((t1a) < (t2a)) ? -1 : 1)) | |
| 134 | |
| 135 | |
| 136 static int | |
| 137 mswindows_ls_sort_fcn (const void *elem1, const void *elem2) | |
| 138 { | |
| 771 | 139 Win32_file *e1, *e2; |
| 140 int status; | |
| 428 | 141 |
| 771 | 142 e1 = (Win32_file *) elem1; |
| 143 e2 = (Win32_file *) elem2; | |
| 144 | |
| 428 | 145 switch (mswindows_sort_method) |
| 146 { | |
| 147 case MSWINDOWS_SORT_BY_NAME: | |
| 1204 | 148 status = qxestrcmp (e1->cFileName, e2->cFileName); |
| 428 | 149 break; |
| 150 case MSWINDOWS_SORT_BY_NAME_NOCASE: | |
| 771 | 151 status = qxestrcasecmp (e1->cFileName, e2->cFileName); |
| 428 | 152 break; |
| 153 case MSWINDOWS_SORT_BY_MOD_DATE: | |
| 771 | 154 status = CMPDWORDS (e1->ftLastWriteTime.dwHighDateTime, |
| 155 e1->ftLastWriteTime.dwLowDateTime, | |
| 156 e2->ftLastWriteTime.dwHighDateTime, | |
| 157 e2->ftLastWriteTime.dwLowDateTime); | |
| 428 | 158 break; |
| 159 case MSWINDOWS_SORT_BY_SIZE: | |
| 771 | 160 status = CMPDWORDS (e1->nFileSizeHigh, e1->nFileSizeLow, |
| 161 e2->nFileSizeHigh, e2->nFileSizeLow); | |
| 428 | 162 break; |
| 163 default: | |
| 164 status = 0; | |
| 165 break; | |
| 166 } | |
| 167 if (mswindows_reverse_sort) | |
| 168 { | |
| 169 status = -status; | |
| 170 } | |
| 171 return (status); | |
| 172 } | |
| 173 | |
| 174 static void | |
| 771 | 175 mswindows_sort_files (Win32_file_dynarr *files, |
| 428 | 176 enum mswindows_sortby sort_by, int reverse) |
| 177 { | |
| 178 mswindows_sort_method = sort_by; | |
| 179 mswindows_reverse_sort = reverse; | |
| 4967 | 180 qsort (Dynarr_begin (files), Dynarr_length (files), |
| 771 | 181 sizeof (Win32_file), mswindows_ls_sort_fcn); |
| 428 | 182 } |
| 183 | |
| 771 | 184 static Win32_file_dynarr * |
| 185 mswindows_get_files (Lisp_Object dirfile, int nowild, Lisp_Object pattern, | |
| 186 int hide_dot, int hide_system) | |
| 428 | 187 { |
| 771 | 188 Win32_file_dynarr *files = Dynarr_new (Win32_file); |
| 189 struct re_pattern_buffer *bufp = NULL; | |
| 190 int findex; | |
| 191 DECLARE_EISTRING (win32pattern); | |
| 192 HANDLE fh; | |
| 2526 | 193 int errm; |
| 428 | 194 |
| 195 while (1) | |
| 196 { | |
| 771 | 197 if (!NILP (pattern)) |
| 428 | 198 { |
| 199 /* PATTERN might be a flawed regular expression. Rather than | |
| 200 catching and signalling our own errors, we just call | |
| 201 compile_pattern to do the work for us. */ | |
| 826 | 202 bufp = compile_pattern (pattern, 0, Qnil, Qnil, 0, 0, ERROR_ME); |
| 428 | 203 } |
| 204 /* Now *bufp is the compiled form of PATTERN; don't call anything | |
| 205 which might compile a new regexp until we're done with the loop! */ | |
| 206 | |
| 2526 | 207 { |
| 208 Ibyte *dir2; | |
| 209 LISP_PATHNAME_RESOLVE_LINKS (dirfile, dir2); | |
| 210 eicpy_rawz (win32pattern, dir2); | |
| 211 } | |
| 212 | |
| 428 | 213 /* for Win32, we need to insure that the pathname ends with "\*". */ |
| 214 if (!nowild) | |
| 215 { | |
| 771 | 216 Charcount len = eicharlen (win32pattern) - 1; |
| 217 if (!IS_DIRECTORY_SEP (eigetch_char (win32pattern, len))) | |
| 2421 | 218 eicat_ascii (win32pattern, "\\"); |
| 219 eicat_ascii (win32pattern, "*"); | |
| 428 | 220 } |
| 771 | 221 eito_external (win32pattern, Qmswindows_tstr); |
| 428 | 222 |
| 223 /* | |
| 224 * Here, we use FindFirstFile()/FindNextFile() instead of opendir(), | |
| 771 | 225 * qxe_stat(), & friends, because qxe_stat() is VERY expensive in |
| 442 | 226 * terms of time. Hence, we take the time to write complicated |
| 227 * Win32-specific code, instead of simple Unix-style stuff. | |
| 428 | 228 */ |
| 229 findex = 0; | |
| 230 fh = INVALID_HANDLE_VALUE; | |
| 819 | 231 errm = SetErrorMode (SEM_FAILCRITICALERRORS |
| 232 | SEM_NOOPENFILEERRORBOX); | |
| 428 | 233 |
| 234 while (1) | |
| 235 { | |
| 771 | 236 Bytecount len; |
| 237 DECLARE_EISTRING (filename); | |
| 238 int result; | |
| 239 WIN32_FIND_DATAW finddat; | |
| 240 Win32_file file; | |
| 826 | 241 struct syntax_cache scache_struct; |
| 242 struct syntax_cache *scache = &scache_struct; | |
| 428 | 243 |
| 244 if (fh == INVALID_HANDLE_VALUE) | |
| 245 { | |
| 771 | 246 fh = qxeFindFirstFile (eiextdata (win32pattern), &finddat); |
| 428 | 247 if (fh == INVALID_HANDLE_VALUE) |
| 819 | 248 { |
| 249 SetErrorMode (errm); | |
| 250 report_file_error ("Opening directory", dirfile); | |
| 251 } | |
| 428 | 252 } |
| 253 else | |
| 254 { | |
| 771 | 255 if (! qxeFindNextFile (fh, &finddat)) |
| 428 | 256 { |
| 819 | 257 if (GetLastError() == ERROR_NO_MORE_FILES) |
| 258 { | |
| 259 break; | |
| 260 } | |
| 261 FindClose(fh); | |
| 262 SetErrorMode (errm); | |
| 771 | 263 report_file_error ("Reading directory", dirfile); |
| 428 | 264 } |
| 265 } | |
| 266 | |
| 771 | 267 file.dwFileAttributes = finddat.dwFileAttributes; |
| 268 file.ftCreationTime = finddat.ftCreationTime; | |
| 269 file.ftLastAccessTime = finddat.ftLastAccessTime; | |
| 270 file.ftLastWriteTime = finddat.ftLastWriteTime; | |
| 271 file.nFileSizeHigh = finddat.nFileSizeHigh; | |
| 272 file.nFileSizeLow = finddat.nFileSizeLow; | |
| 273 eicpy_ext (filename, (Extbyte *) finddat.cFileName, | |
| 274 Qmswindows_tstr); | |
| 275 | |
| 276 if (!NILP (Vmswindows_downcase_file_names)) | |
| 277 eilwr (filename); | |
| 278 len = eilen (filename); | |
| 279 result = (NILP (pattern) | |
| 1204 | 280 || (0 <= re_search (bufp, (char *) eidata (filename), |
| 826 | 281 len, 0, len, 0, Qnil, 0, scache))); |
| 428 | 282 if (result) |
| 283 { | |
| 771 | 284 if ( ! (eigetch_char (filename, 0) == '.' && |
| 285 ((hide_system && | |
| 286 (eigetch_char (filename, 1) == '\0' || | |
| 287 (eigetch_char (filename, 1) == '.' && | |
| 288 eigetch_char (filename, 2) == '\0'))) || | |
| 428 | 289 hide_dot))) |
| 290 { | |
| 2367 | 291 file.cFileName = xnew_ibytes (len + ITEXT_ZTERM_SIZE); |
| 771 | 292 memcpy (file.cFileName, eidata (filename), len); |
| 293 file.cFileName[len] = '\0'; | |
| 294 Dynarr_add (files, file); | |
| 428 | 295 } |
| 296 } | |
| 297 } | |
| 298 if (fh != INVALID_HANDLE_VALUE) | |
| 771 | 299 FindClose (fh); |
| 428 | 300 break; |
| 301 } | |
| 819 | 302 |
| 303 SetErrorMode (errm); | |
| 428 | 304 return (files); |
| 305 } | |
| 306 | |
| 771 | 307 static Lisp_Object |
| 308 mswindows_format_file (Win32_file *file, int display_size, int add_newline) | |
| 428 | 309 { |
| 771 | 310 Lisp_Object luser; |
| 311 double file_size; | |
| 312 DECLARE_EISTRING (puta); | |
| 867 | 313 CIbyte buf[666]; |
| 428 | 314 |
| 315 file_size = | |
| 316 file->nFileSizeHigh * (double)UINT_MAX + file->nFileSizeLow; | |
| 317 #if INDENT_LISTING | |
| 2421 | 318 eicat_ascii (puta, " "); |
| 428 | 319 #endif |
| 320 if (display_size) | |
| 321 { | |
| 771 | 322 sprintf (buf, "%6d ", (int)((file_size + 1023.) / 1024.)); |
| 2421 | 323 eicat_ascii (puta, buf); |
| 428 | 324 } |
| 325 if (file->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) | |
| 2421 | 326 eicat_ascii (puta, "d"); |
| 771 | 327 else |
| 2421 | 328 eicat_ascii (puta, "-"); |
| 771 | 329 buf[0] = buf[3] = buf[6] = 'r'; |
| 428 | 330 if (file->dwFileAttributes & FILE_ATTRIBUTE_READONLY) |
| 771 | 331 buf[1] = buf[4] = buf[7] = '-'; |
| 332 else | |
| 333 buf[1] = buf[4] = buf[7] = 'w'; | |
| 334 { | |
| 335 int is_executable = 0; | |
| 428 | 336 |
| 771 | 337 if (file->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) |
| 338 is_executable = 1; | |
| 339 else if (qxestrcharlen (file->cFileName) > 4) | |
| 340 { | |
| 867 | 341 Ibyte *end = file->cFileName + qxestrlen (file->cFileName); |
| 342 DEC_IBYTEPTR (end); | |
| 343 DEC_IBYTEPTR (end); | |
| 344 DEC_IBYTEPTR (end); | |
| 345 DEC_IBYTEPTR (end); | |
| 2367 | 346 if (qxestrcasecmp_ascii (end, ".exe") == 0 |
| 347 || qxestrcasecmp_ascii (end, ".com") == 0 | |
| 348 || qxestrcasecmp_ascii (end, ".bat") == 0 | |
| 428 | 349 #if 0 |
| 2367 | 350 || qxestrcasecmp_ascii (end, ".pif") == 0 |
| 428 | 351 #endif |
| 771 | 352 ) |
| 353 is_executable = 1; | |
| 428 | 354 } |
| 771 | 355 if (is_executable) |
| 356 buf[2] = buf[5] = buf[8] = 'x'; | |
| 357 else | |
| 358 buf[2] = buf[5] = buf[8] = '-'; | |
| 428 | 359 } |
| 771 | 360 buf[9] = '\0'; |
| 2421 | 361 eicat_ascii (puta, buf); |
| 771 | 362 if (file->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) |
| 2421 | 363 eicat_ascii (puta, " 2 "); |
| 771 | 364 else |
| 2421 | 365 eicat_ascii (puta, " 1 "); |
| 771 | 366 luser = Fuser_login_name (Qnil); |
| 367 if (!STRINGP (luser)) | |
| 368 sprintf (buf, "%-9d", 0); | |
| 428 | 369 else |
| 370 { | |
| 867 | 371 Ibyte *str; |
| 771 | 372 |
| 373 str = XSTRING_DATA (luser); | |
| 374 sprintf (buf, "%-8s ", str); | |
| 428 | 375 } |
| 867 | 376 eicat_raw (puta, (Ibyte *) buf, strlen (buf)); |
| 771 | 377 { |
| 867 | 378 CIbyte *cptr = buf; |
| 771 | 379 sprintf (buf, "%-8d ", getgid ()); |
| 380 cptr += 9; | |
| 381 if (file_size > 99999999.0) | |
| 382 { | |
| 383 file_size = (file_size + 1023.0) / 1024.; | |
| 384 if (file_size > 999999.0) | |
| 385 sprintf (cptr, "%6.0fMB ", (file_size + 1023.0) / 1024.); | |
| 386 else | |
| 387 sprintf (cptr, "%6.0fKB ", file_size); | |
| 388 } | |
| 389 else | |
| 390 sprintf (cptr, "%8.0f ", file_size); | |
| 391 while (*cptr) | |
| 392 ++cptr; | |
| 393 { | |
| 394 time_t t, now; | |
| 867 | 395 Ibyte *ctimebuf; |
| 771 | 396 |
| 397 if ( | |
| 398 #if 0 | |
| 399 /* | |
| 400 * This doesn't work. | |
| 401 * This code should be correct ... | |
| 402 */ | |
| 403 FileTimeToLocalFileTime (&file->ftLastWriteTime, &localtime) && | |
| 404 ((t = mswindows_convert_time (localtime)) != 0) && | |
| 405 #else | |
| 406 /* | |
| 407 * But this code "works" ... | |
| 408 */ | |
| 409 ((t = mswindows_convert_time (file->ftLastWriteTime)) != 0) && | |
| 410 #endif | |
| 411 ((ctimebuf = qxe_ctime (&t)) != NULL)) | |
| 412 { | |
| 413 memcpy (cptr, &ctimebuf[4], 7); | |
| 414 now = time (NULL); | |
| 415 if (now - t > (365. / 2.0) * 86400.) | |
| 416 { | |
| 417 /* more than 6 months */ | |
| 418 cptr[7] = ' '; | |
| 419 memcpy (&cptr[8], &ctimebuf[20], 4); | |
| 420 } | |
| 421 else | |
| 422 { | |
| 423 /* less than 6 months */ | |
| 424 memcpy (&cptr[7], &ctimebuf[11], 5); | |
| 425 } | |
| 426 cptr += 12; | |
| 427 *cptr++ = ' '; | |
| 428 *cptr++ = '\0'; | |
| 429 } | |
| 430 } | |
| 431 } | |
| 432 | |
| 2421 | 433 eicat_ascii (puta, buf); |
| 771 | 434 eicat_raw (puta, file->cFileName, qxestrlen (file->cFileName)); |
| 435 if (add_newline) | |
| 2421 | 436 eicat_ascii (puta, "\n"); |
| 771 | 437 |
| 438 return eimake_string (puta); | |
| 428 | 439 } |
| 440 | |
| 441 | |
| 442 DEFUN ("mswindows-insert-directory", Fmswindows_insert_directory, 2, 4, 0, /* | |
| 443 Insert directory listing for FILE, formatted according to SWITCHES. | |
| 444 Leaves point after the inserted text. | |
| 445 SWITCHES may be a string of options, or a list of strings. | |
| 446 Optional third arg WILDCARD means treat FILE as shell wildcard. | |
| 447 Optional fourth arg FULL-DIRECTORY-P means file is a directory and | |
| 448 switches do not contain `d', so that a full listing is expected. | |
| 449 */ | |
| 450 (file, switches, wildcard, full_directory_p)) | |
| 451 { | |
| 771 | 452 Lisp_Object handler, wildpat = Qnil, basename = Qnil; |
| 453 int nfiles = 0, i; | |
| 454 int hide_system = 1, hide_dot = 1, reverse = 0, display_size = 0; | |
| 455 Win32_file_dynarr *files; | |
| 456 enum mswindows_sortby sort_by = | |
| 457 (mswindows_ls_sort_case_insensitive ? MSWINDOWS_SORT_BY_NAME_NOCASE | |
| 458 : MSWINDOWS_SORT_BY_NAME); | |
| 459 struct gcpro gcpro1, gcpro2, gcpro3; | |
| 460 | |
| 461 GCPRO3 (file, wildpat, basename); | |
| 462 | |
| 463 CHECK_STRING (file); | |
| 464 if (!NILP (wildpat)) | |
| 465 CHECK_STRING (wildpat); | |
| 428 | 466 |
| 771 | 467 handler = Ffind_file_name_handler (file, Qmswindows_insert_directory); |
| 468 if (!NILP (handler)) | |
| 469 { | |
| 470 UNGCPRO; | |
| 471 return call5 (handler, Qmswindows_insert_directory, file, switches, | |
| 472 wildcard, full_directory_p); | |
| 473 } | |
| 474 | |
| 475 if (!NILP (switches)) | |
| 428 | 476 { |
| 867 | 477 Ibyte *cptr, *cptr_end; |
| 771 | 478 |
| 479 CHECK_STRING (switches); | |
| 480 cptr = XSTRING_DATA (switches); | |
| 481 cptr_end = cptr + XSTRING_LENGTH (switches); | |
| 482 while (cptr < cptr_end) | |
| 428 | 483 { |
| 867 | 484 Ichar ch = itext_ichar (cptr); |
| 771 | 485 switch (ch) |
| 428 | 486 { |
| 771 | 487 case 'A': |
| 488 hide_dot = 0; | |
| 489 break; | |
| 490 case 'a': | |
| 491 hide_system = 0; | |
| 492 hide_dot = 0; | |
| 493 break; | |
| 494 case 'r': | |
| 495 reverse = 1; | |
| 496 break; | |
| 497 case 's': | |
| 498 display_size = 1; | |
| 499 break; | |
| 500 case 'S': | |
| 501 sort_by = MSWINDOWS_SORT_BY_SIZE; | |
| 502 break; | |
| 503 case 't': | |
| 504 sort_by = MSWINDOWS_SORT_BY_MOD_DATE; | |
| 428 | 505 break; |
| 506 } | |
| 867 | 507 INC_IBYTEPTR (cptr); |
| 428 | 508 } |
| 771 | 509 } |
| 510 | |
| 511 if (!NILP (wildcard)) | |
| 512 { | |
| 513 Lisp_Object newfile; | |
| 514 | |
| 515 file = Fdirectory_file_name (file); | |
| 516 basename = Ffile_name_nondirectory (file); | |
| 517 wildpat = call1 (Qwildcard_to_regexp, basename); | |
| 518 newfile = Ffile_name_directory (file); | |
| 519 if (NILP (newfile)) | |
| 520 newfile = Ffile_name_directory (Fexpand_file_name (file, Qnil)); | |
| 521 file = newfile; | |
| 522 } | |
| 523 | |
| 524 files = mswindows_get_files (file, | |
| 525 NILP (wildcard) && NILP (full_directory_p), | |
| 526 wildpat, hide_dot, hide_system); | |
| 527 | |
| 528 if (Dynarr_length (files) > 1) | |
| 529 mswindows_sort_files (files, sort_by, reverse); | |
| 530 if (!NILP (wildcard) || !NILP (full_directory_p)) | |
| 531 { | |
| 532 /* | |
| 533 * By using doubles, we can handle files up to 2^53 bytes in | |
| 534 * size (IEEE doubles have 53 bits of resolution). However, | |
| 535 * as we divide by 1024 (or 2^10), the total size is | |
| 536 * accurate up to 2^(53+10) --> 2^63 bytes. | |
| 537 * | |
| 538 * Hopefully, we won't have to handle these file sizes anytime | |
| 539 * soon. | |
| 540 */ | |
| 541 double total_size, file_size, block_size; | |
| 428 | 542 |
| 771 | 543 if ((block_size = mswindows_ls_round_file_size) <= 0) |
| 544 { | |
| 545 block_size = 0; | |
| 546 } | |
| 547 total_size = 0; | |
| 548 for (i = 0; i < Dynarr_length (files); ++i) | |
| 549 { | |
| 550 Win32_file *file = Dynarr_atp (files, i); | |
| 551 file_size = | |
| 552 file->nFileSizeHigh * (double)UINT_MAX + | |
| 553 file->nFileSizeLow; | |
| 554 if (block_size > 0) | |
| 428 | 555 { |
| 771 | 556 /* |
| 557 * Round file_size up to the next nearest block size. | |
| 558 */ | |
| 428 | 559 file_size = |
| 771 | 560 floor ((file_size + block_size - 1) / block_size) |
| 561 * block_size; | |
| 428 | 562 } |
| 771 | 563 /* Here, we round to the nearest 1K */ |
| 564 total_size += floor ((file_size + 512.) / 1024.); | |
| 428 | 565 } |
| 771 | 566 { |
| 800 | 567 write_fmt_string (wrap_buffer (current_buffer), |
| 771 | 568 #if INDENT_LISTING |
| 800 | 569 /* ANSI C compilers auto-concatenate adjacent |
| 570 strings */ | |
| 571 " " | |
| 771 | 572 #endif |
| 800 | 573 "total %.0f\n", total_size); |
| 771 | 574 } |
| 428 | 575 } |
| 771 | 576 for (i = 0; i < Dynarr_length (files); ++i) |
| 428 | 577 { |
| 771 | 578 struct gcpro ngcpro1; |
| 579 Lisp_Object fmtfile = | |
| 580 mswindows_format_file (Dynarr_atp (files, i), display_size, TRUE); | |
| 581 NGCPRO1 (fmtfile); | |
| 582 buffer_insert1 (current_buffer, fmtfile); | |
| 583 NUNGCPRO; | |
| 428 | 584 } |
| 771 | 585 for (i = 0; i < Dynarr_length (files); ++i) |
| 586 { | |
| 587 Win32_file *file = Dynarr_atp (files, i); | |
|
4976
16112448d484
Rename xfree(FOO, TYPE) -> xfree(FOO)
Ben Wing <ben@xemacs.org>
parents:
4967
diff
changeset
|
588 xfree (file->cFileName); |
| 771 | 589 } |
| 590 Dynarr_free (files); | |
| 591 | |
| 428 | 592 UNGCPRO; |
| 771 | 593 return Qnil; |
| 428 | 594 } |
| 595 | |
| 596 | |
| 597 | |
| 598 /************************************************************************/ | |
| 599 /* initialization */ | |
| 600 /************************************************************************/ | |
| 601 | |
| 602 void | |
| 603 syms_of_dired_mswindows (void) | |
| 604 { | |
| 563 | 605 DEFSYMBOL (Qmswindows_insert_directory); |
| 771 | 606 DEFSYMBOL (Qwildcard_to_regexp); |
| 428 | 607 |
| 608 DEFSUBR (Fmswindows_insert_directory); | |
| 609 } | |
| 610 | |
| 611 | |
| 612 void | |
| 613 vars_of_dired_mswindows (void) | |
| 614 { | |
| 771 | 615 DEFVAR_BOOL ("mswindows-ls-sort-case-insensitive", |
| 616 &mswindows_ls_sort_case_insensitive /* | |
| 428 | 617 *Non-nil means filenames are sorted in a case-insensitive fashion. |
| 618 Nil means filenames are sorted in a case-sensitive fashion, just like Unix. | |
| 619 */ ); | |
| 620 mswindows_ls_sort_case_insensitive = 1; | |
| 621 | |
| 622 DEFVAR_INT ("mswindows-ls-round-file-size", &mswindows_ls_round_file_size /* | |
| 623 *If non-zero, file sizes are rounded in terms of this block size when | |
| 624 the file totals are being calculated. This is useful for getting a more | |
| 625 accurate estimate of allocated disk space. Note that this only affects | |
| 626 the total size calculation; the individual displayed file sizes are not | |
| 627 changed. This block size should also be a power of 2 (but this is not | |
| 628 enforced), as filesystem block (cluster) sizes are typically powers-of-2. | |
| 629 */ ); | |
| 630 /* | |
| 631 * Here, we choose 4096 because it's the cluster size for both FAT32 | |
| 632 * and NTFS (?). This is probably much too small for people using | |
| 633 * plain FAT, but, hopefully, plain FAT will go away someday. | |
| 634 * | |
| 635 * We should allow something like a alist here, to make the size | |
| 636 * dependent on the drive letter, etc.. | |
| 637 */ | |
| 638 mswindows_ls_round_file_size = 4096; | |
| 639 } |
