[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: untar.m on Solaris with non-GNU tar
From: |
Bill Denney |
Subject: |
Re: untar.m on Solaris with non-GNU tar |
Date: |
Fri, 20 Oct 2006 20:33:15 -0400 |
User-agent: |
Thunderbird 1.5.0.7 (Windows/20060909) |
John W. Eaton wrote:
On 20-Oct-2006, Bill Denney wrote:
| unwind_protect
| cd (directory);
| [status, output] = system (sprintf ([command " 2>&1"], file));
| cd (origdir);
| unwind_protect_cleanup
| cd (origdir);
| end_unwind_protect
The cleanup code in an unwind_protect block is always executed, so the
above code does "cd (origdir") twice.
OK, I've attached a version with those changes. Also, now that I know
what a bit of the difference is, I made a patch to help.cc that explains
some of the difference between try and unwind_protect. Please fix
anything that I got wrong there.
Bill
src/ChangeLog:
2006-10-20 Bill Denney <address@hidden>
* help.cc: better describe the try and unwind_protect functions
## Copyright (C) 2006 Bill Denney
##
## This file is part of Octave.
##
## Octave is free software; you can redistribute it and/or modify it
## under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 2, or (at your option)
## any later version.
##
## Octave is distributed in the hope that it will be useful, but
## WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
## General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with Octave; see the file COPYING. If not, write to the Free
## Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
## 02110-1301, USA.
## -*- texinfo -*-
## @deftypefn {Function File} address@hidden =} unpack (@var{file}, @var{dir})
## @deftypefnx {Function File} address@hidden =} unpack (@var{file}, @var{dir},
@var{filetype})
## Unpack the archive @var{file} based on its extension to the directory
## @var{dir}. If @var{file} is a cellstr, then all files will be
## handled individually. If @var{dir} is not specified, it defaults to
## the current directory. It returns a list of @var{files}
## unpacked. If a directory is in the file list, then the
## @var{filetype} to unpack must also be specified.
##
## The @var{files} includes the entire path to the output files.
## @seealso{bzip2,bunzip2,tar,untar,gzip,gunzip,zip,unzip}
## @end deftypefn
## Author: Bill Denney <address@hidden>
function varargout = unpack (file, directory, filetype)
if (nargin < 1 || nargin > 3)
print_usage ();
endif
if (nargin < 2)
directory = ".";
endif
if (nargin < 3)
filetype = "";
endif
if ischar (file)
if isdir (file)
if isempty (filetype)
error ("unpack: filetype must be given for a directory");
elseif ~ any (strcmpi (filetype, "gunzip"))
error ("unpack: filetype must be gunzip for a directory");
endif
else
[pathstr, name, ext] = fileparts (file);
## check to see if it's .tar.gz, .tar.Z, etc.
if any (strcmpi ({".gz" ".Z" ".bz2" ".bz"}, ext))
[tmppathstr, tmpname, tmpext] = fileparts (name);
if strcmpi (tmpext, ".tar")
name = tmpname;
ext = [tmpext ext];
endif
endif
## if the file is a url, download it and then work with that
## file
if ~ isempty (strfind (file, "://"))
## FIXME: the above is not a perfect test for a url
urlfile = file;
## FIXME: should we name the file that we download with the
## same file name as the url requests?
tmpfile = [tmpnam() ext];
[file, success, msg] = urlwrite (urlfile, tmpfile);
if (~ success)
error ("unpack: could not get \"%s\": %s", urlfile, msg);
endif
endif
endif
## canonicalize_file_name returns empty if the file isn't found, so
## use that to check for existence
cfile = canonicalize_file_name (file);
if isempty (cfile)
error ("unpack: file \"%s\" not found.", file)
else
file = cfile;
endif
elseif iscellstr (file)
files = {};
for i = 1:numel (file)
tmpfiles = unpack (file{i}, directory);
files = {files{:} tmpfiles{:}};
endfor
else
error ("unpack: invalid input file class, %s", class(file));
endif
## Instructions on what to do for any extension.
##
## The field names are the file extension without periods.
## The first cell is what is executed to unpack an archive.
## The second cell is the function to execute on output to get the
## files list.
## The third cell indicates if the files may need to be manually moved
## (i.e. tar and unzip decompress into the current directory while
## bzip2 and gzip decompress the file at its location).
persistent commandlist;
if (isempty (commandlist))
commandlist.gz = {"gunzip -v -r \"%s\"", @__parse_gzip__, true};
commandlist.z = commandlist.gz;
commandlist.bz2 = {"bunzip2 -v \"%s\"", @__parse_bzip2__, true};
commandlist.bz = commandlist.bz2;
commandlist.tar = {"tar -x -v -f \"%s\"", @__parse_tar__, false};
commandlist.targz = {"gunzip -c \"%s\" | tar -x -v", @__parse_tar__, false};
commandlist.tgz = commandlist.targz;
commandlist.tarbz2 = {"bunzip2 -c \"%s\" | tar -x -v", @__parse_tar__,
false};
commandlist.tarbz = commandlist.tarbz2;
commandlist.tbz2 = commandlist.tarbz2;
commandlist.tbz = commandlist.tarbz2;
commandlist.zip = {"unzip \"%s\"", @__parse_zip__, false};
endif
nodotext = ext(~ ismember (ext, "."));
origdir = pwd ();
if isfield (commandlist, nodotext)
[command, parser, move] = deal (commandlist.(nodotext){:});
cstartdir = canonicalize_file_name (origdir);
cenddir = canonicalize_file_name (directory);
needmove = move && ! strcmp (cstartdir, cenddir);
else
warning ("unpack:filetype", "unrecognised file type, %s", ext);
files = file;
return;
endif
## create the directory if necessary
s = stat (directory);
if (isempty (s))
[status, msg] = mkdir (directory);
if (! status)
error ("unpack: mkdir failed to create %s: %s", directory, msg);
endif
elseif (! S_ISDIR (s.mode))
error ("unpack: %s: not a directory", directory);
endif
unwind_protect
cd (directory);
[status, output] = system (sprintf ([command " 2>&1"], file));
unwind_protect_cleanup
cd (origdir);
end_unwind_protect
if status
error ("unpack: unarchiving program exited with status: %d\n%s", ...
status, output);
endif
## trim the last cr if needed
## FIXME: will this need to change to a check for "\r\n" for windows?
if (output(length (output)) == "\n")
output(length (output)) = [];
endif
files = parser (cellstr (split (output, "\n")))';
## move files if necessary
if needmove
[st, msg, msgid] = movefile (files, directory);
if ~ st
error ("unpack: unable to move files to \"%s\": %s", ...
directory, msg);
endif
## fix the names for the files since they were moved.
for i = 1:numel (files)
files{i} = strrep (files{i}, cstartdir, cenddir);
endfor
endif
## return output if requested
if (nargout > 0)
varargout{1} = files;
endif
endfunction
function files = __parse_zip__ (output)
## parse the output from zip and unzip
for i = 1:length (output)
files{i} = output{i}(14:length(output{i}));
endfor
endfunction
## this is a noop, but it makes things simpler for other cases
function output = __parse_tar__ (output)
endfunction
function files = __parse_gzip__ (output)
## parse the output from gzip and gunzip returning the files
## commpressed (or decompressed)
files = {};
## the middle ": " should indicate a good place to start looking for
## the filename
for i = 1:length (output)
colons = strfind(output{i}, ":");
if isempty (colons)
warning ("unpack:parsing", "Unable to parse line (gzip missing
colon):\n%s", output{i})
else
midcolon = colons(ceil (length (colons)/2));
thisstr = output{i}(midcolon+2:length(output{i}));
idx = index (thisstr, "with") + 5;
if isempty (idx)
warning ("unpack:parsing", "Unable to parse line (gzip missing
with):\n%s", output{i});
else
files{i} = thisstr(idx:length (thisstr));
endif
endif
endfor
endfunction
function files = __parse_bzip2__ (output)
## parse the output from bzip2 and bunzip2 returning the files
## commpressed (or decompressed)
files = {};
for i = 1:length (output)
## the -5 is to remove the ".bz2:"
endoffilename = rindex (output{i}, ": ") - 5;
if isempty(endoffilename)
warning("unpack:parsing", "Unable to parse line:\n%s", output{i});
else
files{i} = output{i}(3:endoffilename);
endif
endfor
endfunction
Index: help.cc
===================================================================
RCS file: /cvs/octave/src/help.cc,v
retrieving revision 1.165
diff -u -r1.165 help.cc
--- help.cc 16 Aug 2006 06:52:19 -0000 1.165
+++ help.cc 21 Oct 2006 00:30:39 -0000
@@ -452,7 +452,12 @@
"-*- texinfo -*-\n\
@deffn Keyword try\n\
Begin a try-catch block.\n\
address@hidden
+\n\
+If an error occurs within a try block, then the catch code will be run and\n\
+execution will proceed after the catch block (though it is often\n\
+recommended to use the lasterr function to re-throw the error after cleanup\n\
+is completed).\n\
address@hidden,unwind_protect}\n\
@end deffn", },
{ "until",
@@ -466,7 +471,14 @@
"-*- texinfo -*-\n\
@deffn Keyword unwind_protect\n\
Begin an unwind_protect block.\n\
address@hidden
+\n\
+If an error occurs within the first part of an unwind_protect block\n\
+the commands within the unwind_protect_cleanup block are executed before\n\
+the error is thrown. If an error is not thrown, then the\n\
+unwind_protect_cleanup block is still executed (in other words, the\n\
+unwind_protect_cleanup will be run with or without an error in the\n\
+unwind_protect block).\n\
address@hidden,try}\n\
@end deffn", },
{ "unwind_protect_cleanup",
- untar.m on Solaris with non-GNU tar, John Swensen, 2006/10/20
- Re: untar.m on Solaris with non-GNU tar, Bill Denney, 2006/10/20
- Re: untar.m on Solaris with non-GNU tar, John W. Eaton, 2006/10/20
- Re: untar.m on Solaris with non-GNU tar,
Bill Denney <=
- Re: untar.m on Solaris with non-GNU tar, Bill Denney, 2006/10/20
- Re: untar.m on Solaris with non-GNU tar, John W. Eaton, 2006/10/20
- Re: untar.m on Solaris with non-GNU tar, Bill Denney, 2006/10/20
- Re: untar.m on Solaris with non-GNU tar, John W. Eaton, 2006/10/24
- Re: untar.m on Solaris with non-GNU tar, Bill Denney, 2006/10/24
- Re: untar.m on Solaris with non-GNU tar, John W. Eaton, 2006/10/24