Initial commit of OpenSPARC T2 design and verification files.
[OpenSPARC-T2-DV] / tools / perl-5.8.0 / lib / site_perl / 5.8.0 / Psh / OS / Unix.pm
CommitLineData
86530b38
AT
1package Psh::OS::Unix;
2
3use strict;
4require POSIX;
5require Psh::Locale;
6
7$Psh::OS::PATH_SEPARATOR=':';
8$Psh::OS::FILE_SEPARATOR='/';
9
10$Psh::history_file = ".psh_history";
11
12# Sets the title of the current window
13sub set_window_title {
14 my $title= shift;
15 my $term= $ENV{TERM};
16 if( $term=~ /^(rxvt.*)|(xterm.*)|(.*xterm)|(kterm)|(aixterm)|(dtterm)/) {
17 print "\017\033]2;$title\007";
18 }
19}
20
21#
22# Returns the hostname of the machine psh is running on, preferrably
23# the full version
24#
25
26sub get_hostname {
27 require Sys::Hostname;
28 return Sys::Hostname::hostname();
29}
30
31sub getcwd_psh {
32 my $cwd;
33 chomp($cwd = `pwd`);
34 $cwd;
35}
36
37#
38# Returns a list of well-known hosts (from /etc/hosts)
39#
40sub get_known_hosts {
41 my $hosts_file = "/etc/hosts"; # TODO: shouldn't be hard-coded?
42 my @result=();
43 local *F_KNOWNHOST;
44 if (open(F_KNOWNHOST,"< $hosts_file")) {
45 my $hosts_text = join ('', <F_KNOWNHOST>);
46 close(F_KNOWNHOST);
47 push @result,Psh::Util::parse_hosts_file($hosts_text);
48 }
49 my $tmp= catfile(Psh::OS::get_home_dir(),
50 '.ssh','known_hosts');
51 if (-r $tmp) {
52 if (open(F_KNOWNHOST, "< $tmp")) {
53 while (<F_KNOWNHOST>) {
54 chomp;
55 next unless $_;
56 if (/^([a-zA-Z].*?)\,/) {
57 push @result, $1;
58 }
59 }
60 }
61 }
62 if (!@result) {
63 push @result,'localhost';
64 }
65 return @result;
66}
67
68#
69# Returns a list of all users on the system, prepended with ~
70#
71{
72 my @user_cache;
73 sub get_all_users {
74 unless (@user_cache) {
75 CORE::setpwent;
76 while (my ($name) = CORE::getpwent) {
77 push(@user_cache,'~'.$name);
78 }
79 CORE::endpwent;
80 }
81 return @user_cache;
82 }
83}
84
85#
86# void display_pod(text)
87#
88sub display_pod {
89 my $tmp= Psh::OS::tmpnam();
90 my $text= shift;
91
92 local *TMP;
93 open( TMP,">$tmp");
94 print TMP $text;
95 close(TMP);
96
97 eval {
98 require Pod::Text;
99 Pod::Text::pod2text($tmp,*STDOUT);
100 };
101 Psh::Util::print_debug_class('e',"Error: $@") if $@;
102 print $text if $@;
103
104 unlink($tmp);
105}
106
107sub get_home_dir {
108 my $user = shift || $ENV{USER};
109 return $ENV{HOME} if ((! $user) && (-d $ENV{HOME}));
110 return (CORE::getpwnam($user))[7]||'';
111}
112
113sub get_rc_files {
114 my @rc=();
115
116 if (-r '/etc/pshrc') {
117 push @rc, '/etc/pshrc';
118 }
119 my $home= Psh::OS::get_home_dir();
120 if ($home) { push @rc, catfile($home,'.pshrc') };
121 return @rc;
122}
123
124sub get_path_extension { return (''); }
125
126#
127# int inc_shlvl ()
128#
129# Increments $ENV{SHLVL}. Also checks for login shell status and does
130# appropriate OS-specific tasks depending on it.
131#
132sub inc_shlvl {
133 my @pwent = CORE::getpwuid($<);
134 if ((! $ENV{SHLVL}) && ($pwent[8] eq $0)) { # would use $Psh::bin, but login shells are guaranteed full paths
135 $Psh::login_shell = 1;
136 $ENV{SHLVL} = 1;
137 } else {
138 $Psh::login_shell = 0;
139 $ENV{SHLVL}++;
140 }
141}
142
143
144###################################################################
145# JOB CONTROL
146###################################################################
147
148
149#
150# void _give_terminal_to (int PID)
151#
152# Make pid the foreground process of the terminal controlling STDIN.
153#
154
155{
156 my $terminal_owner=0;
157
158 sub _give_terminal_to
159 {
160 # If a fork of a psh fork tries to call this then exit
161 # as it would probably mess up the shell
162 # This hack is necessary as e.g.
163 # alias ls=/bin/ls
164 # ls &
165 # call fork_process from within a fork
166
167 return if $Psh::OS::Unix::forked_already;
168 return if $terminal_owner==$_[0];
169 $terminal_owner=$_[0];
170
171 local $SIG{TSTP} = 'IGNORE';
172 local $SIG{TTIN} = 'IGNORE';
173 local $SIG{TTOU} = 'IGNORE';
174 local $SIG{CHLD} = 'IGNORE';
175
176 my ($pkg,$file,$line,$sub)= caller(1);
177 my $status= POSIX::tcsetpgrp(fileno STDIN,$_[0]);
178 }
179
180 sub _get_terminal_owner
181 {
182 return $terminal_owner;
183 }
184}
185
186
187
188#
189# void _wait_for_system(int PID, [bool QUIET_EXIT], [bool NO_TERMINAL])
190#
191# Waits for a program to be stopped/ended, prints no message on normal
192# termination if QUIET_EXIT is specified and true.
193#
194# If NO_TERMINAL is specified and true it won't try to transfer
195# terminal ownership
196#
197
198sub _wait_for_system
199{
200 my($pid, $quiet) = @_;
201 if (!defined($quiet)) { $quiet = 0; }
202
203 my $psh_pgrp = CORE::getpgrp();
204
205 my $pid_status = -1;
206
207 my $job= Psh::Joblist::get_job($pid);
208
209 return if ! $job;
210
211 my $term_pid= $job->{pgrp_leader}||$pid;
212
213 _give_terminal_to($term_pid);
214
215 my $output='';
216 my $status=1;
217 my $returnpid;
218 while (1) {
219 if (!$job->{running}) { $job->continue; }
220 {
221 local $Psh::currently_active = $pid;
222 $returnpid = CORE::waitpid($pid,POSIX::WUNTRACED());
223 $pid_status = $?;
224 }
225 last if $returnpid<1;
226
227 # Very ugly work around for the problem that
228 # processes occasionally get SIGTTOUed without reason
229 # We can do this here because we know the process has
230 # to run and could not have been stopped by TTOU
231 if ($returnpid== $pid &&
232 POSIX::WIFSTOPPED($pid_status) &&
233 Psh::OS::signal_name(POSIX::WSTOPSIG($pid_status)) eq 'TTOU') {
234 $job->continue;
235 next;
236 }
237 # Collect output here - we cannot print it while another
238 # process might possibly be in the foreground;
239 $output.=_handle_wait_status($returnpid, $pid_status, $quiet, 1);
240 if ($returnpid == $pid) {
241 $status=POSIX::WEXITSTATUS($pid_status);
242 last;
243 }
244 }
245 _give_terminal_to($psh_pgrp);
246 Psh::Util::print_out($output) if length($output);
247 return $status==0;
248}
249
250#
251# void _handle_wait_status(int PID, int STATUS, bool QUIET_EXIT)
252#
253# Take the appropriate action given that waiting on PID returned
254# STATUS. Normal termination is not reported if QUIET_EXIT is true.
255#
256
257sub _handle_wait_status {
258 my ($pid, $pid_status, $quiet, $collect) = @_;
259 # Have to obtain these before we potentially delete the job
260 my $job= Psh::Joblist::get_job($pid);
261 my $command = $job->{call};
262 my $visindex= Psh::Joblist::get_job_number($pid);
263 my $verb='';
264
265 if (POSIX::WIFEXITED($pid_status)) {
266 my $status= POSIX::WEXITSTATUS($pid_status);
267 if ($status==0) {
268 $verb= ucfirst(Psh::Locale::get_text('done')) unless $quiet;
269 } else {
270 $verb= ucfirst(Psh::Locale::get_text('error'));
271 }
272 Psh::Joblist::delete_job($pid);
273 } elsif (POSIX::WIFSIGNALED($pid_status)) {
274 my $tmp= Psh::Locale::get_text('terminated');
275 $verb = "\u$tmp (" .
276 Psh::OS::signal_description(POSIX::WTERMSIG($pid_status)) . ')';
277 Psh::Joblist::delete_job($pid);
278 } elsif (POSIX::WIFSTOPPED($pid_status)) {
279 my $tmp= Psh::Locale::get_text('stopped');
280 $verb = "\u$tmp (" .
281 Psh::OS::signal_description(POSIX::WSTOPSIG($pid_status)) . ')';
282 $job->{running}= 0;
283 }
284 if ($verb && $visindex>0) {
285 my $line="[$visindex] $verb $pid $command\n";
286 return $line if $collect;
287
288 Psh::Util::print_out($line );
289 }
290 return '';
291}
292
293
294#
295# void reap_children()
296#
297# Checks wether any children we spawned died
298#
299
300sub reap_children
301{
302 my $returnpid=0;
303 while (($returnpid = CORE::waitpid(-1, POSIX::WNOHANG() |
304 POSIX::WUNTRACED())) > 0) {
305 _handle_wait_status($returnpid, $?);
306 }
307}
308
309sub execute_complex_command {
310 my @array= @{shift()};
311 my $fgflag= shift @array;
312 my @return_val;
313 my $success= 0;
314 my $eval_thingie;
315 my $pgrp_leader= 0;
316 my $pid;
317 my $string='';
318 my @tmp;
319
320 my ($read,$chainout,$chainin);
321
322 for( my $i=0; $i<@array; $i++) {
323 # ([ $strat, $how, \@options, \@words, $line]);
324 my ($strategy, $how, $options, $words, $text, $opt)= @{$array[$i]};
325 local $Psh::current_options= $opt;
326 $text||='';
327
328 my $line= join(' ',@$words);
329 my $forcefork;
330 ($success, $eval_thingie,$words,$forcefork, @return_val)= $strategy->execute( \$line, $words, $how, $i>0);
331
332 $forcefork||=$i<$#array;
333
334 if( defined($eval_thingie)) {
335 if( $#array) {
336 ($read,$chainout)= POSIX::pipe();
337 }
338 foreach (@$options) {
339 if ($_->[0]==Psh::Parser::T_REDIRECT() and
340 ($_->[1] eq '<&' or $_->[1] eq '>&')) {
341 if ($_->[3] eq 'chainin') {
342 $_->[3]= $chainin;
343 } elsif ($_->[3] eq 'chainout') {
344 $_->[3]= $chainout;
345 }
346 }
347 }
348 my $termflag=!($i==$#array);
349
350 ($pid,$success,@tmp)= _fork_process($eval_thingie,$words,
351 $fgflag,$text,$options,
352 $pgrp_leader,$termflag,
353 $forcefork);
354
355 if( !$i && !$pgrp_leader) {
356 $pgrp_leader=$pid;
357 }
358
359 if( $i<$#array && $#array) {
360 POSIX::close($chainout);
361 $chainin= $read;
362 }
363 if( @return_val < 1 ||
364 !defined($return_val[0])) {
365 @return_val= @tmp;
366 }
367 }
368 $string.='|' if $i>0;
369 $string.=$text;
370 }
371
372 if( $pid) {
373 my $job= Psh::Joblist::create_job($pid,$string);
374 $job->{pgrp_leader}=$pgrp_leader;
375 if( $fgflag) {
376 $success=_wait_for_system($pid, 1);
377 } else {
378 my $visindex= Psh::Joblist::get_job_number($job->{pid});
379 Psh::Util::print_out("[$visindex] Background $pgrp_leader $string\n");
380 }
381 }
382 return ($success,\@return_val);
383}
384
385sub _setup_redirects {
386 my $options= shift;
387 my $save= shift;
388
389 return [] if ref $options ne 'ARRAY';
390
391 my @cache=();
392 foreach my $option (@$options) {
393 if( $option->[0] == Psh::Parser::T_REDIRECT()) {
394 my $type= $option->[2];
395 my $cachefileno;
396
397 if ($option->[1] eq '<&') {
398 POSIX::dup2($option->[3], $type);
399 } elsif ($option->[1] eq '>&') {
400 POSIX::dup2($option->[3], $type);
401 } elsif ($option->[1] eq '<') {
402 my $tmpfd= POSIX::open( $option->[3], &POSIX::O_RDONLY);
403 POSIX::dup2($tmpfd, $type);
404 POSIX::close($tmpfd);
405 } elsif ($option->[1] eq '>') {
406 my $tmpfd= POSIX::open( $option->[3], &POSIX::O_WRONLY |
407 &POSIX::O_TRUNC | &POSIX::O_CREAT );
408 POSIX::dup2($tmpfd, $type);
409 POSIX::close($tmpfd);
410 } elsif ($option->[1] eq '>>') {
411 my $tmpfd= POSIX::open( $option->[3], &POSIX::O_WRONLY |
412 &POSIX::O_CREAT);
413 POSIX::lseek($tmpfd,0, &POSIX::SEEK_END);
414 POSIX::dup2($tmpfd, $type);
415 POSIX::close($tmpfd);
416 }
417 if ($^F<$type) { # preserve filedescriptors higher than 2
418 $^F=$type;
419 }
420 }
421 }
422 select(STDOUT);
423 return \@cache;
424}
425
426sub _has_redirects {
427 my $options= shift;
428 return 0 if ref $options ne 'ARRAY';
429
430 foreach my $option (@$options) {
431 return 1 if( $option->[0] == Psh::Parser::T_REDIRECT());
432 }
433 return 0;
434}
435
436#
437# void fork_process( code|program, words,
438# int fgflag, text to display in jobs,
439# redirection options,
440# pid of pgroupleader, do not set terminal flag,
441# force a fork?)
442#
443
444sub _fork_process {
445 my( $code, $words, $fgflag, $string, $options,
446 $pgrp_leader, $termflag, $forcefork) = @_;
447 my($pid);
448
449 # HACK - if it's foreground code AND perl code AND
450 # there are no redirects
451 # we do not fork, otherwise we'll never get
452 # the result value, changed variables etc.
453 if( $fgflag and !$forcefork and ref($code) eq 'CODE'
454 and !_has_redirects($options)
455 ) {
456 my @result= eval { &$code };
457 Psh::Util::print_error($@) if $@ && $@ !~/^SECRET/;
458 return (0,@result);
459 }
460
461 unless ($pid = fork) { #child
462 unless (defined $pid) {
463 Psh::Util::print_error_i18n('fork_failed');
464 return (-1,0,undef);
465 }
466
467 $Psh::OS::Unix::forked_already=1;
468 close(READ) if( $pgrp_leader);
469 _setup_redirects($options,0);
470 POSIX::setpgid(0,$pgrp_leader||$$);
471 _give_terminal_to($pgrp_leader||$$) if $fgflag && !$termflag;
472 remove_signal_handlers();
473
474 if( ref($code) eq 'CODE') {
475 my @tmp=&{$code};
476 if (!@tmp or $tmp[0]) {
477 CORE::exit(0);
478 }
479 CORE::exit(1);
480 } else {
481 {
482 if( ! ref $options) {
483 exec $code;
484 } else {
485 $code= shift @$words;
486 exec { $code } @$words;
487 }
488 } # Avoid unreachable warning
489 Psh::Util::print_error_i18n('exec_failed',$code);
490 CORE::exit(-1);
491 }
492 }
493 POSIX::setpgid($pid,$pgrp_leader||$pid);
494 _give_terminal_to($pgrp_leader||$pid) if $fgflag && !$termflag;
495 return ($pid,0,undef);
496}
497
498sub fork_process {
499 my( $code, $fgflag, $string, $options) = @_;
500 my ($pid,$sucess,@result)= _fork_process($code,undef,$fgflag,$string,$options);
501 return @result if !$pid;
502 my $job= Psh::Joblist::create_job($pid,$string);
503 if( !$fgflag) {
504 my $visindex= Psh::Joblist::get_job_number($job->{pid});
505 Psh::Util::print_out("[$visindex] Background $pid $string\n");
506 }
507 _wait_for_system($pid, 1) if $fgflag;
508 return undef;
509}
510
511#
512# Returns true if the system has job_control abilities
513#
514sub has_job_control { return 1; }
515
516#
517# void restart_job(bool FOREGROUND, int JOB_INDEX)
518#
519sub restart_job
520{
521 my ($fg_flag, $job_to_start) = @_;
522
523 my $job= Psh::Joblist::find_job($job_to_start);
524
525 if(defined($job)) {
526 my $pid = $job->{pid};
527 my $command = $job->{call};
528
529 if ($command) {
530 my $verb;
531 my $qRunning = $job->{running};
532
533 if ($fg_flag) {
534 $verb= ucfirst(Psh::Locale::get_text('foreground'));
535 } elsif ($qRunning) {
536 # bg request, and it's already running:
537 return;
538 } else {
539 $verb= ucfirst(Psh::Locale::get_text('restart'));
540 }
541 my $visindex = Psh::Joblist::get_job_number($pid);
542 Psh::Util::print_out("[$visindex] $verb $pid $command\n");
543
544 if($fg_flag) {
545 eval { _wait_for_system($pid, 0); };
546 Psh::Util::print_debug_class('e',"Error: $@") if $@;
547 } elsif( !$qRunning) {
548 $job->continue;
549 }
550 }
551 }
552}
553
554sub resume_job {
555 my $job= shift;
556
557 kill 'CONT', -$job->{pid};
558 kill 'CONT', -$job->{pgrp_leader} if $job->{pgrp_leader};
559}
560
561# Simply doing backtick eval - mainly for Prompt evaluation
562sub backtick {
563 my $com=join ' ',@_;
564 local $^F=50;
565 my ($read,$write)= POSIX::pipe();
566
567 unless(my $pid=fork) {
568 POSIX::close($read);
569 POSIX::dup2($write,fileno(*STDOUT));
570 $^F=$write if ($write>$^F);
571 my ($success)= Psh::evl($com);
572 CORE::exit(!$success);
573 }
574 POSIX::close($write);
575 my $result='';
576 local(*READ);
577 open(READ,"<&=$read");
578 while(<READ>) {
579 $result.=$_;
580 }
581 close(READ);
582 return $result;
583}
584
585###################################################################
586# SIGNALS
587###################################################################
588
589# Setup special treatment of certain signals
590# Having a value of 0 means to ignore the signal completely in
591# the loops while a code ref installs a different default
592# handler. Note that calling _ignore_handler is different than
593# setting the signal action to ignore - if you set the signal
594# action to ignore, the signal might be passed on to parent processes
595# which could decide to handle them for us
596
597my %special_handlers= (
598 'CHLD' => \&_ignore_handler,
599 'CLD' => \&_ignore_handler,
600 'TTOU' => \&_ttou_handler,
601 'TTIN' => \&_ttou_handler,
602 'TERM' => \&Psh::OS::fb_exit_psh,
603 'HUP' => \&Psh::OS::fb_exit_psh,
604 'SEGV' => 0,
605 'WINCH'=> 0,
606 'ZERO' => 0,
607 );
608
609my @signals= grep { substr($_,0,1) ne '_' } keys %SIG;
610
611#
612# void remove_signal_handlers()
613#
614# This used to manually set INT, QUIT, CONT, STOP, TSTP, TTIN,
615# TTOU, and CHLD.
616#
617# The new technique changes the settings of *all* signals. It is
618# from Recipe 16.13 of The Perl Cookbook (Page 582). It should be
619# compatible with Perl 5.004 and later.
620#
621
622sub remove_signal_handlers
623{
624 foreach my $sig (@signals) {
625 next if exists($special_handlers{$sig}) &&
626 ! ref($special_handlers{$sig});
627 $SIG{$sig} = 'DEFAULT';
628 }
629}
630
631#
632# void setup_signal_handlers
633#
634# This used to manually set INT, QUIT, CONT, STOP, TSTP, TTIN,
635# TTOU, and CHLD.
636#
637# See comment for remove_signal_handlers() for more information.
638#
639
640sub setup_signal_handlers
641{
642 foreach my $sig (@signals) {
643 if( exists($special_handlers{$sig})) {
644 if( ref($special_handlers{$sig})) {
645 $SIG{$sig}= $special_handlers{$sig};
646 }
647 next;
648 }
649 $SIG{$sig} = \&_signal_handler;
650 }
651
652 reinstall_resize_handler();
653}
654
655
656#
657# Setup the SIGSEGV handler
658#
659sub setup_sigsegv_handler
660{
661 $SIG{SEGV} = \&_error_handler;
662}
663
664#
665# Setup SIGINT handler for readline
666#
667sub setup_readline_handler
668{
669 $SIG{INT}= \&_readline_handler;
670}
671
672sub remove_readline_handler
673{
674 $SIG{INT}= \&_signal_handler;
675}
676
677sub reinstall_resize_handler
678{
679 Psh::OS::fb_reinstall_resize_handler();
680 &_resize_handler('WINCH');
681}
682
683
684#
685# readline_handler()
686#
687# Readline ^C handler.
688#
689
690sub _readline_handler
691{
692 my $sig= shift;
693 setup_readline_handler();
694 print "\n"; # Clean up the display
695 die "SECRET $Psh::bin: Signal $sig\n"; # changed to SECRET... just in case
696}
697
698sub _ttou_handler
699{
700 _give_terminal_to($$);
701}
702
703#
704# void _signal_handler( string SIGNAL )
705#
706
707sub _signal_handler
708{
709 my ($sig) = @_;
710
711 if ($Psh::currently_active > 0) {
712 Psh::Util::print_debug("Received signal SIG$sig, sending to $Psh::currently_active\n");
713
714 kill $sig, -$Psh::currently_active;
715 } elsif ($Psh::currently_active < 0) {
716 Psh::Util::print_debug("Received signal SIG$sig, sending to Perl code\n");
717 die "SECRET ${Psh::bin}: Signal $sig\n";
718 } else {
719 _give_terminal_to($$);
720 Psh::Util::print_debug("Received signal SIG$sig, die-ing\n");
721 die "SECRET ${Psh::bin}: Signal $sig\n" if $sig eq 'INT';
722 }
723
724 $SIG{$sig} = \&_signal_handler;
725}
726
727
728#
729# ignore_handler()
730#
731
732sub _ignore_handler
733{
734}
735
736
737sub _error_handler
738{
739 my ($sig) = @_;
740 Psh::Util::print_error_i18n('unix_received_strange_sig',$sig);
741 kill 'INT', $$; # HACK to stop a possible endless loop!
742}
743
744#
745# _resize_handler()
746#
747
748sub _resize_handler
749{
750 my ($sig) = @_;
751
752 Psh::OS::check_terminal_size();
753
754 $SIG{$sig} = \&_resize_handler;
755}
756
757{
758 my $debian=-1;
759 sub _check_debian {
760 if ($debian==-1) {
761 if (-r '/etc/debian-version') {
762 $debian=1;
763 } else {
764 $debian=0;
765 }
766 }
767 return $debian;
768 }
769}
770
771sub get_editor {
772 my $file= shift;
773 my $suggestion= shift;
774 my $editor= $suggestion||$ENV{VISUAL}||$ENV{EDITOR};
775 if (_check_debian()) {
776 $editor ||='editor';
777 } else {
778 $editor ||='vi';
779 }
780 return $editor;
781}
782
783# File::Spec
784
785sub canonpath {
786 my ($path) = @_;
787 $path =~ s|/+|/|g unless($^O eq 'cygwin'); # xx////xx -> xx/xx
788 $path =~ s|(/\.)+/|/|g; # xx/././xx -> xx/xx
789 $path =~ s|^(\./)+||s unless $path eq "./"; # ./xx -> xx
790 $path =~ s|^/(\.\./)+|/|s; # /../../xx -> xx
791 $path =~ s|/\Z(?!\n)|| unless $path eq "/"; # xx/ -> xx
792 return $path;
793}
794
795sub catfile {
796 my $file = pop @_;
797 return $file unless @_;
798 my $dir = catdir(@_);
799 $dir .= "/" unless substr($dir,-1) eq "/";
800 return $dir.$file;
801}
802
803sub catdir {
804 my @args = @_;
805 foreach (@args) {
806 # append a slash to each argument unless it has one there
807 $_ .= "/" if $_ eq '' || substr($_,-1) ne "/";
808 }
809 return canonpath(join('', @args));
810}
811
812sub file_name_is_absolute {
813 my $file= shift;
814 return scalar($file =~ m:^/:s);
815}
816
817sub rootdir {
818 '/';
819}
820
821sub splitdir {
822 my ($directories) = @_ ;
823
824 if ( $directories !~ m|/\Z(?!\n)| ) {
825 return split( m|/|, $directories );
826 }
827 else {
828 my( @directories )= split( m|/|, "${directories}dummy" ) ;
829 $directories[ $#directories ]= '' ;
830 return @directories ;
831 }
832}
833
834sub rel2abs {
835 my ($path,$base ) = @_;
836
837 # Clean up $path
838 if ( ! file_name_is_absolute( $path ) ) {
839 # Figure out the effective $base and clean it up.
840 if ( !defined( $base ) || $base eq '' ) {
841 $base = Psh::getcwd_psh() ;
842 }
843 elsif ( ! file_name_is_absolute( $base ) ) {
844 $base = rel2abs( $base ) ;
845 }
846 else {
847 $base = canonpath( $base ) ;
848 }
849
850 # Glom them together
851 $path = catdir( $base, $path ) ;
852 }
853
854 return canonpath( $path ) ;
855}
856
8571;
858
859__END__
860
861