Mercurial > octave
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%_"); +