(directory_files_internal): Add missing GCPRO's.
[bpt/emacs.git] / src / dired.c
1 /* Lisp functions for making directory listings.
2 Copyright (C) 1985, 1986, 1993, 1994, 1999 Free Software Foundation, Inc.
3
4 This file is part of GNU Emacs.
5
6 GNU Emacs is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU Emacs 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
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; 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
22 #include <config.h>
23
24 #include <stdio.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27
28 #include "systime.h"
29
30 #ifdef VMS
31 #include <string.h>
32 #include <rms.h>
33 #include <rmsdef.h>
34 #endif
35
36 #ifdef HAVE_UNISTD_H
37 #include <unistd.h>
38 #endif
39
40 /* The d_nameln member of a struct dirent includes the '\0' character
41 on some systems, but not on others. What's worse, you can't tell
42 at compile-time which one it will be, since it really depends on
43 the sort of system providing the filesystem you're reading from,
44 not the system you are running on. Paul Eggert
45 <eggert@bi.twinsun.com> says this occurs when Emacs is running on a
46 SunOS 4.1.2 host, reading a directory that is remote-mounted from a
47 Solaris 2.1 host and is in a native Solaris 2.1 filesystem.
48
49 Since applying strlen to the name always works, we'll just do that. */
50 #define NAMLEN(p) strlen (p->d_name)
51
52 #ifdef SYSV_SYSTEM_DIR
53
54 #include <dirent.h>
55 #define DIRENTRY struct dirent
56
57 #else /* not SYSV_SYSTEM_DIR */
58
59 #ifdef NONSYSTEM_DIR_LIBRARY
60 #include "ndir.h"
61 #else /* not NONSYSTEM_DIR_LIBRARY */
62 #ifdef MSDOS
63 #include <dirent.h>
64 #else
65 #include <sys/dir.h>
66 #endif
67 #endif /* not NONSYSTEM_DIR_LIBRARY */
68
69 #include <sys/stat.h>
70
71 #ifndef MSDOS
72 #define DIRENTRY struct direct
73
74 extern DIR *opendir ();
75 extern struct direct *readdir ();
76
77 #endif /* not MSDOS */
78 #endif /* not SYSV_SYSTEM_DIR */
79
80 #ifdef MSDOS
81 #define DIRENTRY_NONEMPTY(p) ((p)->d_name[0] != 0)
82 #else
83 #define DIRENTRY_NONEMPTY(p) ((p)->d_ino)
84 #endif
85
86 #include "lisp.h"
87 #include "buffer.h"
88 #include "commands.h"
89 #include "charset.h"
90 #include "coding.h"
91 #include "regex.h"
92
93 /* Returns a search buffer, with a fastmap allocated and ready to go. */
94 extern struct re_pattern_buffer *compile_pattern ();
95
96 /* From filemode.c. Can't go in Lisp.h because of `stat'. */
97 extern void filemodestring P_ ((struct stat *, char *));
98
99 #define min(a, b) ((a) < (b) ? (a) : (b))
100
101 /* if system does not have symbolic links, it does not have lstat.
102 In that case, use ordinary stat instead. */
103
104 #ifndef S_IFLNK
105 #define lstat stat
106 #endif
107
108 extern int completion_ignore_case;
109 extern Lisp_Object Vcompletion_regexp_list;
110 extern Lisp_Object Vfile_name_coding_system, Vdefault_file_name_coding_system;
111
112 Lisp_Object Vcompletion_ignored_extensions;
113 Lisp_Object Qcompletion_ignore_case;
114 Lisp_Object Qdirectory_files;
115 Lisp_Object Qdirectory_files_and_attributes;
116 Lisp_Object Qfile_name_completion;
117 Lisp_Object Qfile_name_all_completions;
118 Lisp_Object Qfile_attributes;
119 Lisp_Object Qfile_attributes_lessp;
120 \f
121
122 Lisp_Object
123 directory_files_internal_unwind (dh)
124 Lisp_Object dh;
125 {
126 DIR *d = (DIR *) ((XINT (XCAR (dh)) << 16) + XINT (XCDR (dh)));
127 closedir (d);
128 return Qnil;
129 }
130
131 /* Function shared by Fdirectory_files and Fdirectory_files_and_attributes.
132 When ATTRS is zero, return a list of directory filenames; when
133 non-zero, return a list of directory filenames and their attributes. */
134 Lisp_Object
135 directory_files_internal (directory, full, match, nosort, attrs)
136 Lisp_Object directory, full, match, nosort;
137 int attrs;
138 {
139 DIR *d;
140 int directory_nbytes;
141 Lisp_Object list, dirfilename, encoded_directory;
142 Lisp_Object handler;
143 struct re_pattern_buffer *bufp = NULL;
144 int needsep = 0;
145 int count = specpdl_ptr - specpdl;
146 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
147
148 /* Because of file name handlers, these functions might call
149 Ffuncall, and cause a GC. */
150 list = encoded_directory = dirfilename = Qnil;
151 GCPRO5 (match, directory, list, dirfilename, encoded_directory);
152 directory = Fexpand_file_name (directory, Qnil);
153 dirfilename = Fdirectory_file_name (directory);
154
155 if (!NILP (match))
156 {
157 CHECK_STRING (match, 3);
158
159 /* MATCH might be a flawed regular expression. Rather than
160 catching and signaling our own errors, we just call
161 compile_pattern to do the work for us. */
162 /* Pass 1 for the MULTIBYTE arg
163 because we do make multibyte strings if the contents warrant. */
164 #ifdef VMS
165 bufp = compile_pattern (match, 0,
166 buffer_defaults.downcase_table, 0, 1);
167 #else
168 bufp = compile_pattern (match, 0, Qnil, 0, 1);
169 #endif
170 }
171
172 /* Note: ENOCDE_FILE and DECODE_FILE can GC because they can run
173 run_pre_post_conversion_on_str which calls Lisp directly and
174 indirectly. */
175 dirfilename = ENCODE_FILE (dirfilename);
176 encoded_directory = ENCODE_FILE (directory);
177
178 /* Now *bufp is the compiled form of MATCH; don't call anything
179 which might compile a new regexp until we're done with the loop! */
180
181 /* Do this opendir after anything which might signal an error; if
182 an error is signaled while the directory stream is open, we
183 have to make sure it gets closed, and setting up an
184 unwind_protect to do so would be a pain. */
185 d = opendir (XSTRING (dirfilename)->data);
186 if (d == NULL)
187 report_file_error ("Opening directory", Fcons (directory, Qnil));
188
189 /* Unfortunately, we can now invoke expand-file-name and
190 file-attributes on filenames, both of which can throw, so we must
191 do a proper unwind-protect. */
192 record_unwind_protect (directory_files_internal_unwind,
193 Fcons (make_number (((unsigned long) d) >> 16),
194 make_number (((unsigned long) d) & 0xffff)));
195
196 directory_nbytes = STRING_BYTES (XSTRING (directory));
197 re_match_object = Qt;
198
199 /* Decide whether we need to add a directory separator. */
200 #ifndef VMS
201 if (directory_nbytes == 0
202 || !IS_ANY_SEP (XSTRING (directory)->data[directory_nbytes - 1]))
203 needsep = 1;
204 #endif /* not VMS */
205
206 /* Loop reading blocks */
207 while (1)
208 {
209 DIRENTRY *dp = readdir (d);
210
211 if (dp == NULL)
212 break;
213
214 if (DIRENTRY_NONEMPTY (dp))
215 {
216 int len;
217 int wanted = 0;
218 Lisp_Object name, finalname;
219 struct gcpro gcpro1, gcpro2;
220
221 len = NAMLEN (dp);
222 name = finalname = make_string (dp->d_name, len);
223 GCPRO2 (finalname, name);
224
225 /* Note: ENCODE_FILE can GC; it should protect its argument,
226 though. */
227 name = DECODE_FILE (name);
228 len = STRING_BYTES (XSTRING (name));
229
230 /* Now that we have unwind_protect in place, we might as well
231 allow matching to be interrupted. */
232 immediate_quit = 1;
233 QUIT;
234
235 if (NILP (match)
236 || (0 <= re_search (bufp, XSTRING (name)->data, len, 0, len, 0)))
237 wanted = 1;
238
239 immediate_quit = 0;
240
241 if (wanted)
242 {
243 if (!NILP (full))
244 {
245 Lisp_Object fullname;
246 int nbytes = len + directory_nbytes + needsep;
247 int nchars;
248
249 fullname = make_uninit_multibyte_string (nbytes, nbytes);
250 bcopy (XSTRING (directory)->data, XSTRING (fullname)->data,
251 directory_nbytes);
252
253 if (needsep)
254 XSTRING (fullname)->data[directory_nbytes + 1]
255 = DIRECTORY_SEP;
256
257 bcopy (XSTRING (name)->data,
258 XSTRING (fullname)->data + directory_nbytes + needsep,
259 len);
260
261 nchars = chars_in_text (XSTRING (fullname)->data, nbytes);
262
263 /* Some bug somewhere. */
264 if (nchars > nbytes)
265 abort ();
266
267 XSTRING (fullname)->size = nchars;
268 if (nchars == nbytes)
269 SET_STRING_BYTES (XSTRING (fullname), -1);
270
271 finalname = fullname;
272 }
273
274 if (attrs)
275 {
276 /* Construct an expanded filename for the directory entry.
277 Use the decoded names for input to Ffile_attributes. */
278 Lisp_Object decoded_fullname, fileattrs;
279 struct gcpro gcpro1, gcpro2;
280
281 decoded_fullname = fileattrs = Qnil;
282 GCPRO2 (decoded_fullname, fileattrs);
283
284 /* Both Fexpand_file_name and Ffile_attributes can GC. */
285 decoded_fullname = Fexpand_file_name (name, directory);
286 fileattrs = Ffile_attributes (decoded_fullname);
287
288 list = Fcons (Fcons (finalname, fileattrs), list);
289 UNGCPRO;
290 }
291 else
292 list = Fcons (finalname, list);
293 }
294
295 UNGCPRO;
296 }
297 }
298
299 closedir (d);
300
301 /* Discard the unwind protect. */
302 specpdl_ptr = specpdl + count;
303
304 if (NILP (nosort))
305 list = Fsort (Fnreverse (list),
306 attrs ? Qfile_attributes_lessp : Qstring_lessp);
307
308 RETURN_UNGCPRO (list);
309 }
310
311
312 DEFUN ("directory-files", Fdirectory_files, Sdirectory_files, 1, 4, 0,
313 "Return a list of names of files in DIRECTORY.\n\
314 There are three optional arguments:\n\
315 If FULL is non-nil, return absolute file names. Otherwise return names\n\
316 that are relative to the specified directory.\n\
317 If MATCH is non-nil, mention only file names that match the regexp MATCH.\n\
318 If NOSORT is non-nil, the list is not sorted--its order is unpredictable.\n\
319 NOSORT is useful if you plan to sort the result yourself.")
320 (directory, full, match, nosort)
321 Lisp_Object directory, full, match, nosort;
322 {
323 Lisp_Object handler;
324
325 /* If the file name has special constructs in it,
326 call the corresponding file handler. */
327 handler = Ffind_file_name_handler (directory, Qdirectory_files);
328 if (!NILP (handler))
329 {
330 Lisp_Object args[6];
331
332 args[0] = handler;
333 args[1] = Qdirectory_files;
334 args[2] = directory;
335 args[3] = full;
336 args[4] = match;
337 args[5] = nosort;
338 return Ffuncall (6, args);
339 }
340
341 return directory_files_internal (directory, full, match, nosort, 0);
342 }
343
344 DEFUN ("directory-files-and-attributes", Fdirectory_files_and_attributes, Sdirectory_files_and_attributes, 1, 4, 0,
345 "Return a list of names of files and their attributes in DIRECTORY.\n\
346 There are three optional arguments:\n\
347 If FULL is non-nil, return absolute file names. Otherwise return names\n\
348 that are relative to the specified directory.\n\
349 If MATCH is non-nil, mention only file names that match the regexp MATCH.\n\
350 If NOSORT is non-nil, the list is not sorted--its order is unpredictable.\n\
351 NOSORT is useful if you plan to sort the result yourself.")
352 (directory, full, match, nosort)
353 Lisp_Object directory, full, match, nosort;
354 {
355 Lisp_Object handler;
356
357 /* If the file name has special constructs in it,
358 call the corresponding file handler. */
359 handler = Ffind_file_name_handler (directory, Qdirectory_files_and_attributes);
360 if (!NILP (handler))
361 {
362 Lisp_Object args[6];
363
364 args[0] = handler;
365 args[1] = Qdirectory_files_and_attributes;
366 args[2] = directory;
367 args[3] = full;
368 args[4] = match;
369 args[5] = nosort;
370 return Ffuncall (6, args);
371 }
372
373 return directory_files_internal (directory, full, match, nosort, 1);
374 }
375
376 \f
377 Lisp_Object file_name_completion ();
378
379 DEFUN ("file-name-completion", Ffile_name_completion, Sfile_name_completion,
380 2, 2, 0,
381 "Complete file name FILE in directory DIRECTORY.\n\
382 Returns the longest string\n\
383 common to all file names in DIRECTORY that start with FILE.\n\
384 If there is only one and FILE matches it exactly, returns t.\n\
385 Returns nil if DIR contains no name starting with FILE.")
386 (file, directory)
387 Lisp_Object file, directory;
388 {
389 Lisp_Object handler;
390
391 /* If the directory name has special constructs in it,
392 call the corresponding file handler. */
393 handler = Ffind_file_name_handler (directory, Qfile_name_completion);
394 if (!NILP (handler))
395 return call3 (handler, Qfile_name_completion, file, directory);
396
397 /* If the file name has special constructs in it,
398 call the corresponding file handler. */
399 handler = Ffind_file_name_handler (file, Qfile_name_completion);
400 if (!NILP (handler))
401 return call3 (handler, Qfile_name_completion, file, directory);
402
403 return file_name_completion (file, directory, 0, 0);
404 }
405
406 DEFUN ("file-name-all-completions", Ffile_name_all_completions,
407 Sfile_name_all_completions, 2, 2, 0,
408 "Return a list of all completions of file name FILE in directory DIRECTORY.\n\
409 These are all file names in directory DIRECTORY which begin with FILE.")
410 (file, directory)
411 Lisp_Object file, directory;
412 {
413 Lisp_Object handler;
414
415 /* If the directory name has special constructs in it,
416 call the corresponding file handler. */
417 handler = Ffind_file_name_handler (directory, Qfile_name_all_completions);
418 if (!NILP (handler))
419 return call3 (handler, Qfile_name_all_completions, file, directory);
420
421 /* If the file name has special constructs in it,
422 call the corresponding file handler. */
423 handler = Ffind_file_name_handler (file, Qfile_name_all_completions);
424 if (!NILP (handler))
425 return call3 (handler, Qfile_name_all_completions, file, directory);
426
427 return file_name_completion (file, directory, 1, 0);
428 }
429
430 static int file_name_completion_stat ();
431
432 Lisp_Object
433 file_name_completion (file, dirname, all_flag, ver_flag)
434 Lisp_Object file, dirname;
435 int all_flag, ver_flag;
436 {
437 DIR *d;
438 DIRENTRY *dp;
439 int bestmatchsize = 0, skip;
440 register int compare, matchsize;
441 unsigned char *p1, *p2;
442 int matchcount = 0;
443 Lisp_Object bestmatch, tem, elt, name;
444 Lisp_Object encoded_file;
445 Lisp_Object encoded_dir;
446 struct stat st;
447 int directoryp;
448 int passcount;
449 int count = specpdl_ptr - specpdl;
450 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
451
452 elt = Qnil;
453
454 #ifdef VMS
455 extern DIRENTRY * readdirver ();
456
457 DIRENTRY *((* readfunc) ());
458
459 /* Filename completion on VMS ignores case, since VMS filesys does. */
460 specbind (Qcompletion_ignore_case, Qt);
461
462 readfunc = readdir;
463 if (ver_flag)
464 readfunc = readdirver;
465 file = Fupcase (file);
466 #else /* not VMS */
467 CHECK_STRING (file, 0);
468 #endif /* not VMS */
469
470 #ifdef FILE_SYSTEM_CASE
471 file = FILE_SYSTEM_CASE (file);
472 #endif
473 bestmatch = Qnil;
474 encoded_file = encoded_dir = Qnil;
475 GCPRO5 (file, dirname, bestmatch, encoded_file, encoded_dir);
476 dirname = Fexpand_file_name (dirname, Qnil);
477
478 /* Do completion on the encoded file name
479 because the other names in the directory are (we presume)
480 encoded likewise. We decode the completed string at the end. */
481 encoded_file = ENCODE_FILE (file);
482
483 encoded_dir = ENCODE_FILE (dirname);
484
485 /* With passcount = 0, ignore files that end in an ignored extension.
486 If nothing found then try again with passcount = 1, don't ignore them.
487 If looking for all completions, start with passcount = 1,
488 so always take even the ignored ones.
489
490 ** It would not actually be helpful to the user to ignore any possible
491 completions when making a list of them.** */
492
493 for (passcount = !!all_flag; NILP (bestmatch) && passcount < 2; passcount++)
494 {
495 d = opendir (XSTRING (Fdirectory_file_name (encoded_dir))->data);
496 if (!d)
497 report_file_error ("Opening directory", Fcons (dirname, Qnil));
498
499 /* Loop reading blocks */
500 /* (att3b compiler bug requires do a null comparison this way) */
501 while (1)
502 {
503 DIRENTRY *dp;
504 int len;
505
506 #ifdef VMS
507 dp = (*readfunc) (d);
508 #else
509 dp = readdir (d);
510 #endif
511 if (!dp) break;
512
513 len = NAMLEN (dp);
514
515 if (!NILP (Vquit_flag) && NILP (Vinhibit_quit))
516 goto quit;
517 if (! DIRENTRY_NONEMPTY (dp)
518 || len < XSTRING (encoded_file)->size
519 || 0 <= scmp (dp->d_name, XSTRING (encoded_file)->data,
520 XSTRING (encoded_file)->size))
521 continue;
522
523 if (file_name_completion_stat (encoded_dir, dp, &st) < 0)
524 continue;
525
526 directoryp = ((st.st_mode & S_IFMT) == S_IFDIR);
527 tem = Qnil;
528 if (directoryp)
529 {
530 #ifndef TRIVIAL_DIRECTORY_ENTRY
531 #define TRIVIAL_DIRECTORY_ENTRY(n) (!strcmp (n, ".") || !strcmp (n, ".."))
532 #endif
533 /* "." and ".." are never interesting as completions, but are
534 actually in the way in a directory contains only one file. */
535 if (!passcount && TRIVIAL_DIRECTORY_ENTRY (dp->d_name))
536 continue;
537 }
538 else
539 {
540 /* Compare extensions-to-be-ignored against end of this file name */
541 /* if name is not an exact match against specified string */
542 if (!passcount && len > XSTRING (encoded_file)->size)
543 /* and exit this for loop if a match is found */
544 for (tem = Vcompletion_ignored_extensions;
545 CONSP (tem); tem = XCDR (tem))
546 {
547 elt = XCAR (tem);
548 if (!STRINGP (elt)) continue;
549 skip = len - XSTRING (elt)->size;
550 if (skip < 0) continue;
551
552 if (0 <= scmp (dp->d_name + skip,
553 XSTRING (elt)->data,
554 XSTRING (elt)->size))
555 continue;
556 break;
557 }
558 }
559
560 /* If an ignored-extensions match was found,
561 don't process this name as a completion. */
562 if (!passcount && CONSP (tem))
563 continue;
564
565 if (!passcount)
566 {
567 Lisp_Object regexps;
568 Lisp_Object zero;
569 XSETFASTINT (zero, 0);
570
571 /* Ignore this element if it fails to match all the regexps. */
572 for (regexps = Vcompletion_regexp_list; CONSP (regexps);
573 regexps = XCDR (regexps))
574 {
575 tem = Fstring_match (XCAR (regexps), elt, zero);
576 if (NILP (tem))
577 break;
578 }
579 if (CONSP (regexps))
580 continue;
581 }
582
583 /* Update computation of how much all possible completions match */
584
585 matchcount++;
586
587 if (all_flag || NILP (bestmatch))
588 {
589 /* This is a possible completion */
590 if (directoryp)
591 {
592 /* This completion is a directory; make it end with '/' */
593 name = Ffile_name_as_directory (make_string (dp->d_name, len));
594 }
595 else
596 name = make_string (dp->d_name, len);
597 if (all_flag)
598 {
599 name = DECODE_FILE (name);
600 bestmatch = Fcons (name, bestmatch);
601 }
602 else
603 {
604 bestmatch = name;
605 bestmatchsize = XSTRING (name)->size;
606 }
607 }
608 else
609 {
610 compare = min (bestmatchsize, len);
611 p1 = XSTRING (bestmatch)->data;
612 p2 = (unsigned char *) dp->d_name;
613 matchsize = scmp(p1, p2, compare);
614 if (matchsize < 0)
615 matchsize = compare;
616 if (completion_ignore_case)
617 {
618 /* If this is an exact match except for case,
619 use it as the best match rather than one that is not
620 an exact match. This way, we get the case pattern
621 of the actual match. */
622 /* This tests that the current file is an exact match
623 but BESTMATCH is not (it is too long). */
624 if ((matchsize == len
625 && matchsize + !!directoryp
626 < XSTRING (bestmatch)->size)
627 ||
628 /* If there is no exact match ignoring case,
629 prefer a match that does not change the case
630 of the input. */
631 /* If there is more than one exact match aside from
632 case, and one of them is exact including case,
633 prefer that one. */
634 /* This == checks that, of current file and BESTMATCH,
635 either both or neither are exact. */
636 (((matchsize == len)
637 ==
638 (matchsize + !!directoryp
639 == XSTRING (bestmatch)->size))
640 && !bcmp (p2, XSTRING (encoded_file)->data, XSTRING (encoded_file)->size)
641 && bcmp (p1, XSTRING (encoded_file)->data, XSTRING (encoded_file)->size)))
642 {
643 bestmatch = make_string (dp->d_name, len);
644 if (directoryp)
645 bestmatch = Ffile_name_as_directory (bestmatch);
646 }
647 }
648
649 /* If this dirname all matches, see if implicit following
650 slash does too. */
651 if (directoryp
652 && compare == matchsize
653 && bestmatchsize > matchsize
654 && IS_ANY_SEP (p1[matchsize]))
655 matchsize++;
656 bestmatchsize = matchsize;
657 }
658 }
659 closedir (d);
660 }
661
662 UNGCPRO;
663 bestmatch = unbind_to (count, bestmatch);
664
665 if (all_flag || NILP (bestmatch))
666 {
667 if (STRINGP (bestmatch))
668 bestmatch = DECODE_FILE (bestmatch);
669 return bestmatch;
670 }
671 if (matchcount == 1 && bestmatchsize == XSTRING (file)->size)
672 return Qt;
673 bestmatch = Fsubstring (bestmatch, make_number (0),
674 make_number (bestmatchsize));
675 /* Now that we got the right initial segment of BESTMATCH,
676 decode it from the coding system in use. */
677 bestmatch = DECODE_FILE (bestmatch);
678 return bestmatch;
679
680 quit:
681 if (d) closedir (d);
682 Vquit_flag = Qnil;
683 return Fsignal (Qquit, Qnil);
684 }
685
686 static int
687 file_name_completion_stat (dirname, dp, st_addr)
688 Lisp_Object dirname;
689 DIRENTRY *dp;
690 struct stat *st_addr;
691 {
692 int len = NAMLEN (dp);
693 int pos = XSTRING (dirname)->size;
694 int value;
695 char *fullname = (char *) alloca (len + pos + 2);
696
697 #ifdef MSDOS
698 #if __DJGPP__ > 1
699 /* Some fields of struct stat are *very* expensive to compute on MS-DOS,
700 but aren't required here. Avoid computing the following fields:
701 st_inode, st_size and st_nlink for directories, and the execute bits
702 in st_mode for non-directory files with non-standard extensions. */
703
704 unsigned short save_djstat_flags = _djstat_flags;
705
706 _djstat_flags = _STAT_INODE | _STAT_EXEC_MAGIC | _STAT_DIRSIZE;
707 #endif /* __DJGPP__ > 1 */
708 #endif /* MSDOS */
709
710 bcopy (XSTRING (dirname)->data, fullname, pos);
711 #ifndef VMS
712 if (!IS_DIRECTORY_SEP (fullname[pos - 1]))
713 fullname[pos++] = DIRECTORY_SEP;
714 #endif
715
716 bcopy (dp->d_name, fullname + pos, len);
717 fullname[pos + len] = 0;
718
719 #ifdef S_IFLNK
720 /* We want to return success if a link points to a nonexistent file,
721 but we want to return the status for what the link points to,
722 in case it is a directory. */
723 value = lstat (fullname, st_addr);
724 stat (fullname, st_addr);
725 return value;
726 #else
727 value = stat (fullname, st_addr);
728 #ifdef MSDOS
729 #if __DJGPP__ > 1
730 _djstat_flags = save_djstat_flags;
731 #endif /* __DJGPP__ > 1 */
732 #endif /* MSDOS */
733 return value;
734 #endif /* S_IFLNK */
735 }
736 \f
737 #ifdef VMS
738
739 DEFUN ("file-name-all-versions", Ffile_name_all_versions,
740 Sfile_name_all_versions, 2, 2, 0,
741 "Return a list of all versions of file name FILE in directory DIRECTORY.")
742 (file, directory)
743 Lisp_Object file, directory;
744 {
745 return file_name_completion (file, directory, 1, 1);
746 }
747
748 DEFUN ("file-version-limit", Ffile_version_limit, Sfile_version_limit, 1, 1, 0,
749 "Return the maximum number of versions allowed for FILE.\n\
750 Returns nil if the file cannot be opened or if there is no version limit.")
751 (filename)
752 Lisp_Object filename;
753 {
754 Lisp_Object retval;
755 struct FAB fab;
756 struct RAB rab;
757 struct XABFHC xabfhc;
758 int status;
759
760 filename = Fexpand_file_name (filename, Qnil);
761 fab = cc$rms_fab;
762 xabfhc = cc$rms_xabfhc;
763 fab.fab$l_fna = XSTRING (filename)->data;
764 fab.fab$b_fns = strlen (fab.fab$l_fna);
765 fab.fab$l_xab = (char *) &xabfhc;
766 status = sys$open (&fab, 0, 0);
767 if (status != RMS$_NORMAL) /* Probably non-existent file */
768 return Qnil;
769 sys$close (&fab, 0, 0);
770 if (xabfhc.xab$w_verlimit == 32767)
771 return Qnil; /* No version limit */
772 else
773 return make_number (xabfhc.xab$w_verlimit);
774 }
775
776 #endif /* VMS */
777 \f
778 Lisp_Object
779 make_time (time)
780 time_t time;
781 {
782 return Fcons (make_number (time >> 16),
783 Fcons (make_number (time & 0177777), Qnil));
784 }
785
786 DEFUN ("file-attributes", Ffile_attributes, Sfile_attributes, 1, 1, 0,
787 "Return a list of attributes of file FILENAME.\n\
788 Value is nil if specified file cannot be opened.\n\
789 Otherwise, list elements are:\n\
790 0. t for directory, string (name linked to) for symbolic link, or nil.\n\
791 1. Number of links to file.\n\
792 2. File uid.\n\
793 3. File gid.\n\
794 4. Last access time, as a list of two integers.\n\
795 First integer has high-order 16 bits of time, second has low 16 bits.\n\
796 5. Last modification time, likewise.\n\
797 6. Last status change time, likewise.\n\
798 7. Size in bytes.\n\
799 This is a floating point number if the size is too large for an integer.\n\
800 8. File modes, as a string of ten letters or dashes as in ls -l.\n\
801 9. t iff file's gid would change if file were deleted and recreated.\n\
802 10. inode number. If inode number is larger than the Emacs integer,\n\
803 this is a cons cell containing two integers: first the high part,\n\
804 then the low 16 bits.\n\
805 11. Device number.\n\
806 \n\
807 If file does not exist, returns nil.")
808 (filename)
809 Lisp_Object filename;
810 {
811 Lisp_Object values[12];
812 Lisp_Object dirname;
813 Lisp_Object encoded;
814 struct stat s;
815 struct stat sdir;
816 char modes[10];
817 Lisp_Object handler;
818
819 filename = Fexpand_file_name (filename, Qnil);
820
821 /* If the file name has special constructs in it,
822 call the corresponding file handler. */
823 handler = Ffind_file_name_handler (filename, Qfile_attributes);
824 if (!NILP (handler))
825 return call2 (handler, Qfile_attributes, filename);
826
827 encoded = ENCODE_FILE (filename);
828
829 if (lstat (XSTRING (encoded)->data, &s) < 0)
830 return Qnil;
831
832 switch (s.st_mode & S_IFMT)
833 {
834 default:
835 values[0] = Qnil; break;
836 case S_IFDIR:
837 values[0] = Qt; break;
838 #ifdef S_IFLNK
839 case S_IFLNK:
840 values[0] = Ffile_symlink_p (filename); break;
841 #endif
842 }
843 values[1] = make_number (s.st_nlink);
844 values[2] = make_number (s.st_uid);
845 values[3] = make_number (s.st_gid);
846 values[4] = make_time (s.st_atime);
847 values[5] = make_time (s.st_mtime);
848 values[6] = make_time (s.st_ctime);
849 values[7] = make_number (s.st_size);
850 /* If the size is out of range for an integer, return a float. */
851 if (XINT (values[7]) != s.st_size)
852 values[7] = make_float ((double)s.st_size);
853 filemodestring (&s, modes);
854 values[8] = make_string (modes, 10);
855 #ifdef BSD4_3 /* Gross kludge to avoid lack of "#if defined(...)" in VMS */
856 #define BSD4_2 /* A new meaning to the term `backwards compatibility' */
857 #endif
858 #ifdef BSD4_2 /* file gid will be dir gid */
859 dirname = Ffile_name_directory (filename);
860 if (! NILP (dirname))
861 encoded = ENCODE_FILE (dirname);
862 if (! NILP (dirname) && stat (XSTRING (encoded)->data, &sdir) == 0)
863 values[9] = (sdir.st_gid != s.st_gid) ? Qt : Qnil;
864 else /* if we can't tell, assume worst */
865 values[9] = Qt;
866 #else /* file gid will be egid */
867 values[9] = (s.st_gid != getegid ()) ? Qt : Qnil;
868 #endif /* BSD4_2 (or BSD4_3) */
869 #ifdef BSD4_3
870 #undef BSD4_2 /* ok, you can look again without throwing up */
871 #endif
872 /* Cast -1 to avoid warning if int is not as wide as VALBITS. */
873 if (s.st_ino & (((EMACS_INT) (-1)) << VALBITS))
874 /* To allow inode numbers larger than VALBITS, separate the bottom
875 16 bits. */
876 values[10] = Fcons (make_number (s.st_ino >> 16),
877 make_number (s.st_ino & 0xffff));
878 else
879 /* But keep the most common cases as integers. */
880 values[10] = make_number (s.st_ino);
881
882 /* Likewise for device. */
883 if (s.st_dev & (((EMACS_INT) (-1)) << VALBITS))
884 values[11] = Fcons (make_number (s.st_dev >> 16),
885 make_number (s.st_dev & 0xffff));
886 else
887 values[11] = make_number (s.st_dev);
888
889 return Flist (sizeof(values) / sizeof(values[0]), values);
890 }
891
892 DEFUN ("file-attributes-lessp", Ffile_attributes_lessp, Sfile_attributes_lessp, 2, 2, 0,
893 "Return t if first arg file attributes list is less than second.\n\
894 Comparison is in lexicographic order and case is significant.")
895 (f1, f2)
896 Lisp_Object f1, f2;
897 {
898 return Fstring_lessp (Fcar (f1), Fcar (f2));
899 }
900 \f
901 void
902 syms_of_dired ()
903 {
904 Qdirectory_files = intern ("directory-files");
905 Qdirectory_files_and_attributes = intern ("directory-files-and-attributes");
906 Qfile_name_completion = intern ("file-name-completion");
907 Qfile_name_all_completions = intern ("file-name-all-completions");
908 Qfile_attributes = intern ("file-attributes");
909 Qfile_attributes_lessp = intern ("file-attributes-lessp");
910
911 staticpro (&Qdirectory_files);
912 staticpro (&Qdirectory_files_and_attributes);
913 staticpro (&Qfile_name_completion);
914 staticpro (&Qfile_name_all_completions);
915 staticpro (&Qfile_attributes);
916 staticpro (&Qfile_attributes_lessp);
917
918 defsubr (&Sdirectory_files);
919 defsubr (&Sdirectory_files_and_attributes);
920 defsubr (&Sfile_name_completion);
921 #ifdef VMS
922 defsubr (&Sfile_name_all_versions);
923 defsubr (&Sfile_version_limit);
924 #endif /* VMS */
925 defsubr (&Sfile_name_all_completions);
926 defsubr (&Sfile_attributes);
927 defsubr (&Sfile_attributes_lessp);
928
929 #ifdef VMS
930 Qcompletion_ignore_case = intern ("completion-ignore-case");
931 staticpro (&Qcompletion_ignore_case);
932 #endif /* VMS */
933
934 DEFVAR_LISP ("completion-ignored-extensions", &Vcompletion_ignored_extensions,
935 "*Completion ignores filenames ending in any string in this list.\n\
936 This variable does not affect lists of possible completions,\n\
937 but does affect the commands that actually do completions.");
938 Vcompletion_ignored_extensions = Qnil;
939 }