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