File Coverage

blib/lib/Psh/OS.pm
Criterion Covered Total %
statement 10 145 6.9
branch 2 66 3.0
condition 0 28 0.0
subroutine 3 25 12.0
pod 0 19 0.0
total 15 283 5.3


line stmt bran cond sub pod time code
1             package Psh::OS;
2              
3 1     1   884 use strict;
  1         2  
  1         166  
4              
5             my $ospackage;
6              
7             BEGIN {
8 1 50   1   6 if ($^O eq 'MSWin32') {
9 0         0 $ospackage='Psh::OS::Win';
10 0         0 require Psh::OS::Win;
11 0 0       0 die "Could not find OS specific package $ospackage: $@" if $@;
12             } else {
13 1         4 $ospackage='Psh::OS::Unix';
14 1         670 require Psh::OS::Unix;
15 1 50       30 die "Could not find OS specific package $ospackage: $@" if $@;
16             }
17             }
18              
19             sub AUTOLOAD {
20 1     1   4 no strict;
  1         1  
  1         1716  
21 0     0     $AUTOLOAD=~ s/.*:://;
22 0           my $name="${ospackage}::$AUTOLOAD";
23 0 0         $name="Psh::OS::fb_$AUTOLOAD" unless ref *{$name}{CODE} eq 'CODE';
  0            
24 0 0         unless (ref *{$name}{CODE} eq 'CODE') {
  0            
25 0           require Carp;
26 0           eval {
27 0           Carp::croak("Function `$AUTOLOAD' in Psh::OS does not exist.");
28             };
29             }
30 0           *$AUTOLOAD= *$name;
31 0           goto &$AUTOLOAD;
32             }
33              
34             #
35             # The following code is here because it is most probably
36             # portable across at least a large number of platforms
37             # If you need to override them, then modify the symbol
38             # table :-)
39              
40             # recursive glob function used for **/anything glob
41             sub _recursive_glob {
42 0     0     my( $pattern, $dir)= @_;
43 0 0         opendir( DIR, $dir) || return ();
44 0           my @files= readdir(DIR);
45 0           closedir( DIR);
46 0           my @result= map { catdir($dir,$_) }
  0            
47 0           grep { /^$pattern$/ } @files;
48 0           foreach my $tmp (@files) {
49 0           my $tmpdir= catdir($dir,$tmp);
50 0 0 0       next if ! -d $tmpdir || !no_upwards($tmp);
51 0           push @result, _recursive_glob($pattern, $tmpdir);
52             }
53 0           return @result;
54             }
55              
56             sub _escape {
57 0     0     my $text= shift;
58 0 0         if ($] >= 5.005) {
59 0           $text=~s/(?
60             } else {
61             # TODO: no escaping yet
62             }
63 0           return $text;
64             }
65              
66             #
67             # The Perl builtin glob STILL uses csh, furthermore it is
68             # not possible to supply a base directory... so I guess this
69             # is faster
70             #
71             sub fb_glob {
72 0     0 0   my( $pattern, $dir, $already_absed) = @_;
73              
74 0 0         return () unless $pattern;
75              
76 0           my @result;
77 0 0         if( !$dir) {
78 0           $dir=$ENV{PWD};
79             } else {
80 0 0         $dir=Psh::Util::abs_path($dir) unless $already_absed;
81             }
82 0 0         return unless $dir;
83              
84             # Expand ~
85 0   0       my $home= $ENV{HOME}||get_home_dir();
86 0 0         if ($pattern eq '~') {
87 0           $pattern=$home;
88             } else {
89 0           $pattern=~ s|^\~/|$home/|;
90 0           $pattern=~ s|^\~([^/]+)|&get_home_dir($1)|e;
  0            
91             }
92              
93 0 0         return $pattern if $pattern !~ /[*?]/;
94            
95             # Special recursion handling for **/anything globs
96 0 0         if( $pattern=~ m:^([^\*]+/)?\*\*/(.*)$: ) {
    0          
97 0           my $tlen= length($dir)+1;
98 0   0       my $prefix= $1||'';
99 0           $pattern= $2;
100 0           $prefix=~ s:/$::;
101 0           $dir= catdir($dir,$prefix);
102 0           $pattern=_escape($pattern);
103 0           $pattern=~s/\*/[^\/]*/g;
104 0           $pattern=~s/\?/./g;
105 0 0         $pattern='[^\.]'.$pattern if( substr($pattern,0,2) eq '.*');
106 0           @result= map { substr($_,$tlen) } _recursive_glob($pattern,$dir);
  0            
107             } elsif( $pattern=~ m:/:) {
108             # Too difficult to simulate, so use slow variant
109 0           my $old=$ENV{PWD};
110 0           CORE::chdir $dir;
111 0           $pattern=_escape($pattern);
112 0           @result= eval { CORE::glob($pattern); };
  0            
113 0           CORE::chdir $old;
114             } else {
115             # The fast variant for simple matches
116 0           $pattern=_escape($pattern);
117 0           $pattern=~s/\*/.*/g;
118 0           $pattern=~s/\?/./g;
119 0 0         $pattern='[^\.]'.$pattern if( substr($pattern,0,2) eq '.*');
120            
121 0 0         opendir( DIR, $dir) || return ();
122 0           @result= grep { /^$pattern$/ } readdir(DIR);
  0            
123 0           closedir( DIR);
124             }
125 0           return @result;
126             }
127              
128             #
129             # string signal_name( int )
130             # Looks up the name of a signal
131             #
132              
133             sub fb_signal_name {
134 0     0 0   my $signalnum = shift;
135 0           require Config;
136 0           my @numbers= split ',',$Config::Config{sig_num};
137 0 0         @numbers= split ' ',$Config::Config{sig_num} if( @numbers==1);
138             # Strange incompatibility between perl versions
139              
140 0           my @names= split ' ',$Config::Config{sig_name};
141 0           for( my $i=0; $i<$#numbers; $i++)
142             {
143 0 0         return $names[$i] if( $numbers[$i]==$signalnum);
144             }
145 0           return $signalnum;
146             }
147              
148             #
149             # string signal_description( int signal_number | string signal_name )
150             # returns a descriptive name for the POSIX signals
151             #
152              
153             sub fb_signal_description {
154 0     0 0   my $signal_name= signal_name(shift);
155 0           my $desc= Psh::Locale::get_text('sig_description')->{$signal_name};
156 0 0 0       if( defined($desc) and $desc) {
157 0           return "SIG$signal_name - $desc";
158             }
159 0           return "signal $signal_name";
160             }
161              
162             # Return a name for a temp file
163              
164             sub fb_tmpnam {
165 0     0 0   return POSIX::tmpnam();
166             }
167              
168 0     0 0   sub fb_get_window_size {}
169 0     0 0   sub fb_remove_signal_handlers {1}
170 0     0 0   sub fb_setup_signal_handlers {1}
171 0     0 0   sub fb_setup_sigsegv_handler {1}
172 0     0 0   sub fb_setup_readline_handler {1}
173 0     0 0   sub fb_reap_children {1}
174 0     0 0   sub fb_abs_path { undef }
175              
176             #
177             # Exit psh - you won't believe it, but exit needs special treatment on
178             # MacOS
179             #
180             sub fb_exit_psh {
181 0     0 0   Psh::Util::print_debug_class('i',"[Psh::OS::exit_psh() called]\n");
182 0           Psh::save_history();
183 0 0         $ENV{SHELL} = $Psh::old_shell if $Psh::old_shell;
184 0 0         CORE::exit($_[0]) if $_[0];
185 0           CORE::exit(0);
186             }
187              
188             sub fb_getcwd_psh {
189 0     0 0   eval { require Cwd; };
  0            
190 0   0       return eval { Cwd::getcwd(); } || '';
191             }
192              
193             sub fb_LOCK_SH() { 1; }
194             sub fb_LOCK_EX() { 2; }
195             sub fb_LOCK_NB() { 4; }
196             sub fb_LOCK_UN() { 8; }
197              
198             sub fb_lock {
199 0     0 0   my $file= shift;
200 0   0       my $type= shift || Psh::OS::LOCK_SH();
201 0           my $count=3;
202 0           my $status=0;
203 0   0       while ($count-- and !$status) {
204 0           $status= flock($file, $type| Psh::OS::LOCK_NB());
205             }
206 0           return $status;
207             }
208              
209             sub fb_unlock {
210 0     0 0   my $file= shift;
211 0           flock($file, Psh::OS::LOCK_UN()| Psh::OS::LOCK_NB());
212             }
213              
214 0     0 0   sub fb_reinstall_resize_handler { 1; }
215              
216             {
217             my $handler_type=0;
218              
219             sub fb_install_resize_handler {
220 0     0 0   eval '$Psh::term->get_screen_size()';
221 0 0         unless ($@) {
222 0           $handler_type=3;
223 0           return;
224             }
225 0           eval 'use Term::Size;';
226 0 0         if ($@) {
227 0           eval 'use Term::ReadKey;';
228 0 0         unless ($@) {
229 0           $handler_type=2;
230             }
231             } else {
232 0           $handler_type=1;
233             }
234             }
235              
236              
237             sub fb_check_terminal_size {
238 0     0 0   my ($cols,$rows);
239              
240 0 0         if ($handler_type==0) {
    0          
    0          
    0          
241 0           return;
242             } elsif ($handler_type==3) {
243 0           eval {
244 0           ($rows,$cols)= $Psh::term->get_screen_size();
245             };
246             } elsif ($handler_type==1) {
247 0           eval {
248 0           ($cols,$rows)= Term::Size::chars();
249             };
250             } elsif ($handler_type==2) {
251 0           eval {
252 0           ($cols,$rows)= Term::ReadKey::GetTerminalSize(*STDOUT);
253             };
254             }
255              
256 0 0 0       if($cols && $rows && ($cols > 0) && ($rows > 0)) {
      0        
      0        
257 0           $ENV{COLUMNS} = $cols;
258 0           $ENV{LINES} = $rows;
259 0 0         if( $Psh::term) {
260 0           $Psh::term->Attribs->{screen_width}=$cols-1;
261             }
262             # for ReadLine::Perl
263             }
264             }
265             }
266              
267              
268             # File::Spec
269             #
270             # We add the necessary functions directly because:
271             # 1) Changes to File::Spec might be fatal to psh's file location mechanisms
272             # 2) File::Spec loads unwanted modules
273             # 3) We don't need it anyway as we need platform-specific OS modules
274             # anyway
275             #
276             # Normally I wouldn't do it - but this is a shell and memory
277             # consumption and startup time is worth something for everyday work...
278              
279             sub fb_no_upwards {
280 0     0 0   return grep(!/^\.{1,2}\Z(?!\n)/s, @_);
281             }
282              
283              
284             1;
285              
286             __END__