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