diff scripts/miscellaneous/dir.m @ 19198:931cc13a6f3b

Rework ls.m and dir.m * dir.m: Improve docstring. Place input validation first. Use numel in place of length for clarity. Add BIST tests. * ls.m: Improve docstring. Use interpreter to concatenate strings rather than sprintf. Eliminate unnecessary test for empty retval, strvcat works with empty inputs. Add expected error outpu to %!error test.
author Rik <rik@octave.org>
date Wed, 01 Oct 2014 10:58:03 -0700
parents 7df8f5372ea8
children 0e1f5a750d00
line wrap: on
line diff
--- a/scripts/miscellaneous/dir.m	Wed Oct 01 07:51:43 2014 -0700
+++ b/scripts/miscellaneous/dir.m	Wed Oct 01 10:58:03 2014 -0700
@@ -51,21 +51,21 @@
 ## than a single directory or file.
 ##
 ## @var{directory} is subject to shell expansion if it contains any wildcard
-## characters @samp{*}, @samp{?}, @samp{[]}.  If you want to find a
-## literal example of a wildcard character you must escape it using the
-## backslash operator @samp{\}.
+## characters @samp{*}, @samp{?}, @samp{[]}.  To find a literal example of a
+## wildcard character the wildcard must be escaped using the backslash operator
+## @samp{\}.
 ##
 ## Note that for symbolic links, @code{dir} returns information about
 ## the file that the symbolic link points to rather than the link itself.
 ## However, if the link points to a nonexistent file, @code{dir} returns
 ## information about the link.
-## @seealso{ls, readdir, glob, what, stat}
+## @seealso{ls, readdir, glob, what, stat, lstat}
 ## @end deftypefn
 
 ## Author: jwe
 
-## FIXME: This is quite slow for large directories, so perhaps
-##        it should be converted to C++.
+## FIXME: This is quite slow for large directories.
+##        Perhaps it should be converted to C++?
 
 function retval = dir (directory)
 
@@ -75,79 +75,78 @@
     print_usage ();
   endif
 
+  if (! ischar (directory))
+    error ("dir: DIRECTORY argument must be a string");
+  endif
+
   ## Prep the retval.
   info = struct (zeros (0, 1),
                  {"name", "date", "bytes", "isdir", "datenum", "statinfo"});
 
-  if (ischar (directory))
-    if (strcmp (directory, "*"))
-      directory = ".";
-    endif
-    if (strcmp (directory, "."))
-      flst = {"."};
-      nf = 1;
-    else
-      flst = glob (directory);
-      nf = length (flst);
-    endif
 
-    ## Determine the file list for the case where a single directory is
-    ## specified.
-    if (nf == 1)
-      fn = flst{1};
-      [st, err, msg] = stat (fn);
-      if (err < 0)
-        warning ("dir: 'stat (%s)' failed: %s", fn, msg);
-        nf = 0;
-      elseif (S_ISDIR (st.mode))
-        flst = readdir (flst{1});
-        nf = length (flst);
-        for i = 1:nf
-          flst{i} = fullfile (fn, flst{i});
-        endfor
-      endif
-    endif
+  if (strcmp (directory, "*"))
+    directory = ".";
+  endif
+  if (strcmp (directory, "."))
+    flst = {"."};
+    nf = 1;
+  else
+    flst = glob (directory);
+    nf = numel (flst);
+  endif
 
-    if (length (flst) > 0)
-      ## Collect results.
-      for i = nf:-1:1
-        fn = flst{i};
-        [st, err, msg] = lstat (fn);
-        if (err < 0)
-          warning ("dir: 'lstat (%s)' failed: %s", fn, msg);
-        else
-          ## If we are looking at a link that points to something,
-          ## return info about the target of the link, otherwise, return
-          ## info about the link itself.
-          if (S_ISLNK (st.mode))
-            [xst, err, msg] = stat (fn);
-            if (! err)
-              st = xst;
-            endif
-          endif
-          [dummy, fn, ext] = fileparts (fn);
-          fn = [fn ext];
-          info(i,1).name = fn;
-          lt = localtime (st.mtime);
-          info(i,1).date = strftime ("%d-%b-%Y %T", lt);
-          info(i,1).bytes = st.size;
-          info(i,1).isdir = S_ISDIR (st.mode);
-          info(i,1).datenum = datenum (lt.year + 1900, lt.mon + 1, lt.mday,
-                                       lt.hour, lt.min, lt.sec);
-          info(i,1).statinfo = st;
-        endif
+  ## Determine the file list for the case where a single directory is specified.
+  if (nf == 1)
+    fn = flst{1};
+    [st, err, msg] = stat (fn);
+    if (err < 0)
+      warning ("dir: 'stat (%s)' failed: %s", fn, msg);
+      nf = 0;
+    elseif (S_ISDIR (st.mode))
+      flst = readdir (flst{1});
+      nf = numel (flst);
+      for i = 1:nf
+        flst{i} = fullfile (fn, flst{i});
       endfor
     endif
+  endif
 
-  else
-    error ("dir: expecting directory or filename to be a char array");
+  if (numel (flst) > 0)
+    ## Collect results.
+    for i = nf:-1:1
+      fn = flst{i};
+      [st, err, msg] = lstat (fn);
+      if (err < 0)
+        warning ("dir: 'lstat (%s)' failed: %s", fn, msg);
+      else
+        ## If we are looking at a link that points to something,
+        ## return info about the target of the link, otherwise, return
+        ## info about the link itself.
+        if (S_ISLNK (st.mode))
+          [xst, err, msg] = stat (fn);
+          if (! err)
+            st = xst;
+          endif
+        endif
+        [dummy, fn, ext] = fileparts (fn);
+        fn = [fn ext];
+        info(i,1).name = fn;
+        lt = localtime (st.mtime);
+        info(i,1).date = strftime ("%d-%b-%Y %T", lt);
+        info(i,1).bytes = st.size;
+        info(i,1).isdir = S_ISDIR (st.mode);
+        info(i,1).datenum = datenum (lt.year + 1900, lt.mon + 1, lt.mday,
+                                     lt.hour, lt.min, lt.sec);
+        info(i,1).statinfo = st;
+      endif
+    endfor
   endif
 
   ## Return the output arguments.
   if (nargout > 0)
     ## Return the requested structure.
     retval = info;
-  elseif (length (info) > 0)
+  elseif (numel (info) > 0)
     ## Print the structure to the screen.
     printf ("%s", list_in_columns ({info.name}));
   else
@@ -156,3 +155,26 @@
 
 endfunction
 
+
+%!test
+%! list = dir ();
+%! assert (isstruct (list) && ! isempty (list));
+%! assert (fieldnames (list),
+%!         {"name"; "date"; "bytes"; "isdir"; "datenum"; "statinfo"});
+%!
+%! if (isunix ())
+%!   assert ({list(1:2).name}, {".", ".."});
+%!   assert ([list(1:2).isdir], [true true]);
+%! endif
+%!
+%! ## test that specifying a filename works the same as using a directory.
+%! found = find (! [list.isdir], 1);
+%! if (! isempty (found))
+%!   list2 = dir (list(found).name);
+%!   assert (list(found), list2);
+%! endif
+
+## Test input validation
+%!error <DIRECTORY argument must be a string> dir (1)
+%!warning <nonexistent directory> dir ("_%UNLIKELY_DIR_NAME%_");
+