Mercurial > octave-nkf
changeset 19232: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 | 09bc8304f182 |
children | 3a6fd52e1458 |
files | scripts/miscellaneous/dir.m scripts/miscellaneous/ls.m |
diffstat | 2 files changed, 111 insertions(+), 82 deletions(-) [+] |
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%_"); +
--- a/scripts/miscellaneous/ls.m Wed Oct 01 07:51:43 2014 -0700 +++ b/scripts/miscellaneous/ls.m Wed Oct 01 10:58:03 2014 -0700 @@ -18,10 +18,26 @@ ## -*- texinfo -*- ## @deftypefn {Command} {} ls -## @deftypefnx {Command} {} ls filenames -## @deftypefnx {Command} {} ls options -## @deftypefnx {Command} {} ls options filenames -## List directory contents. For example: +## @deftypefnx {Command} {} ls @var{filenames} +## @deftypefnx {Command} {} ls @var{options} +## @deftypefnx {Command} {} ls @var{options} @var{filenames} +## @deftypefnx {Function File} {@var{list} =} ls (@dots{}) +## +## List directory contents. +## +## The @code{ls} command is implemented by calling the native operating +## system's directory listing command---available @var{options} will vary from +## system to system. +## +## Filenames are subject to shell expansion if they contain any wildcard +## characters @samp{*}, @samp{?}, @samp{[]}. To find a literal example of a +## wildcard character the wildcard must be escaped using the backslash operator +## @samp{\}. +## +## If the optional output @var{list} is requested then @code{ls} returns a +## character array with one row for each file/directory name. +## +## Example usage on a UNIX-like system: ## ## @example ## @group @@ -32,14 +48,6 @@ ## @end group ## @end example ## -## The @code{dir} and @code{ls} commands are implemented by calling your -## system's directory listing command, so the available options will vary -## from system to system. -## -## Filenames are subject to shell expansion if they contain 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{\}. ## @seealso{dir, readdir, glob, what, stat, filesep, ls_command} ## @end deftypefn @@ -50,8 +58,7 @@ global __ls_command__; if (isempty (__ls_command__) || ! ischar (__ls_command__)) - ## Initialize value for __ls_command__. - ls_command (); + ls_command (); # Initialize global value for __ls_command__. endif if (! iscellstr (varargin)) @@ -75,7 +82,7 @@ args = ""; endif - cmd = sprintf ("%s %s", __ls_command__, args); + cmd = [__ls_command__ args]; if (page_screen_output () || nargout > 0) [status, output] = system (cmd); @@ -84,8 +91,6 @@ error ("ls: command exited abnormally with status %d\n", status); elseif (nargout == 0) puts (output); - elseif (isempty (output)) - retval = ""; else retval = strvcat (regexp (output, '\S+', 'match'){:}); endif @@ -104,5 +109,7 @@ %! assert (ischar (list)); %! assert (! isempty (list)); -%!error ls (1) +%!error <all arguments must be character strings> ls (1) +## Test below is valid, but produces confusing output on screen +%!#error <command exited abnormally> ls ("-!")