Subversion Repositories DevTools

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

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