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: }

Defined functions

DEFUN defined in line 272; never used
file_name_completion defined in line 127; used 3 times
file_name_completion_stat defined in line 246; used 1 times
make_time defined in line 264; used 3 times
syms_of_dired defined in line 313; used 1 times

Defined variables

Vcompletion_ignored_extensions defined in line 52; used 3 times

Defined macros

lstat defined in line 46; used 1 times
min defined in line 40; used 2 times
Last modified: 1986-03-12
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1289
Valid CSS Valid XHTML 1.0 Strict