(bdffont): Add nchars.
[bpt/emacs.git] / src / dired.c
1 /* Lisp functions for making directory listings.
2 Copyright (C) 1985, 1986, 1993, 1994, 1999 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 #include "systime.h"
29
30 #ifdef VMS
31 #include <string.h>
32 #include <rms.h>
33 #include <rmsdef.h>
34 #endif
35
36 #ifdef HAVE_UNISTD_H
37 #include <unistd.h>
38 #endif
39
40 /* The d_nameln member of a struct dirent includes the '\0' character
41 on some systems, but not on others. What's worse, you can't tell
42 at compile-time which one it will be, since it really depends on
43 the sort of system providing the filesystem you're reading from,
44 not the system you are running on. Paul Eggert
45 <eggert@bi.twinsun.com> says this occurs when Emacs is running on a
46 SunOS 4.1.2 host, reading a directory that is remote-mounted from a
47 Solaris 2.1 host and is in a native Solaris 2.1 filesystem.
48
49 Since applying strlen to the name always works, we'll just do that. */
50 #define NAMLEN(p) strlen (p->d_name)
51
52 #ifdef SYSV_SYSTEM_DIR
53
54 #include <dirent.h>
55 #define DIRENTRY struct dirent
56
57 #else /* not SYSV_SYSTEM_DIR */
58
59 #ifdef NONSYSTEM_DIR_LIBRARY
60 #include "ndir.h"
61 #else /* not NONSYSTEM_DIR_LIBRARY */
62 #ifdef MSDOS
63 #include <dirent.h>
64 #else
65 #include <sys/dir.h>
66 #endif
67 #endif /* not NONSYSTEM_DIR_LIBRARY */
68
69 #include <sys/stat.h>
70
71 #ifndef MSDOS
72 #define DIRENTRY struct direct
73
74 extern DIR *opendir ();
75 extern struct direct *readdir ();
76
77 #endif /* not MSDOS */
78 #endif /* not SYSV_SYSTEM_DIR */
79
80 #ifdef MSDOS
81 #define DIRENTRY_NONEMPTY(p) ((p)->d_name[0] != 0)
82 #else
83 #define DIRENTRY_NONEMPTY(p) ((p)->d_ino)
84 #endif
85
86 #include "lisp.h"
87 #include "buffer.h"
88 #include "commands.h"
89 #include "charset.h"
90 #include "coding.h"
91 #include "regex.h"
92
93 /* Returns a search buffer, with a fastmap allocated and ready to go. */
94 extern struct re_pattern_buffer *compile_pattern ();
95
96 /* From filemode.c. Can't go in Lisp.h because of `stat'. */
97 extern void filemodestring P_ ((struct stat *, char *));
98
99 #define min(a, b) ((a) < (b) ? (a) : (b))
100
101 /* if system does not have symbolic links, it does not have lstat.
102 In that case, use ordinary stat instead. */
103
104 #ifndef S_IFLNK
105 #define lstat stat
106 #endif
107
108 extern int completion_ignore_case;
109 extern Lisp_Object Vcompletion_regexp_list;
110 extern Lisp_Object Vfile_name_coding_system, Vdefault_file_name_coding_system;
111
112 Lisp_Object Vcompletion_ignored_extensions;
113 Lisp_Object Qcompletion_ignore_case;
114 Lisp_Object Qdirectory_files;
115 Lisp_Object Qdirectory_files_and_attributes;
116 Lisp_Object Qfile_name_completion;
117 Lisp_Object Qfile_name_all_completions;
118 Lisp_Object Qfile_attributes;
119 Lisp_Object Qfile_attributes_lessp;
120 \f
121
122 Lisp_Object
123 directory_files_internal_unwind (dh)
124 Lisp_Object dh;
125 {
126 DIR *d = (DIR *) ((XINT (XCAR (dh)) << 16) + XINT (XCDR (dh)));
127 closedir (d);
128 return Qnil;
129 }
130
131 /* Function shared by Fdirectory_files and Fdirectory_files_and_attributes.
132 When ATTRS is zero, return a list of directory filenames; when
133 non-zero, return a list of directory filenames and their attributes. */
134 Lisp_Object
135 directory_files_internal (directory, full, match, nosort, attrs)
136 Lisp_Object directory, full, match, nosort;
137 int attrs;
138 {
139 DIR *d;
140 int dirnamelen;
141 Lisp_Object list, name, dirfilename;
142 Lisp_Object encoded_directory;
143 Lisp_Object handler;
144 struct re_pattern_buffer *bufp = NULL;
145 int needsep = 0;
146 int count = specpdl_ptr - specpdl;
147 struct gcpro gcpro1, gcpro2;
148
149 /* Because of file name handlers, these functions might call
150 Ffuncall, and cause a GC. */
151 GCPRO1 (match);
152 directory = Fexpand_file_name (directory, Qnil);
153 UNGCPRO;
154 GCPRO2 (match, directory);
155 dirfilename = Fdirectory_file_name (directory);
156 UNGCPRO;
157
158 if (!NILP (match))
159 {
160 CHECK_STRING (match, 3);
161
162 /* MATCH might be a flawed regular expression. Rather than
163 catching and signaling our own errors, we just call
164 compile_pattern to do the work for us. */
165 /* Pass 1 for the MULTIBYTE arg
166 because we do make multibyte strings if the contents warrant. */
167 #ifdef VMS
168 bufp = compile_pattern (match, 0,
169 buffer_defaults.downcase_table, 0, 1);
170 #else
171 bufp = compile_pattern (match, 0, Qnil, 0, 1);
172 #endif
173 }
174
175 dirfilename = ENCODE_FILE (dirfilename);
176
177 encoded_directory = ENCODE_FILE (directory);
178
179 /* Now *bufp is the compiled form of MATCH; don't call anything
180 which might compile a new regexp until we're done with the loop! */
181
182 /* Do this opendir after anything which might signal an error; if
183 an error is signaled while the directory stream is open, we
184 have to make sure it gets closed, and setting up an
185 unwind_protect to do so would be a pain. */
186 d = opendir (XSTRING (dirfilename)->data);
187 if (! d)
188 report_file_error ("Opening directory", Fcons (directory, Qnil));
189
190 /* Unfortunately, we can now invoke expand-file-name and
191 file-attributes on filenames, both of which can throw, so we must
192 do a proper unwind-protect. */
193 record_unwind_protect (directory_files_internal_unwind,
194 Fcons (make_number (((unsigned long) d) >> 16),
195 make_number (((unsigned long) d) & 0xffff)));
196
197 list = Qnil;
198 dirnamelen = STRING_BYTES (XSTRING (directory));
199 re_match_object = Qt;
200
201 /* Decide whether we need to add a directory separator. */
202 #ifndef VMS
203 if (dirnamelen == 0
204 || !IS_ANY_SEP (XSTRING (directory)->data[dirnamelen - 1]))
205 needsep = 1;
206 #endif /* not VMS */
207
208 GCPRO2 (encoded_directory, list);
209
210 /* Loop reading blocks */
211 while (1)
212 {
213 DIRENTRY *dp = readdir (d);
214
215 if (!dp) break;
216 if (DIRENTRY_NONEMPTY (dp))
217 {
218 int len;
219 int wanted = 0;
220
221 len = NAMLEN (dp);
222 name = DECODE_FILE (make_string (dp->d_name, len));
223 len = STRING_BYTES (XSTRING (name));
224
225 /* Now that we have unwind_protect in place, we might as well
226 allow matching to be interrupted. */
227 immediate_quit = 1;
228 QUIT;
229
230 if (NILP (match)
231 || (0 <= re_search (bufp, XSTRING (name)->data, len, 0, len, 0)))
232 {
233 wanted = 1;
234 }
235
236 immediate_quit = 0;
237
238 if (wanted)
239 {
240 Lisp_Object finalname;
241
242 finalname = name;
243 if (!NILP (full))
244 {
245 int afterdirindex = dirnamelen;
246 int total = len + dirnamelen;
247 int nchars;
248 Lisp_Object fullname;
249
250 fullname = make_uninit_multibyte_string (total + needsep,
251 total + needsep);
252 bcopy (XSTRING (directory)->data, XSTRING (fullname)->data,
253 dirnamelen);
254 if (needsep)
255 XSTRING (fullname)->data[afterdirindex++] = DIRECTORY_SEP;
256 bcopy (XSTRING (name)->data,
257 XSTRING (fullname)->data + afterdirindex, len);
258 nchars = chars_in_text (XSTRING (fullname)->data,
259 afterdirindex + len);
260 XSTRING (fullname)->size = nchars;
261 if (nchars == STRING_BYTES (XSTRING (fullname)))
262 SET_STRING_BYTES (XSTRING (fullname), -1);
263 finalname = fullname;
264 }
265
266 if (attrs)
267 {
268 /* Construct an expanded filename for the directory entry.
269 Use the decoded names for input to Ffile_attributes. */
270 Lisp_Object decoded_fullname;
271 Lisp_Object fileattrs;
272
273 decoded_fullname = Fexpand_file_name (name, directory);
274 fileattrs = Ffile_attributes (decoded_fullname);
275
276 list = Fcons (Fcons (finalname, fileattrs), list);
277 }
278 else
279 {
280 list = Fcons (finalname, list);
281 }
282 }
283 }
284 }
285
286 closedir (d);
287
288 /* Discard the unwind protect. */
289 specpdl_ptr = specpdl + count;
290
291 UNGCPRO;
292 if (!NILP (nosort))
293 return list;
294 if (attrs)
295 return Fsort (Fnreverse (list), Qfile_attributes_lessp);
296 else
297 return Fsort (Fnreverse (list), Qstring_lessp);
298 }
299
300
301 DEFUN ("directory-files", Fdirectory_files, Sdirectory_files, 1, 4, 0,
302 "Return a list of names of files in DIRECTORY.\n\
303 There are three optional arguments:\n\
304 If FULL is non-nil, return absolute file names. Otherwise return names\n\
305 that are relative to the specified directory.\n\
306 If MATCH is non-nil, mention only file names that match the regexp MATCH.\n\
307 If NOSORT is non-nil, the list is not sorted--its order is unpredictable.\n\
308 NOSORT is useful if you plan to sort the result yourself.")
309 (directory, full, match, nosort)
310 Lisp_Object directory, full, match, nosort;
311 {
312 Lisp_Object handler;
313
314 /* If the file name has special constructs in it,
315 call the corresponding file handler. */
316 handler = Ffind_file_name_handler (directory, Qdirectory_files);
317 if (!NILP (handler))
318 {
319 Lisp_Object args[6];
320
321 args[0] = handler;
322 args[1] = Qdirectory_files;
323 args[2] = directory;
324 args[3] = full;
325 args[4] = match;
326 args[5] = nosort;
327 return Ffuncall (6, args);
328 }
329
330 return directory_files_internal (directory, full, match, nosort, 0);
331 }
332
333 DEFUN ("directory-files-and-attributes", Fdirectory_files_and_attributes, Sdirectory_files_and_attributes, 1, 4, 0,
334 "Return a list of names of files and their attributes in DIRECTORY.\n\
335 There are three optional arguments:\n\
336 If FULL is non-nil, return absolute file names. Otherwise return names\n\
337 that are relative to the specified directory.\n\
338 If MATCH is non-nil, mention only file names that match the regexp MATCH.\n\
339 If NOSORT is non-nil, the list is not sorted--its order is unpredictable.\n\
340 NOSORT is useful if you plan to sort the result yourself.")
341 (directory, full, match, nosort)
342 Lisp_Object directory, full, match, nosort;
343 {
344 Lisp_Object handler;
345
346 /* If the file name has special constructs in it,
347 call the corresponding file handler. */
348 handler = Ffind_file_name_handler (directory, Qdirectory_files_and_attributes);
349 if (!NILP (handler))
350 {
351 Lisp_Object args[6];
352
353 args[0] = handler;
354 args[1] = Qdirectory_files_and_attributes;
355 args[2] = directory;
356 args[3] = full;
357 args[4] = match;
358 args[5] = nosort;
359 return Ffuncall (6, args);
360 }
361
362 return directory_files_internal (directory, full, match, nosort, 1);
363 }
364
365 \f
366 Lisp_Object file_name_completion ();
367
368 DEFUN ("file-name-completion", Ffile_name_completion, Sfile_name_completion,
369 2, 2, 0,
370 "Complete file name FILE in directory DIRECTORY.\n\
371 Returns the longest string\n\
372 common to all file names in DIRECTORY that start with FILE.\n\
373 If there is only one and FILE matches it exactly, returns t.\n\
374 Returns nil if DIR contains no name starting with FILE.")
375 (file, directory)
376 Lisp_Object file, directory;
377 {
378 Lisp_Object handler;
379
380 /* If the directory name has special constructs in it,
381 call the corresponding file handler. */
382 handler = Ffind_file_name_handler (directory, Qfile_name_completion);
383 if (!NILP (handler))
384 return call3 (handler, Qfile_name_completion, file, directory);
385
386 /* If the file name has special constructs in it,
387 call the corresponding file handler. */
388 handler = Ffind_file_name_handler (file, Qfile_name_completion);
389 if (!NILP (handler))
390 return call3 (handler, Qfile_name_completion, file, directory);
391
392 return file_name_completion (file, directory, 0, 0);
393 }
394
395 DEFUN ("file-name-all-completions", Ffile_name_all_completions,
396 Sfile_name_all_completions, 2, 2, 0,
397 "Return a list of all completions of file name FILE in directory DIRECTORY.\n\
398 These are all file names in directory DIRECTORY which begin with FILE.")
399 (file, directory)
400 Lisp_Object file, directory;
401 {
402 Lisp_Object handler;
403
404 /* If the directory name has special constructs in it,
405 call the corresponding file handler. */
406 handler = Ffind_file_name_handler (directory, Qfile_name_all_completions);
407 if (!NILP (handler))
408 return call3 (handler, Qfile_name_all_completions, file, directory);
409
410 /* If the file name has special constructs in it,
411 call the corresponding file handler. */
412 handler = Ffind_file_name_handler (file, Qfile_name_all_completions);
413 if (!NILP (handler))
414 return call3 (handler, Qfile_name_all_completions, file, directory);
415
416 return file_name_completion (file, directory, 1, 0);
417 }
418
419 static int file_name_completion_stat ();
420
421 Lisp_Object
422 file_name_completion (file, dirname, all_flag, ver_flag)
423 Lisp_Object file, dirname;
424 int all_flag, ver_flag;
425 {
426 DIR *d;
427 DIRENTRY *dp;
428 int bestmatchsize = 0, skip;
429 register int compare, matchsize;
430 unsigned char *p1, *p2;
431 int matchcount = 0;
432 Lisp_Object bestmatch, tem, elt, name;
433 Lisp_Object encoded_file;
434 Lisp_Object encoded_dir;
435 struct stat st;
436 int directoryp;
437 int passcount;
438 int count = specpdl_ptr - specpdl;
439 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
440
441 elt = Qnil;
442
443 #ifdef VMS
444 extern DIRENTRY * readdirver ();
445
446 DIRENTRY *((* readfunc) ());
447
448 /* Filename completion on VMS ignores case, since VMS filesys does. */
449 specbind (Qcompletion_ignore_case, Qt);
450
451 readfunc = readdir;
452 if (ver_flag)
453 readfunc = readdirver;
454 file = Fupcase (file);
455 #else /* not VMS */
456 CHECK_STRING (file, 0);
457 #endif /* not VMS */
458
459 #ifdef FILE_SYSTEM_CASE
460 file = FILE_SYSTEM_CASE (file);
461 #endif
462 bestmatch = Qnil;
463 encoded_file = encoded_dir = Qnil;
464 GCPRO5 (file, dirname, bestmatch, encoded_file, encoded_dir);
465 dirname = Fexpand_file_name (dirname, Qnil);
466
467 /* Do completion on the encoded file name
468 because the other names in the directory are (we presume)
469 encoded likewise. We decode the completed string at the end. */
470 encoded_file = ENCODE_FILE (file);
471
472 encoded_dir = ENCODE_FILE (dirname);
473
474 /* With passcount = 0, ignore files that end in an ignored extension.
475 If nothing found then try again with passcount = 1, don't ignore them.
476 If looking for all completions, start with passcount = 1,
477 so always take even the ignored ones.
478
479 ** It would not actually be helpful to the user to ignore any possible
480 completions when making a list of them.** */
481
482 for (passcount = !!all_flag; NILP (bestmatch) && passcount < 2; passcount++)
483 {
484 d = opendir (XSTRING (Fdirectory_file_name (encoded_dir))->data);
485 if (!d)
486 report_file_error ("Opening directory", Fcons (dirname, Qnil));
487
488 /* Loop reading blocks */
489 /* (att3b compiler bug requires do a null comparison this way) */
490 while (1)
491 {
492 DIRENTRY *dp;
493 int len;
494
495 #ifdef VMS
496 dp = (*readfunc) (d);
497 #else
498 dp = readdir (d);
499 #endif
500 if (!dp) break;
501
502 len = NAMLEN (dp);
503
504 if (!NILP (Vquit_flag) && NILP (Vinhibit_quit))
505 goto quit;
506 if (! DIRENTRY_NONEMPTY (dp)
507 || len < XSTRING (encoded_file)->size
508 || 0 <= scmp (dp->d_name, XSTRING (encoded_file)->data,
509 XSTRING (encoded_file)->size))
510 continue;
511
512 if (file_name_completion_stat (encoded_dir, dp, &st) < 0)
513 continue;
514
515 directoryp = ((st.st_mode & S_IFMT) == S_IFDIR);
516 tem = Qnil;
517 if (directoryp)
518 {
519 #ifndef TRIVIAL_DIRECTORY_ENTRY
520 #define TRIVIAL_DIRECTORY_ENTRY(n) (!strcmp (n, ".") || !strcmp (n, ".."))
521 #endif
522 /* "." and ".." are never interesting as completions, but are
523 actually in the way in a directory contains only one file. */
524 if (!passcount && TRIVIAL_DIRECTORY_ENTRY (dp->d_name))
525 continue;
526 }
527 else
528 {
529 /* Compare extensions-to-be-ignored against end of this file name */
530 /* if name is not an exact match against specified string */
531 if (!passcount && len > XSTRING (encoded_file)->size)
532 /* and exit this for loop if a match is found */
533 for (tem = Vcompletion_ignored_extensions;
534 CONSP (tem); tem = XCDR (tem))
535 {
536 elt = XCAR (tem);
537 if (!STRINGP (elt)) continue;
538 skip = len - XSTRING (elt)->size;
539 if (skip < 0) continue;
540
541 if (0 <= scmp (dp->d_name + skip,
542 XSTRING (elt)->data,
543 XSTRING (elt)->size))
544 continue;
545 break;
546 }
547 }
548
549 /* If an ignored-extensions match was found,
550 don't process this name as a completion. */
551 if (!passcount && CONSP (tem))
552 continue;
553
554 if (!passcount)
555 {
556 Lisp_Object regexps;
557 Lisp_Object zero;
558 XSETFASTINT (zero, 0);
559
560 /* Ignore this element if it fails to match all the regexps. */
561 for (regexps = Vcompletion_regexp_list; CONSP (regexps);
562 regexps = XCDR (regexps))
563 {
564 tem = Fstring_match (XCAR (regexps), elt, zero);
565 if (NILP (tem))
566 break;
567 }
568 if (CONSP (regexps))
569 continue;
570 }
571
572 /* Update computation of how much all possible completions match */
573
574 matchcount++;
575
576 if (all_flag || NILP (bestmatch))
577 {
578 /* This is a possible completion */
579 if (directoryp)
580 {
581 /* This completion is a directory; make it end with '/' */
582 name = Ffile_name_as_directory (make_string (dp->d_name, len));
583 }
584 else
585 name = make_string (dp->d_name, len);
586 if (all_flag)
587 {
588 name = DECODE_FILE (name);
589 bestmatch = Fcons (name, bestmatch);
590 }
591 else
592 {
593 bestmatch = name;
594 bestmatchsize = XSTRING (name)->size;
595 }
596 }
597 else
598 {
599 compare = min (bestmatchsize, len);
600 p1 = XSTRING (bestmatch)->data;
601 p2 = (unsigned char *) dp->d_name;
602 matchsize = scmp(p1, p2, compare);
603 if (matchsize < 0)
604 matchsize = compare;
605 if (completion_ignore_case)
606 {
607 /* If this is an exact match except for case,
608 use it as the best match rather than one that is not
609 an exact match. This way, we get the case pattern
610 of the actual match. */
611 /* This tests that the current file is an exact match
612 but BESTMATCH is not (it is too long). */
613 if ((matchsize == len
614 && matchsize + !!directoryp
615 < XSTRING (bestmatch)->size)
616 ||
617 /* If there is no exact match ignoring case,
618 prefer a match that does not change the case
619 of the input. */
620 /* If there is more than one exact match aside from
621 case, and one of them is exact including case,
622 prefer that one. */
623 /* This == checks that, of current file and BESTMATCH,
624 either both or neither are exact. */
625 (((matchsize == len)
626 ==
627 (matchsize + !!directoryp
628 == XSTRING (bestmatch)->size))
629 && !bcmp (p2, XSTRING (encoded_file)->data, XSTRING (encoded_file)->size)
630 && bcmp (p1, XSTRING (encoded_file)->data, XSTRING (encoded_file)->size)))
631 {
632 bestmatch = make_string (dp->d_name, len);
633 if (directoryp)
634 bestmatch = Ffile_name_as_directory (bestmatch);
635 }
636 }
637
638 /* If this dirname all matches, see if implicit following
639 slash does too. */
640 if (directoryp
641 && compare == matchsize
642 && bestmatchsize > matchsize
643 && IS_ANY_SEP (p1[matchsize]))
644 matchsize++;
645 bestmatchsize = matchsize;
646 }
647 }
648 closedir (d);
649 }
650
651 UNGCPRO;
652 bestmatch = unbind_to (count, bestmatch);
653
654 if (all_flag || NILP (bestmatch))
655 {
656 if (STRINGP (bestmatch))
657 bestmatch = DECODE_FILE (bestmatch);
658 return bestmatch;
659 }
660 if (matchcount == 1 && bestmatchsize == XSTRING (file)->size)
661 return Qt;
662 bestmatch = Fsubstring (bestmatch, make_number (0),
663 make_number (bestmatchsize));
664 /* Now that we got the right initial segment of BESTMATCH,
665 decode it from the coding system in use. */
666 bestmatch = DECODE_FILE (bestmatch);
667 return bestmatch;
668
669 quit:
670 if (d) closedir (d);
671 Vquit_flag = Qnil;
672 return Fsignal (Qquit, Qnil);
673 }
674
675 static int
676 file_name_completion_stat (dirname, dp, st_addr)
677 Lisp_Object dirname;
678 DIRENTRY *dp;
679 struct stat *st_addr;
680 {
681 int len = NAMLEN (dp);
682 int pos = XSTRING (dirname)->size;
683 int value;
684 char *fullname = (char *) alloca (len + pos + 2);
685
686 #ifdef MSDOS
687 #if __DJGPP__ > 1
688 /* Some fields of struct stat are *very* expensive to compute on MS-DOS,
689 but aren't required here. Avoid computing the following fields:
690 st_inode, st_size and st_nlink for directories, and the execute bits
691 in st_mode for non-directory files with non-standard extensions. */
692
693 unsigned short save_djstat_flags = _djstat_flags;
694
695 _djstat_flags = _STAT_INODE | _STAT_EXEC_MAGIC | _STAT_DIRSIZE;
696 #endif /* __DJGPP__ > 1 */
697 #endif /* MSDOS */
698
699 bcopy (XSTRING (dirname)->data, fullname, pos);
700 #ifndef VMS
701 if (!IS_DIRECTORY_SEP (fullname[pos - 1]))
702 fullname[pos++] = DIRECTORY_SEP;
703 #endif
704
705 bcopy (dp->d_name, fullname + pos, len);
706 fullname[pos + len] = 0;
707
708 #ifdef S_IFLNK
709 /* We want to return success if a link points to a nonexistent file,
710 but we want to return the status for what the link points to,
711 in case it is a directory. */
712 value = lstat (fullname, st_addr);
713 stat (fullname, st_addr);
714 return value;
715 #else
716 value = stat (fullname, st_addr);
717 #ifdef MSDOS
718 #if __DJGPP__ > 1
719 _djstat_flags = save_djstat_flags;
720 #endif /* __DJGPP__ > 1 */
721 #endif /* MSDOS */
722 return value;
723 #endif /* S_IFLNK */
724 }
725 \f
726 #ifdef VMS
727
728 DEFUN ("file-name-all-versions", Ffile_name_all_versions,
729 Sfile_name_all_versions, 2, 2, 0,
730 "Return a list of all versions of file name FILE in directory DIRECTORY.")
731 (file, directory)
732 Lisp_Object file, directory;
733 {
734 return file_name_completion (file, directory, 1, 1);
735 }
736
737 DEFUN ("file-version-limit", Ffile_version_limit, Sfile_version_limit, 1, 1, 0,
738 "Return the maximum number of versions allowed for FILE.\n\
739 Returns nil if the file cannot be opened or if there is no version limit.")
740 (filename)
741 Lisp_Object filename;
742 {
743 Lisp_Object retval;
744 struct FAB fab;
745 struct RAB rab;
746 struct XABFHC xabfhc;
747 int status;
748
749 filename = Fexpand_file_name (filename, Qnil);
750 fab = cc$rms_fab;
751 xabfhc = cc$rms_xabfhc;
752 fab.fab$l_fna = XSTRING (filename)->data;
753 fab.fab$b_fns = strlen (fab.fab$l_fna);
754 fab.fab$l_xab = (char *) &xabfhc;
755 status = sys$open (&fab, 0, 0);
756 if (status != RMS$_NORMAL) /* Probably non-existent file */
757 return Qnil;
758 sys$close (&fab, 0, 0);
759 if (xabfhc.xab$w_verlimit == 32767)
760 return Qnil; /* No version limit */
761 else
762 return make_number (xabfhc.xab$w_verlimit);
763 }
764
765 #endif /* VMS */
766 \f
767 Lisp_Object
768 make_time (time)
769 time_t time;
770 {
771 return Fcons (make_number (time >> 16),
772 Fcons (make_number (time & 0177777), Qnil));
773 }
774
775 DEFUN ("file-attributes", Ffile_attributes, Sfile_attributes, 1, 1, 0,
776 "Return a list of attributes of file FILENAME.\n\
777 Value is nil if specified file cannot be opened.\n\
778 Otherwise, list elements are:\n\
779 0. t for directory, string (name linked to) for symbolic link, or nil.\n\
780 1. Number of links to file.\n\
781 2. File uid.\n\
782 3. File gid.\n\
783 4. Last access time, as a list of two integers.\n\
784 First integer has high-order 16 bits of time, second has low 16 bits.\n\
785 5. Last modification time, likewise.\n\
786 6. Last status change time, likewise.\n\
787 7. Size in bytes.\n\
788 This is a floating point number if the size is too large for an integer.\n\
789 8. File modes, as a string of ten letters or dashes as in ls -l.\n\
790 9. t iff file's gid would change if file were deleted and recreated.\n\
791 10. inode number. If inode number is larger than the Emacs integer,\n\
792 this is a cons cell containing two integers: first the high part,\n\
793 then the low 16 bits.\n\
794 11. Device number.\n\
795 \n\
796 If file does not exist, returns nil.")
797 (filename)
798 Lisp_Object filename;
799 {
800 Lisp_Object values[12];
801 Lisp_Object dirname;
802 Lisp_Object encoded;
803 struct stat s;
804 struct stat sdir;
805 char modes[10];
806 Lisp_Object handler;
807
808 filename = Fexpand_file_name (filename, Qnil);
809
810 /* If the file name has special constructs in it,
811 call the corresponding file handler. */
812 handler = Ffind_file_name_handler (filename, Qfile_attributes);
813 if (!NILP (handler))
814 return call2 (handler, Qfile_attributes, filename);
815
816 encoded = ENCODE_FILE (filename);
817
818 if (lstat (XSTRING (encoded)->data, &s) < 0)
819 return Qnil;
820
821 switch (s.st_mode & S_IFMT)
822 {
823 default:
824 values[0] = Qnil; break;
825 case S_IFDIR:
826 values[0] = Qt; break;
827 #ifdef S_IFLNK
828 case S_IFLNK:
829 values[0] = Ffile_symlink_p (filename); break;
830 #endif
831 }
832 values[1] = make_number (s.st_nlink);
833 values[2] = make_number (s.st_uid);
834 values[3] = make_number (s.st_gid);
835 values[4] = make_time (s.st_atime);
836 values[5] = make_time (s.st_mtime);
837 values[6] = make_time (s.st_ctime);
838 values[7] = make_number (s.st_size);
839 /* If the size is out of range for an integer, return a float. */
840 if (XINT (values[7]) != s.st_size)
841 values[7] = make_float ((double)s.st_size);
842 filemodestring (&s, modes);
843 values[8] = make_string (modes, 10);
844 #ifdef BSD4_3 /* Gross kludge to avoid lack of "#if defined(...)" in VMS */
845 #define BSD4_2 /* A new meaning to the term `backwards compatibility' */
846 #endif
847 #ifdef BSD4_2 /* file gid will be dir gid */
848 dirname = Ffile_name_directory (filename);
849 if (! NILP (dirname))
850 encoded = ENCODE_FILE (dirname);
851 if (! NILP (dirname) && stat (XSTRING (encoded)->data, &sdir) == 0)
852 values[9] = (sdir.st_gid != s.st_gid) ? Qt : Qnil;
853 else /* if we can't tell, assume worst */
854 values[9] = Qt;
855 #else /* file gid will be egid */
856 values[9] = (s.st_gid != getegid ()) ? Qt : Qnil;
857 #endif /* BSD4_2 (or BSD4_3) */
858 #ifdef BSD4_3
859 #undef BSD4_2 /* ok, you can look again without throwing up */
860 #endif
861 /* Cast -1 to avoid warning if int is not as wide as VALBITS. */
862 if (s.st_ino & (((EMACS_INT) (-1)) << VALBITS))
863 /* To allow inode numbers larger than VALBITS, separate the bottom
864 16 bits. */
865 values[10] = Fcons (make_number (s.st_ino >> 16),
866 make_number (s.st_ino & 0xffff));
867 else
868 /* But keep the most common cases as integers. */
869 values[10] = make_number (s.st_ino);
870
871 /* Likewise for device. */
872 if (s.st_dev & (((EMACS_INT) (-1)) << VALBITS))
873 values[11] = Fcons (make_number (s.st_dev >> 16),
874 make_number (s.st_dev & 0xffff));
875 else
876 values[11] = make_number (s.st_dev);
877
878 return Flist (sizeof(values) / sizeof(values[0]), values);
879 }
880
881 DEFUN ("file-attributes-lessp", Ffile_attributes_lessp, Sfile_attributes_lessp, 2, 2, 0,
882 "Return t if first arg file attributes list is less than second.\n\
883 Comparison is in lexicographic order and case is significant.")
884 (f1, f2)
885 Lisp_Object f1, f2;
886 {
887 return Fstring_lessp (Fcar (f1), Fcar (f2));
888 }
889 \f
890 void
891 syms_of_dired ()
892 {
893 Qdirectory_files = intern ("directory-files");
894 Qdirectory_files_and_attributes = intern ("directory-files-and-attributes");
895 Qfile_name_completion = intern ("file-name-completion");
896 Qfile_name_all_completions = intern ("file-name-all-completions");
897 Qfile_attributes = intern ("file-attributes");
898 Qfile_attributes_lessp = intern ("file-attributes-lessp");
899
900 staticpro (&Qdirectory_files);
901 staticpro (&Qdirectory_files_and_attributes);
902 staticpro (&Qfile_name_completion);
903 staticpro (&Qfile_name_all_completions);
904 staticpro (&Qfile_attributes);
905 staticpro (&Qfile_attributes_lessp);
906
907 defsubr (&Sdirectory_files);
908 defsubr (&Sdirectory_files_and_attributes);
909 defsubr (&Sfile_name_completion);
910 #ifdef VMS
911 defsubr (&Sfile_name_all_versions);
912 defsubr (&Sfile_version_limit);
913 #endif /* VMS */
914 defsubr (&Sfile_name_all_completions);
915 defsubr (&Sfile_attributes);
916 defsubr (&Sfile_attributes_lessp);
917
918 #ifdef VMS
919 Qcompletion_ignore_case = intern ("completion-ignore-case");
920 staticpro (&Qcompletion_ignore_case);
921 #endif /* VMS */
922
923 DEFVAR_LISP ("completion-ignored-extensions", &Vcompletion_ignored_extensions,
924 "*Completion ignores filenames ending in any string in this list.\n\
925 This variable does not affect lists of possible completions,\n\
926 but does affect the commands that actually do completions.");
927 Vcompletion_ignored_extensions = Qnil;
928 }