File Coverage

blib/lib/VMS/FileUtils/SafeName.pm
Criterion Covered Total %
statement 79 90 87.7
branch 69 76 90.7
condition 3 3 100.0
subroutine 6 7 85.7
pod 5 5 100.0
total 162 181 89.5


line stmt bran cond sub pod time code
1              
2             #
3             # UNIX/VMS Filename "special character" and upper/lower case mapping
4             # as used by Multinet and UCX NFS
5             #
6             # Version: 0.021
7             # Author: C. Lane lane@duphy4.physics.drexel.edu
8             # Revised: 4 Jan 2001
9             #
10              
11             =head1 NAME
12              
13             VMS::FileUtils::SafeName -- convert special chars and case of filenames
14              
15             =head1 Synopsis
16              
17             use VMS::FileUtils::SafeName qw(:all) ;
18              
19             $vmsusablename = safename('unix:..name &tc',$do_all_dots);
20             $unixname = unsafename($vmsusablename);
21             $path = safepath('x.y/version:1.2.3',$do_all_dots_filename);
22             $unixpath = unsafepath($safepathoutput);
23             $archivename = safe_archive('HTML-Parser-1.07.tar.gz');
24              
25             =head1 DESCRIPTION
26              
27             This package provides conversion between Unix filenames and VMS filenames
28             where the Unix filenames may have characters that are illegal under VMS.
29              
30             Spaces, punctuation, control characters, etc. get mapped to a sequence of
31             the form '$6C'. Also the case of the original unix filename is preserved
32             using '$' to shift from lower to uppercase:
33              
34             Unix filename safename output
35             ------------- ---------------
36             abc.DEF.ghi -> $ABC.$DEF$5NGHI
37             ^ ^ ^^^ extra periods get converted
38             +----+-------change case
39              
40             The conversion may be reversed with unsafename
41              
42             The conversion provided here is the same as is contained in the
43             Multinet and UCX NFS software.
44              
45             Routines:
46              
47             =head2 safename
48              
49             Converts upper/lower case, punctuation etc. to chars valid for VMS filename.
50             The first '.' in the filename is left intact (unless the second parameter
51             to vmsify_name is true, in which case all .s are converted).
52              
53             Lowercase is taken as the default for input filenames.
54              
55             =head2 unsafename
56              
57             Converts filenames produced by safename back to their original form.
58              
59             =head2 safepath
60              
61             Converts path elements into VMS-safe form. The trailing element
62             (if the path doesn't end in a '/') can optionally have all periods
63             converted, or (default) all but the first period converted. Path
64             elements that correspond to directory names have all periods converted
65              
66             =head2 unsafepath
67              
68             Reverses the conversion done by safepath
69              
70             =head2 safe_archive
71              
72             Converts filename of the type typically used for CPAN archives into
73             a VMS-compatible format:
74              
75             HTML-Parser-1.07.tar.gz -> HTML-Parser-1_07.tar-gz
76              
77              
78             =head1 REVISION
79              
80             This document was last revised on 10 Mar 1998, for Perl 5.004.59
81              
82             =cut
83              
84             package VMS::FileUtils::SafeName;
85             require 5.002;
86 1     1   603 use vars qw($VERSION @ISA @EXPORT_OK %EXPORT_TAGS);
  1         1  
  1         77  
87 1     1   4 use Exporter();
  1         2  
  1         1557  
88              
89              
90             $VERSION = '0.02';
91             @ISA = qw( Exporter );
92             @EXPORT_OK = qw(safename unsafename safepath unsafepath safe_archive);
93             %EXPORT_TAGS = (
94             all => [qw(safename unsafename safepath unsafepath safe_archive)]
95             );
96              
97              
98             sub safename ($;$) {
99 274     274 1 6472 my (@fn) = split(//,$_[0]);
100 274         483 my ($doalldots) = $_[1];
101 274         338 my ($out) = '';
102 274         285 my ($shift) = 0;
103 274   100     656 my ($dots) = defined($doalldots) && $doalldots;
104              
105 274         393 foreach (@fn) {
106 1884 100       6686 if (/[a-z]/) {
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
107 867 100       1453 $out .= ($shift==0 ? uc($_) : '$'.uc($_)) ;
108 867         1130 $shift = 0;
109             } elsif (/[A-Z]/) {
110 797 100       1314 $out .= ($shift==1 ? uc($_) : '$'.uc($_)) ;
111 797         1213 $shift = 1;
112             } elsif (/[0-9\-_]/) {
113 12         21 $out .= $_;
114             } elsif ($_ eq '$') {
115 1         3 $out .= '$$';
116             } elsif ($_ eq '.') {
117 17 100       31 $out .= $dots ? '$5N': '.';
118 17         20 $dots++;
119             } elsif (ord($_) == 0) {
120 1         3 $out .= '$6A';
121             } elsif ($_ eq ' ') {
122 1         3 $out .= '$7A';
123             } elsif (ord($_) == 0x40) {
124 1         3 $out .= '$8A';
125             } elsif (ord($_) == 0x60) {
126 1         2 $out .= '$9A';
127             } elsif (ord($_) <= 0x1A) {
128 26         57 $out .= '$4'.chr(ord($_)-0x01+ord('A'));
129             } elsif (ord($_) <= 0x1F) {
130 5         14 $out .= '$6'.chr(ord($_)-0x1B+ord('B'));
131             } elsif (ord($_) <= 0x3A) {
132 13         29 $out .= '$5'.chr(ord($_)-0x21+ord('A'));
133             } elsif (ord($_) <= 0x3F) {
134 5         14 $out .= '$7'.chr(ord($_)-0x3B+ord('B'));
135             } elsif (ord($_) <= 0x5E) {
136 4         10 $out .= '$8'.chr(ord($_)-0x5B+ord('B'));
137             } elsif (ord($_) <= 0x7F) {
138 5         16 $out .= '$9'.chr(ord($_)-0x7B+ord('B'));
139             } else {
140 128         328 $out .= sprintf('$%03.3o',ord($_));
141             }
142             }
143 274         908 return($out);
144             }
145              
146              
147             sub unsafename ($) {
148 257     257 1 798 my ($in) = uc($_[0]);
149 257         243 my ($shift, $i, $mod, $out);
150              
151 257         251 $mod =1 ;
152 257         484 while ($mod) {
153 449         397 $mod = 0;
154 449 100       2126 if ($in =~ /\$([0-7]{3,3})/) {
    100          
155 128         380 $in = $`.chr(oct($1)).$';
156 128         248 $mod = 1;
157             } elsif ($in =~ /\$([4-9])([A-Z])/) {
158 64         103 $i = ord($2) - ord('A');
159 64 100       226 if ($1 == 4) {
    100          
    100          
    100          
    100          
    50          
160 26         62 $in = $`.chr($i+0x01).$';
161             } elsif ($1 == 5) {
162 15         40 $in = $`.chr($i+0x21).$';
163             } elsif ($1 == 6) {
164 6 100       55 $in = $`.($i ? chr($i+0x1A) : chr(0)).$';
165             } elsif ($1 == 7) {
166 6 100       23 $in = $`.($i ? chr($i+0x3A) : ' ').$';
167             } elsif ($1 == 8) {
168 5 100       18 $in = $`.($i ? chr($i+0x5A) : chr(0x40)).$';
169             } elsif ($1 == 9) {
170 6 100       26 $in = $`.($i ? chr($i+0x7A) : chr(0x60)).$';
171             }
172 64         167 $mod = 1;
173             }
174             }
175              
176 257         259 $mod = 1;
177 257         234 $shift = 0;
178 257         382 $in = lc($in);
179 257         268 $out = '';
180 257         432 while ($mod) {
181 514         507 $mod = 0;
182 514 100       1561 if ($in =~ /\$([A-Z\$])/i) {
183 257 100       519 if ($1 eq '$') {
184 1         4 $out .= $`.'$';
185 1         3 $in = $';
186 1         3 $mod = 1;
187             } else {
188 256         302 $shift = !$shift;
189 256 50       622 $out .= $`.($shift? uc($1) : lc($1));
190 256 50       530 $in = $shift ? uc($') : lc($');
191 256         487 $mod = 1;
192             }
193             }
194             }
195 257         698 return ($out.$in);
196             }
197              
198             sub safepath ($;$) {
199 5     5 1 33 my ($path, $dolast) = @_;
200 5         16 my (@e) = split('/',$path);
201 5         5 my ($j, $isadir);
202              
203 5 100       11 if (!defined($dolast)) {$dolast = 0;}
  3         4  
204 5         11 $isadir = ($path =~ /\/$/);
205 5         6 $dolast ^= $isadir;
206              
207 5         16 for ($j = 0; $j < $#e ; $j++) {
208 9         17 $e[$j] = safename($e[$j],1);
209             }
210 5         13 $e[$#e] = safename($e[$#e],$dolast);
211 5 100       19 $path = join('/',@e).($isadir ? '/' : '');
212 5         16 return $path;
213             }
214              
215             sub unsafepath ($) {
216 1     1 1 11 return unsafename($_[0]);
217             }
218              
219              
220             sub safe_archive ($) {
221 0     0 1   my $name = shift;
222 0           my $suff = '';
223 0 0         if ($name =~ /\.([\w\-\$]+)\.(gz|Z|zip|gzip)\Z/i) {
    0          
224 0           $suff = $1.'-'.$2;
225 0           $name = $`;
226             } elsif ($name =~ /\.([\w\-\$]+)\Z/i) {
227 0           $suff = $1;
228 0           $name = $`;
229             }
230 0           $name =~ s#\.$##;
231 0           $name =~ s#\.#_#g;
232 0           $name .= '.'.$suff;
233 0           return $name;
234             }
235              
236              
237              
238             1;
239              
240