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