(syms_of_dired): staticpro Qdirectory_files, Qfile_name_completion,
[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
33d5e9cc
KH
298#ifdef MSDOS
299#if __DJGPP__ > 1
300 /* Some fields of struct stat are *very* expensive to compute on MS-DOS,
301 but aren't required here. Avoid computing the following fields:
302 st_inode, st_size and st_nlink for directories, and the execute bits
303 in st_mode for non-directory files with non-standard extensions. */
304
305 unsigned short save_djstat_flags = _djstat_flags;
306
307 _djstat_flags = _STAT_INODE | _STAT_EXEC_MAGIC | _STAT_DIRSIZE;
308#endif
309#endif
310
14d55bce
RS
311#ifdef VMS
312 extern DIRENTRY * readdirver ();
313
314 DIRENTRY *((* readfunc) ());
315
316 /* Filename completion on VMS ignores case, since VMS filesys does. */
317 specbind (Qcompletion_ignore_case, Qt);
318
319 readfunc = readdir;
320 if (ver_flag)
321 readfunc = readdirver;
322 file = Fupcase (file);
323#else /* not VMS */
324 CHECK_STRING (file, 0);
325#endif /* not VMS */
326
128ecc89
RS
327#ifdef FILE_SYSTEM_CASE
328 file = FILE_SYSTEM_CASE (file);
329#endif
14d55bce 330 bestmatch = Qnil;
3fcc88cc
RS
331 GCPRO3 (file, dirname, bestmatch);
332 dirname = Fexpand_file_name (dirname, Qnil);
14d55bce
RS
333
334 /* With passcount = 0, ignore files that end in an ignored extension.
335 If nothing found then try again with passcount = 1, don't ignore them.
336 If looking for all completions, start with passcount = 1,
337 so always take even the ignored ones.
338
339 ** It would not actually be helpful to the user to ignore any possible
340 completions when making a list of them.** */
341
265a9e55 342 for (passcount = !!all_flag; NILP (bestmatch) && passcount < 2; passcount++)
14d55bce
RS
343 {
344 if (!(d = opendir (XSTRING (Fdirectory_file_name (dirname))->data)))
345 report_file_error ("Opening directory", Fcons (dirname, Qnil));
346
347 /* Loop reading blocks */
348 /* (att3b compiler bug requires do a null comparison this way) */
349 while (1)
350 {
351 DIRENTRY *dp;
352 int len;
353
354#ifdef VMS
355 dp = (*readfunc) (d);
356#else
357 dp = readdir (d);
358#endif
359 if (!dp) break;
360
361 len = NAMLEN (dp);
362
265a9e55 363 if (!NILP (Vquit_flag) && NILP (Vinhibit_quit))
14d55bce 364 goto quit;
128ecc89 365 if (! DIRENTRY_NONEMPTY (dp)
14d55bce
RS
366 || len < XSTRING (file)->size
367 || 0 <= scmp (dp->d_name, XSTRING (file)->data,
368 XSTRING (file)->size))
369 continue;
370
371 if (file_name_completion_stat (dirname, dp, &st) < 0)
372 continue;
373
374 directoryp = ((st.st_mode & S_IFMT) == S_IFDIR);
375 tem = Qnil;
ad456ad4
RS
376 if (directoryp)
377 {
378#ifndef TRIVIAL_DIRECTORY_ENTRY
379#define TRIVIAL_DIRECTORY_ENTRY(n) (!strcmp (n, ".") || !strcmp (n, ".."))
380#endif
381 /* "." and ".." are never interesting as completions, but are
382 actually in the way in a directory contains only one file. */
383 if (!passcount && TRIVIAL_DIRECTORY_ENTRY (dp->d_name))
384 continue;
385 }
386 else
14d55bce
RS
387 {
388 /* Compare extensions-to-be-ignored against end of this file name */
389 /* if name is not an exact match against specified string */
390 if (!passcount && len > XSTRING (file)->size)
391 /* and exit this for loop if a match is found */
392 for (tem = Vcompletion_ignored_extensions;
393 CONSP (tem); tem = XCONS (tem)->cdr)
394 {
395 elt = XCONS (tem)->car;
88cf1852 396 if (!STRINGP (elt)) continue;
14d55bce
RS
397 skip = len - XSTRING (elt)->size;
398 if (skip < 0) continue;
399
400 if (0 <= scmp (dp->d_name + skip,
401 XSTRING (elt)->data,
402 XSTRING (elt)->size))
403 continue;
404 break;
405 }
406 }
407
f676868d
KH
408 /* If an ignored-extensions match was found,
409 don't process this name as a completion. */
410 if (!passcount && CONSP (tem))
411 continue;
412
413 if (!passcount)
14d55bce 414 {
f676868d
KH
415 Lisp_Object regexps;
416 Lisp_Object zero;
617b3bfe 417 XSETFASTINT (zero, 0);
f676868d
KH
418
419 /* Ignore this element if it fails to match all the regexps. */
420 for (regexps = Vcompletion_regexp_list; CONSP (regexps);
421 regexps = XCONS (regexps)->cdr)
422 {
423 tem = Fstring_match (XCONS (regexps)->car, elt, zero);
424 if (NILP (tem))
425 break;
426 }
427 if (CONSP (regexps))
428 continue;
429 }
14d55bce 430
f676868d 431 /* Update computation of how much all possible completions match */
14d55bce 432
f676868d
KH
433 matchcount++;
434
435 if (all_flag || NILP (bestmatch))
436 {
437 /* This is a possible completion */
438 if (directoryp)
14d55bce 439 {
f676868d
KH
440 /* This completion is a directory; make it end with '/' */
441 name = Ffile_name_as_directory (make_string (dp->d_name, len));
442 }
443 else
444 name = make_string (dp->d_name, len);
445 if (all_flag)
446 {
447 bestmatch = Fcons (name, bestmatch);
14d55bce
RS
448 }
449 else
450 {
f676868d
KH
451 bestmatch = name;
452 bestmatchsize = XSTRING (name)->size;
453 }
454 }
455 else
456 {
457 compare = min (bestmatchsize, len);
458 p1 = XSTRING (bestmatch)->data;
459 p2 = (unsigned char *) dp->d_name;
460 matchsize = scmp(p1, p2, compare);
461 if (matchsize < 0)
462 matchsize = compare;
463 if (completion_ignore_case)
464 {
465 /* If this is an exact match except for case,
466 use it as the best match rather than one that is not
467 an exact match. This way, we get the case pattern
468 of the actual match. */
f5ec5d3d
RS
469 /* This tests that the current file is an exact match
470 but BESTMATCH is not (it is too long). */
f676868d
KH
471 if ((matchsize == len
472 && matchsize + !!directoryp
473 < XSTRING (bestmatch)->size)
474 ||
475 /* If there is no exact match ignoring case,
476 prefer a match that does not change the case
477 of the input. */
f5ec5d3d
RS
478 /* If there is more than one exact match aside from
479 case, and one of them is exact including case,
480 prefer that one. */
481 /* This == checks that, of current file and BESTMATCH,
482 either both or neither are exact. */
f676868d
KH
483 (((matchsize == len)
484 ==
485 (matchsize + !!directoryp
486 == XSTRING (bestmatch)->size))
f676868d
KH
487 && !bcmp (p2, XSTRING (file)->data, XSTRING (file)->size)
488 && bcmp (p1, XSTRING (file)->data, XSTRING (file)->size)))
97e98a56 489 {
f676868d
KH
490 bestmatch = make_string (dp->d_name, len);
491 if (directoryp)
492 bestmatch = Ffile_name_as_directory (bestmatch);
97e98a56 493 }
14d55bce 494 }
f676868d
KH
495
496 /* If this dirname all matches, see if implicit following
497 slash does too. */
498 if (directoryp
499 && compare == matchsize
500 && bestmatchsize > matchsize
0b39d75d 501 && IS_ANY_SEP (p1[matchsize]))
f676868d
KH
502 matchsize++;
503 bestmatchsize = matchsize;
14d55bce
RS
504 }
505 }
506 closedir (d);
507 }
508
3fcc88cc
RS
509 UNGCPRO;
510 bestmatch = unbind_to (count, bestmatch);
14d55bce 511
33d5e9cc
KH
512#ifdef MSDOS
513#if __DJGPP__ > 1
514 _djstat_flags = save_djstat_flags;
515#endif
516#endif
517
265a9e55 518 if (all_flag || NILP (bestmatch))
14d55bce
RS
519 return bestmatch;
520 if (matchcount == 1 && bestmatchsize == XSTRING (file)->size)
521 return Qt;
522 return Fsubstring (bestmatch, make_number (0), make_number (bestmatchsize));
523 quit:
524 if (d) closedir (d);
525 Vquit_flag = Qnil;
526 return Fsignal (Qquit, Qnil);
527}
528
529file_name_completion_stat (dirname, dp, st_addr)
530 Lisp_Object dirname;
531 DIRENTRY *dp;
532 struct stat *st_addr;
533{
534 int len = NAMLEN (dp);
535 int pos = XSTRING (dirname)->size;
7e3cf34f 536 int value;
14d55bce
RS
537 char *fullname = (char *) alloca (len + pos + 2);
538
539 bcopy (XSTRING (dirname)->data, fullname, pos);
540#ifndef VMS
0b39d75d
RS
541 if (!IS_DIRECTORY_SEP (fullname[pos - 1]))
542 fullname[pos++] = DIRECTORY_SEP;
14d55bce
RS
543#endif
544
545 bcopy (dp->d_name, fullname + pos, len);
546 fullname[pos + len] = 0;
547
a889bd0e 548#ifdef S_IFLNK
7e3cf34f
RS
549 /* We want to return success if a link points to a nonexistent file,
550 but we want to return the status for what the link points to,
551 in case it is a directory. */
552 value = lstat (fullname, st_addr);
553 stat (fullname, st_addr);
554 return value;
a889bd0e 555#else
14d55bce 556 return stat (fullname, st_addr);
a889bd0e 557#endif
14d55bce
RS
558}
559\f
3ed991aa
RS
560#ifdef VMS
561
562DEFUN ("file-name-all-versions", Ffile_name_all_versions,
563 Sfile_name_all_versions, 2, 2, 0,
23bd240f
EN
564 "Return a list of all versions of file name FILE in directory DIRECTORY.")
565 (file, directory)
566 Lisp_Object file, directory;
3ed991aa 567{
23bd240f 568 return file_name_completion (file, directory, 1, 1);
3ed991aa
RS
569}
570
571DEFUN ("file-version-limit", Ffile_version_limit, Sfile_version_limit, 1, 1, 0,
572 "Return the maximum number of versions allowed for FILE.\n\
573Returns nil if the file cannot be opened or if there is no version limit.")
574 (filename)
575 Lisp_Object filename;
576{
577 Lisp_Object retval;
578 struct FAB fab;
579 struct RAB rab;
580 struct XABFHC xabfhc;
581 int status;
582
583 filename = Fexpand_file_name (filename, Qnil);
584 fab = cc$rms_fab;
585 xabfhc = cc$rms_xabfhc;
586 fab.fab$l_fna = XSTRING (filename)->data;
587 fab.fab$b_fns = strlen (fab.fab$l_fna);
588 fab.fab$l_xab = (char *) &xabfhc;
589 status = sys$open (&fab, 0, 0);
590 if (status != RMS$_NORMAL) /* Probably non-existent file */
591 return Qnil;
592 sys$close (&fab, 0, 0);
593 if (xabfhc.xab$w_verlimit == 32767)
594 return Qnil; /* No version limit */
595 else
596 return make_number (xabfhc.xab$w_verlimit);
597}
598
599#endif /* VMS */
600\f
14d55bce
RS
601Lisp_Object
602make_time (time)
603 int time;
604{
605 return Fcons (make_number (time >> 16),
606 Fcons (make_number (time & 0177777), Qnil));
607}
608
609DEFUN ("file-attributes", Ffile_attributes, Sfile_attributes, 1, 1, 0,
610 "Return a list of attributes of file FILENAME.\n\
611Value is nil if specified file cannot be opened.\n\
612Otherwise, list elements are:\n\
613 0. t for directory, string (name linked to) for symbolic link, or nil.\n\
614 1. Number of links to file.\n\
615 2. File uid.\n\
616 3. File gid.\n\
617 4. Last access time, as a list of two integers.\n\
618 First integer has high-order 16 bits of time, second has low 16 bits.\n\
619 5. Last modification time, likewise.\n\
620 6. Last status change time, likewise.\n\
60fc6069 621 7. Size in bytes (-1, if number is out of range).\n\
14d55bce
RS
622 8. File modes, as a string of ten letters or dashes as in ls -l.\n\
623 9. t iff file's gid would change if file were deleted and recreated.\n\
62410. inode number.\n\
62511. Device number.\n\
626\n\
ccbcf979 627If file does not exist, returns nil.")
14d55bce
RS
628 (filename)
629 Lisp_Object filename;
630{
631 Lisp_Object values[12];
632 Lisp_Object dirname;
633 struct stat s;
634 struct stat sdir;
635 char modes[10];
32f4334d 636 Lisp_Object handler;
14d55bce
RS
637
638 filename = Fexpand_file_name (filename, Qnil);
32f4334d
RS
639
640 /* If the file name has special constructs in it,
641 call the corresponding file handler. */
a617e913 642 handler = Ffind_file_name_handler (filename, Qfile_attributes);
32f4334d
RS
643 if (!NILP (handler))
644 return call2 (handler, Qfile_attributes, filename);
645
14d55bce
RS
646 if (lstat (XSTRING (filename)->data, &s) < 0)
647 return Qnil;
648
649 switch (s.st_mode & S_IFMT)
650 {
651 default:
652 values[0] = Qnil; break;
653 case S_IFDIR:
654 values[0] = Qt; break;
655#ifdef S_IFLNK
656 case S_IFLNK:
657 values[0] = Ffile_symlink_p (filename); break;
658#endif
659 }
660 values[1] = make_number (s.st_nlink);
661 values[2] = make_number (s.st_uid);
662 values[3] = make_number (s.st_gid);
663 values[4] = make_time (s.st_atime);
664 values[5] = make_time (s.st_mtime);
665 values[6] = make_time (s.st_ctime);
ed2ef6c9 666 values[7] = make_number ((int) s.st_size);
60fc6069
RS
667 /* If the size is out of range, give back -1. */
668 if (XINT (values[7]) != s.st_size)
669 XSETINT (values[7], -1);
14d55bce
RS
670 filemodestring (&s, modes);
671 values[8] = make_string (modes, 10);
672#ifdef BSD4_3 /* Gross kludge to avoid lack of "#if defined(...)" in VMS */
eb8c3be9 673#define BSD4_2 /* A new meaning to the term `backwards compatibility' */
14d55bce
RS
674#endif
675#ifdef BSD4_2 /* file gid will be dir gid */
676 dirname = Ffile_name_directory (filename);
ccbcf979 677 if (! NILP (dirname) && stat (XSTRING (dirname)->data, &sdir) == 0)
14d55bce
RS
678 values[9] = (sdir.st_gid != s.st_gid) ? Qt : Qnil;
679 else /* if we can't tell, assume worst */
680 values[9] = Qt;
681#else /* file gid will be egid */
682 values[9] = (s.st_gid != getegid ()) ? Qt : Qnil;
683#endif /* BSD4_2 (or BSD4_3) */
684#ifdef BSD4_3
685#undef BSD4_2 /* ok, you can look again without throwing up */
686#endif
687 values[10] = make_number (s.st_ino);
688 values[11] = make_number (s.st_dev);
689 return Flist (sizeof(values) / sizeof(values[0]), values);
690}
691\f
692syms_of_dired ()
693{
32f4334d
RS
694 Qdirectory_files = intern ("directory-files");
695 Qfile_name_completion = intern ("file-name-completion");
696 Qfile_name_all_completions = intern ("file-name-all-completions");
434e6714 697 Qfile_attributes = intern ("file-attributes");
32f4334d 698
a2d3836c
EN
699 staticpro (&Qdirectory_files);
700 staticpro (&Qfile_name_completion);
701 staticpro (&Qfile_name_all_completions);
702 staticpro (&Qfile_attributes);
703
14d55bce
RS
704 defsubr (&Sdirectory_files);
705 defsubr (&Sfile_name_completion);
706#ifdef VMS
707 defsubr (&Sfile_name_all_versions);
3ed991aa 708 defsubr (&Sfile_version_limit);
14d55bce
RS
709#endif /* VMS */
710 defsubr (&Sfile_name_all_completions);
711 defsubr (&Sfile_attributes);
712
713#ifdef VMS
714 Qcompletion_ignore_case = intern ("completion-ignore-case");
715 staticpro (&Qcompletion_ignore_case);
716#endif /* VMS */
717
718 DEFVAR_LISP ("completion-ignored-extensions", &Vcompletion_ignored_extensions,
719 "*Completion ignores filenames ending in any string in this list.\n\
720This variable does not affect lists of possible completions,\n\
721but does affect the commands that actually do completions.");
722 Vcompletion_ignored_extensions = Qnil;
723}