Mercurial > hg > xemacs-beta
comparison src/dired.c @ 0:376386a54a3c r19-14
Import from CVS: tag r19-14
author | cvs |
---|---|
date | Mon, 13 Aug 2007 08:45:50 +0200 |
parents | |
children | ac2d302a0011 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:376386a54a3c |
---|---|
1 /* Lisp functions for making directory listings. | |
2 Copyright (C) 1985, 1986, 1992, 1993, 1994 Free Software Foundation, Inc. | |
3 | |
4 This file is part of XEmacs. | |
5 | |
6 XEmacs is free software; you can redistribute it and/or modify it | |
7 under the terms of the GNU General Public License as published by the | |
8 Free Software Foundation; either version 2, or (at your option) any | |
9 later version. | |
10 | |
11 XEmacs is distributed in the hope that it will be useful, but WITHOUT | |
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
14 for more details. | |
15 | |
16 You should have received a copy of the GNU General Public License | |
17 along with XEmacs; see the file COPYING. If not, write to | |
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
19 Boston, MA 02111-1307, USA. */ | |
20 | |
21 /* Synched up with: FSF 19.30. */ | |
22 | |
23 #include <config.h> | |
24 #include "lisp.h" | |
25 | |
26 #include "buffer.h" | |
27 #include "commands.h" | |
28 #include "elhash.h" | |
29 #include "regex.h" | |
30 | |
31 #include "sysfile.h" | |
32 #include "sysdir.h" | |
33 | |
34 Lisp_Object Vcompletion_ignored_extensions; | |
35 | |
36 Lisp_Object Qdirectory_files; | |
37 Lisp_Object Qfile_name_completion; | |
38 Lisp_Object Qfile_name_all_completions; | |
39 Lisp_Object Qfile_attributes; | |
40 | |
41 DEFUN ("directory-files", Fdirectory_files, Sdirectory_files, 1, 5, 0 /* | |
42 Return a list of names of files in DIRECTORY. | |
43 There are four optional arguments: | |
44 If FULL is non-nil, absolute pathnames of the files are returned. | |
45 If MATCH is non-nil, only pathnames containing that regexp are returned. | |
46 If NOSORT is non-nil, the list is not sorted--its order is unpredictable. | |
47 NOSORT is useful if you plan to sort the result yourself. | |
48 If FILES-ONLY is the symbol t, then only the \"files\" in the directory | |
49 will be returned; subdirectories will be excluded. If FILES-ONLY is not | |
50 nil and not t, then only the subdirectories will be returned. Otherwise, | |
51 if FILES-ONLY is nil (the default) then both files and subdirectories will | |
52 be returned. | |
53 */ ) | |
54 (dirname, full, match, nosort, files_only) | |
55 Lisp_Object dirname, full, match, nosort, files_only; | |
56 { | |
57 /* This function can GC */ | |
58 DIR *d; | |
59 Bytecount dirname_length; | |
60 Lisp_Object list, name, dirfilename = Qnil; | |
61 Lisp_Object handler; | |
62 struct re_pattern_buffer *bufp; | |
63 | |
64 char statbuf [MAXNAMLEN+2]; | |
65 char *statbuf_tail; | |
66 Lisp_Object tail_cons; | |
67 char slashfilename[MAXNAMLEN+2]; | |
68 char *filename = slashfilename; | |
69 | |
70 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5; | |
71 | |
72 /* #### Needs more gcpro's */ | |
73 GCPRO5 (dirname, match, files_only, tail_cons, dirfilename); | |
74 | |
75 /* If the file name has special constructs in it, | |
76 call the corresponding file handler. */ | |
77 handler = Ffind_file_name_handler (dirname, Qdirectory_files); | |
78 if (!NILP (handler)) | |
79 { | |
80 UNGCPRO; | |
81 if (!NILP (files_only)) | |
82 return call6 (handler, Qdirectory_files, dirname, full, match, nosort, | |
83 files_only); | |
84 else | |
85 return call5 (handler, Qdirectory_files, dirname, full, match, | |
86 nosort); | |
87 } | |
88 | |
89 dirname = Fexpand_file_name (dirname, Qnil); | |
90 dirfilename = Fdirectory_file_name (dirname); | |
91 | |
92 { | |
93 /* XEmacs: this should come before the opendir() because it might error. */ | |
94 Lisp_Object name_as_dir = Ffile_name_as_directory (dirname); | |
95 CHECK_STRING (name_as_dir); | |
96 memcpy (statbuf, ((char *) string_data (XSTRING (name_as_dir))), | |
97 string_length (XSTRING (name_as_dir))); | |
98 statbuf_tail = statbuf + string_length (XSTRING (name_as_dir)); | |
99 } | |
100 | |
101 /* XEmacs: this should come after Ffile_name_as_directory() to avoid | |
102 potential regexp cache smashage. This should come before the | |
103 opendir() because it might signal an error. | |
104 */ | |
105 if (!NILP (match)) | |
106 { | |
107 CHECK_STRING (match); | |
108 | |
109 /* MATCH might be a flawed regular expression. Rather than | |
110 catching and signalling our own errors, we just call | |
111 compile_pattern to do the work for us. */ | |
112 #ifdef VMS | |
113 bufp = | |
114 compile_pattern (match, 0, | |
115 (char *) MIRROR_DOWNCASE_TABLE_AS_STRING | |
116 (XBUFFER (Vbuffer_defaults)), 0, ERROR_ME); | |
117 #else | |
118 bufp = compile_pattern (match, 0, 0, 0, ERROR_ME); | |
119 #endif | |
120 } | |
121 | |
122 /* Now *bufp is the compiled form of MATCH; don't call anything | |
123 which might compile a new regexp until we're done with the loop! */ | |
124 | |
125 /* Do this opendir after anything which might signal an error; if | |
126 an error is signalled while the directory stream is open, we | |
127 have to make sure it gets closed, and setting up an | |
128 unwind_protect to do so would be a pain. */ | |
129 d = opendir ((char *) string_data (XSTRING (dirfilename))); | |
130 if (! d) | |
131 report_file_error ("Opening directory", list1 (dirname)); | |
132 | |
133 list = Qnil; | |
134 tail_cons = Qnil; | |
135 dirname_length = string_length (XSTRING (dirname)); | |
136 #ifndef VMS | |
137 if (dirname_length == 0 | |
138 || !IS_ANY_SEP (string_byte (XSTRING (dirname), dirname_length - 1))) | |
139 { | |
140 *filename++ = DIRECTORY_SEP; | |
141 dirname_length++; | |
142 } | |
143 #endif /* VMS */ | |
144 | |
145 /* Loop reading blocks */ | |
146 while (1) | |
147 { | |
148 DIRENTRY *dp = readdir (d); | |
149 int len; | |
150 | |
151 if (!dp) break; | |
152 len = NAMLEN (dp); | |
153 if (DIRENTRY_NONEMPTY (dp)) | |
154 { | |
155 int result; | |
156 Lisp_Object oinhibit_quit = Vinhibit_quit; | |
157 strncpy (filename, dp->d_name, len); | |
158 filename[len] = 0; | |
159 /* re_search can now QUIT, so prevent it to avoid | |
160 filedesc lossage */ | |
161 Vinhibit_quit = Qt; | |
162 result = (NILP (match) | |
163 || (0 <= re_search (bufp, filename, len, 0, len, 0))); | |
164 Vinhibit_quit = oinhibit_quit; | |
165 if (result) | |
166 { | |
167 if (!NILP (files_only)) | |
168 { | |
169 int dir_p; | |
170 struct stat st; | |
171 | |
172 memcpy (statbuf_tail, filename, len); | |
173 statbuf_tail [len] = 0; | |
174 | |
175 if (stat (statbuf, &st) < 0) | |
176 dir_p = 0; | |
177 else | |
178 dir_p = ((st.st_mode & S_IFMT) == S_IFDIR); | |
179 | |
180 if (EQ (files_only, Qt) && dir_p) | |
181 continue; | |
182 else if (!EQ (files_only, Qt) && !dir_p) | |
183 continue; | |
184 } | |
185 | |
186 if (!NILP (full)) | |
187 name = concat2 (dirname, build_string (slashfilename)); | |
188 else | |
189 name = make_string ((Bufbyte *) filename, len); | |
190 | |
191 if (NILP (tail_cons)) | |
192 { | |
193 list = list1 (name); | |
194 tail_cons = list; | |
195 } | |
196 else | |
197 { | |
198 XCDR (tail_cons) = list1 (name); | |
199 tail_cons = XCDR (tail_cons); | |
200 } | |
201 } | |
202 } | |
203 } | |
204 closedir (d); | |
205 UNGCPRO; | |
206 if (!NILP (nosort)) | |
207 return list; | |
208 return Fsort (Fnreverse (list), Qstring_lessp); | |
209 } | |
210 | |
211 static Lisp_Object file_name_completion (Lisp_Object file, | |
212 Lisp_Object dirname, | |
213 int all_flag, int ver_flag); | |
214 | |
215 DEFUN ("file-name-completion", Ffile_name_completion, Sfile_name_completion, | |
216 2, 2, 0 /* | |
217 Complete file name FILE in directory DIR. | |
218 Returns the longest string common to all filenames in DIR | |
219 that start with FILE. | |
220 If there is only one and FILE matches it exactly, returns t. | |
221 Returns nil if DIR contains no name starting with FILE. | |
222 | |
223 Filenames which end with any member of `completion-ignored-extensions' | |
224 are not considered as possible completions for FILE unless there is no | |
225 other possible completion. `completion-ignored-extensions' is not applied | |
226 to the names of directories. | |
227 */ ) | |
228 (file, dirname) | |
229 Lisp_Object file, dirname; | |
230 { | |
231 /* This function can GC */ | |
232 Lisp_Object handler; | |
233 | |
234 /* If the directory name has special constructs in it, | |
235 call the corresponding file handler. */ | |
236 handler = Ffind_file_name_handler (dirname, Qfile_name_completion); | |
237 if (!NILP (handler)) | |
238 return call3 (handler, Qfile_name_completion, file, dirname); | |
239 | |
240 /* If the file name has special constructs in it, | |
241 call the corresponding file handler. */ | |
242 handler = Ffind_file_name_handler (file, Qfile_name_completion); | |
243 if (!NILP (handler)) | |
244 return call3 (handler, Qfile_name_completion, file, dirname); | |
245 | |
246 return file_name_completion (file, dirname, 0, 0); | |
247 } | |
248 | |
249 DEFUN ("file-name-all-completions", Ffile_name_all_completions, | |
250 Sfile_name_all_completions, 2, 2, 0 /* | |
251 Return a list of all completions of file name FILE in directory DIR. | |
252 These are all file names in directory DIR which begin with FILE. | |
253 | |
254 Filenames which end with any member of `completion-ignored-extensions' | |
255 are not considered as possible completions for FILE unless there is no | |
256 other possible completion. `completion-ignored-extensions' is not applied | |
257 to the names of directories. | |
258 */ ) | |
259 (file, dirname) | |
260 Lisp_Object file, dirname; | |
261 { | |
262 /* This function can GC */ | |
263 Lisp_Object handler; | |
264 | |
265 /* If the file name has special constructs in it, | |
266 call the corresponding file handler. */ | |
267 handler = Ffind_file_name_handler (dirname, Qfile_name_all_completions); | |
268 if (!NILP (handler)) | |
269 return call3 (handler, Qfile_name_all_completions, file, | |
270 dirname); | |
271 | |
272 return file_name_completion (file, dirname, 1, 0); | |
273 } | |
274 | |
275 static int | |
276 file_name_completion_stat (Lisp_Object dirname, DIRENTRY *dp, | |
277 struct stat *st_addr) | |
278 { | |
279 Bytecount len = NAMLEN (dp); | |
280 Bytecount pos = string_length (XSTRING (dirname)); | |
281 int value; | |
282 char *fullname = (char *) alloca (len + pos + 2); | |
283 | |
284 memcpy (fullname, string_data (XSTRING (dirname)), pos); | |
285 #ifndef VMS | |
286 if (!IS_DIRECTORY_SEP (fullname[pos - 1])) | |
287 fullname[pos++] = DIRECTORY_SEP; | |
288 #endif | |
289 | |
290 memcpy (fullname + pos, dp->d_name, len); | |
291 fullname[pos + len] = 0; | |
292 | |
293 #ifdef S_IFLNK | |
294 /* We want to return success if a link points to a nonexistent file, | |
295 but we want to return the status for what the link points to, | |
296 in case it is a directory. */ | |
297 value = lstat (fullname, st_addr); | |
298 if (S_ISLNK (st_addr->st_mode)) | |
299 stat (fullname, st_addr); | |
300 #else | |
301 value = stat (fullname, st_addr); | |
302 #endif | |
303 return (value); | |
304 } | |
305 | |
306 static Lisp_Object | |
307 file_name_completion (Lisp_Object file, Lisp_Object dirname, int all_flag, | |
308 int ver_flag) | |
309 { | |
310 /* This function can GC */ | |
311 DIR *d = 0; | |
312 int matchcount = 0; | |
313 Lisp_Object bestmatch = Qnil; | |
314 Charcount bestmatchsize = 0; | |
315 struct stat st; | |
316 int passcount; | |
317 int speccount = specpdl_depth (); | |
318 Charcount file_name_length; | |
319 DIRENTRY *((*readfunc) (DIR *)) = readdir; | |
320 struct gcpro gcpro1, gcpro2, gcpro3; | |
321 | |
322 GCPRO3 (file, dirname, bestmatch); | |
323 | |
324 CHECK_STRING (file); | |
325 | |
326 #ifdef VMS | |
327 /* Filename completion on VMS ignores case, since VMS filesys does. */ | |
328 specbind (Qcompletion_ignore_case, Qt); | |
329 | |
330 if (ver_flag) | |
331 readfunc = readdirver; | |
332 #endif /* VMS */ | |
333 | |
334 #ifdef FILE_SYSTEM_CASE | |
335 file = FILE_SYSTEM_CASE (file); | |
336 #endif | |
337 dirname = Fexpand_file_name (dirname, Qnil); | |
338 bestmatch = Qnil; | |
339 file_name_length = string_char_length (XSTRING (file)); | |
340 | |
341 /* With passcount = 0, ignore files that end in an ignored extension. | |
342 If nothing found then try again with passcount = 1, don't ignore them. | |
343 If looking for all completions, start with passcount = 1, | |
344 so always take even the ignored ones. | |
345 | |
346 ** It would not actually be helpful to the user to ignore any possible | |
347 completions when making a list of them.** */ | |
348 | |
349 for (passcount = !!all_flag; NILP (bestmatch) && passcount < 2; passcount++) | |
350 { | |
351 d = opendir ((char *) | |
352 string_data (XSTRING (Fdirectory_file_name (dirname)))); | |
353 if (!d) | |
354 report_file_error ("Opening directory", list1 (dirname)); | |
355 | |
356 /* Loop reading blocks */ | |
357 /* (att3b compiler bug requires do a null comparison this way) */ | |
358 while (1) | |
359 { | |
360 DIRENTRY *dp; | |
361 Bytecount len; | |
362 /* scmp() works in characters, not bytes, so we have to compute | |
363 this value: */ | |
364 Charcount cclen; | |
365 int directoryp; | |
366 int ignored_extension_p = 0; | |
367 Bufbyte *d_name; | |
368 | |
369 dp = (*readfunc) (d); | |
370 if (!dp) break; | |
371 | |
372 d_name = (Bufbyte *) dp->d_name; | |
373 len = NAMLEN (dp); | |
374 /* mrb: #### FIX: The Name must be converted using | |
375 file-name-coding system or some such. At least this | |
376 change allows the saving of files in directories with | |
377 Japanese file names */ | |
378 /*cclen = bytecount_to_charcount (d_name, len);*/ | |
379 cclen = len; | |
380 | |
381 /* Can't just use QUIT because we have to make sure the file | |
382 descriptor gets closed. */ | |
383 if (QUITP) | |
384 { | |
385 closedir (d); | |
386 signal_quit (); | |
387 } | |
388 | |
389 if (! DIRENTRY_NONEMPTY (dp) | |
390 || cclen < file_name_length | |
391 || 0 <= scmp (d_name, | |
392 string_data (XSTRING (file)), | |
393 file_name_length)) | |
394 continue; | |
395 | |
396 if (file_name_completion_stat (dirname, dp, &st) < 0) | |
397 continue; | |
398 | |
399 directoryp = ((st.st_mode & S_IFMT) == S_IFDIR); | |
400 if (directoryp) | |
401 { | |
402 #ifndef TRIVIAL_DIRECTORY_ENTRY | |
403 #define TRIVIAL_DIRECTORY_ENTRY(n) (!strcmp (n, ".") || !strcmp (n, "..")) | |
404 #endif | |
405 /* "." and ".." are never interesting as completions, but are | |
406 actually in the way in a directory contains only one file. */ | |
407 if (!passcount && TRIVIAL_DIRECTORY_ENTRY (dp->d_name)) | |
408 continue; | |
409 } | |
410 else | |
411 { | |
412 /* Compare extensions-to-be-ignored against end of this file name */ | |
413 /* if name is not an exact match against specified string */ | |
414 if (!passcount && cclen > file_name_length) | |
415 { | |
416 Lisp_Object tem; | |
417 /* and exit this for loop if a match is found */ | |
418 for (tem = Vcompletion_ignored_extensions; | |
419 CONSP (tem); | |
420 tem = XCDR (tem)) | |
421 { | |
422 Lisp_Object elt = XCAR (tem); | |
423 Charcount skip; | |
424 | |
425 if (!STRINGP (elt)) continue; | |
426 skip = cclen - string_char_length (XSTRING (elt)); | |
427 if (skip < 0) continue; | |
428 | |
429 if (0 > scmp (charptr_n_addr (d_name, skip), | |
430 string_data (XSTRING (elt)), | |
431 string_char_length (XSTRING (elt)))) | |
432 { | |
433 ignored_extension_p = 1; | |
434 break; | |
435 } | |
436 } | |
437 } | |
438 } | |
439 | |
440 /* If an ignored-extensions match was found, | |
441 don't process this name as a completion. */ | |
442 if (!passcount && ignored_extension_p) | |
443 continue; | |
444 | |
445 if (!passcount && regexp_ignore_completion_p (d_name, Qnil, 0, len)) | |
446 continue; | |
447 | |
448 /* Update computation of how much all possible completions match */ | |
449 matchcount++; | |
450 | |
451 if (all_flag || NILP (bestmatch)) | |
452 { | |
453 Lisp_Object name = Qnil; | |
454 struct gcpro ngcpro1; | |
455 NGCPRO1 (name); | |
456 /* This is a possible completion */ | |
457 if (directoryp) | |
458 { | |
459 /* This completion is a directory; make it end with '/' */ | |
460 name = Ffile_name_as_directory | |
461 /* make_string (d_name, len); */ | |
462 (make_ext_string (d_name, len, FORMAT_BINARY)); | |
463 } | |
464 else | |
465 /* name = make_string (d_name, len) */ | |
466 name = make_ext_string (d_name, len, FORMAT_BINARY); | |
467 if (all_flag) | |
468 { | |
469 bestmatch = Fcons (name, bestmatch); | |
470 } | |
471 else | |
472 { | |
473 bestmatch = name; | |
474 bestmatchsize = string_char_length (XSTRING (name)); | |
475 } | |
476 NUNGCPRO; | |
477 } | |
478 else | |
479 { | |
480 Charcount compare = min (bestmatchsize, cclen); | |
481 Bufbyte *p1 = string_data (XSTRING (bestmatch)); | |
482 Bufbyte *p2 = d_name; | |
483 Charcount matchsize = scmp (p1, p2, compare); | |
484 | |
485 if (matchsize < 0) | |
486 matchsize = compare; | |
487 if (completion_ignore_case) | |
488 { | |
489 /* If this is an exact match except for case, | |
490 use it as the best match rather than one that is not | |
491 an exact match. This way, we get the case pattern | |
492 of the actual match. */ | |
493 if ((matchsize == len | |
494 && matchsize + !!directoryp | |
495 < string_char_length (XSTRING (bestmatch))) | |
496 || | |
497 /* If there is no exact match ignoring case, | |
498 prefer a match that does not change the case | |
499 of the input. */ | |
500 (((matchsize == len) | |
501 == | |
502 (matchsize + !!directoryp | |
503 == string_char_length (XSTRING (bestmatch)))) | |
504 /* If there is more than one exact match aside from | |
505 case, and one of them is exact including case, | |
506 prefer that one. */ | |
507 && 0 > scmp_1 (p2, string_data (XSTRING (file)), | |
508 file_name_length, 0) | |
509 && 0 <= scmp_1 (p1, string_data (XSTRING (file)), | |
510 file_name_length, 0))) | |
511 { | |
512 /* bestmatch = make_string (d_name, len); */ /* mrb */ | |
513 bestmatch = make_ext_string (d_name, len, FORMAT_BINARY); | |
514 if (directoryp) | |
515 bestmatch = | |
516 Ffile_name_as_directory (bestmatch); | |
517 } | |
518 } | |
519 | |
520 /* If this dirname all matches, | |
521 see if implicit following slash does too. */ | |
522 if (directoryp | |
523 && compare == matchsize | |
524 && bestmatchsize > matchsize | |
525 && IS_ANY_SEP (charptr_emchar_n (p1, matchsize))) | |
526 matchsize++; | |
527 bestmatchsize = matchsize; | |
528 } | |
529 } | |
530 closedir (d); | |
531 } | |
532 | |
533 unbind_to (speccount, Qnil); | |
534 | |
535 UNGCPRO; | |
536 | |
537 if (all_flag || NILP (bestmatch)) | |
538 return bestmatch; | |
539 if (matchcount == 1 && bestmatchsize == file_name_length) | |
540 return Qt; | |
541 return Fsubstring (bestmatch, make_int (0), make_int (bestmatchsize)); | |
542 } | |
543 | |
544 | |
545 Lisp_Object | |
546 make_directory_hash_table (char *path) | |
547 { | |
548 DIR *d; | |
549 DIRENTRY *dp; | |
550 Bytecount len; | |
551 Lisp_Object hash = make_lisp_hashtable (100, HASHTABLE_NONWEAK, | |
552 HASHTABLE_EQUAL); | |
553 if ((d = opendir (path))) | |
554 { | |
555 while ((dp = readdir (d))) | |
556 { | |
557 len = NAMLEN (dp); | |
558 if (DIRENTRY_NONEMPTY (dp)) | |
559 Fputhash (make_string ((Bufbyte *) dp->d_name, len), Qt, hash); | |
560 } | |
561 closedir (d); | |
562 } | |
563 return hash; | |
564 } | |
565 | |
566 #ifdef VMS | |
567 | |
568 DEFUN ("file-name-all-versions", Ffile_name_all_versions, | |
569 Sfile_name_all_versions, 2, 2, 0 /* | |
570 Return a list of all versions of file name FILE in directory DIR. | |
571 */ ) | |
572 (file, dirname) | |
573 Lisp_Object file, dirname; | |
574 { | |
575 /* This function can GC */ | |
576 return file_name_completion (file, dirname, 1, 1); | |
577 } | |
578 | |
579 DEFUN ("file-version-limit", Ffile_version_limit, Sfile_version_limit, 1, 1, 0 /* | |
580 Return the maximum number of versions allowed for FILE. | |
581 Returns nil if the file cannot be opened or if there is no version limit. | |
582 */ ) | |
583 (filename) | |
584 Lisp_Object filename; | |
585 { | |
586 /* This function can GC */ | |
587 Lisp_Object retval; | |
588 struct FAB fab; | |
589 struct RAB rab; | |
590 struct XABFHC xabfhc; | |
591 int status; | |
592 | |
593 filename = Fexpand_file_name (filename, Qnil); | |
594 CHECK_STRING (filename); | |
595 fab = cc$rms_fab; | |
596 xabfhc = cc$rms_xabfhc; | |
597 fab.fab$l_fna = string_data (XSTRING (filename)); | |
598 fab.fab$b_fns = strlen (fab.fab$l_fna); | |
599 fab.fab$l_xab = (char *) &xabfhc; | |
600 status = sys$open (&fab, 0, 0); | |
601 if (status != RMS$_NORMAL) /* Probably non-existent file */ | |
602 return Qnil; | |
603 sys$close (&fab, 0, 0); | |
604 if (xabfhc.xab$w_verlimit == 32767) | |
605 return Qnil; /* No version limit */ | |
606 else | |
607 return make_int (xabfhc.xab$w_verlimit); | |
608 } | |
609 | |
610 #endif /* VMS */ | |
611 | |
612 | |
613 Lisp_Object | |
614 wasteful_word_to_lisp (unsigned int item) | |
615 { | |
616 /* Compatibility: in other versions, file-attributes returns a LIST | |
617 of two 16 bit integers... */ | |
618 Lisp_Object cons = word_to_lisp (item); | |
619 XCDR (cons) = Fcons (XCDR (cons), Qnil); | |
620 return cons; | |
621 } | |
622 | |
623 DEFUN ("file-attributes", Ffile_attributes, Sfile_attributes, 1, 1, 0 /* | |
624 Return a list of attributes of file FILENAME. | |
625 Value is nil if specified file cannot be opened. | |
626 Otherwise, list elements are: | |
627 0. t for directory, string (name linked to) for symbolic link, or nil. | |
628 1. Number of links to file. | |
629 2. File uid. | |
630 3. File gid. | |
631 4. Last access time, as a list of two integers. | |
632 First integer has high-order 16 bits of time, second has low 16 bits. | |
633 5. Last modification time, likewise. | |
634 6. Last status change time, likewise. | |
635 7. Size in bytes. (-1, if number is out of range). | |
636 8. File modes, as a string of ten letters or dashes as in ls -l. | |
637 9. t iff file's gid would change if file were deleted and recreated. | |
638 10. inode number. | |
639 11. Device number. | |
640 | |
641 If file does not exist, returns nil. | |
642 */ ) | |
643 (filename) | |
644 Lisp_Object filename; | |
645 { | |
646 /* This function can GC */ | |
647 Lisp_Object values[12]; | |
648 Lisp_Object dirname = Qnil; | |
649 struct stat s; | |
650 char modes[10]; | |
651 Lisp_Object handler; | |
652 struct gcpro gcpro1, gcpro2; | |
653 | |
654 GCPRO1 (filename); | |
655 filename = Fexpand_file_name (filename, Qnil); | |
656 | |
657 /* If the file name has special constructs in it, | |
658 call the corresponding file handler. */ | |
659 handler = Ffind_file_name_handler (filename, Qfile_attributes); | |
660 UNGCPRO; | |
661 if (!NILP (handler)) | |
662 return call2 (handler, Qfile_attributes, filename); | |
663 | |
664 if (lstat ((char *) string_data (XSTRING (filename)), &s) < 0) | |
665 return Qnil; | |
666 | |
667 GCPRO2 (filename, dirname); | |
668 | |
669 #ifdef BSD4_2 | |
670 dirname = Ffile_name_directory (filename); | |
671 #endif | |
672 | |
673 #ifdef MSDOS | |
674 { | |
675 char *tmpnam = | |
676 (char *) string_data (XSTRING (Ffile_name_nondirectory (filename))); | |
677 int l = strlen (tmpnam); | |
678 | |
679 if (l >= 5 | |
680 && S_ISREG (s.st_mode) | |
681 && (stricmp (&tmpnam[l - 4], ".com") == 0 | |
682 || stricmp (&tmpnam[l - 4], ".exe") == 0 | |
683 || stricmp (&tmpnam[l - 4], ".bat") == 0)) | |
684 { | |
685 s.st_mode |= S_IEXEC; | |
686 } | |
687 } | |
688 #endif /* MSDOS */ | |
689 | |
690 switch (s.st_mode & S_IFMT) | |
691 { | |
692 default: | |
693 values[0] = Qnil; | |
694 break; | |
695 case S_IFDIR: | |
696 values[0] = Qt; | |
697 break; | |
698 #ifdef S_IFLNK | |
699 case S_IFLNK: | |
700 values[0] = Ffile_symlink_p (filename); | |
701 break; | |
702 #endif | |
703 } | |
704 values[1] = make_int (s.st_nlink); | |
705 values[2] = make_int (s.st_uid); | |
706 values[3] = make_int (s.st_gid); | |
707 values[4] = wasteful_word_to_lisp (s.st_atime); | |
708 values[5] = wasteful_word_to_lisp (s.st_mtime); | |
709 values[6] = wasteful_word_to_lisp (s.st_ctime); | |
710 values[7] = make_int ((EMACS_INT) s.st_size); | |
711 /* If the size is out of range, give back -1. */ | |
712 /* #### Fix when Emacs gets bignums! */ | |
713 if (XINT (values[7]) != s.st_size) | |
714 XSETINT (values[7], -1); | |
715 filemodestring (&s, modes); | |
716 values[8] = make_string ((Bufbyte *) modes, 10); | |
717 #if defined (BSD4_2) || defined (BSD4_3) /* file gid will be dir gid */ | |
718 { | |
719 struct stat sdir; | |
720 | |
721 if (!NILP (dirname) && stat ((char *) string_data (XSTRING (dirname)), &sdir) == 0) | |
722 values[9] = (sdir.st_gid != s.st_gid) ? Qt : Qnil; | |
723 else /* if we can't tell, assume worst */ | |
724 values[9] = Qt; | |
725 } | |
726 #else /* file gid will be egid */ | |
727 #ifdef WINDOWSNT | |
728 values[9] = Qnil; /* sorry, no group IDs on NT */ | |
729 #else /* not WINDOWSNT */ | |
730 values[9] = (s.st_gid != getegid ()) ? Qt : Qnil; | |
731 #endif /* not WINDOWSNT */ | |
732 #endif /* BSD4_2 or BSD4_3 */ | |
733 #ifdef WINDOWSNT | |
734 /* Fill in the inode and device values specially...see nt.c. */ | |
735 if (!get_inode_and_device_vals (filename, &values[10], &values[11])) | |
736 { | |
737 UNGCPRO; | |
738 return Qnil; | |
739 } | |
740 #else /* not WINDOWSNT */ | |
741 values[10] = make_int (s.st_ino); | |
742 values[11] = make_int (s.st_dev); | |
743 #endif /* not WINDOWSNT */ | |
744 UNGCPRO; | |
745 return Flist (countof (values), values); | |
746 } | |
747 | |
748 | |
749 /************************************************************************/ | |
750 /* initialization */ | |
751 /************************************************************************/ | |
752 | |
753 void | |
754 syms_of_dired (void) | |
755 { | |
756 defsymbol (&Qdirectory_files, "directory-files"); | |
757 defsymbol (&Qfile_name_completion, "file-name-completion"); | |
758 defsymbol (&Qfile_name_all_completions, "file-name-all-completions"); | |
759 defsymbol (&Qfile_attributes, "file-attributes"); | |
760 | |
761 defsubr (&Sdirectory_files); | |
762 defsubr (&Sfile_name_completion); | |
763 #ifdef VMS | |
764 defsubr (&Sfile_name_all_versions); | |
765 defsubr (&Sfile_version_limit); | |
766 #endif /* VMS */ | |
767 defsubr (&Sfile_name_all_completions); | |
768 defsubr (&Sfile_attributes); | |
769 } | |
770 | |
771 void | |
772 vars_of_dired (void) | |
773 { | |
774 DEFVAR_LISP ("completion-ignored-extensions", &Vcompletion_ignored_extensions /* | |
775 *Completion ignores filenames ending in any string in this list. | |
776 This variable does not affect lists of possible completions, | |
777 but does affect the commands that actually do completions. | |
778 It is used by the functions `file-name-completion' and | |
779 `file-name-all-completions'. | |
780 */ ); | |
781 Vcompletion_ignored_extensions = Qnil; | |
782 } |