Annotation of 43BSD/contrib/emacs/src/dired.c, revision 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.