ld --as-needed compilation fixes with external libs.
[fvwm.git] / perllib / General / FileSystem.pm
blob6182a4711bfa8d729fe294ea33e5d958cb777895
1 # Copyright (C) 1998-2009, Mikhael Goikhman
3 # This program is free software; you can redistribute it and/or modify
4 # it under the terms of the GNU General Public License as published by
5 # the Free Software Foundation; either version 2 of the License, or
6 # (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software
15 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 package General::FileSystem;
18 require 5.004;
19 use strict;
21 use vars qw(@ISA @EXPORT);
22 require Exporter;
23 @ISA = qw(Exporter);
24 @EXPORT = qw(
25 load_file save_file append_file remove_file copy_file move_file
26 make_dir make_path clean_dir remove_dir copy_dir move_dir
27 list_filenames find_file find_executable
28 default_dir_perm preserve_stat parse_path get_cwd
31 use vars qw($CACHE_FILE_NUM $cache_counter @prev_filenames @prev_file_content_refs);
32 use vars qw($ENABLE_CACHE %NEVER_COPY_FILES %NEVER_REMOVE_FILES);
33 use vars qw($DEFAULT_DIR_PERM $PRESERVED_STAT);
34 use vars qw($DEBUG_ENABLED $ERROR_HANDLER $LOAD_FILE_DIRS $SAVE_FILE_DIR);
36 BEGIN {
37 $ENABLE_CACHE = 0; # this is risky for dynamical files
38 %NEVER_COPY_FILES = ( 'CVS' => 1, 'core' => 1 );
39 %NEVER_REMOVE_FILES = ( 'CVS' => 1 );
40 $DEFAULT_DIR_PERM = 0775;
41 $PRESERVED_STAT = 0;
43 # allow these constants to be set directly from outside
44 $ERROR_HANDLER ||= "warn"; # may be "die", "warn", "quiet" or CODE
45 $DEBUG_ENABLED ||= 0;
46 $LOAD_FILE_DIRS ||= [ "." ]; # for non fully qualified files only
47 $SAVE_FILE_DIR ||= "."; # for non fully qualified files only
51 # ----------------------------------------------------------------------------
53 =head1 NAME
55 General::FileSystem - file system specific functions
57 =head1 SYNOPSIS
59 use General::FileSystem "-die", "-debug"; # die on errors
61 eval {
62 make_path("/tmp/my-own/dir");
64 my $file_content_ref = load_file("/etc/issue");
65 save_file("/tmp/my-own/dir/issue", $file_content_ref);
67 # This is equivalent to the previous two lines, but optimized
68 copy_file("/etc/issue", "/tmp/my-own/dir/issue");
70 make_dir("/tmp/my-own/dir2", 0711);
71 copy_file("/etc/issue", "/tmp/my-own/dir2/issue");
72 move_file("/tmp/my-own/dir2/issue", "/tmp/my-own/dir2/issue2");
73 remove_file("/tmp/my-own/dir2/issue2");
74 clean_dir("/tmp/my-own/dir2"); # no effect, it's empty already
76 remove_dir("/tmp/my-own");
78 if ($@) {
79 print "File System Error: $@";
82 or just:
84 use General::FileSystem;
85 copy_file("origin.txt", "backup.txt");
87 =head1 DESCRIPTION
89 This package contains common file operation functions:
91 B<load_file>, B<save_file>, B<append_file>, B<remove_file>, B<copy_file>, B<move_file>,
92 B<make_dir>, B<make_path>, B<clean_dir>, B<remove_dir>, B<copy_dir>, B<move_dir>,
93 B<list_filenames>, B<find_file>, B<find_executable>,
94 B<default_dir_perm>, B<preserve_stat>, B<parse_path>, B<get_cwd>.
96 On fatal file system errors all functions call the error handler, that may
97 throw exception (die), issue a warning or quietly return undef.
98 You may control this by passing one of the arguments I<-die>, I<-warn>
99 or I<-quiet> in B<use> or by setting C<$ERROR_HANDLER> to one of these
100 values (don't specify a dash in this case).
102 =head1 REQUIREMENTS
104 L<Cwd>, L<File::Basename>, L<File::Copy>.
106 =head1 FUNCTIONS
108 =cut
109 # ============================================================================
112 use Cwd;
113 use File::Basename;
114 use File::Copy;
117 sub import ($;$) {
118 my $package = shift;
119 while (@_ && $_[0] =~ /^-/) {
120 local $_ = shift;
121 $ERROR_HANDLER = $1 if /^-(die|warn|quiet)$/i;
122 $DEBUG_ENABLED = $1 if /^-(debug)$/i;
124 $package->export_to_level(1, @_);
128 # private function
129 sub call_error_handler ($) {
130 my $msg = shift;
131 die "$msg: [$!]\n" if $ERROR_HANDLER eq "die";
132 warn "$msg: [$!]\n" if $ERROR_HANDLER eq "warn";
133 return undef if $ERROR_HANDLER eq "quiet";
134 &$ERROR_HANDLER($msg) if ref($ERROR_HANDLER) eq "CODE";
135 return undef;
139 # private function
140 sub print_log ($) {
141 my $msg = shift;
142 return unless $DEBUG_ENABLED;
143 print STDERR "FileSystem: $msg\n";
147 # ----------------------------------------------------------------------------
149 =head2 load_file
151 =over 4
153 =item usage
155 $content_ref = load_file($filename)
157 =item description
159 Loads file with given file-name from local filesystem.
161 =item parameters
163 * filename - name of the file to be loaded.
165 =item returns
167 Reference to file content string on success, otherwise either dies or warns
168 and returns undef as configured.
170 =back
172 =cut
173 # ============================================================================
176 BEGIN {
177 $CACHE_FILE_NUM = 6;
178 $cache_counter = -1;
179 @prev_filenames = ("", "", "", "", "", "");
180 @prev_file_content_refs = \("", "", "", "", "", "");
184 sub load_file ($) {
185 my $filename = shift;
187 foreach (@$LOAD_FILE_DIRS) {
188 if (-f "$_/$filename") { $filename = "$_/$filename"; last; }
190 print_log("Loading file $filename") if $DEBUG_ENABLED;
192 if ($ENABLE_CACHE) {
193 for (0 .. $CACHE_FILE_NUM-1) {
194 if ($filename eq $prev_filenames[$_] && -r $filename) {
195 print_log("getting from file cache") if $DEBUG_ENABLED;
196 return $prev_file_content_refs[$_];
201 open(FILE, "<$filename") || return call_error_handler("Can't open $filename");
202 my $content = join("", <FILE>);
203 close(FILE) || return call_error_handler("Can't close $filename");
205 if ($ENABLE_CACHE) {
206 $cache_counter = ($cache_counter+1) % $CACHE_FILE_NUM;
207 $prev_filenames[$cache_counter] = $filename;
208 $prev_file_content_refs[$cache_counter] = \$content;
210 return \$content;
214 # ----------------------------------------------------------------------------
216 =head2 save_file
218 =over 4
220 =item description
222 Saves file-content to local filesystem with given file-name.
224 =item usage
226 save_file($filename, \$content);
228 =item parameters
230 * filename - name of the file to be saved into
231 * content_ref - reference to file content string
232 * create_subdirs - optional flag (default is 0 - don't create subdirs)
234 =item returns
236 C<1> on success, otherwise either dies or warns and returns undef as configured.
238 =back
240 =cut
241 # ============================================================================
244 sub save_file ($$;$) {
245 my ($filename, $content_ref, $create_dirs) = @_;
247 if ($filename !~ m=^[/\\]|\w:\\=) {
248 $filename = "$SAVE_FILE_DIR/$filename";
250 print_log("Saving file $filename") if $DEBUG_ENABLED;
251 die("save_file: No SCALAR ref parameter\n")
252 unless ref($content_ref) eq 'SCALAR';
254 if ($ENABLE_CACHE) {
255 for (0 .. $CACHE_FILE_NUM-1) {
256 $prev_file_content_refs[$_] = $content_ref
257 if $filename eq $prev_filenames[$_];
260 if ($create_dirs) {
261 my $dirname = dirname($filename);
262 make_path($dirname) unless -d $dirname;
265 open(FILE, ">$filename") || return call_error_handler("Can't open $filename");
266 print FILE $$content_ref;
267 close(FILE) || return call_error_handler("Can't close $filename");
268 return 1;
272 # ----------------------------------------------------------------------------
274 =head2 append_file
276 =over 4
278 =item description
280 Appends file-content to local filesystem with given file-name.
282 =item usage
284 append_file($filename, \$appended_content);
286 =item parameters
288 * filename - name of the file to be saved into
289 * appended_content_ref - reference to appended-content string
291 =item returns
293 C<1> on success, otherwise either dies or warns and returns undef as configured.
295 =back
297 =cut
298 # ============================================================================
301 sub append_file ($$) {
302 my ($filename, $appended_content_ref) = @_;
303 print_log("Append>>file $filename") if $DEBUG_ENABLED;
305 if ($ENABLE_CACHE) {
306 for (0 .. $CACHE_FILE_NUM-1 && -r $filename) {
307 ${$prev_file_content_refs[$_]} .= $$appended_content_ref
308 if $filename eq $prev_filenames[$_];
312 open(FILE, ">>$filename") || return call_error_handler("Can't append to $filename");
313 print FILE $$appended_content_ref;
314 close(FILE) || return call_error_handler("Can't close $filename");
315 return 1;
319 # ----------------------------------------------------------------------------
321 =head2 remove_file
323 =over 4
325 =item description
327 Removes all files from given directory.
329 =item usage
331 remove_file($filename);
333 =item parameters
335 * filename - name of the file to be deleted
337 =item returns
339 C<1> on success, otherwise either dies or warns and returns undef as configured.
341 =back
343 =cut
344 # ============================================================================
347 sub remove_file ($;$) {
348 my $filename = shift;
349 print_log("Removin file $filename") if $DEBUG_ENABLED;
350 unlink($filename) || return call_error_handler("Can't unlink $filename");
351 return 1;
355 # ----------------------------------------------------------------------------
357 =head2 make_dir
359 =over 4
361 =item description
363 Removes all files from given directory.
365 =item usage
367 make_dir($PREVIEW_DIR);
369 =item parameters
371 * directory to make
372 * optional creating dir permissions (default is $DEFAULT_DIR_PERM)
374 =item returns
376 C<1> on success, otherwise either dies or warns and returns undef as configured.
378 =back
380 =cut
381 # ============================================================================
384 sub make_dir ($;$) {
385 my $dirname = shift;
386 my $perm = shift || $DEFAULT_DIR_PERM;
387 print_log("Creating dir $dirname, " . sprintf("%o", $perm))
388 if $DEBUG_ENABLED;
389 mkdir($dirname, $perm) || return call_error_handler("Can't mkdir $dirname");
390 return 1;
394 # ----------------------------------------------------------------------------
396 =head2 make_path
398 =over 4
400 =item description
402 Removes all files from given directory.
404 =item usage
406 make_path($PUBLISH_DIR);
408 =item parameters
410 * path to make
411 * optional creating dir permissions (default is $DEFAULT_DIR_PERM)
413 =item returns
415 C<1> on success, otherwise either dies or warns and returns undef as configured.
417 =back
419 =cut
420 # ============================================================================
423 sub make_path ($;$) {
424 my $dirname = shift;
425 my $perm = shift || $DEFAULT_DIR_PERM;
426 print_log("Making path $dirname, " . sprintf("%o", $perm))
427 if $DEBUG_ENABLED;
429 return 1 if -d $dirname;
430 my $parent_dir = dirname($dirname);
432 local $DEBUG_ENABLED = 0;
433 &make_path($parent_dir, $perm) unless -d $parent_dir;
434 make_dir($dirname, $perm);
436 return 1;
440 # ----------------------------------------------------------------------------
442 =head2 copy_file
444 =over 4
446 =item description
448 Copies a file to another location.
450 =item usage
452 copy_file($from, $to);
454 =item parameters
456 * file name to copy from
457 * file name to copy to
459 =item returns
461 C<1> on success, otherwise either dies or warns and returns undef as configured.
463 =back
465 =cut
466 # ============================================================================
469 sub copy_file ($$) {
470 my ($src_filename, $dst_filename) = @_;
471 print_log("Copying file $src_filename to $dst_filename")
472 if $DEBUG_ENABLED;
474 # Must manage symbolic links somehow
475 # return if -l $src_filename;
477 copy($src_filename, $dst_filename)
478 or return call_error_handler("Can't copy $src_filename $dst_filename");
480 if ($PRESERVED_STAT) {
481 my ($device, $inode, $mode) = stat($src_filename);
482 chmod($mode, $dst_filename);
484 return 1;
488 # ----------------------------------------------------------------------------
490 =head2 move_file
492 =over 4
494 =item description
496 Moves (or renames) a file to another location.
498 =item usage
500 move_file($from, $to);
502 =item parameters
504 * file name to move from
505 * file name to move to
507 =item returns
509 C<1> on success, otherwise either dies or warns and returns undef as configured.
511 =back
513 =cut
514 # ============================================================================
517 sub move_file ($$) {
518 my ($src_filename, $dst_filename) = @_;
519 print_log("Moving file $src_filename to $dst_filename")
520 if $DEBUG_ENABLED;
522 move($src_filename, $dst_filename)
523 or return call_error_handler("Can't move $src_filename $dst_filename");
524 return 1;
528 # ----------------------------------------------------------------------------
530 =head2 clean_dir
532 =over 4
534 =item description
536 Removes all files from given directory.
538 =item usage
540 clean_dir($PREVIEW_DIR);
542 =item parameters
544 * directory to clean
545 * optional flag:
546 0 - don't go recursively, unlink files in first level only
547 1 - recursively clean subdirs (default)
548 2 - unlink subdirs
549 3 - unlink given directory
551 =item returns
553 C<1> on success, otherwise either dies or warns and returns undef as configured.
555 =back
557 =cut
558 # ============================================================================
561 sub clean_dir ($;$) {
562 my $dirname = shift;
563 my $recursive = shift || 1;
564 die("clean_dir: Unsupported flag $recursive\n")
565 if $recursive > 3 || $recursive < 0;
566 print_log(($recursive != 3 ? "Cleaning" : "Removing") . " dir $dirname "
567 . ["files only", "recursively files only", "recursively", "completely"]->[$recursive])
568 if $DEBUG_ENABLED;
570 local $DEBUG_ENABLED = 0;
572 my @subdirs = ();
573 my $filenames = list_filenames($dirname);
575 # process files
576 foreach (@$filenames) {
577 next if $NEVER_REMOVE_FILES{$_};
578 my $filename = "$dirname/$_";
579 if (-d $filename) { push @subdirs, $filename; }
580 else { unlink("$filename") || return call_error_handler("Can't unlink $filename"); }
583 # process subdirs
584 map {
585 clean_dir($_, $recursive);
586 rmdir($_) || return call_error_handler("Can't unlink $_") if $recursive == 2;
587 } @subdirs if $recursive;
588 rmdir($dirname) || return call_error_handler("Can't unlink $dirname") if $recursive == 3;
590 return 1;
594 # ----------------------------------------------------------------------------
596 =head2 remove_dir
598 =over 4
600 =item description
602 Entirely removes given directory and its content (if any).
603 This is an alias to C<clean_dir(3)>.
605 =item usage
607 remove_dir($TMP_DIR);
609 =item parameters
611 * directory to clean
613 =item returns
615 C<1> on success, otherwise either dies or warns and returns undef as configured.
617 =back
619 =cut
620 # ============================================================================
623 sub remove_dir ($) {
624 my $dirname = shift;
625 return clean_dir($dirname, 3);
629 # ----------------------------------------------------------------------------
631 =head2 copy_dir
633 =over 4
635 =item description
637 Recursively copies all files and subdirectories inside given directory
638 to new location.
640 Destination directory must not exist. Use: C<trap { remove_dir($dest); };>
641 to remove it before copying.
643 =item usage
645 copy_dir($dir_from, $dir_to);
647 =item parameters
649 * source directory to copy
650 * destination directory to copy to (may not exist)
651 * optional creating dir permissions (default is $DEFAULT_DIR_PERM)
653 =item returns
655 C<1> on success, otherwise either dies or warns and returns undef as configured.
657 =back
659 =cut
660 # ============================================================================
663 sub copy_dir ($$) {
664 my ($src_dirname, $dst_dirname, $perm) = @_;
666 return call_error_handler("Directory $src_dirname does not exist")
667 unless -d $src_dirname;
668 make_dir($dst_dirname, $perm) unless -d $dst_dirname;
670 print_log("Copying dir $src_dirname to $dst_dirname recursively")
671 if $DEBUG_ENABLED;;
673 local $DEBUG_ENABLED = 0;
675 my $error = 0;
676 my @subdirs = ();
677 my $filenames = list_filenames($src_dirname);
679 # process files
680 foreach (@$filenames) {
681 next if $NEVER_COPY_FILES{$_};
682 my $src_filename = "$src_dirname/$_";
683 my $dst_filename = "$dst_dirname/$_";
684 if (-d $src_filename) { push @subdirs, $_; }
685 elsif (-l $src_filename) { next if "# We ignore links for now! TO FIX!" }
686 else { copy_file($src_filename, $dst_filename) or $error = 1; }
689 # process subdirs
690 foreach (@subdirs) {
691 my $src_subdirname = "$src_dirname/$_";
692 my $dst_subdirname = "$dst_dirname/$_";
693 &copy_dir($src_subdirname, $dst_subdirname) or $error = 1;
696 return call_error_handler("Errors while copying some files/subdirs in $src_dirname to $dst_dirname")
697 if $error;
698 return 1;
702 # ----------------------------------------------------------------------------
704 =head2 move_dir
706 =over 4
708 =item description
710 Moves (or actually renames) a directory to another location.
712 Destination directory must not exist. Use: C<trap { remove_dir($dest); };>
713 to remove it before copying.
715 =item usage
717 move_dir($dir_from, $dir_to);
719 =item parameters
721 * source directory to move from
722 * destination directory to move to (must not exist)
724 =item returns
726 C<1> on success, otherwise either dies or warns and returns undef as configured.
728 =back
730 =cut
731 # ============================================================================
734 sub move_dir ($$) {
735 my ($src_dirname, $dst_dirname) = @_;
736 print_log("Moving dir $src_dirname to $dst_dirname")
737 if $DEBUG_ENABLED;
739 rename($src_dirname, $dst_dirname)
740 or return call_error_handler("Can't rename $src_dirname $dst_dirname");
741 return 1;
745 # ----------------------------------------------------------------------------
747 =head2 list_filenames
749 =over 4
751 =item description
753 Returns the file names in the given directory including all types of files
754 (regular, directory, link, other), not including '.' and '..' entries.
756 =item usage
758 # mini file lister
759 $dir = '/home/ftp';
760 foreach my $file (@{list_filenames($dir)}) {
761 print "File $file\n" if -f "$dir/$file";
762 print "Dir $file\n" if -d "$dir/$file";
765 =item parameters
767 * directory to list (or array ref of directories)
768 * optional flag, 1 means work recursively, the default is 0
770 =item returns
772 Array ref of scalars (file names) on success.
773 Otherwise either dies or warns and returns undef as configured.
775 =back
777 =cut
778 # ============================================================================
781 sub list_filenames ($;$) {
782 my $dirname = shift;
783 my $recursive = shift || 0;
784 if (ref($dirname) eq "ARRAY") {
785 my @files = ();
786 foreach (@$dirname) { push @files, &list_filenames($_); }
787 return \@files;
789 print_log("Listing dir $dirname") if $DEBUG_ENABLED;
791 opendir(DIR, $dirname) || return call_error_handler("Can't opendir $dirname");
792 my @files = grep { $_ ne '.' && $_ ne '..' } readdir(DIR);
793 closedir(DIR) || return call_error_handler("Can't closedir $dirname");
795 if ($recursive) {
796 my $i = 0;
797 for (; $i < @files; ) {
798 my $subdir = $files[$i];
799 if (-d "$dirname/$subdir") {
800 splice(@files, $i, 1, map { "$subdir/$_" }
801 @{&list_filenames("$dirname/$subdir")});
802 } else {
803 $i++;
808 return \@files;
812 # ----------------------------------------------------------------------------
814 =head2 find_file
816 =over 4
818 =item description
820 Searches for the given file in the given directories.
822 Returns the fully qualified file name.
824 =item usage
826 my $gtkrc = find_file(".gtkrc", [$home, "$home/.gnome"]);
828 =item parameters
830 * file name to search for
831 * array ref of directories to search in
833 =item returns
835 File name with full path if found, or undef if not found.
837 =back
839 =cut
840 # ============================================================================
843 sub find_file ($$) {
844 my $filename = shift;
845 my $dirs = shift();
846 die "find_file: no dirs given\n" unless ref($dirs) eq "ARRAY";
847 foreach (@$dirs) {
848 my $file_path = "$_/$filename";
849 return $file_path if -f $file_path;
851 return undef;
855 # ----------------------------------------------------------------------------
857 =head2 find_executable
859 =over 4
861 =item description
863 Searches for the given executable file in the directories that are in the
864 environmebt variable $PATH or in the additional parameter.
866 Returns the fully qualified file name.
868 =item usage
870 my $gzip_exe = find_executable("gzip", ["/usr/gnu/bin", "/gnu/bin"]);
872 =item parameters
874 * file name to search for (only executables are tested)
875 * optional array ref of extra directories to search in
877 =item returns
879 File name with full path if found, or undef if not found.
881 =back
883 =cut
884 # ============================================================================
887 sub find_executable ($;$) {
888 my $filename = shift;
889 my $extra_dirs = shift;
890 my @dirs = split(":", $ENV{"PATH"} || "");
891 if (ref($extra_dirs) eq "ARRAY") {
892 push @dirs, @$extra_dirs;
894 foreach (@dirs) {
895 my $file_path = "$_/$filename";
896 return $file_path if -x $file_path;
898 return undef;
902 # ----------------------------------------------------------------------------
904 =head2 default_dir_perm
906 =over 4
908 =item description
910 This functions changes default directory permissions, used in
911 C<make_dir>, C<make_path>, C<copy_dir> and C<move_dir> functions.
913 The default of this package is 0775.
915 If no parameters specified, the current value is returned.
917 =item usage
919 default_dir_perm(0700);
921 =item parameters
923 * optional default directory permission (integer)
925 =item returns
927 Previous value.
929 =back
931 =cut
932 # ============================================================================
935 sub default_dir_perm (;$) {
936 return if $^O =~ /Win|DOS/;
937 my $new_value = shift;
938 my $old_value = $DEFAULT_DIR_PERM;
940 if (defined $new_value) {
941 print_log("default_dir_perm = $new_value") if $DEBUG_ENABLED;
942 $DEFAULT_DIR_PERM = $new_value;
944 return $old_value;
948 # ----------------------------------------------------------------------------
950 =head2 preserve_stat
952 =over 4
954 =item description
956 This functions changes behavior of C<copy_file> and C<copy_dir> functions.
957 If 0 is given as a parameter stats will not be preserved.
959 TODO: specify values for diferent preserves:
961 0 nothing
962 1 mode file mode (type and permissions)
963 2 uid numeric user ID of file's owner
964 4 gid numeric group ID of file's owner
965 8 atime last access time since the epoch
966 16 mtime last modify time since the epoch
967 32 ctime inode change time (NOT creation time!) since the epo
969 The default of this package is 0.
971 If no parameters specified, nothing is set (only current value is returned).
973 =item usage
975 preserve_stat(1);
977 =item parameters
979 * optional flag (currently 0 or 1)
981 =item returns
983 Previous value.
985 =back
987 =cut
988 # ============================================================================
991 sub preserve_stat (;$) {
992 return if $^O =~ /Win|DOS/;
993 my $new_value = shift;
994 my $old_value = $PRESERVED_STAT;
996 if (defined $new_value) {
997 print_log("preserve_stat = $new_value") if $DEBUG_ENABLED;
998 $PRESERVED_STAT = $new_value;
1000 return $old_value;
1004 # ----------------------------------------------------------------------------
1006 =head2 parse_path
1008 =over 4
1010 =item usage
1012 my ($dirname, $basename) = parse_path($filename);
1014 =item examples
1016 # in: "/data/projects/magazine" out: ("/data/projects", "magazine")
1017 # in: "/magazine" out: ("", "magazine")
1018 # in: "dir/" out: (dir", "")
1019 # in: "magazine" out: (".", "magazine")
1021 # in: "c:\projects\magazine" out: ("c:\projects", "magazine")
1022 # in: "c:\magazine" out: ("c:", "magazine")
1023 # in: "c:magazine" out: ("c:.", "magazine")
1025 =item description
1027 Returns a list of 2 scalars: directory name and base name. All unix and dos
1028 file names supported.
1030 Note, the rule is this: you can join both scalars using a directory delimiter
1031 (slash or backslash) and you will always get the the original (logical)
1032 file name.
1034 =back
1036 =cut
1037 # ============================================================================
1040 sub parse_path ($) {
1041 my $path = shift;
1042 if ($path =~ m=^(.*)[/\\]+([^/\\]*)$=) {
1043 return ($1, $2);
1044 } else {
1045 # support even funny dos form c:file
1046 return $path =~ m=^(\w:)(.*)$=
1047 ? ($1 . ".", $2)
1048 : (".", $path);
1053 # ----------------------------------------------------------------------------
1055 =head2 get_cwd
1057 =over 4
1059 =item usage
1061 my $cwd = get_cwd();
1063 =item description
1065 Returns the current working directory.
1067 =back
1069 =cut
1070 # ============================================================================
1073 sub get_cwd () {
1074 $^O eq "MSWin32" ? Win32::GetCwd() : require "getcwd.pl" && getcwd();
1078 # ----------------------------------------------------------------------------
1080 =head1 BUGS
1082 All global functions and constants in this package should probably be
1083 instantiated into a class object. As usual there are pros and cons.
1085 =head1 AUTHOR
1087 Mikhael Goikhman <migo@homemail.com>
1089 =cut
1090 # ============================================================================