Subversion Repositories DevTools

Rev

Rev 5969 | Rev 6177 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
227 dpurdie 1
########################################################################
5710 dpurdie 2
# Copyright (c) VIX TECHNOLOGY (AUST) LTD
227 dpurdie 3
#
4
# Module name   : jats.sh
5
# Module type   : Perl Package
6
# Compiler(s)   : n/a
7
# Environment(s): jats
8
#
9
# Description   : This package contains functions to manipulate file paths
10
#                 directories and names.
11
#
12
#                    Getcwd                     - Get current directory
13
#                    Realpath                   - Get real path
14
#                    Realfile                   - Get real path ?
15
#                    RelPath                    - Convert to relative path
16
#                    AbsPath                    - Convert to Abs path
17
#                    FullPath                   - Convert to Abs path with driver letter
257 dpurdie 18
#                    TruePath                   - Case Corrected pathname
227 dpurdie 19
#                    CleanPath                  - Clean up a path
20
#                    StripDrive                 - Remove drive letter
21
#                    StripDir                   - Return file + extension
22
#                    StripExt                   - Return dir + file
23
#                    StripFile                  - Returns extension
24
#                    StripFileExt               - Returns directory
25
#                    StripDirExt                - Returns filename ( with optional ext)
26
#                    CleanDirName               - Clean up a path
261 dpurdie 27
#                    TouchFile                  - Touch a file
28
#                    FileIsNewer                - Test if newer
5486 dpurdie 29
#                    DisplayPath                - Generate a Path that can be displayed
261 dpurdie 30
#                    FileCreate                 - Create a simple text file
31
#                    FileAppend                 - Append to a simple text file
6133 dpurdie 32
#                    TagFileMatch               - Simple (oneline) file content matcher
33
#                    TagFileRead                - Return the contents of the tagfile
379 dpurdie 34
#                    RmDirTree                  - Remove a directory tree
4421 dpurdie 35
#           ReExported
36
#                    catdir                     - Concatenate path elements
37
#                    catfile                    - Concatenate path elements and a file
227 dpurdie 38
#
39
#......................................................................#
40
 
255 dpurdie 41
use 5.006_001;
227 dpurdie 42
use strict;
43
use warnings;
44
 
45
################################################################################
46
#   Global variables used by functions in this package
47
#   For historical reasons many of these variabeles are global
48
#
49
 
50
package FileUtils;
283 dpurdie 51
use base qw(Exporter);
361 dpurdie 52
use File::Path;
4309 dpurdie 53
use File::Spec::Functions;
283 dpurdie 54
 
227 dpurdie 55
use JatsError;
56
use Cwd;
283 dpurdie 57
our (@EXPORT, @EXPORT_OK, %EXPORT_TAGS, $VERSION);
227 dpurdie 58
 
59
$VERSION = 1.00;
60
 
61
# Symbols to autoexport (:DEFAULT tag)
62
@EXPORT = qw(   InitFileUtils
63
                Getcwd
64
                Realpath
65
                RelPath
66
                AbsPath
67
                FullPath
68
                CleanPath
69
                StripDrive
70
                StripDir
71
                StripExt
72
                StripFile
73
                StripFileExt
74
                StripDirExt
75
                CleanDirName
76
                TouchFile
77
                FileIsNewer
78
                DisplayPath
257 dpurdie 79
                TruePath
261 dpurdie 80
                FileCreate
81
                FileAppend
6133 dpurdie 82
                TagFileMatch
83
                TagFileRead
361 dpurdie 84
                RmDirTree
4309 dpurdie 85
                catfile
86
                catdir
227 dpurdie 87
 
88
                $ScmPathSep
261 dpurdie 89
                $ScmDirSep
227 dpurdie 90
                $Cwd
91
                $CwdDrive
92
                $ScmHost
93
            );
94
#
95
# exported package globals go here
96
#
97
our $ScmPathSep;                # Windows/Unix path seperator
261 dpurdie 98
our $ScmDirSep;                 # Windows/Unix dir sep
227 dpurdie 99
our $Cwd       ;                # Current directory ( no drive letter )
247 dpurdie 100
our $CwdFull   ;                # Current directory ( with drive letter )
227 dpurdie 101
our $CwdDrive  ;                # Current drive
102
our $ScmHost   ;                # Host Type. Unix, WIN
103
 
104
#
105
#   Internal variables
106
#
4546 dpurdie 107
our  $isCygWin;                 # Running under CygWin
108
our  $isUnix;                   # Is Unix
227 dpurdie 109
 
110
#-------------------------------------------------------------------------------
111
# Function        : BEGIN
112
#
113
# Description     : Determine some values very early
114
#
115
#
116
BEGIN
117
{
118
    $ScmHost = "Unix";                                # UNIX, default
119
 
120
    Debug( "PerlHost:  $^O" );
121
    $ScmHost = "DOS"      if ($^O eq "win95");        # DOS Perl dependent
122
    $ScmHost = "WIN"      if ($^O eq "MSWin32");      # ActivePerl
123
    $ScmHost = "WIN"      if ($^O eq "cygwin");       # Cygwin
124
 
4546 dpurdie 125
    $isUnix = ( $ScmHost eq "Unix"  ) ? 1 : 0;
126
    $isCygWin = ( $ENV{'SHELL'} || $ENV{'CYGWIN'} ) ? 1 : 0;
227 dpurdie 127
 
128
    $ScmPathSep = $isUnix ? ':' : ';';     # Unix / Windows
261 dpurdie 129
    $ScmDirSep = $isUnix ? '/' : '\\';     # Unix / Windows
227 dpurdie 130
}
131
 
132
#-------------------------------------------------------------------------------
133
# Function        : InitFileUtils
134
#
135
# Description     : Initialise this package
136
#                   This function should be called once the user has determined
137
#                   settled on a working directory
138
#
139
#                   The function may be called multiple times
140
#                   to allow various globals to be reset - when the user has
141
#                   changed directory
142
#
143
# Inputs          : Nothing
144
#
145
# Returns         : Nothing
146
#
147
sub InitFileUtils
148
{
149
    #
150
    #   Setup current directory and drive
151
    #
152
 
247 dpurdie 153
    $CwdFull = Getcwd();                    # Current working dir
227 dpurdie 154
 
155
    $CwdDrive = '';
247 dpurdie 156
    $CwdDrive = substr( $CwdFull, 0, 2 )    # Saved Drive letter
227 dpurdie 157
        if ( ! $isUnix );
158
 
247 dpurdie 159
    $Cwd = StripDrive( $CwdFull );          # With drive spec striped
227 dpurdie 160
 
161
    Debug ("InitFileUtils: ScmHost     : $ScmHost");
247 dpurdie 162
    Debug ("InitFileUtils: CwdFull     : $CwdFull");
227 dpurdie 163
    Debug ("InitFileUtils: Cwd         : $Cwd");
164
    Debug ("InitFileUtils: CwdDrive    : $CwdDrive");
165
    Debug ("InitFileUtils: ScmPathSep  : $ScmPathSep");
166
}
167
 
168
 
169
#-------------------------------------------------------------------------------
170
# Function        : Getcwd
171
#
172
# Description     : Retrieve current working directory
173
#
174
# Inputs          : None
175
#
176
# Returns         : The current working directory
177
#
178
# Notes           : Don't use 'pwd' program as it gets symbolic links wrong
179
#
180
sub Getcwd
181
{
182
    my $cwd = getcwd();
183
    return $cwd;
184
}
185
 
186
#-------------------------------------------------------------------------------
261 dpurdie 187
# Function        : TouchFile 
227 dpurdie 188
#
189
# Description     : touch a file
190
#                   Real use is to touch a marker file
191
#
192
# Inputs          : path        - path to the file
193
#
194
# Returns         : TRUE if an error occured in creating the file
195
#
196
sub TouchFile
197
{
198
    my ($path, $text) = @_;
199
    my $result = 0;
283 dpurdie 200
    my $tfh;
201
 
227 dpurdie 202
    Verbose ("Touching file: $path" );
203
    if ( ! -f $path )
204
    {
283 dpurdie 205
        open ($tfh, ">>", $path) || ($result = 1);
206
        close $tfh;
227 dpurdie 207
    }
208
    else
209
    {
210
 
211
        #
212
        #   Modify the file
213
        #
214
        #   Need to physically modify the file
215
        #   Need to change the 'change time' on the file. Simply setting the
216
        #   last-mod and last-access is not enough to get past WIN32
217
        #   OR 'utime()' does not work as expected
218
        #
219
        #   Read in the first character of the file, rewind and write it
220
        #   out again.
221
        #
222
        my $data;
283 dpurdie 223
        open ($tfh , "+<", $path ) || return 1;
224
        if ( read ( $tfh, $data, 1 ) )
225
        {
226
            seek  ( $tfh, 0, 0 );
227
            print $tfh $data;
227 dpurdie 228
        }
229
        else
230
        {
231
            #
232
            #   File must have been of zero length
233
            #   Delete the file and create it
234
            #
283 dpurdie 235
            close ($tfh);
227 dpurdie 236
            unlink ( $path );
283 dpurdie 237
            open ($tfh, ">>", $path) || ($result = 1);
227 dpurdie 238
        }
283 dpurdie 239
        close ($tfh);
227 dpurdie 240
    }
241
    return $result;
242
}
243
 
244
#-------------------------------------------------------------------------------
261 dpurdie 245
# Function        : FileCreate
246
#                   FileAppend
247
#                   _FileWrite
248
#
249
# Description     : Simple Text File Creation function
250
#                   Suited to the creation of small, simple text files.
251
#
252
# Inputs          : Name of the file
253
#                   Remainder are:
254
#                       Lines of data to output to the file
255
#                       Or a reference to an array of lines
256
#                       Or a mixture
257
#                   All lines will be terminated with a "\n"
258
#
259
# Returns         : Nothing
260
#
261
sub FileCreate
262
{
263
    _FileWrite ( '>', @_ );
264
}
265
 
266
sub FileAppend
267
{
268
    _FileWrite ( '>>', @_ );
269
}
270
 
271
sub _FileWrite
272
{
273
    my $mode = shift @_;
274
    my $name = shift @_;
283 dpurdie 275
    my $fh;
261 dpurdie 276
 
277
    Error ("FileCreate: No file specified") unless ( $name );
278
    Error ("FileCreate: Path is directory") if ( -d $name );
279
 
283 dpurdie 280
    open  ($fh, $mode, $name ) || Error( "Cannot create file: $name", "Reason: $!" );
261 dpurdie 281
 
282
    foreach my $entry ( @_ ) {
283
        if ( ref ($entry ) eq 'ARRAY'  ) {
283 dpurdie 284
            print $fh $_ . "\n" foreach  ( @$entry );
261 dpurdie 285
        } else {
283 dpurdie 286
            print $fh $entry . "\n"
261 dpurdie 287
        }
288
    }
283 dpurdie 289
    close $fh;
261 dpurdie 290
}
291
 
292
#-------------------------------------------------------------------------------
6133 dpurdie 293
# Function        : TagFileMatch 
294
#
295
# Description     : Test the contents of a simple (one line) file against a string    
296
#
297
# Inputs          : $tfile      - Name of the tag file
298
#                   $tag        - Tag to match 
299
#
300
# Returns         : True - is a match
301
#
302
sub TagFileMatch
303
{
304
    my ($tfile, $tag) = @_;
305
    return 0 unless -f $tfile;
306
 
307
    open( my $file, '<', $tfile) || return 0;
308
    my $text = <$file>;
309
    close $file;
310
 
311
    $text = '' unless defined ($text);
312
    # Remove trailing new line and white space
313
    $text =~ s~\s*$~~;
314
    Debug("TagFileMatch:'$text':'$tag'", $text eq $tag );
315
 
316
    return $text eq $tag;
317
}
318
 
319
#-------------------------------------------------------------------------------
320
# Function        : TagFileRead
321
#
322
# Description     : Read the contents of a simple (one line) file against a string    
323
#
324
# Inputs          : $tfile      - Name of the tag file
325
#
326
# Returns         : One line of the file
327
#
328
sub TagFileRead
329
{
330
    my ($tfile) = @_;
331
    return "" unless -f $tfile;
332
 
333
    open( my $file, '<', $tfile) || Error("Cannot open '$tfile'. $!");
334
    my $text = <$file>;
335
    close $file;
336
 
337
    $text = '' unless defined ($text);
338
    $text =~ s~\s*$~~;
339
    return $text;
340
}
341
 
342
#-------------------------------------------------------------------------------
227 dpurdie 343
# Function        : FileIsNewer
344
#
345
# Description     : Test two files to see if the files are newer
346
#
347
# Inputs          : file1
348
#                   file2
349
#
350
# Returns         : Returns true if file1 is newer than file2 or file2 does not
351
#                   exist.
352
#
353
#                   If file 1 does not exist then it will return false
354
#
355
sub FileIsNewer
356
{
357
    my ($file1, $file2) = @_;
358
 
359
    my $f1_timestamp = (stat($file1))[9] || 0;
360
    my $f2_timestamp = (stat($file2))[9] || 0;
361
    my $result = $f1_timestamp > $f2_timestamp ? 1 : 0;
362
 
363
    Verbose2 ("FileIsNewer: TS: $f1_timestamp, File: $file1");
364
    Verbose2 ("FileIsNewer: TS: $f2_timestamp, File: $file2");
365
    Verbose2 ("FileIsNewer: $result" );
366
 
367
    return $result;
368
}
369
 
370
#-------------------------------------------------------------------------------
371
# Function        : Realpath
372
#
373
# Description     : Returns the 'real path'
374
#
375
# Inputs          : $path       - Path to process
376
#
377
# Returns         : The real path
378
#
379
sub Realpath
380
{
381
    my( $path ) = @_;
382
    my( $real, $cwd );
383
 
384
    $cwd = Getcwd();
385
    if (!chdir( $path )) {
386
        $real = "";
387
    } else {
388
        $real = Getcwd();
389
        Error ("FATAL: Realpath($path) could not restore directory ($cwd)." )
390
            unless (chdir( $cwd ));
391
    }
392
    Debug( "Realpath:   = $real ($path)" );
393
    return $real;
394
}
395
 
396
#-------------------------------------------------------------------------------
397
# Function        : Realfile
398
#
399
# Description     : Returns the 'real path'
400
#
401
# Inputs          : $path       - Path to process
402
#
403
# Returns         : The real path
404
#
405
#sub Realfile
406
#{
407
#    my( $path ) = @_;
408
#    my( $real, $cwd );
409
#
410
#    $cwd = Getcwd();
411
#    if (!chdir( $path )) {
412
#        $real = "";
413
#    } else {
414
#        $real = Getcwd();
415
#        Error ("FATAL: Realpath($path) could not restore directory ($cwd)." )
416
#            unless (chdir( $cwd ));
417
#    }
418
#    Debug( "Realpath:   = $real ($path)" );
419
#    return $real;
420
#}
421
 
422
#-------------------------------------------------------------------------------
423
# Function        : RelPath
424
#
425
# Description     : Return the relative path to the current working directory
426
#                   as provided in $Cwd
427
#
285 dpurdie 428
# Inputs          : $base       - Base directory to convert
4421 dpurdie 429
#                                 Expected to be well formed absolute path
285 dpurdie 430
#                   $here       - Optional current directory
4421 dpurdie 431
#                                 Expected to be well formed absolute path
285 dpurdie 432
#                                 $Cwd will be used if non provided
227 dpurdie 433
#
434
# Returns         : Relative path from the current directory to the base directory
435
#
436
sub RelPath
437
{
285 dpurdie 438
    my ($base, $here) = @_;
227 dpurdie 439
 
285 dpurdie 440
    $here = $Cwd unless ( defined $here );
227 dpurdie 441
    my @base = split ('/', $base );
285 dpurdie 442
    my @here = split ('/', $here );
227 dpurdie 443
    my $result;
444
 
4265 dpurdie 445
    Debug("RelPath: Here  : $here");
227 dpurdie 446
    Debug("RelPath: Source: $base");
447
 
4421 dpurdie 448
    # Not absolute - just return it
6133 dpurdie 449
    return $base unless ( $base =~ m~^/~ || $base =~ m~^\w+:/~ );
450
 
227 dpurdie 451
    #
452
    #   Remove common bits from the head of both lists
453
    #
454
    while ( $#base >= 0 && $#here >= 0 && $base[0] eq $here[0] )
455
    {
456
        shift @base;
457
        shift @here;
458
    }
459
 
460
    #
461
    #   Need to go up some directories from here and then down into base
462
    #
463
    $result = '../' x ($#here + 1);
464
    $result .= join ( '/', @base);
465
    $result = '.' unless ( $result );
466
    $result =~ s~/$~~;
467
 
468
    Debug("RelPath: Result: $result");
469
    return $result;
470
}
471
 
472
#-------------------------------------------------------------------------------
473
# Function        : AbsPath
474
#
475
# Description     : Return the absolute path to the file
476
#                   Add the current directory if the path is absolute
477
#                   Clean up xxx/.. constructs
478
#
479
#                   If an absolute path is provided then it will simply be
480
#                   cleaned up.
481
#
482
# Assumption      : Absolute paths start with a "/" and do not have a drive letter
483
#
2450 dpurdie 484
# Inputs          : $dpath      - Source file path
325 dpurdie 485
#                   $here       - Optional current directory
486
#                                 $Cwd will be used if non provided
2450 dpurdie 487
#                   $mode       - Defined: No error
488
#                                 Used during error reporting
227 dpurdie 489
#
490
# Returns         : Cleaned abs path
491
#
492
sub AbsPath
493
{
2450 dpurdie 494
    my ($dpath, $here, $mode) = @_;
227 dpurdie 495
    my @result;
496
 
497
    #
498
    #   If we have a relative path then prepend the current directory
499
    #   An absolute path is:
500
    #           /aaa/aa/aa
501
    #       or  c:/aaa/aa/aa
502
    #
325 dpurdie 503
    $here = $Cwd unless ( defined $here );
3859 dpurdie 504
    $here =~ s~^\w:~~;
325 dpurdie 505
    $dpath = $here . '/' . $dpath
3832 dpurdie 506
        unless ( $dpath =~ m~^/|\w:[/\\]~  );
227 dpurdie 507
    $dpath =~ s~//~/~g;
508
 
509
    #
510
    #   Walk the bits and remove ".." directories
511
    #       Done by pushing non-.. elements and poping last entry for .. elements.
512
    #   Have a leading "/" which is good.
513
    #
514
    foreach ( split ( '/', $dpath ) )
515
    {
516
        next if ( $_ eq '.' );
517
        unless ( $_ eq '..' )
518
        {
519
            push @result, $_;
520
        }
521
        else
522
        {
2450 dpurdie 523
            if ( $#result <= 0 )
524
            {
525
                Error ("Bad Pathname: $dpath") unless ( $mode );
526
                return $dpath;
527
            }
528
            else
529
            {
530
                pop @result;
531
            }
227 dpurdie 532
        }
533
    }
534
 
535
    #
536
    #   Create a nice directory name again.
537
    #
538
    return join ( '/', @result );
539
}
540
 
541
#-------------------------------------------------------------------------------
542
# Function        : FullPath
543
#
544
# Description     : Return the absolute path to the file - with driver letter
545
#                   Add the current directory if the path is absolute
546
#                   Clean up xxx/.. constructs
547
#
548
#                   If an absolute path is provided then it will simply be
549
#                   cleaned up.
550
#
551
# Inputs          : Source file path
325 dpurdie 552
#                   $here       - Optional current directory
553
#                                 $Cwd will be used if non provided
227 dpurdie 554
#
555
# Returns         : Cleaned abs path
556
#
557
sub FullPath
558
{
559
    my $path = AbsPath (@_ );
229 dpurdie 560
    $path = $CwdDrive . $path unless ( $path =~ m~^\w:~  );
227 dpurdie 561
    return $path;
562
}
563
 
564
#-------------------------------------------------------------------------------
257 dpurdie 565
# Function        : TruePath
566
#
567
# Description     : Returns a case correct pathname
568
#                   Really only applicable to windows, under unix it returns
569
#                   its input path.
570
#
571
#                   Maintains a cache to speed up processing
572
#
573
# Inputs          : Confused path (Absolute with a driver letter)
574
#
575
# Returns         : Case Correct Path : Windows
576
#                   Input Path : Non Windows
577
#
578
my %TruePathCache;
579
my %DirRead;
580
sub TruePath
581
{
582
    my ($path) = @_;
583
    $path =~ tr~\\/~/~s;
584
 
585
    #
586
    #   On Unix systems the path is case sensitive to start with
587
    #   Can't get it wrong - can't do anything.
588
    #
589
    return $path if ( $isUnix );
590
 
591
    #
592
    #   If the path does not exist at all then return the user input
593
    #   Assume that the user will handle this later
594
    #
595
    unless ( -e $path )
596
    {
597
        Warning ("TruePath given invalid path: $path");
598
        return $path;
599
    }
600
 
601
    #
602
    #   Look in the cache - have we seen this before
603
    #
604
    if ( exists $TruePathCache{lc($path)} )
605
    {
5969 dpurdie 606
        Verbose2( "TruePath Cache Hit: $path");
257 dpurdie 607
        return $TruePathCache{lc($path)};
608
    }
609
 
610
    #
611
    #   Split the directory into components
612
    #
613
    my $TrueComponent = '';
614
    my @components = split ('/', $path );
615
    foreach my $elem ( @components )
616
    {
617
        Debug ("Process: $elem in $TrueComponent");
618
        my $tag;
619
        #
620
        #   Handle driver letter
621
        #
622
        if ( $elem =~ m~^[a-zA-Z]:$~ )
623
        {
624
            $elem = uc($elem);
625
            $TrueComponent = $elem;
626
 
627
            $tag = lc($TrueComponent);
628
            $TruePathCache{$tag} = $elem;
629
            Debug ("     Add: $elem");
630
            next;
631
        }
632
 
633
        #
634
        #   Ensure that we have read in containing directory
635
        #   Note: Append / to ensure we read root directories correctly
636
        #
637
        $TrueComponent .= '/';
638
        unless ( $DirRead{ $TrueComponent }  )
639
        {
640
            Debug ("Reading: $TrueComponent");
285 dpurdie 641
            opendir (my $tp, $TrueComponent ) or Error ("Cannot open $TrueComponent");
642
            my @dirlist = readdir $tp;
643
            closedir $tp;
257 dpurdie 644
            $DirRead {$TrueComponent } = 1;
645
 
646
            #
647
            #   Add cache entries for each path in the directory
648
            #
649
            foreach my $dir ( @dirlist )
650
            {
651
                next if ( $dir eq '.' );
652
                next if ( $dir eq '..' );
653
                my $fullpath = $TrueComponent . $dir;
654
                Debug ("     Add: $fullpath");
655
                $TruePathCache{lc($fullpath)} = $fullpath;
656
            }
657
        }
658
 
659
        #
660
        #   Now that we have populated the cache with data from the directory
661
        #   we can expect to find our desired entry in the cache.
662
        #
663
        $tag = lc($TrueComponent . $elem );
664
        if ( exists $TruePathCache{ $tag } )
665
        {
666
            $TrueComponent = $TruePathCache{ $tag };
667
        }
668
        else
669
        {
670
            DebugDumpData ("Cache", \%TruePathCache);
671
            Error ("TruePath Internal error. File may have been deleted: $tag");
672
        }
673
        Debug ("Have: $TrueComponent");
674
    }
675
 
5969 dpurdie 676
    Verbose2 ("TruePath: $TrueComponent");
257 dpurdie 677
    return $TrueComponent;
678
}
679
 
680
#-------------------------------------------------------------------------------
227 dpurdie 681
# Function        : CleanPath
682
#
683
# Description     : Cleanup a path
684
#                   Remove xxx/.. constructs
6133 dpurdie 685
#                   Replace /./ constructs with /
227 dpurdie 686
#
687
# Note            : Will not perform error detection on badly formed
688
#                   absolute paths.
689
#
690
# Inputs          : Source file path
691
#
692
# Returns         : Clean absolute or relative path
693
#
694
#
695
sub CleanPath
696
{
697
    my ($dpath) = @_;
698
    my @result;
699
    Debug("CleanPath: Source: $dpath");
700
 
701
    #
702
    #   Cleanup the the user input. Remove double delimiters and ensure there
703
    #   is no trailing delemiter
704
    #
245 dpurdie 705
    $dpath =~ s~/+~/~g;
227 dpurdie 706
    $dpath =~ s~/$~~g;
6133 dpurdie 707
    $dpath =~ s~/\./~/~g;
227 dpurdie 708
 
709
    #
710
    #   Walk the bits and remove "xxx/.." directories
711
    #
712
    foreach ( split ( '/', $dpath ) )
713
    {
714
        if ( $_ ne '..' || $#result < 0 )
715
        {
716
            push @result, $_;
717
        }
718
        else
719
        {
720
            if ( $#result >= 0 )
721
            {
283 dpurdie 722
                my $last_dir = pop @result;
723
                push (@result, $last_dir, $_)
724
                    if ($last_dir eq '..' || $last_dir eq '');
227 dpurdie 725
            }
726
        }
727
    }
728
 
729
    my $result = join ( '/', @result );
730
    Debug("CleanPath: Result: $result");
731
    return $result;
732
}
733
 
734
#-------------------------------------------------------------------------------
735
# Function        : StripDrive
736
#
737
# Description     : Strip any leading drive speification
738
#
739
# Inputs          : $fname          - Path to process
740
#
741
# Returns         : Path, with drive letter stripped
742
#                   Will do nothing on Unix systems
743
#
744
sub StripDrive
745
{
746
    my( $fname ) = @_;                          # Full name
747
 
748
    $fname =~ s/^[A-Za-z]://g                  # leading drive spec
749
        if ( ! $isUnix );
750
    return $fname;
751
}
752
 
753
#-------------------------------------------------------------------------------
754
# Function        : StripDir
755
#
756
# Description     : Strip directory (returns file, including extension)
757
#
758
# Inputs          : $fname          - Path to process
759
#
760
# Returns         : filename + extension
761
#
762
sub StripDir
763
{
764
    my( $fname ) = @_;                          # Full name
765
    my( $idx );
766
 
767
    if (($idx = rindex($fname, "/")) == -1) {
768
        if (($idx = rindex($fname, "\\")) == -1) {
769
            return $fname;                      # No path ...
770
        }
771
    }
772
    return substr($fname, $idx+1, 512);
773
}
774
 
775
#-------------------------------------------------------------------------------
776
# Function        : StripExt
777
#
778
# Description     : Strip extension (return basename, plus any dir)
779
#
780
# Inputs          : $fname          - Path to process
781
#
782
# Returns         : basename, plus any dir
783
#                   Simply removes one extension
784
#
785
sub StripExt
786
{
787
    my( $fname ) = @_;
788
 
789
    $fname =~ s/(\S+)(\.\S+)/$1/;               # strip out trailing '.<ext>'
790
    return ($fname);
791
}
792
 
793
#-------------------------------------------------------------------------------
794
# Function        : StripFile
795
#
796
# Description     : Strip filename (returns extension)
797
#
798
# Inputs          : $fname          - Path to process
799
#
800
# Returns         : extension
801
#                   Will return an empty string if the input does not have an
802
#                   extension.
803
#
804
sub StripFile
805
{
806
    my( $fname ) = @_;
807
 
808
    $fname =~ s/(\S+)(\.\S+)/$2/;               # Strip out items before '.<ext>'
809
    return ("")                                 # No extension
810
        if ("$fname" eq "@_");
811
    return ($fname);
812
}
813
 
814
#-------------------------------------------------------------------------------
815
# Function        : StripFileExt
816
#
817
# Description     : Strip filename and ext (returns dir)
818
#
819
# Inputs          : $fname          - Path to process
820
#
821
# Returns         : Directory of a file path
822
#
823
 
824
 
825
#   StripFileExt( path ) ---
826
#       Strip filename and ext (returns dir)
827
#..
828
 
829
sub StripFileExt
830
{
831
    my( $fname ) = @_;                          # Full name
832
    my( $idx );
833
    my $dir;
834
 
835
    if (($idx = rindex($fname, "/")) == -1) {
836
        if (($idx = rindex($fname, "\\")) == -1) {
837
            return "";                          # No path ...
838
        }
839
    }
840
 
841
    return substr($fname, 0, $idx);
842
}
843
 
844
#-------------------------------------------------------------------------------
845
# Function        : StripDirExt
846
#
847
# Description     : Strip the directory and extension from a file
848
#                   Returning the base file. Optionally replace the extension
849
#                   with a user value
850
#
851
# Inputs          : Full path name
852
#                   Optional extension to be replaced
853
#
854
# Returns         :
855
#
856
sub StripDirExt
857
{
858
    my ($fname, $ext ) = (@_, '');
859
    $fname =~ s~.*[/\\]~~;                      # Strip directory
860
    $fname =~ s/\.[^.]+$/$ext/;
861
    return $fname;
862
}
863
 
864
 
865
#-------------------------------------------------------------------------------
866
# Function        : CleanDirName
867
#
868
# Description     : Clean up a directory path string
869
#                       1) Remove multiple //
870
#                       2) Remove multiple /./
871
#                       2) Remove leading ./
872
#                       3) Remove trailing /
873
#                       4) Remove /xxxx/../
874
#
875
# Inputs          : A dirty directory path
876
#
877
# Returns         : A clean directory path
878
#
879
sub CleanDirName
880
{
881
    my ( $dir ) = @_;
882
    $dir =~ s~//~/~g;                   # Kill multiple //
883
    $dir =~ s~/\./~/~g;                 # Kill multiple /./
884
    $dir =~ s~^\./~~;                   # Kill leading ./
885
    $dir = '.' unless ( $dir );         # Ensure we have a path
886
 
887
    #
888
    #   Remove /xxxxx/../ bits
889
    #
890
    unless ( $dir =~ m~^\.\./~  )
891
    {
892
        while ( $dir =~ s~
893
                        (^|/)               # Allow for stings that may not start with a /
894
                        [^/]+/\.\.          # xxxxx/.., where xxxx is anything other than a /
895
                        (/|$)               # Allow for strings ending with /..
896
                        ~$1~x               # Replace with the start character
897
              )
898
        {
899
            last if ( $dir =~ m~^\.\./~ );  # Too far. Stop now !
900
        }
901
    }
902
 
903
    $dir =~ s~/$~~;                     # No trailing /
904
    $dir =~ s~/\.$~~;                   # No trailing /.
905
    return $dir;
906
}
907
 
908
#-------------------------------------------------------------------------------
909
# Function        : DisplayPath
910
#
911
# Description     : Cleanup a path for display purposes
912
#                   Useful under windows to provide paths with \ that can be
913
#                   cut and pasted.
914
#
915
#                   If cygwin is located in the environment, then this function
916
#                   will not convert / to \.
917
#
918
# Inputs          : A path to modify
919
#
920
# Returns         : Modified path
921
#
922
sub DisplayPath
923
{
924
    my ($path) = @_;
925
    if ( ! $isUnix && ! $isCygWin )
926
    {
927
        $path =~ s~/~\\~g;
928
    }
4546 dpurdie 929
    else
930
    {
931
        $path =~ s~\\~/~g;
932
    }
227 dpurdie 933
    return $path;
934
}
935
 
361 dpurdie 936
#-------------------------------------------------------------------------------
937
# Function        : RmDirTree
938
#
939
# Description     : Delete a directory tree
940
#                   Really delete it. Allow for users to remove directory
941
#                   without search permissions under unix.
942
#
943
#                   Can also delete a file
944
#
2439 dpurdie 945
#                   This function has a bit of history
946
#                   I've tried the Perl rmtree(), but there were situations
947
#                   where the OS(WIN32) says the directory exists after its been
948
#                   deleted. Also the Jats-Win32 version of chmod would issue
949
#                   messages if it couldn't find the dir/file.
950
#
951
#                   The solution is to use JATS' own JatsFileUtil utility
952
#                   This appears to do the right thing
953
#
361 dpurdie 954
# Inputs          : $path                   - Path to directory
4344 dpurdie 955
#                                             May be empty, in which case nothing is done
361 dpurdie 956
#
957
# Returns         : 1                       - Still there
958
#
959
sub RmDirTree
960
{
961
    my ($path) = @_;
4344 dpurdie 962
    return 0 unless $path;
361 dpurdie 963
    if ( -e $path )
964
    {
2439 dpurdie 965
        #  Need to know if its a file or a directory
966
        #
967
        my $mode = ( -d $path ) ? 'T' : 'r';
968
 
969
        #
970
        #   Use JATS's own utility to do the hardwork
971
        #   Used as it address a number of issues
972
        #
973
        #   Merge in verbosity
974
        #
975
        system ("$ENV{GBE_BIN}/JatsFileUtil", $mode . $::ScmVerbose, '', $path );
976
 
977
        #
978
        #   Shouldn't happen but ...
979
        #   If the path still exists try another (one this has known problems)
980
        #
981
        if ( -e $path )
982
        {
983
            Verbose3 ("RmDirTree: Directory still exists. Change permissions: $path");
984
            system ("$ENV{GBE_BIN}/chmod", '-R', 'u+wrx', $path);
5568 dpurdie 985
            eval { rmtree( $path ); };
2439 dpurdie 986
        }
361 dpurdie 987
    }
988
    return ( -e $path );
989
}
990
 
227 dpurdie 991
1;
992
 
993