|
|
1.1 ! root 1: /* Lisp functions for making directory listings. ! 2: Copyright (C) 1985 Richard M. Stallman. ! 3: ! 4: This file is part of GNU Emacs. ! 5: ! 6: GNU Emacs is distributed in the hope that it will be useful, ! 7: but WITHOUT ANY WARRANTY. No author or distributor ! 8: accepts responsibility to anyone for the consequences of using it ! 9: or for whether it serves any particular purpose or works at all, ! 10: unless he says so in writing. Refer to the GNU Emacs General Public ! 11: License for full details. ! 12: ! 13: Everyone is granted permission to copy, modify and redistribute ! 14: GNU Emacs, but only under the conditions described in the ! 15: GNU Emacs General Public License. A copy of this license is ! 16: supposed to have been given to you along with GNU Emacs so you ! 17: can know your rights and responsibilities. It should be in a ! 18: file named COPYING. Among other things, the copyright notice ! 19: and this notice must be preserved on all copies. */ ! 20: ! 21: ! 22: #include <stdio.h> ! 23: #include <sys/types.h> ! 24: #include <sys/stat.h> ! 25: ! 26: #include "config.h" ! 27: ! 28: #ifdef NONSYSTEM_DIR_LIBRARY ! 29: #include "ndir.h" ! 30: #else /* not NONSYSTEM_DIR_LIBRARY */ ! 31: #include <sys/dir.h> ! 32: #endif /* not NONSYSTEM_DIR_LIBRARY */ ! 33: ! 34: #undef NULL ! 35: ! 36: #include "lisp.h" ! 37: #include "buffer.h" ! 38: #include "commands.h" ! 39: ! 40: #define min(a, b) ((a) < (b) ? (a) : (b)) ! 41: ! 42: /* if system does not have symbolic links, it does not have lstat. ! 43: In that case, use ordinary stat instead. */ ! 44: ! 45: #ifndef S_IFLNK ! 46: #define lstat stat ! 47: #endif ! 48: ! 49: extern DIR *opendir (); ! 50: extern struct direct *readdir (); ! 51: ! 52: Lisp_Object Vcompletion_ignored_extensions; ! 53: ! 54: DEFUN ("directory-files", Fdirectory_files, Sdirectory_files, 1, 2, 0, ! 55: "Return a list of names of files in DIRECTORY.\n\ ! 56: If FULL is non-NIL, absolute pathnames of the files are returned.") ! 57: (dirname, full) ! 58: Lisp_Object dirname, full; ! 59: { ! 60: DIR *d; ! 61: struct direct *dp; ! 62: char slashfilename[MAXNAMLEN+2]; ! 63: char *filename = slashfilename; ! 64: int length; ! 65: Lisp_Object list, name; ! 66: ! 67: dirname = Fexpand_file_name (dirname, Qnil); ! 68: if (!(d = opendir (XSTRING (dirname)->data))) ! 69: report_file_error ("Opening directory", Fcons (dirname, Qnil)); ! 70: ! 71: list = Qnil; ! 72: length = XSTRING (dirname)->size; ! 73: if (length == 0 || XSTRING (dirname)->data[length - 1] != '/') ! 74: *filename++ = '/'; ! 75: ! 76: /* Loop reading blocks */ ! 77: while (1) ! 78: { ! 79: dp = readdir (d); ! 80: if (!dp) break; ! 81: if (dp->d_ino) ! 82: { ! 83: strncpy (filename, dp->d_name, dp->d_namlen); ! 84: filename[dp->d_namlen] = 0; ! 85: if (!NULL (full)) ! 86: name = concat2 (dirname, build_string (slashfilename)); ! 87: else ! 88: name = build_string (filename); ! 89: list = Fcons (name, list); ! 90: } ! 91: } ! 92: closedir (d); ! 93: return Fsort (Fnreverse (list), Qstring_lessp); ! 94: } ! 95: ! 96: Lisp_Object file_name_completion (); ! 97: ! 98: DEFUN ("file-name-completion", Ffile_name_completion, Sfile_name_completion, ! 99: 2, 2, 0, ! 100: "Complete file name FILE in directory DIR.\n\ ! 101: Returns the longest string common to all filenames in DIR\n\ ! 102: that start with FILE.\n\ ! 103: If there is only one and FILE matches it exactly, returns t.\n\ ! 104: Returns nil if DIR contains no name starting with FILE.") ! 105: (file, dirname) ! 106: Lisp_Object file, dirname; ! 107: { ! 108: /* Don't waste time trying to complete a null string. ! 109: Besides, this case happens when user is being asked for ! 110: a directory name and has supplied one ending in a /. ! 111: We would not want to add anything in that case ! 112: even if there are some unique characters in that directory. */ ! 113: if (XTYPE (file) == Lisp_String && XSTRING (file)->size == 0) ! 114: return file; ! 115: return file_name_completion (file, dirname, 0); ! 116: } ! 117: ! 118: DEFUN ("file-name-all-completions", Ffile_name_all_completions, ! 119: Sfile_name_all_completions, 2, 2, 0, ! 120: "Return a list of all completions of file name FILE in directory DIR.") ! 121: (file, dirname) ! 122: Lisp_Object file, dirname; ! 123: { ! 124: return file_name_completion (file, dirname, 1); ! 125: } ! 126: ! 127: Lisp_Object ! 128: file_name_completion (file, dirname, all_flag) ! 129: Lisp_Object file, dirname; ! 130: int all_flag; ! 131: { ! 132: DIR *d; ! 133: struct direct *dp; ! 134: int bestmatchsize, skip; ! 135: register int compare, matchsize; ! 136: unsigned char *p1, *p2; ! 137: int matchcount = 0; ! 138: Lisp_Object bestmatch, tem, elt, name; ! 139: struct stat st; ! 140: int directoryp; ! 141: int passcount; ! 142: ! 143: dirname = Fexpand_file_name (dirname, Qnil); ! 144: bestmatch = Qnil; ! 145: ! 146: /* passcount = 0, ignore files that end in an ignored extension. ! 147: If nothing found then try again with passcount = 1, don't ignore them. ! 148: If looking for all completions, start with passcount = 1, ! 149: so always take even the ignored ones. */ ! 150: for (passcount = !!all_flag; NULL (bestmatch) && passcount < 2; passcount++) ! 151: { ! 152: if (!(d = opendir (XSTRING (dirname)->data))) ! 153: report_file_error ("Opening directory", Fcons (dirname, Qnil)); ! 154: ! 155: /* Loop reading blocks */ ! 156: while (dp = readdir (d)) ! 157: { ! 158: if (!NULL (Vquit_flag) && NULL (Vinhibit_quit)) ! 159: goto quit; ! 160: if (!dp->d_ino || ! 161: dp->d_namlen < XSTRING (file)->size || ! 162: bcmp (dp->d_name, XSTRING (file)->data, XSTRING (file)->size)) ! 163: continue; ! 164: ! 165: tem = Qnil; ! 166: /* Compare extensions-to-be-ignored against end of this file name */ ! 167: /* if name is not an exact match against specified string */ ! 168: if (!passcount && dp->d_namlen > XSTRING (file)->size) ! 169: /* and exit this for loop if a match is found */ ! 170: for (tem = Vcompletion_ignored_extensions; ! 171: LISTP (tem); tem = XCONS (tem)->cdr) ! 172: { ! 173: elt = XCONS (tem)->car; ! 174: if (XTYPE (elt) != Lisp_String) continue; ! 175: skip = dp->d_namlen - XSTRING (elt)->size; ! 176: if (skip < 0) continue; ! 177: ! 178: if (bcmp (dp->d_name + skip, ! 179: XSTRING (elt)->data, ! 180: XSTRING (elt)->size)) ! 181: continue; ! 182: break; ! 183: } ! 184: ! 185: /* Unless a match was found, process this name as a completion */ ! 186: if ((passcount || NULL (tem)) ! 187: && file_name_completion_stat (dirname, dp, &st) >= 0) ! 188: { ! 189: /* Update computation of how much all possible completions match */ ! 190: ! 191: matchcount++; ! 192: directoryp = ((st.st_mode & S_IFMT) == S_IFDIR); ! 193: if (all_flag || NULL (bestmatch)) ! 194: { ! 195: /* This is a possible completion */ ! 196: if (directoryp) ! 197: { ! 198: /* This completion is a directory; make it end with '/' */ ! 199: name = make_string (dp->d_name, dp->d_namlen + 1); ! 200: XSTRING (name)->data[dp->d_namlen] = '/'; ! 201: } ! 202: else ! 203: name = make_string (dp->d_name, dp->d_namlen); ! 204: if (all_flag) ! 205: { ! 206: bestmatch = Fcons (name, bestmatch); ! 207: } ! 208: else ! 209: { ! 210: bestmatch = name; ! 211: bestmatchsize = XSTRING (name)->size; ! 212: } ! 213: } ! 214: else ! 215: { ! 216: compare = min (bestmatchsize, dp->d_namlen); ! 217: p1 = XSTRING (bestmatch)->data; ! 218: p2 = (unsigned char *) dp->d_name; ! 219: for (matchsize = 0; matchsize < compare; matchsize++) ! 220: if (p1[matchsize] != p2[matchsize]) break; ! 221: /* If this dirname all matches, ! 222: see if implicit following slash does too. */ ! 223: if (directoryp && ! 224: compare == matchsize && ! 225: bestmatchsize > matchsize && ! 226: p1[matchsize] == '/') ! 227: matchsize++; ! 228: bestmatchsize = min (matchsize, bestmatchsize); ! 229: } ! 230: } ! 231: } ! 232: closedir (d); ! 233: } ! 234: ! 235: if (all_flag || NULL (bestmatch)) ! 236: return bestmatch; ! 237: if (matchcount == 1 && bestmatchsize == XSTRING (file)->size) ! 238: return Qt; ! 239: return Fsubstring (bestmatch, make_number (0), make_number (bestmatchsize)); ! 240: quit: ! 241: if (d) closedir (d); ! 242: Vquit_flag = Qnil; ! 243: return Fsignal (Qquit, Qnil); ! 244: } ! 245: ! 246: file_name_completion_stat (dirname, dp, st_addr) ! 247: Lisp_Object dirname; ! 248: struct direct *dp; ! 249: struct stat *st_addr; ! 250: { ! 251: char *fullname = (char *) alloca (dp->d_namlen + XSTRING (dirname)->size + 2); ! 252: int pos = XSTRING (dirname)->size; ! 253: ! 254: bcopy (XSTRING (dirname)->data, fullname, pos); ! 255: if (fullname[pos - 1] != '/') ! 256: fullname[pos++] = '/'; ! 257: ! 258: bcopy (dp->d_name, fullname + pos, dp->d_namlen); ! 259: fullname[pos + dp->d_namlen] = 0; ! 260: ! 261: return stat (fullname, st_addr); ! 262: } ! 263: ! 264: Lisp_Object ! 265: make_time (time) ! 266: int time; ! 267: { ! 268: return Fcons (make_number (time >> 16), ! 269: Fcons (make_number (time & 0177777), Qnil)); ! 270: } ! 271: ! 272: DEFUN ("file-attributes", Ffile_attributes, Sfile_attributes, 1, 1, 0, ! 273: "Return a list of attributes of file FILENAME.\n\ ! 274: Elements are:\n\ ! 275: 0. t for directory, string (name linked to) for symbolic link, or nil.\n\ ! 276: 1. Number of links to file.\n\ ! 277: 2. File uid.\n\ ! 278: 3. File gid.\n\ ! 279: 4. Last access time, as a list of two integers.\n\ ! 280: First integer has high-order 16 bits of time, second has low 16 bits.\n\ ! 281: 5. Last modification time, likewise.\n\ ! 282: 6. Last status change time, likewise.\n\ ! 283: 7. Size in bytes.\n\ ! 284: 8. File modes, as a string of nine letters or dashes as in ls -l.") ! 285: (filename) ! 286: Lisp_Object filename; ! 287: { ! 288: Lisp_Object values[9]; ! 289: struct stat s; ! 290: char modes[10]; ! 291: ! 292: filename = Fexpand_file_name (filename, Qnil); ! 293: if (lstat(XSTRING (filename)->data, &s)<0) ! 294: return Qnil; ! 295: ! 296: values[0] = ((s.st_mode & S_IFMT)==S_IFDIR) ? Qt : Qnil; ! 297: #ifdef S_IFLNK ! 298: if ((s.st_mode & S_IFMT) == S_IFLNK) ! 299: values[0] = Ffile_symlink_p (filename); ! 300: #endif ! 301: XFASTINT (values[1]) = s.st_nlink; ! 302: XFASTINT (values[2]) = s.st_uid; ! 303: XFASTINT (values[3]) = s.st_gid; ! 304: values[4] = make_time(s.st_atime); ! 305: values[5] = make_time(s.st_mtime); ! 306: values[6] = make_time(s.st_ctime); ! 307: XFASTINT (values[7]) = s.st_size; ! 308: filemodestring (&s, modes); ! 309: values[8] = make_string (modes, 10); ! 310: return Flist (9, values); ! 311: } ! 312: ! 313: syms_of_dired () ! 314: { ! 315: defsubr (&Sdirectory_files); ! 316: defsubr (&Sfile_name_completion); ! 317: defsubr (&Sfile_name_all_completions); ! 318: defsubr (&Sfile_attributes); ! 319: ! 320: DefLispVar ("completion-ignored-extensions", &Vcompletion_ignored_extensions, ! 321: "*Completion ignores filenames ending in any string in this list."); ! 322: Vcompletion_ignored_extensions = Qnil; ! 323: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.