(vc-find-file-hook): Follow multiple links all the way.
[bpt/emacs.git] / src / dired.c
CommitLineData
14d55bce 1/* Lisp functions for making directory listings.
3a22ee35 2 Copyright (C) 1985, 1986, 1993, 1994 Free Software Foundation, Inc.
14d55bce
RS
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
7c938215 8the Free Software Foundation; either version 2, or (at your option)
14d55bce
RS
9any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs; see the file COPYING. If not, write to
3b7ad313
EN
18the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19Boston, MA 02111-1307, USA. */
14d55bce
RS
20
21
3964b9a7
RS
22#include <config.h>
23
14d55bce
RS
24#include <stdio.h>
25#include <sys/types.h>
26#include <sys/stat.h>
27
3ed991aa
RS
28#ifdef VMS
29#include <string.h>
30#include <rms.h>
31#include <rmsdef.h>
32#endif
33
d6717cdb
JB
34/* The d_nameln member of a struct dirent includes the '\0' character
35 on some systems, but not on others. What's worse, you can't tell
36 at compile-time which one it will be, since it really depends on
37 the sort of system providing the filesystem you're reading from,
38 not the system you are running on. Paul Eggert
39 <eggert@bi.twinsun.com> says this occurs when Emacs is running on a
40 SunOS 4.1.2 host, reading a directory that is remote-mounted from a
41 Solaris 2.1 host and is in a native Solaris 2.1 filesystem.
42
43 Since applying strlen to the name always works, we'll just do that. */
44#define NAMLEN(p) strlen (p->d_name)
45
14d55bce
RS
46#ifdef SYSV_SYSTEM_DIR
47
48#include <dirent.h>
49#define DIRENTRY struct dirent
14d55bce 50
128ecc89 51#else /* not SYSV_SYSTEM_DIR */
14d55bce
RS
52
53#ifdef NONSYSTEM_DIR_LIBRARY
54#include "ndir.h"
55#else /* not NONSYSTEM_DIR_LIBRARY */
128ecc89
RS
56#ifdef MSDOS
57#include <dirent.h>
58#else
14d55bce 59#include <sys/dir.h>
128ecc89 60#endif
14d55bce
RS
61#endif /* not NONSYSTEM_DIR_LIBRARY */
62
128ecc89 63#ifndef MSDOS
14d55bce 64#define DIRENTRY struct direct
14d55bce
RS
65
66extern DIR *opendir ();
67extern struct direct *readdir ();
68
128ecc89
RS
69#endif /* not MSDOS */
70#endif /* not SYSV_SYSTEM_DIR */
71
72#ifdef MSDOS
73#define DIRENTRY_NONEMPTY(p) ((p)->d_name[0] != 0)
74#else
75#define DIRENTRY_NONEMPTY(p) ((p)->d_ino)
14d55bce
RS
76#endif
77
14d55bce
RS
78#include "lisp.h"
79#include "buffer.h"
80#include "commands.h"
81
82#include "regex.h"
14d55bce 83
e50c66d3
KH
84/* Returns a search buffer, with a fastmap allocated and ready to go. */
85extern struct re_pattern_buffer *compile_pattern ();
c7e466e1 86
14d55bce
RS
87#define min(a, b) ((a) < (b) ? (a) : (b))
88
89/* if system does not have symbolic links, it does not have lstat.
90 In that case, use ordinary stat instead. */
91
92#ifndef S_IFLNK
93#define lstat stat
94#endif
95
97e98a56 96extern int completion_ignore_case;
f676868d 97extern Lisp_Object Vcompletion_regexp_list;
ccbcf979 98
14d55bce 99Lisp_Object Vcompletion_ignored_extensions;
14d55bce 100Lisp_Object Qcompletion_ignore_case;
32f4334d
RS
101Lisp_Object Qdirectory_files;
102Lisp_Object Qfile_name_completion;
103Lisp_Object Qfile_name_all_completions;
434e6714 104Lisp_Object Qfile_attributes;
14d55bce
RS
105\f
106DEFUN ("directory-files", Fdirectory_files, Sdirectory_files, 1, 4, 0,
107 "Return a list of names of files in DIRECTORY.\n\
108There are three optional arguments:\n\
7b6540dd
RS
109If FULL is non-nil, return absolute file names. Otherwise return names\n\
110 that are relative to the specified directory.\n\
111If MATCH is non-nil, mention only file names that match the regexp MATCH.\n\
14d55bce
RS
112If NOSORT is non-nil, the list is not sorted--its order is unpredictable.\n\
113 NOSORT is useful if you plan to sort the result yourself.")
23bd240f
EN
114 (directory, full, match, nosort)
115 Lisp_Object directory, full, match, nosort;
14d55bce
RS
116{
117 DIR *d;
5617588f 118 int dirnamelen;
6155fae1 119 Lisp_Object list, name, dirfilename;
32f4334d 120 Lisp_Object handler;
e50c66d3 121 struct re_pattern_buffer *bufp;
32f4334d
RS
122
123 /* If the file name has special constructs in it,
124 call the corresponding file handler. */
23bd240f 125 handler = Ffind_file_name_handler (directory, Qdirectory_files);
32f4334d
RS
126 if (!NILP (handler))
127 {
128 Lisp_Object args[6];
129
130 args[0] = handler;
131 args[1] = Qdirectory_files;
23bd240f 132 args[2] = directory;
32f4334d
RS
133 args[3] = full;
134 args[4] = match;
135 args[5] = nosort;
136 return Ffuncall (6, args);
137 }
14d55bce 138
6155fae1
JB
139 {
140 struct gcpro gcpro1, gcpro2;
141
142 /* Because of file name handlers, these functions might call
143 Ffuncall, and cause a GC. */
144 GCPRO1 (match);
23bd240f 145 directory = Fexpand_file_name (directory, Qnil);
3254eb1e 146 UNGCPRO;
23bd240f
EN
147 GCPRO2 (match, directory);
148 dirfilename = Fdirectory_file_name (directory);
6155fae1
JB
149 UNGCPRO;
150 }
151
265a9e55 152 if (!NILP (match))
14d55bce
RS
153 {
154 CHECK_STRING (match, 3);
ebb9e16f
JB
155
156 /* MATCH might be a flawed regular expression. Rather than
8e6208c5 157 catching and signaling our own errors, we just call
ebb9e16f 158 compile_pattern to do the work for us. */
14d55bce 159#ifdef VMS
e50c66d3 160 bufp = compile_pattern (match, 0,
8a590062 161 buffer_defaults.downcase_table->contents, 0);
14d55bce 162#else
8a590062 163 bufp = compile_pattern (match, 0, 0, 0);
14d55bce
RS
164#endif
165 }
166
e50c66d3 167 /* Now *bufp is the compiled form of MATCH; don't call anything
6155fae1
JB
168 which might compile a new regexp until we're done with the loop! */
169
170 /* Do this opendir after anything which might signal an error; if
8e6208c5 171 an error is signaled while the directory stream is open, we
6155fae1
JB
172 have to make sure it gets closed, and setting up an
173 unwind_protect to do so would be a pain. */
174 d = opendir (XSTRING (dirfilename)->data);
175 if (! d)
23bd240f 176 report_file_error ("Opening directory", Fcons (directory, Qnil));
14d55bce
RS
177
178 list = Qnil;
23bd240f 179 dirnamelen = XSTRING (directory)->size;
14d55bce
RS
180
181 /* Loop reading blocks */
182 while (1)
183 {
184 DIRENTRY *dp = readdir (d);
185 int len;
186
187 if (!dp) break;
188 len = NAMLEN (dp);
128ecc89 189 if (DIRENTRY_NONEMPTY (dp))
14d55bce 190 {
265a9e55 191 if (NILP (match)
e50c66d3 192 || (0 <= re_search (bufp, dp->d_name, len, 0, len, 0)))
14d55bce 193 {
265a9e55 194 if (!NILP (full))
14d55bce 195 {
5617588f
RS
196 int afterdirindex = dirnamelen;
197 int total = len + dirnamelen;
198 int needsep = 0;
199
200 /* Decide whether we need to add a directory separator. */
14d55bce 201#ifndef VMS
5617588f 202 if (dirnamelen == 0
23bd240f 203 || !IS_ANY_SEP (XSTRING (directory)->data[dirnamelen - 1]))
5617588f 204 needsep = 1;
14d55bce
RS
205#endif /* VMS */
206
5617588f 207 name = make_uninit_string (total + needsep);
23bd240f 208 bcopy (XSTRING (directory)->data, XSTRING (name)->data,
5617588f
RS
209 dirnamelen);
210 if (needsep)
211 XSTRING (name)->data[afterdirindex++] = DIRECTORY_SEP;
212 bcopy (dp->d_name,
213 XSTRING (name)->data + afterdirindex, len);
14d55bce
RS
214 }
215 else
216 name = make_string (dp->d_name, len);
217 list = Fcons (name, list);
218 }
219 }
220 }
221 closedir (d);
265a9e55 222 if (!NILP (nosort))
14d55bce
RS
223 return list;
224 return Fsort (Fnreverse (list), Qstring_lessp);
225}
226\f
227Lisp_Object file_name_completion ();
228
229DEFUN ("file-name-completion", Ffile_name_completion, Sfile_name_completion,
230 2, 2, 0,
23bd240f 231 "Complete file name FILE in directory DIRECTORY.\n\
14d55bce 232Returns the longest string\n\
7b6540dd 233common to all file names in DIRECTORY that start with FILE.\n\
14d55bce
RS
234If there is only one and FILE matches it exactly, returns t.\n\
235Returns nil if DIR contains no name starting with FILE.")
23bd240f
EN
236 (file, directory)
237 Lisp_Object file, directory;
14d55bce 238{
32f4334d 239 Lisp_Object handler;
32f4334d 240
8436e231 241 /* If the directory name has special constructs in it,
32f4334d 242 call the corresponding file handler. */
23bd240f 243 handler = Ffind_file_name_handler (directory, Qfile_name_completion);
32f4334d 244 if (!NILP (handler))
23bd240f 245 return call3 (handler, Qfile_name_completion, file, directory);
32f4334d 246
8436e231
RS
247 /* If the file name has special constructs in it,
248 call the corresponding file handler. */
249 handler = Ffind_file_name_handler (file, Qfile_name_completion);
250 if (!NILP (handler))
23bd240f 251 return call3 (handler, Qfile_name_completion, file, directory);
8436e231 252
23bd240f 253 return file_name_completion (file, directory, 0, 0);
14d55bce
RS
254}
255
256DEFUN ("file-name-all-completions", Ffile_name_all_completions,
257 Sfile_name_all_completions, 2, 2, 0,
23bd240f
EN
258 "Return a list of all completions of file name FILE in directory DIRECTORY.\n\
259These are all file names in directory DIRECTORY which begin with FILE.")
260 (file, directory)
261 Lisp_Object file, directory;
14d55bce 262{
32f4334d
RS
263 Lisp_Object handler;
264
8436e231 265 /* If the directory name has special constructs in it,
32f4334d 266 call the corresponding file handler. */
23bd240f 267 handler = Ffind_file_name_handler (directory, Qfile_name_all_completions);
32f4334d 268 if (!NILP (handler))
23bd240f 269 return call3 (handler, Qfile_name_all_completions, file, directory);
32f4334d 270
8436e231
RS
271 /* If the file name has special constructs in it,
272 call the corresponding file handler. */
273 handler = Ffind_file_name_handler (file, Qfile_name_all_completions);
274 if (!NILP (handler))
23bd240f 275 return call3 (handler, Qfile_name_all_completions, file, directory);
8436e231 276
23bd240f 277 return file_name_completion (file, directory, 1, 0);
14d55bce
RS
278}
279
14d55bce
RS
280Lisp_Object
281file_name_completion (file, dirname, all_flag, ver_flag)
282 Lisp_Object file, dirname;
283 int all_flag, ver_flag;
284{
285 DIR *d;
286 DIRENTRY *dp;
287 int bestmatchsize, skip;
288 register int compare, matchsize;
289 unsigned char *p1, *p2;
290 int matchcount = 0;
291 Lisp_Object bestmatch, tem, elt, name;
292 struct stat st;
293 int directoryp;
294 int passcount;
295 int count = specpdl_ptr - specpdl;
3fcc88cc
RS
296 struct gcpro gcpro1, gcpro2, gcpro3;
297
14d55bce
RS
298#ifdef VMS
299 extern DIRENTRY * readdirver ();
300
301 DIRENTRY *((* readfunc) ());
302
303 /* Filename completion on VMS ignores case, since VMS filesys does. */
304 specbind (Qcompletion_ignore_case, Qt);
305
306 readfunc = readdir;
307 if (ver_flag)
308 readfunc = readdirver;
309 file = Fupcase (file);
310#else /* not VMS */
311 CHECK_STRING (file, 0);
312#endif /* not VMS */
313
128ecc89
RS
314#ifdef FILE_SYSTEM_CASE
315 file = FILE_SYSTEM_CASE (file);
316#endif
14d55bce 317 bestmatch = Qnil;
3fcc88cc
RS
318 GCPRO3 (file, dirname, bestmatch);
319 dirname = Fexpand_file_name (dirname, Qnil);
14d55bce
RS
320
321 /* With passcount = 0, ignore files that end in an ignored extension.
322 If nothing found then try again with passcount = 1, don't ignore them.
323 If looking for all completions, start with passcount = 1,
324 so always take even the ignored ones.
325
326 ** It would not actually be helpful to the user to ignore any possible
327 completions when making a list of them.** */
328
265a9e55 329 for (passcount = !!all_flag; NILP (bestmatch) && passcount < 2; passcount++)
14d55bce
RS
330 {
331 if (!(d = opendir (XSTRING (Fdirectory_file_name (dirname))->data)))
332 report_file_error ("Opening directory", Fcons (dirname, Qnil));
333
334 /* Loop reading blocks */
335 /* (att3b compiler bug requires do a null comparison this way) */
336 while (1)
337 {
338 DIRENTRY *dp;
339 int len;
340
341#ifdef VMS
342 dp = (*readfunc) (d);
343#else
344 dp = readdir (d);
345#endif
346 if (!dp) break;
347
348 len = NAMLEN (dp);
349
265a9e55 350 if (!NILP (Vquit_flag) && NILP (Vinhibit_quit))
14d55bce 351 goto quit;
128ecc89 352 if (! DIRENTRY_NONEMPTY (dp)
14d55bce
RS
353 || len < XSTRING (file)->size
354 || 0 <= scmp (dp->d_name, XSTRING (file)->data,
355 XSTRING (file)->size))
356 continue;
357
358 if (file_name_completion_stat (dirname, dp, &st) < 0)
359 continue;
360
361 directoryp = ((st.st_mode & S_IFMT) == S_IFDIR);
362 tem = Qnil;
ad456ad4
RS
363 if (directoryp)
364 {
365#ifndef TRIVIAL_DIRECTORY_ENTRY
366#define TRIVIAL_DIRECTORY_ENTRY(n) (!strcmp (n, ".") || !strcmp (n, ".."))
367#endif
368 /* "." and ".." are never interesting as completions, but are
369 actually in the way in a directory contains only one file. */
370 if (!passcount && TRIVIAL_DIRECTORY_ENTRY (dp->d_name))
371 continue;
372 }
373 else
14d55bce
RS
374 {
375 /* Compare extensions-to-be-ignored against end of this file name */
376 /* if name is not an exact match against specified string */
377 if (!passcount && len > XSTRING (file)->size)
378 /* and exit this for loop if a match is found */
379 for (tem = Vcompletion_ignored_extensions;
380 CONSP (tem); tem = XCONS (tem)->cdr)
381 {
382 elt = XCONS (tem)->car;
88cf1852 383 if (!STRINGP (elt)) continue;
14d55bce
RS
384 skip = len - XSTRING (elt)->size;
385 if (skip < 0) continue;
386
387 if (0 <= scmp (dp->d_name + skip,
388 XSTRING (elt)->data,
389 XSTRING (elt)->size))
390 continue;
391 break;
392 }
393 }
394
f676868d
KH
395 /* If an ignored-extensions match was found,
396 don't process this name as a completion. */
397 if (!passcount && CONSP (tem))
398 continue;
399
400 if (!passcount)
14d55bce 401 {
f676868d
KH
402 Lisp_Object regexps;
403 Lisp_Object zero;
617b3bfe 404 XSETFASTINT (zero, 0);
f676868d
KH
405
406 /* Ignore this element if it fails to match all the regexps. */
407 for (regexps = Vcompletion_regexp_list; CONSP (regexps);
408 regexps = XCONS (regexps)->cdr)
409 {
410 tem = Fstring_match (XCONS (regexps)->car, elt, zero);
411 if (NILP (tem))
412 break;
413 }
414 if (CONSP (regexps))
415 continue;
416 }
14d55bce 417
f676868d 418 /* Update computation of how much all possible completions match */
14d55bce 419
f676868d
KH
420 matchcount++;
421
422 if (all_flag || NILP (bestmatch))
423 {
424 /* This is a possible completion */
425 if (directoryp)
14d55bce 426 {
f676868d
KH
427 /* This completion is a directory; make it end with '/' */
428 name = Ffile_name_as_directory (make_string (dp->d_name, len));
429 }
430 else
431 name = make_string (dp->d_name, len);
432 if (all_flag)
433 {
434 bestmatch = Fcons (name, bestmatch);
14d55bce
RS
435 }
436 else
437 {
f676868d
KH
438 bestmatch = name;
439 bestmatchsize = XSTRING (name)->size;
440 }
441 }
442 else
443 {
444 compare = min (bestmatchsize, len);
445 p1 = XSTRING (bestmatch)->data;
446 p2 = (unsigned char *) dp->d_name;
447 matchsize = scmp(p1, p2, compare);
448 if (matchsize < 0)
449 matchsize = compare;
450 if (completion_ignore_case)
451 {
452 /* If this is an exact match except for case,
453 use it as the best match rather than one that is not
454 an exact match. This way, we get the case pattern
455 of the actual match. */
456 if ((matchsize == len
457 && matchsize + !!directoryp
458 < XSTRING (bestmatch)->size)
459 ||
460 /* If there is no exact match ignoring case,
461 prefer a match that does not change the case
462 of the input. */
463 (((matchsize == len)
464 ==
465 (matchsize + !!directoryp
466 == XSTRING (bestmatch)->size))
467 /* If there is more than one exact match aside from
468 case, and one of them is exact including case,
469 prefer that one. */
470 && !bcmp (p2, XSTRING (file)->data, XSTRING (file)->size)
471 && bcmp (p1, XSTRING (file)->data, XSTRING (file)->size)))
97e98a56 472 {
f676868d
KH
473 bestmatch = make_string (dp->d_name, len);
474 if (directoryp)
475 bestmatch = Ffile_name_as_directory (bestmatch);
97e98a56 476 }
14d55bce 477 }
f676868d
KH
478
479 /* If this dirname all matches, see if implicit following
480 slash does too. */
481 if (directoryp
482 && compare == matchsize
483 && bestmatchsize > matchsize
0b39d75d 484 && IS_ANY_SEP (p1[matchsize]))
f676868d
KH
485 matchsize++;
486 bestmatchsize = matchsize;
14d55bce
RS
487 }
488 }
489 closedir (d);
490 }
491
3fcc88cc
RS
492 UNGCPRO;
493 bestmatch = unbind_to (count, bestmatch);
14d55bce 494
265a9e55 495 if (all_flag || NILP (bestmatch))
14d55bce
RS
496 return bestmatch;
497 if (matchcount == 1 && bestmatchsize == XSTRING (file)->size)
498 return Qt;
499 return Fsubstring (bestmatch, make_number (0), make_number (bestmatchsize));
500 quit:
501 if (d) closedir (d);
502 Vquit_flag = Qnil;
503 return Fsignal (Qquit, Qnil);
504}
505
506file_name_completion_stat (dirname, dp, st_addr)
507 Lisp_Object dirname;
508 DIRENTRY *dp;
509 struct stat *st_addr;
510{
511 int len = NAMLEN (dp);
512 int pos = XSTRING (dirname)->size;
7e3cf34f 513 int value;
14d55bce
RS
514 char *fullname = (char *) alloca (len + pos + 2);
515
516 bcopy (XSTRING (dirname)->data, fullname, pos);
517#ifndef VMS
0b39d75d
RS
518 if (!IS_DIRECTORY_SEP (fullname[pos - 1]))
519 fullname[pos++] = DIRECTORY_SEP;
14d55bce
RS
520#endif
521
522 bcopy (dp->d_name, fullname + pos, len);
523 fullname[pos + len] = 0;
524
a889bd0e 525#ifdef S_IFLNK
7e3cf34f
RS
526 /* We want to return success if a link points to a nonexistent file,
527 but we want to return the status for what the link points to,
528 in case it is a directory. */
529 value = lstat (fullname, st_addr);
530 stat (fullname, st_addr);
531 return value;
a889bd0e 532#else
14d55bce 533 return stat (fullname, st_addr);
a889bd0e 534#endif
14d55bce
RS
535}
536\f
3ed991aa
RS
537#ifdef VMS
538
539DEFUN ("file-name-all-versions", Ffile_name_all_versions,
540 Sfile_name_all_versions, 2, 2, 0,
23bd240f
EN
541 "Return a list of all versions of file name FILE in directory DIRECTORY.")
542 (file, directory)
543 Lisp_Object file, directory;
3ed991aa 544{
23bd240f 545 return file_name_completion (file, directory, 1, 1);
3ed991aa
RS
546}
547
548DEFUN ("file-version-limit", Ffile_version_limit, Sfile_version_limit, 1, 1, 0,
549 "Return the maximum number of versions allowed for FILE.\n\
550Returns nil if the file cannot be opened or if there is no version limit.")
551 (filename)
552 Lisp_Object filename;
553{
554 Lisp_Object retval;
555 struct FAB fab;
556 struct RAB rab;
557 struct XABFHC xabfhc;
558 int status;
559
560 filename = Fexpand_file_name (filename, Qnil);
561 fab = cc$rms_fab;
562 xabfhc = cc$rms_xabfhc;
563 fab.fab$l_fna = XSTRING (filename)->data;
564 fab.fab$b_fns = strlen (fab.fab$l_fna);
565 fab.fab$l_xab = (char *) &xabfhc;
566 status = sys$open (&fab, 0, 0);
567 if (status != RMS$_NORMAL) /* Probably non-existent file */
568 return Qnil;
569 sys$close (&fab, 0, 0);
570 if (xabfhc.xab$w_verlimit == 32767)
571 return Qnil; /* No version limit */
572 else
573 return make_number (xabfhc.xab$w_verlimit);
574}
575
576#endif /* VMS */
577\f
14d55bce
RS
578Lisp_Object
579make_time (time)
580 int time;
581{
582 return Fcons (make_number (time >> 16),
583 Fcons (make_number (time & 0177777), Qnil));
584}
585
586DEFUN ("file-attributes", Ffile_attributes, Sfile_attributes, 1, 1, 0,
587 "Return a list of attributes of file FILENAME.\n\
588Value is nil if specified file cannot be opened.\n\
589Otherwise, list elements are:\n\
590 0. t for directory, string (name linked to) for symbolic link, or nil.\n\
591 1. Number of links to file.\n\
592 2. File uid.\n\
593 3. File gid.\n\
594 4. Last access time, as a list of two integers.\n\
595 First integer has high-order 16 bits of time, second has low 16 bits.\n\
596 5. Last modification time, likewise.\n\
597 6. Last status change time, likewise.\n\
60fc6069 598 7. Size in bytes (-1, if number is out of range).\n\
14d55bce
RS
599 8. File modes, as a string of ten letters or dashes as in ls -l.\n\
600 9. t iff file's gid would change if file were deleted and recreated.\n\
60110. inode number.\n\
60211. Device number.\n\
603\n\
ccbcf979 604If file does not exist, returns nil.")
14d55bce
RS
605 (filename)
606 Lisp_Object filename;
607{
608 Lisp_Object values[12];
609 Lisp_Object dirname;
610 struct stat s;
611 struct stat sdir;
612 char modes[10];
32f4334d 613 Lisp_Object handler;
14d55bce
RS
614
615 filename = Fexpand_file_name (filename, Qnil);
32f4334d
RS
616
617 /* If the file name has special constructs in it,
618 call the corresponding file handler. */
a617e913 619 handler = Ffind_file_name_handler (filename, Qfile_attributes);
32f4334d
RS
620 if (!NILP (handler))
621 return call2 (handler, Qfile_attributes, filename);
622
14d55bce
RS
623 if (lstat (XSTRING (filename)->data, &s) < 0)
624 return Qnil;
625
626 switch (s.st_mode & S_IFMT)
627 {
628 default:
629 values[0] = Qnil; break;
630 case S_IFDIR:
631 values[0] = Qt; break;
632#ifdef S_IFLNK
633 case S_IFLNK:
634 values[0] = Ffile_symlink_p (filename); break;
635#endif
636 }
637 values[1] = make_number (s.st_nlink);
638 values[2] = make_number (s.st_uid);
639 values[3] = make_number (s.st_gid);
640 values[4] = make_time (s.st_atime);
641 values[5] = make_time (s.st_mtime);
642 values[6] = make_time (s.st_ctime);
ed2ef6c9 643 values[7] = make_number ((int) s.st_size);
60fc6069
RS
644 /* If the size is out of range, give back -1. */
645 if (XINT (values[7]) != s.st_size)
646 XSETINT (values[7], -1);
14d55bce
RS
647 filemodestring (&s, modes);
648 values[8] = make_string (modes, 10);
649#ifdef BSD4_3 /* Gross kludge to avoid lack of "#if defined(...)" in VMS */
eb8c3be9 650#define BSD4_2 /* A new meaning to the term `backwards compatibility' */
14d55bce
RS
651#endif
652#ifdef BSD4_2 /* file gid will be dir gid */
653 dirname = Ffile_name_directory (filename);
ccbcf979 654 if (! NILP (dirname) && stat (XSTRING (dirname)->data, &sdir) == 0)
14d55bce
RS
655 values[9] = (sdir.st_gid != s.st_gid) ? Qt : Qnil;
656 else /* if we can't tell, assume worst */
657 values[9] = Qt;
658#else /* file gid will be egid */
659 values[9] = (s.st_gid != getegid ()) ? Qt : Qnil;
660#endif /* BSD4_2 (or BSD4_3) */
661#ifdef BSD4_3
662#undef BSD4_2 /* ok, you can look again without throwing up */
663#endif
664 values[10] = make_number (s.st_ino);
665 values[11] = make_number (s.st_dev);
666 return Flist (sizeof(values) / sizeof(values[0]), values);
667}
668\f
669syms_of_dired ()
670{
32f4334d
RS
671 Qdirectory_files = intern ("directory-files");
672 Qfile_name_completion = intern ("file-name-completion");
673 Qfile_name_all_completions = intern ("file-name-all-completions");
434e6714 674 Qfile_attributes = intern ("file-attributes");
32f4334d 675
14d55bce
RS
676 defsubr (&Sdirectory_files);
677 defsubr (&Sfile_name_completion);
678#ifdef VMS
679 defsubr (&Sfile_name_all_versions);
3ed991aa 680 defsubr (&Sfile_version_limit);
14d55bce
RS
681#endif /* VMS */
682 defsubr (&Sfile_name_all_completions);
683 defsubr (&Sfile_attributes);
684
685#ifdef VMS
686 Qcompletion_ignore_case = intern ("completion-ignore-case");
687 staticpro (&Qcompletion_ignore_case);
688#endif /* VMS */
689
690 DEFVAR_LISP ("completion-ignored-extensions", &Vcompletion_ignored_extensions,
691 "*Completion ignores filenames ending in any string in this list.\n\
692This variable does not affect lists of possible completions,\n\
693but does affect the commands that actually do completions.");
694 Vcompletion_ignored_extensions = Qnil;
695}