Re: Excel::Writer on OpenVMS

[email protected] ("Craig A. Berry") Fri, 30 Oct 2015 09:43:52 -0500
Newsgroups perl.vmsperl
Message-ID <[email protected]>
> On Oct 29, 2015, at 6:44 PM, Craig A. Berry <[email protected]> wrote:
>=20
>=20
> I got somewhat farther by setting this:
>=20
> $ DEFINE DECC$FILENAME_UNIX_REPORT 1
>=20
> and testing with [.examples]demo.pl, but the resulting file is =
corrupt.=20

> Nothing looks greatly amiss in the VMS version except that the oddly =
named file [Content_Types].xml is missing.  The file does exist in the =
temp directory on VMS:
>=20
> $ dir/size [...]^[Content_Types^].xml;1
>=20
> Directory MDA0:[CRAIG.SCRATCH.bGENbxoyB2]
>=20
> ^[Content_Types^].xml;1
>                           3
>=20
> Total of 1 file, 3 blocks.
>=20
> so something is preventing that file from getting added to the =
zip/xlsx archive. =20

And that something is the following line of code:

 my $wanted =3D sub { push @xlsx_files, $File::Find::name if -f };

The -f file test operator is a pretty thin wrapper around the CRTL stat =
function, which fails with [Content_Types].xml, presumably because, =
while it=E2=80=99s a valid Unix-format specification, it=E2=80=99s also =
a valid VMS-format directory and file specification.  There is no choice =
about what to name this file =E2=80=94 it=E2=80=99s a standard part of =
an XLSX archive. =20

If you give it a hint by prepending a little Unix syntax (=E2=80=9C./=E2=80=
=9C) or escape the brackets to make it unambiguously a VMS-syntax file, =
it=E2=80=99s ok, but on its own it is not recognized as a file.

$ perl -e "print -f './[Content_Types].xml' ? 'Y' : 'N';"
Y
$ perl -e "print -f '^[Content_Types^].xml' ? 'Y' : 'N';"
Y
$ perl -e "print -f '[Content_Types].xml' ? 'Y' : 'N=E2=80=99=E2=80=9D
N

The solution is simple because what the code in question is doing is =
trying to exclude directories from its list of files to include in the =
archive and only include files.  So instead of saying =E2=80=9Cis it a =
file?=E2=80=9D we can say =E2=80=9Cis it not a directory?=E2=80=9D, like =
so:

$ gdiff -pu lib/Excel/Writer/XLSX/Workbook.pm;-0 =
lib/Excel/Writer/XLSX/Workbook.pm
--- lib/Excel/Writer/XLSX/Workbook.pm;-0	2015-10-29 14:09:16 =
-0500
+++ lib/Excel/Writer/XLSX/Workbook.pm	2015-10-30 09:14:16 -0500
@@ -964,7 +964,7 @@ sub _store_workbook {
     # with File::Find and pass each one to addFile().
     my @xlsx_files;

-    my $wanted =3D sub { push @xlsx_files, $File::Find::name if -f };
+    my $wanted =3D sub { push @xlsx_files, $File::Find::name unless -d =
};

     File::Find::find(
         {
[end]

That in conjunction with DECC$FILENAME_UNIX_REPORT is all you need to =
get a valid XLSX file.  You can ignore my previous suggestion to convert =
the temp directory to Unix format as the DECC$ setting already does the =
equivalent.  In case it=E2=80=99s not obvious you also need an ODS-5 =
disk and a recentish version of Perl (I tested with 5.20.1). =20

It still fails to clean up the temp directory and I think it=E2=80=99s =
that same [Content_Types].xml file that is causing the problem.  Don=E2=80=
=99t have a solution for that yet.
________________________________________
Craig A. Berry
mailto:[email protected]

"... getting out of a sonnet is much more
 difficult than getting in."
                 Brad Leithauser