Annotation of 43BSD/contrib/emacs/src/dired.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.