X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/dfcf069d565c347abf3cb7cec80e6ed8432037ba..563b67aafd1cdfa239c5ce1f6d3d6fc5567dee39:/src/dired.c diff --git a/src/dired.c b/src/dired.c index 2e72c4706d..bedda2a7f1 100644 --- a/src/dired.c +++ b/src/dired.c @@ -1,5 +1,5 @@ /* Lisp functions for making directory listings. - Copyright (C) 1985, 1986, 1993, 1994 Free Software Foundation, Inc. + Copyright (C) 1985, 1986, 1993, 1994, 1999 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -25,6 +25,8 @@ Boston, MA 02111-1307, USA. */ #include #include +#include "systime.h" + #ifdef VMS #include #include @@ -64,6 +66,8 @@ Boston, MA 02111-1307, USA. */ #endif #endif /* not NONSYSTEM_DIR_LIBRARY */ +#include + #ifndef MSDOS #define DIRENTRY struct direct @@ -89,6 +93,9 @@ extern struct direct *readdir (); /* Returns a search buffer, with a fastmap allocated and ready to go. */ extern struct re_pattern_buffer *compile_pattern (); +/* From filemode.c. Can't go in Lisp.h because of `stat'. */ +extern void filemodestring P_ ((struct stat *, char *)); + #define min(a, b) ((a) < (b) ? (a) : (b)) /* if system does not have symbolic links, it does not have lstat. @@ -105,20 +112,19 @@ extern Lisp_Object Vfile_name_coding_system, Vdefault_file_name_coding_system; Lisp_Object Vcompletion_ignored_extensions; Lisp_Object Qcompletion_ignore_case; Lisp_Object Qdirectory_files; +Lisp_Object Qdirectory_files_and_attributes; Lisp_Object Qfile_name_completion; Lisp_Object Qfile_name_all_completions; Lisp_Object Qfile_attributes; +Lisp_Object Qfile_attributes_lessp; -DEFUN ("directory-files", Fdirectory_files, Sdirectory_files, 1, 4, 0, - "Return a list of names of files in DIRECTORY.\n\ -There are three optional arguments:\n\ -If FULL is non-nil, return absolute file names. Otherwise return names\n\ - that are relative to the specified directory.\n\ -If MATCH is non-nil, mention only file names that match the regexp MATCH.\n\ -If NOSORT is non-nil, the list is not sorted--its order is unpredictable.\n\ - NOSORT is useful if you plan to sort the result yourself.") - (directory, full, match, nosort) +/* Function shared by Fdirectory_files and Fdirectory_files_and_attributes. + When ATTRS is zero, return a list of directory filenames; when + non-zero, return a list of directory filenames and their attributes. */ +Lisp_Object +directory_files_internal (directory, full, match, nosort, attrs) Lisp_Object directory, full, match, nosort; + int attrs; { DIR *d; int dirnamelen; @@ -129,22 +135,6 @@ If NOSORT is non-nil, the list is not sorted--its order is unpredictable.\n\ int needsep = 0; struct gcpro gcpro1, gcpro2; - /* If the file name has special constructs in it, - call the corresponding file handler. */ - handler = Ffind_file_name_handler (directory, Qdirectory_files); - if (!NILP (handler)) - { - Lisp_Object args[6]; - - args[0] = handler; - args[1] = Qdirectory_files; - args[2] = directory; - args[3] = full; - args[4] = match; - args[5] = nosort; - return Ffuncall (6, args); - } - /* Because of file name handlers, these functions might call Ffuncall, and cause a GC. */ GCPRO1 (match); @@ -187,13 +177,13 @@ If NOSORT is non-nil, the list is not sorted--its order is unpredictable.\n\ report_file_error ("Opening directory", Fcons (directory, Qnil)); list = Qnil; - dirnamelen = STRING_BYTES (XSTRING (encoded_directory)); + dirnamelen = STRING_BYTES (XSTRING (directory)); re_match_object = Qt; /* Decide whether we need to add a directory separator. */ #ifndef VMS if (dirnamelen == 0 - || !IS_ANY_SEP (XSTRING (encoded_directory)->data[dirnamelen - 1])) + || !IS_ANY_SEP (XSTRING (directory)->data[dirnamelen - 1])) needsep = 1; #endif /* not VMS */ @@ -203,39 +193,61 @@ If NOSORT is non-nil, the list is not sorted--its order is unpredictable.\n\ while (1) { DIRENTRY *dp = readdir (d); - int len; if (!dp) break; - len = NAMLEN (dp); if (DIRENTRY_NONEMPTY (dp)) { + int len; + + len = NAMLEN (dp); + name = DECODE_FILE (make_string (dp->d_name, len)); + len = STRING_BYTES (XSTRING (name)); + if (NILP (match) - || (0 <= re_search (bufp, dp->d_name, len, 0, len, 0))) + || (0 <= re_search (bufp, XSTRING (name)->data, len, 0, len, 0))) { + Lisp_Object finalname; + + finalname = name; if (!NILP (full)) { int afterdirindex = dirnamelen; int total = len + dirnamelen; int nchars; + Lisp_Object fullname; - name = make_uninit_multibyte_string (total + needsep, - total + needsep); - bcopy (XSTRING (encoded_directory)->data, XSTRING (name)->data, + fullname = make_uninit_multibyte_string (total + needsep, + total + needsep); + bcopy (XSTRING (directory)->data, XSTRING (fullname)->data, dirnamelen); if (needsep) - XSTRING (name)->data[afterdirindex++] = DIRECTORY_SEP; - bcopy (dp->d_name, - XSTRING (name)->data + afterdirindex, len); - nchars = chars_in_text (XSTRING (name)->data, + XSTRING (fullname)->data[afterdirindex++] = DIRECTORY_SEP; + bcopy (XSTRING (name)->data, + XSTRING (fullname)->data + afterdirindex, len); + nchars = chars_in_text (XSTRING (fullname)->data, afterdirindex + len); - XSTRING (name)->size = nchars; - if (nchars == STRING_BYTES (XSTRING (name))) - SET_STRING_BYTES (XSTRING (name), -1); + XSTRING (fullname)->size = nchars; + if (nchars == STRING_BYTES (XSTRING (fullname))) + SET_STRING_BYTES (XSTRING (fullname), -1); + finalname = fullname; + } + + if (attrs) + { + /* Construct an expanded filename for the directory entry. + Use the decoded names for input to Ffile_attributes. */ + Lisp_Object decoded_fullname; + Lisp_Object fileattrs; + + decoded_fullname = Fexpand_file_name (name, directory); + fileattrs = Ffile_attributes (decoded_fullname); + + list = Fcons (Fcons (finalname, fileattrs), list); } else - name = make_string (dp->d_name, len); - name = DECODE_FILE (name); - list = Fcons (name, list); + { + list = Fcons (finalname, list); + } } } } @@ -243,8 +255,77 @@ If NOSORT is non-nil, the list is not sorted--its order is unpredictable.\n\ UNGCPRO; if (!NILP (nosort)) return list; - return Fsort (Fnreverse (list), Qstring_lessp); + if (attrs) + return Fsort (Fnreverse (list), Qfile_attributes_lessp); + else + return Fsort (Fnreverse (list), Qstring_lessp); +} + + +DEFUN ("directory-files", Fdirectory_files, Sdirectory_files, 1, 4, 0, + "Return a list of names of files in DIRECTORY.\n\ +There are three optional arguments:\n\ +If FULL is non-nil, return absolute file names. Otherwise return names\n\ + that are relative to the specified directory.\n\ +If MATCH is non-nil, mention only file names that match the regexp MATCH.\n\ +If NOSORT is non-nil, the list is not sorted--its order is unpredictable.\n\ + NOSORT is useful if you plan to sort the result yourself.") + (directory, full, match, nosort) + Lisp_Object directory, full, match, nosort; +{ + Lisp_Object handler; + + /* If the file name has special constructs in it, + call the corresponding file handler. */ + handler = Ffind_file_name_handler (directory, Qdirectory_files); + if (!NILP (handler)) + { + Lisp_Object args[6]; + + args[0] = handler; + args[1] = Qdirectory_files; + args[2] = directory; + args[3] = full; + args[4] = match; + args[5] = nosort; + return Ffuncall (6, args); + } + + return directory_files_internal (directory, full, match, nosort, 0); } + +DEFUN ("directory-files-and-attributes", Fdirectory_files_and_attributes, Sdirectory_files_and_attributes, 1, 4, 0, + "Return a list of names of files and their attributes in DIRECTORY.\n\ +There are three optional arguments:\n\ +If FULL is non-nil, return absolute file names. Otherwise return names\n\ + that are relative to the specified directory.\n\ +If MATCH is non-nil, mention only file names that match the regexp MATCH.\n\ +If NOSORT is non-nil, the list is not sorted--its order is unpredictable.\n\ + NOSORT is useful if you plan to sort the result yourself.") + (directory, full, match, nosort) + Lisp_Object directory, full, match, nosort; +{ + Lisp_Object handler; + + /* If the file name has special constructs in it, + call the corresponding file handler. */ + handler = Ffind_file_name_handler (directory, Qdirectory_files_and_attributes); + if (!NILP (handler)) + { + Lisp_Object args[6]; + + args[0] = handler; + args[1] = Qdirectory_files_and_attributes; + args[2] = directory; + args[3] = full; + args[4] = match; + args[5] = nosort; + return Ffuncall (6, args); + } + + return directory_files_internal (directory, full, match, nosort, 1); +} + Lisp_Object file_name_completion (); @@ -412,9 +493,9 @@ file_name_completion (file, dirname, all_flag, ver_flag) if (!passcount && len > XSTRING (encoded_file)->size) /* and exit this for loop if a match is found */ for (tem = Vcompletion_ignored_extensions; - CONSP (tem); tem = XCONS (tem)->cdr) + CONSP (tem); tem = XCDR (tem)) { - elt = XCONS (tem)->car; + elt = XCAR (tem); if (!STRINGP (elt)) continue; skip = len - XSTRING (elt)->size; if (skip < 0) continue; @@ -440,9 +521,9 @@ file_name_completion (file, dirname, all_flag, ver_flag) /* Ignore this element if it fails to match all the regexps. */ for (regexps = Vcompletion_regexp_list; CONSP (regexps); - regexps = XCONS (regexps)->cdr) + regexps = XCDR (regexps)) { - tem = Fstring_match (XCONS (regexps)->car, elt, zero); + tem = Fstring_match (XCAR (regexps), elt, zero); if (NILP (tem)) break; } @@ -647,7 +728,7 @@ Returns nil if the file cannot be opened or if there is no version limit.") Lisp_Object make_time (time) - int time; + time_t time; { return Fcons (make_number (time >> 16), Fcons (make_number (time & 0177777), Qnil)); @@ -665,10 +746,13 @@ Otherwise, list elements are:\n\ First integer has high-order 16 bits of time, second has low 16 bits.\n\ 5. Last modification time, likewise.\n\ 6. Last status change time, likewise.\n\ - 7. Size in bytes (-1, if number is out of range).\n\ + 7. Size in bytes.\n\ + This is a floating point number if the size is too large for an integer.\n\ 8. File modes, as a string of ten letters or dashes as in ls -l.\n\ 9. t iff file's gid would change if file were deleted and recreated.\n\ -10. inode number.\n\ +10. inode number. If inode number is larger than the Emacs integer,\n\ + this is a cons cell containing two integers: first the high part,\n\ + then the low 16 bits.\n\ 11. Device number.\n\ \n\ If file does not exist, returns nil.") @@ -713,10 +797,10 @@ If file does not exist, returns nil.") values[4] = make_time (s.st_atime); values[5] = make_time (s.st_mtime); values[6] = make_time (s.st_ctime); - values[7] = make_number ((int) s.st_size); - /* If the size is out of range, give back -1. */ + values[7] = make_number (s.st_size); + /* If the size is out of range for an integer, return a float. */ if (XINT (values[7]) != s.st_size) - XSETINT (values[7], -1); + values[7] = make_float ((double)s.st_size); filemodestring (&s, modes); values[8] = make_string (modes, 10); #ifdef BSD4_3 /* Gross kludge to avoid lack of "#if defined(...)" in VMS */ @@ -745,24 +829,45 @@ If file does not exist, returns nil.") else /* But keep the most common cases as integers. */ values[10] = make_number (s.st_ino); - values[11] = make_number (s.st_dev); + + /* Likewise for device. */ + if (s.st_dev & (((EMACS_INT) (-1)) << VALBITS)) + values[11] = Fcons (make_number (s.st_dev >> 16), + make_number (s.st_dev & 0xffff)); + else + values[11] = make_number (s.st_dev); + return Flist (sizeof(values) / sizeof(values[0]), values); } + +DEFUN ("file-attributes-lessp", Ffile_attributes_lessp, Sfile_attributes_lessp, 2, 2, 0, + "Return t if first arg file attributes list is less than second.\n\ +Comparison is in lexicographic order and case is significant.") + (f1, f2) + Lisp_Object f1, f2; +{ + return Fstring_lessp (Fcar (f1), Fcar (f2)); +} void syms_of_dired () { Qdirectory_files = intern ("directory-files"); + Qdirectory_files_and_attributes = intern ("directory-files-and-attributes"); Qfile_name_completion = intern ("file-name-completion"); Qfile_name_all_completions = intern ("file-name-all-completions"); Qfile_attributes = intern ("file-attributes"); + Qfile_attributes_lessp = intern ("file-attributes-lessp"); staticpro (&Qdirectory_files); + staticpro (&Qdirectory_files_and_attributes); staticpro (&Qfile_name_completion); staticpro (&Qfile_name_all_completions); staticpro (&Qfile_attributes); + staticpro (&Qfile_attributes_lessp); defsubr (&Sdirectory_files); + defsubr (&Sdirectory_files_and_attributes); defsubr (&Sfile_name_completion); #ifdef VMS defsubr (&Sfile_name_all_versions); @@ -770,6 +875,7 @@ syms_of_dired () #endif /* VMS */ defsubr (&Sfile_name_all_completions); defsubr (&Sfile_attributes); + defsubr (&Sfile_attributes_lessp); #ifdef VMS Qcompletion_ignore_case = intern ("completion-ignore-case");