.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.13) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is turned on, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .ie \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . nr % 0 . rr F .\} .el \{\ . de IX .. .\} .\" .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). .\" Fear. Run. Save yourself. No user-serviceable parts. . \" fudge factors for nroff and troff .if n \{\ . ds #H 0 . ds #V .8m . ds #F .3m . ds #[ \f1 . ds #] \fP .\} .if t \{\ . ds #H ((1u-(\\\\n(.fu%2u))*.13m) . ds #V .6m . ds #F 0 . ds #[ \& . ds #] \& .\} . \" simple accents for nroff and troff .if n \{\ . ds ' \& . ds ` \& . ds ^ \& . ds , \& . ds ~ ~ . ds / .\} .if t \{\ . ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" . ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' . ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' . ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' . ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' . ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' .\} . \" troff and (daisy-wheel) nroff accents .ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' .ds 8 \h'\*(#H'\(*b\h'-\*(#H' .ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] .ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' .ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' .ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] .ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] .ds ae a\h'-(\w'a'u*4/10)'e .ds Ae A\h'-(\w'A'u*4/10)'E . \" corrections for vroff .if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' .if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' . \" for low resolution devices (crt and lpr) .if \n(.H>23 .if \n(.V>19 \ \{\ . ds : e . ds 8 ss . ds o a . ds d- d\h'-1'\(ga . ds D- D\h'-1'\(hy . ds th \o'bp' . ds Th \o'LP' . ds ae ae . ds Ae AE .\} .rm #[ #] #H #V #F C .\" ======================================================================== .\" .IX Title "MNI::FileUtilities 3" .TH MNI::FileUtilities 3 "1999-11-30" "perl v5.10.1" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "NAME" MNI::FileUtilities \- manipulate/check/validate/search files and directories .SH "SYNOPSIS" .IX Header "SYNOPSIS" .Vb 6 \& use MNI::FileUtilities qw(:check); \& check_output_dirs (@dirs) || exit 1; \& check_output_path ($path) || exit 1; \& check_input_dirs (@dirs) || exit 1; \& $file = test_file ($test, $file) || die "couldn\*(Aqt find $file\en"; \& check_files (@files) || exit 1; \& \& use MNI::FileUtilities qw(:search); \& $dir = search_directories ($file, \e@search_dirs [, $test]) \& || die "couldn\*(Aqt find $file\en"; \& $program = find_program ($program [, \e@path]) || exit 1; \& (@programs = find_programs (\e@programs [, \e@path])) || exit 1; \& \& use MNI::FileUtilities qw(:misc); \& $file = generate_numbered_filename ($base, $ext [, $add_date]); \& ($type, $blocksize, $blocks, $blocksfree, $files, $ffree) = \& statfs ($path); .Ve .SH "DESCRIPTION" .IX Header "DESCRIPTION" \&\fIMNI::FileUtilities\fR provides a loosely-related collection of utility subroutines for performing various common operations that help maximize your program's likelihood of running successfully and provide thorough diagnostics when things go wrong. The module is rife with assumptions that it's running under a POSIX-compliant operating system (i.e. Unix and Unix-like systems such as Linux), so using it under another \s-1OS\s0 will be dodgy at best. .PP The subroutines fall roughly into the following groups: .IP "checking/testing" 4 .IX Item "checking/testing" Check that files or directories exist and are writeable/readable (as appropriate): \f(CW\*(C`check_output_dirs\*(C'\fR, \f(CW\*(C`check_output_path\*(C'\fR, \&\f(CW\*(C`check_input_dirs\*(C'\fR, \f(CW\*(C`check_files\*(C'\fR, \f(CW\*(C`test_file\*(C'\fR. .IP "searching" 4 .IX Item "searching" Search for file(s) across a list of directories: \f(CW\*(C`search_directories\*(C'\fR, \&\f(CW\*(C`find_program\*(C'\fR, \f(CW\*(C`find_programs\*(C'\fR. .IP "miscellaneous" 4 .IX Item "miscellaneous" \&\f(CW\*(C`generate_numbered_filename\*(C'\fR, \f(CW\*(C`statfs\*(C'\fR. .SH "EXPORTS" .IX Header "EXPORTS" By default, \fIMNI::FileUtilities\fR exports no symbols. You can import in the usual one-name-at-a-time way like this: .PP .Vb 1 \& use MNI::FileUtilities qw(check_output_dirs test_file); .Ve .PP which works fine if you're only using a few routines. This quickly gets cumbersome in large programs that use lots of routines, though, so the module provides a couple of \*(L"export tags\*(R" to let you specify subroutines by group. The tags are: .ie n .IP """check""" 4 .el .IP "\f(CWcheck\fR" 4 .IX Item "check" \&\f(CW\*(C`check_output_dirs\*(C'\fR, \f(CW\*(C`check_output_path\*(C'\fR, \f(CW\*(C`check_input_dirs\*(C'\fR, \&\f(CW\*(C`check_files\*(C'\fR, and \f(CW\*(C`test_file\*(C'\fR .ie n .IP """search""" 4 .el .IP "\f(CWsearch\fR" 4 .IX Item "search" \&\f(CW\*(C`search_directories\*(C'\fR, \f(CW\*(C`find_program\*(C'\fR, and \f(CW\*(C`find_programs\*(C'\fR .ie n .IP """misc""" 4 .el .IP "\f(CWmisc\fR" 4 .IX Item "misc" \&\f(CW\*(C`generate_numbered_filename\*(C'\fR and \f(CW\*(C`statfs\*(C'\fR .PP For example, to import the names of all the file/directory checking subroutines: .PP .Vb 1 \& use MNI::FileUtilities qw(:check); .Ve .PP Finally, an \f(CW\*(C`all\*(C'\fR tag is provided to import all exportable symbols. .SH "ERROR HANDLING" .IX Header "ERROR HANDLING" Error handling is fairly consistent: in general, the routines here print a warning and return false when they discover an error. The guiding principle is to tell the user as much as he/she needs to know; all you (the programmer using \fIMNI::FileUtilities\fR) have to do is know when to pay attention to the return values from \fIMNI::FileUtilities\fR routines, and what to do when they fail. In most cases, you should pay attention to the return value; usually, you will want to bomb (e.g. \f(CW\*(C`exit 1\*(C'\fR) as soon as an error is reported. I've deliberately left this choice up to you (rather than having the subroutines \f(CW\*(C`die\*(C'\fR on any error), because there are situations where you might want to blunder on ahead. .PP If for any reason you need to capture the warning message, rather than have it printed to \f(CW\*(C`STDERR\*(C'\fR, you can set \f(CW$SIG{\*(Aq_\|_WARN_\|_\*(Aq}\fR. See perlvar for more information. .PP There are a few routines that will \f(CW\*(C`die\*(C'\fR on failure. Generally, if you mess up by supplying bad arguments, the \fIMNI::FileUtilities\fR routines will \&\f(CW\*(C`die\*(C'\fR or \f(CW\*(C`croak\*(C'\fR. If blundering on in the face of error would cause serious problems for future invocations of a routine, it will \f(CW\*(C`die\*(C'\fR (\f(CW\*(C`generate_numbered filename\*(C'\fR is the only one that falls in this category). Finally, if you ask a routine for the impossible, it will \&\f(CW\*(C`die\*(C'\fR. (The only instance of this currently is calling \f(CW\*(C`statfs\*(C'\fR on an architecture other than Linux/x86 or \s-1IRIX\s0.) .PP That said, the documentation below should mention the error handling behaviour for every individual subroutine. If any such information is missing, that's a documentation bug\-\-\-please tell me! Also, the calling summaries in the synopsis above implicitly tell you the preferred way for dealing with errors from each subroutine. .SH "SUBROUTINES" .IX Header "SUBROUTINES" .SS "Checking/testing routines" .IX Subsection "Checking/testing routines" .IP "check_output_dirs (\s-1DIRS\s0)" 4 .IX Item "check_output_dirs (DIRS)" \&\s-1DIRS\s0 should be a list of directories to check; \f(CW\*(C`check_output_dirs\*(C'\fR ensures that each element of the list is a writeable directory, and attempts to create (with \f(CW\*(C`mkdir\*(C'\fR) those that are not. Note that \&\f(CW\*(C`check_output_dirs\*(C'\fR will not attempt to create more than one level of directory; if you try to check \fI/foo/bar/baz\fR, and only \fI/foo\fR exists, it will not try to create both \fI/bar\fR and \fIbaz\fR. You should be using \&\f(CW\*(C`check_output_path\*(C'\fR if you require that behaviour. .Sp If any elements of \s-1DIRS\s0 are false (e.g., undefined or the empty string), they are silently skipped. .Sp Prints a complete and self-sufficient warning for every error found. Note that if one element of the list fails, it will keep trying with the others. Returns true if every element of the list was successfully tested or created; false if there were any errors at all. .Sp Possible errors are: 1) already exists, but isn't a directory, 2) is a directory but not writeable, and 3) \f(CW\*(C`mkdir\*(C'\fR fails. .IP "check_output_path (\s-1PATH\s0)" 4 .IX Item "check_output_path (PATH)" If \s-1PATH\s0 is a filename (doesn't end with a slash), \f(CW\*(C`check_output_path\*(C'\fR ensures that conditions are optimal for creating it. (That is, it treats everything up to the last slash in \s-1PATH\s0 as a directory, and attempts to create that directory a little more vigorously than \&\f(CW\*(C`check_output_dirs\*(C'\fR. In particular, it will create as many levels of directories as are needed to ensure that \s-1PATH\s0 can be written to.) .Sp If \s-1PATH\s0 ends with a slash, then it is assume to be a directory with no filename component, and the same applies\-\-\-\f(CW\*(C`check_output_path\*(C'\fR attempts to create as many levels of directory as are needed to bring \&\s-1PATH\s0 into existence as a writeable directory. .Sp Prints a comprehensive warning and returns false if any errors occur. Possible errors are: 1) \f(CW\*(C`mkdir\*(C'\fR fails at any level; 2) some `directory' in \&\s-1PATH\s0 exists, but isn't actually a directory; and 3) the final component of \&\s-1PATH\s0 exists and is a directory, but isn't writeable. .Sp The reasoning behind the trailing slash business is as follows: \s-1PATH\s0 can be either a file that you will need to create, or a directory in which you will create several files. A trailing slash is just used to tell \&\f(CW\*(C`check_output_dirs\*(C'\fR that this is indeed a directory you're interested in. .Sp For example, you might be about to create a file \fI/tmp/mydir/tmpfile\fR. To maximize your chances of success, you want to be sure that \&\fI/tmp/mydir\fR exists, is a directory, and is writeable by you. Either \&\f(CW\*(C`check_output_dirs\*(C'\fR or \f(CW\*(C`check_output_path\*(C'\fR can help you with this, but in slightly different ways. .Sp If all you have (and care about) is a filename, it's usually more convenient to use \f(CW\*(C`check_output_path\*(C'\fR; for example, .Sp .Vb 2 \& $file = \*(Aq/tmp/mydir/tmpfile\*(Aq; \& check_output_path ($file) || exit 1; .Ve .Sp ensures that conditions are optimal for creating \f(CW$file\fR. If it fails, you're not going to be able to create \f(CW$file\fR, so you may as well give up before even trying to open the file. No error message is necessary because \f(CW\*(C`check_output_path\*(C'\fR prints a clear and detailed warning before returning. .Sp However, if you're carrying around a directory name and using it to generate filenames, you can usually get away with using \&\f(CW\*(C`check_output_dirs\*(C'\fR. For example: .Sp .Vb 2 \& $dir = \*(Aq/tmp/mydir\*(Aq; \& check_output_dirs ($dir) || exit 1; .Ve .Sp Note that if you passed \f(CW$dir\fR without a trailing slash to \&\f(CW\*(C`check_output_path\*(C'\fR it would merely ensure that conditions are optimal for creating \fI/tmp/mydir\fR\-\-\-probably not what you want. .Sp The main drawback to \f(CW\*(C`check_output_dirs\*(C'\fR is that it will only create one level of directory; \f(CW\*(C`check_output_path\*(C'\fR's main flaw is that you can only check one path at a time. Furthermore, its logic is quite a bit more complicated and prone to subtle bugs\-\-\-but I think I've got that one licked. .IP "check_input_dirs (\s-1DIRS\s0)" 4 .IX Item "check_input_dirs (DIRS)" \&\s-1DIRS\s0 should be a list of directories to check. Each item in the list is checked to make sure it exists, is a directory, and is both readable and executable. Prints a comprehensive warning message for any directory that doesn't meet all these conditions. Returns true if all directories in \s-1DIRS\s0 are ok, false if there were any errors. Any element of \s-1DIRS\s0 may be false (undefined or the empty string), and it will be silently skipped. .IP "check_files (\s-1FILES\s0 [, \s-1VARIANTS\s0])" 4 .IX Item "check_files (FILES [, VARIANTS])" \&\s-1FILES\s0 should be a list of files to check. (It must be an array ref if the optional argument \s-1VARIANTS\s0 is supplied; otherwise, \s-1FILES\s0 can just be an array using up the whole argument list to \f(CW\*(C`check_files\*(C'\fR. This is just a hack for backwards compatibility, though; new code should pass an array ref for \s-1FILES\s0.) Each item in the list is checked to make sure it exists, is a regular file (or a symlink to one), and is readable. Any element of \s-1FILES\s0 may be false (undefined or the empty string), and it will be silently skipped. .Sp \&\s-1VARIANTS\s0 can be used to make \f(CW\*(C`check_files\*(C'\fR check several variations on each filename. This is done by calling \f(CW\*(C`test_file\*(C'\fR; see below for details on its operation. The easiest way to use this feature is to pass a true scalar value in as \s-1VARIANTS\s0; this will just use \&\f(CW\*(C`test_file\*(C'\fR's default list of extensions, which (conveniently enough) is \f(CW\*(C`(\*(Aqgz\*(Aq,\*(Aqz\*(Aq,\*(AqZ\*(Aq)\*(C'\fR. If you need to use a different list of extensions, make \s-1VARIANTS\s0 a reference to a list of those extensions (without dots, just like \f(CW\*(C`test_file\*(C'\fR). If \s-1VARIANTS\s0 is not supplied or is false, then just the filenames passed in as \s-1FILES\s0 will be tested. .Sp In a scalar context, returns true if all files in \s-1FILES\s0 are ok, false if there were any errors. Thus, the following is a common idiom: .Sp .Vb 2 \& ($infile1, $infile2) = @ARGV; \& check_files ($infile1, $infile2) || exit 1; .Ve .Sp It's \s-1OK\s0 to fail silently since \f(CW\*(C`check_files\*(C'\fR prints ample warnings in case of any error. Note that you should check that \f(CW@ARGV\fR has the number of elements you expect before doing this, as \&\f(CW\*(C`check_files\*(C'\fR silently skips any members of \s-1FILES\s0 that are undefined. (Yes, this is a feature.) .Sp In an array context, returns the list of found files. This list will have the same length as the \s-1FILES\s0 list that you pass in, but any files that weren't found will be replaced with \f(CW\*(C`undef\*(C'\fR. This is most useful when used in conjunction with the variant-extensions feature, e.g. you could do something like this .Sp .Vb 2 \& ($infile1, $infile2) = check_files (\e@ARGV, 1); \& exit 1 unless $infile1 && $infile2; .Ve .Sp to pull filenames from the command line, make sure each one exists (possibly in compressed form), and fail silently if any weren't found in any form. Again, it's \s-1OK\s0 to fail silently, and again, you should check the length of \f(CW@ARGV\fR before doing this. .IP "test_file (\s-1TEST\s0, \s-1FILE\s0 [, \s-1VARIANTS\s0])" 4 .IX Item "test_file (TEST, FILE [, VARIANTS])" \&\f(CW\*(C`test_file\*(C'\fR performs a file test (or tests) on \s-1FILE\s0, as well as on variations of \s-1FILE\s0 if necessary. \s-1VARIANTS\s0 is a list of extensions which are used to generate the variant filenames; it defaults to \&\f(CW\*(C`[\*(Aqgz\*(Aq,\*(Aqz\*(Aq,\*(AqZ\*(Aq]\*(C'\fR\-\-\-this is convenient for testing a filename that might exist in either original form or compressed form. You could pass in a different list of variant extensions to look for other variations on a file, e.g. \f(CW\*(C`[\*(Aqpgp\*(Aq]\*(C'\fR to look for an encrypted variant. .Sp \&\s-1TEST\s0 is a string containing some Perl expression which evaluates to true or false depending on the value of \f(CW$_\fR. The most common use is a single file test operator such as \f(CW\*(C`\-e\*(C'\fR; you could also use a boolean combination of file test operators, such as \f(CW\*(C`\-e && (\-f || \-l) && \-x\*(C'\fR to test that \s-1FILE\s0 (or one of its variants) exists, is a regular file or symlink, and is executable. .Sp \&\s-1VARIANTS\s0 could be an array ref (as implied above), where the array is a list of filename extensions with no leading dot. Or, it could be a false scalar value, meaning not to test any variations in \s-1FILE\s0 (this is the same as passing a reference to an empty list, but possibly more convenient in some circumstances). Finally, if \s-1VARIANTS\s0 is undefined or not supplied, it defaults to \f(CW\*(C`[\*(Aqgz\*(Aq,\*(Aqz\*(Aq,\*(AqZ\*(Aq]\*(C'\fR. .Sp Returns the filename that ultimately passes \s-1TEST\s0, or a false value if no passing filename is found. Dies with a useful error message if you pass in bogus arguments. .Sp The exact modus operandi is as follows: \s-1TEST\s0 is \f(CW\*(C`eval\*(C'\fR'd with \f(CW$_\fR set to \s-1FILE\s0. If this returns true, \s-1FILE\s0 is returned. Then, the variant filenames are tried out (this step is skipped if \s-1VARIANTS\s0 is an empty list or false). First, \f(CW\*(C`test_file\*(C'\fR attempts to strip off any variant extension already on \s-1FILE\s0, and tests the resulting base filename. If this succeeds, the base filename is returned. If an extension was stripped, but the base filename failed the test, then \f(CW\*(C`test_file\*(C'\fR fails and returns false. Finally, each possible variant extension is appended to \s-1FILE\s0 (with an intervening dot), and the resulting filename is tested. As soon as a passing filename is found, it is returned. If no passing filename is found, \f(CW\*(C`test_file\*(C'\fR fails and returns false. .SS "Search routines" .IX Subsection "Search routines" .IP "search_directories (\s-1FILE\s0, \s-1DIRS\s0 [, \s-1TEST\s0])" 4 .IX Item "search_directories (FILE, DIRS [, TEST])" Searches for \s-1FILE\s0 in the directories listed in \s-1DIRS\s0, which must be an array ref. The current directory may be denoted in \s-1DIRS\s0 either as a single dot or as the empty string. .Sp The optional argument \s-1TEST\s0 can be used to supply a file-test operator used to determine if \s-1FILE\s0 in fact \*(L"exists\*(R" in a given directory; e.g., if you require that a file exist and not be a symbolic link, \s-1TEST\s0 could be the string \f(CW"\-e && ! \-l"\fR. This works because \s-1TEST\s0 is \f(CW\*(C`eval\*(C'\fR'd with \f(CW$_\fR set to the filename currently under consideration, and the file-test operators (except \f(CW\*(C`\-t\*(C'\fR) default to working on \f(CW$_\fR. .Sp Returns false if \s-1FILE\s0 wasn't found in any of the directories in \s-1DIRS\s0, otherwise returns the directory where \s-1FILE\s0 was found. The directory is returned in a form suitable for direct concatenation with \s-1FILE\s0, i.e. either the empty string (if it was supplied in \s-1DIRS\s0) or with a trailing slash. .IP "find_program (\s-1PROGRAM\s0 [, \s-1PATH\s0])" 4 .IX Item "find_program (PROGRAM [, PATH])" \&\f(CW\*(C`find_program\*(C'\fR is a front-end to \f(CW\*(C`search_directories\*(C'\fR for finding executable programs. It has the following differences from \&\f(CW\*(C`search_directories\*(C'\fR: .RS 4 .IP "\(bu" 4 can accept the search path either as a reference to a list of directories (same as \f(CW\*(C`search_directories\*(C'\fR) or as a colon-separated string .IP "\(bu" 4 search path defaults to \f(CW$ENV{\*(AqPATH\*(Aq}\fR (so you don't actually need that search-path-as-string feature very often) .IP "\(bu" 4 prints a warning if \s-1PROGRAM\s0 was not found (as opposed to \&\f(CW\*(C`search_directories\*(C'\fR, which just returns false and lets you take care of informing the user) .IP "\(bu" 4 you can't specify the file test\-\-\-it's hard-coded to \f(CW"\-f && \-x"\fR. .IP "\(bu" 4 \&\f(CW\*(C`find_program\*(C'\fR returns the complete path of the found program (directory plus program name), rather than just the directory where the program was found .RE .RS 4 .Sp Apart from that, though, the two subroutines act the same. In particular, \f(CW\*(C`find_program\*(C'\fR also returns false if \s-1PROGRAM\s0 wasn't found in any of the directories in \s-1PATH\s0. .RE .IP "find_programs (\s-1PROGRAMS\s0 [, \s-1PATH\s0])" 4 .IX Item "find_programs (PROGRAMS [, PATH])" \&\f(CW\*(C`find_programs\*(C'\fR calls \f(CW\*(C`find_program\*(C'\fR for each program listed in \&\s-1PROGRAMS\s0. \s-1PROGRAMS\s0 must be a reference to a list of program names; \s-1PATH\s0 is the same as for \f(CW\*(C`find_program\*(C'\fR, i.e. it can be a reference to a list of directories, a colon-separated string, or if not given it defaults to \&\f(CW$ENV{\*(AqPATH\*(Aq}\fR. .Sp If all programs listed in \s-1PROGRAMS\s0 are found, returns a list of complete paths to those programs. If any are not found, \f(CW\*(C`find_program\*(C'\fR will print a warning and \f(CW\*(C`find_programs\*(C'\fR will return an empty list. Thus, a common idiom is: .Sp .Vb 3 \& @programs = qw(ls rm mv cp); \& @programs = find_programs (\e@programs); \& exit 1 unless @programs; .Ve .Sp (Note that if you are using the \fIMNI::Spawn\fR module, you'll probably never need to call \f(CW\*(C`find_programs\*(C'\fR directly. Rather, there is a \&\f(CW\*(C`RegisterPrograms\*(C'\fR subroutine in \fIMNI::Spawn\fR that maintains a private hash of all \*(L"known\*(R" programs and their full paths, so you never have to worry about keeping track of both program names and their full paths. Unsurprisingly, \f(CW\*(C`MNI::FileUtilities::find_programs\*(C'\fR is called by \&\f(CW\*(C`MNI::Spawn::RegisterPrograms\*(C'\fR. See the MNI::Spawn for more details.) .SS "Miscellaneous routines" .IX Subsection "Miscellaneous routines" .IP "generate_numbered_filename (\s-1BASE\s0, \s-1EXT\s0 [, \s-1ADD_DATE\s0])" 4 .IX Item "generate_numbered_filename (BASE, EXT [, ADD_DATE])" Generates a new filename in a numbered sequence, with the current date optionally added. Works by generating a filename like \f(CW\*(C`BASE_${i}EXT\*(C'\fR, and incrementing \f(CW$i\fR until the named file does not exist. If \f(CW$i\fR is 1, omits the number from the filename; it will be renamed the next time you call \f(CW\*(C`generate_numbered_filename\*(C'\fR with the same \s-1BASE\s0 and \s-1EXT\s0. .Sp For example, the very first call like this (i.e. before any \f(CW\*(C`foo*.log\*(C'\fR files exist): .Sp .Vb 1 \& $file = generate_numbered_filename (\*(Aqfoo\*(Aq, \*(Aq.log\*(Aq); .Ve .Sp would return \f(CW"foo.log"\fR. Assuming you then use that filename to create a file, the next call would notice that \f(CW"foo.log"\fR exists, but \&\f(CW"foo_2.log"\fR does not exist. It would thus rename \f(CW"foo.log"\fR to \&\f(CW"foo_1.log"\fR, and return \f(CW"foo_2.log"\fR. Future calls would return \&\f(CW"foo_3.log"\fR, \f(CW"foo_4.log"\fR, etc. .Sp If \s-1ADD_DATE\s0 is true, the current date (formatted as YYYY-MM-DD) is appended to \s-1BASE\s0 before anything else is done. .Sp Dies on any error, of which there are currently only two. The first possible error is that \f(CW"foo.log"\fR and \f(CW"foo_1.log"\fR both exist; this should never happen if you only use \f(CW\*(C`generate_numbered_filename\*(C'\fR to generate filenames for this sequence, so it's considered sufficiently serious to \f(CW\*(C`die\*(C'\fR on. The other possibile error is that \f(CW\*(C`rename\*(C'\fR failed, which would also cause a corrupt sequence of filenames\-\-\-hence it's deemed fatal as well. .IP "statfs (\s-1PATH\s0)" 4 .IX Item "statfs (PATH)" Does a system call to \f(CWstatfs(2)\fR. This is very non-portable, and currently only works on \s-1IRIX\s0 and Linux/i86. Dies if called on any other architecture. Return values are: .Sp .Vb 1 \& ($type, $bsize, $blocks, $bfree, $files, $ffree) = statfs ($path); .Ve .Sp Note that this is merely a stopgap measure until the mythical \&\fIFile::statfs\fR (or maybe \fIFilesystem::stat\fR) module appears on \s-1CPAN\s0. When and if that happens, I reserve the right to remove \f(CW\*(C`statfs\*(C'\fR from \&\fIMNI::FileUtilities\fR. .SH "AUTHOR" .IX Header "AUTHOR" Greg Ward, . .SH "COPYRIGHT" .IX Header "COPYRIGHT" Copyright (c) 1997 by Gregory P. Ward, McConnell Brain Imaging Centre, Montreal Neurological Institute, McGill University. .PP This file is part of the \s-1MNI\s0 Perl Library. It is free software, and may be distributed under the same terms as Perl itself.