changeset 20836:ce8c465aa6a4

fileattrib.m: Overhaul file for greater Windows and Matlab compatibility. Add support for Windows attributes like Hidden, System when running on Windows. Return NaN for unsupported group and other permission bits on Windows. * fileattrib.m: Improve docstring. Use default argument in function header to simplify input validation. Move input validation to top of function. Directly build struct array for output rather than creating cell arrays and then calling struct() at end of function. Call system command 'attrib' on Windows platforms to get special attributes. Add BIST tests.
author Rik <rik@octave.org>
date Wed, 09 Dec 2015 15:43:37 -0800
parents 14cd86258b3d
children c54ae1fb7e3b
files scripts/miscellaneous/fileattrib.m
diffstat 1 files changed, 92 insertions(+), 60 deletions(-) [+]
line wrap: on
line diff
--- a/scripts/miscellaneous/fileattrib.m	Wed Dec 09 16:35:12 2015 -0500
+++ b/scripts/miscellaneous/fileattrib.m	Wed Dec 09 15:43:37 2015 -0800
@@ -17,7 +17,9 @@
 ## <http://www.gnu.org/licenses/>.
 
 ## -*- texinfo -*-
-## @deftypefn {Function File} {[@var{status}, @var{result}, @var{msgid}] =} fileattrib (@var{file})
+## @deftypefn  {Function File} {} fileattrib ()
+## @deftypefnx {Function File} {} fileattrib (@var{file})
+## @deftypefnx {Function File} {[@var{status}, @var{msg}, @var{msgid}] =} fileattrib (@var{file})
 ## Return information about @var{file}.
 ##
 ## If successful, @var{status} is 1, with @var{result} containing a structure
@@ -65,78 +67,108 @@
 ## @seealso{glob}
 ## @end deftypefn
 
-function [status, msg, msgid] = fileattrib (file)
+function [status, msg, msgid] = fileattrib (file = ".")
+
+  if (nargin > 1)
+    print_usage ();
+  endif
+
+  if (! ischar (file))
+    error ("fileattrib: FILE must be a string");
+  endif
 
   status = true;
   msg = "";
   msgid = "";
 
-  if (nargin == 0)
-    file = ".";
+  files = glob (file);
+  if (isempty (files))
+    files = {file};
   endif
+  nfiles = numel (files);
+
+  for i = [nfiles, 1:nfiles-1]  # first time in loop extends the struct array
+    [info, err, msg] = stat (files{i});
+    if (! err)
+      r(i).Name = canonicalize_file_name (files{i});
 
-  if (ischar (file))
-    files = glob (file);
-    if (isempty (files))
-      files = {file};
-      nfiles = 1;
-    else
-      nfiles = length (files);
-    endif
-  else
-    error ("fileattrib: FILE must be a string");
-  endif
+      if (isunix ())
+        r(i).archive = NaN;
+        r(i).system = NaN;
+        r(i).hidden = NaN;
+      else
+        [~, attrib] = dos (sprintf ('attrib "%s"', r(i).Name));        
+        ## dos() never returns error status so have to check it indirectly
+        if (length (attrib) < 12
+            || ! strcmp (deblank (attrib(12:end)), r(i).Name))
+          status = false;
+          msgid = "fileattrib";
+          break;
+        endif
+        attrib = attrib(1:11);
+        r(i).archive = any (attrib == "A");
+        r(i).system = any (attrib == "S");
+        r(i).hidden = any (attrib == "H");
+      endif
 
-  if (nargin == 0 || nargin == 1)
-
-    r_n = r_a = r_s = r_h = r_d ...
-        = r_u_r = r_u_w = r_u_x ...
-        = r_g_r = r_g_w = r_g_x ...
-        = r_o_r = r_o_w = r_o_x = cell (nfiles, 1);
-
-    curr_dir = pwd ();
+      r(i).directory = S_ISDIR (info.mode);
 
-    for i = 1:nfiles
-      [info, err, msg] = stat (files{i});
-      if (! err)
-        r_n{i} = canonicalize_file_name (files{i});
-        r_a{i} = NaN;
-        r_s{i} = NaN;
-        r_h{i} = NaN;
-        r_d{i} = S_ISDIR (info.mode);
-        ## FIXME: Maybe we should have S_IRUSR etc. masks?
-        modestr = info.modestr;
-        r_u_r{i} = modestr(2) == "r";
-        r_u_w{i} = modestr(3) == "w";
-        r_u_x{i} = modestr(4) == "x";
-        r_g_r{i} = modestr(5) == "r";
-        r_g_w{i} = modestr(6) == "w";
-        r_g_x{i} = modestr(7) == "x";
-        r_o_r{i} = modestr(8) == "r";
-        r_o_w{i} = modestr(9) == "w";
-        r_o_x{i} = modestr(10) == "x";
+      modestr = info.modestr;
+      r(i).UserRead = (modestr(2) == "r");
+      r(i).UserWrite = (modestr(3) == "w");
+      r(i).UserExecute = (modestr(4) == "x");
+      if (isunix ())
+        r(i).GroupRead = (modestr(5) == "r");
+        r(i).GroupWrite = (modestr(6) == "w");
+        r(i).GroupExecute = (modestr(7) == "x");
+        r(i).OtherRead  = (modestr(8) == "r");
+        r(i).OtherWrite = (modestr(9) == "w");
+        r(i).OtherExecute = (modestr(10) == "x");
       else
-        status = false;
-        msgid = "fileattrib";
-        break;
+        r(i).GroupRead = NaN;
+        r(i).GroupWrite = NaN;
+        r(i).GroupExecute = NaN;
+        r(i).OtherRead = NaN;
+        r(i).OtherWrite = NaN;
+        r(i).OtherExecute = NaN;
       endif
-    endfor
-    if (status)
-      r = struct ("Name", r_n, "archive", r_a, "system", r_s,
-                  "hidden", r_s, "directory", r_d, "UserRead", r_u_r,
-                  "UserWrite", r_u_w, "UserExecute", r_u_x,
-                  "GroupRead", r_g_r, "GroupWrite", r_g_w,
-                  "GroupExecute", r_g_x, "OtherRead", r_o_r,
-                  "OtherWrite", r_o_w, "OtherExecute", r_o_x);
-      if (nargout == 0)
-        status = r;
-      else
-        msg = r;
-      endif
+    else
+      status = false;
+      msgid = "fileattrib";
+      break;
     endif
-  else
-    print_usage ();
+  endfor
+
+  if (status)
+    if (nargout == 0)
+      status = r;
+    else
+      msg = r;
+    endif
   endif
 
 endfunction
 
+
+%!test
+%! [status, attr] = fileattrib (P_tmpdir ()); 
+%! assert (status);
+%! assert (isstruct (attr));
+%! assert (numel (fieldnames (attr)), 14);
+%! assert (attr.Name, P_tmpdir ());
+%! assert (attr.directory);
+%! if (ispc ())
+%!   assert (! isnan (attr.archive));
+%! else
+%!   assert (isnan (attr.archive));
+%! endif
+%! assert (attr.UserRead);
+%! if (ispc ())
+%!   assert (isnan (attr.GroupRead));
+%! else
+%!   assert (! isnan (attr.GroupRead));
+%! endif
+
+%!error fileattrib (1, 2)
+%!error <FILE must be a string> fileattrib (1)
+