[svn-inject] Installing original source of libfile-util-perl (3.27)
Takaki Taniguchi
13 years ago
0 | This library is free software, you may redistribute it and/or modify it | |
1 | under the same terms as Perl itself. |
0 | Revision history for Perl extension File::Util.pm | |
1 | ||
2 | 2.27 | |
3 | Sat Dec 6 13:10:00 CST 2008 | |
4 | Fixed a bug that caused root directories using Micro$oft filesystem | |
5 | notation to be mis-read when using the '--dirs-only' flag for | |
6 | File::Util::list_dir() | |
7 | ||
8 | 3.26 | |
9 | Tue Dec 2 20:07:09 CST 2008 | |
10 | Added to test suite in order to avoid errant test failures | |
11 | when flock'ing on solaris. This is a big deal, since the point of | |
12 | File::Util is to be easy, and portable! | |
13 | ||
14 | Added some yet more extra examples in the documentation. | |
15 | ||
16 | 3.25 | |
17 | Mon Dec 1 15:11:20 CST 2008 | |
18 | Fixed a bug in File::Util::touch() | |
19 | ||
20 | Added some extra examples and corrected one minor error in the | |
21 | documentation. | |
22 | ||
23 | 3.24 | |
24 | Wed May 23 16:27:20 CDT 2007 | |
25 | Added method File::Util::last_changed (get inode change time for a file) | |
26 | Added method File::Util::touch (works like *nix touch command) | |
27 | ||
28 | Both touch and last_changed are autoloaded methods | |
29 | ||
30 | Applied patch from S. Muskiewicz that fixes the File::Util::last_modified | |
31 | method that was using a similar but incorrect "-" file test operator. | |
32 | ||
33 | 3.23 | |
34 | Fri Feb 15 07:34:29 CST 2008 | |
35 | No major code changes. Small bug fixes-- | |
36 | Corrected syntax on package makefile that causes warnings to be | |
37 | generated in cases of older Perl versions. Also corrected a problem | |
38 | in the documentation where the section "Get the path preceeding a | |
39 | file name" was showing incorrect information. | |
40 | ||
41 | 3.22 | |
42 | Wed May 23 16:27:20 CDT 2007 | |
43 | Fixed windows-specific bugs associated with the handling of newlines | |
44 | and directory path separators. Now compatible with Strawberry Perl | |
45 | and once again Active$tate Perl for MSWin*. | |
46 | ||
47 | 3.21 | |
48 | Mon May 21 18:22:11 CDT 2007 | |
49 | Fixed solaris-specific bug in test suite causing a simple regular | |
50 | expression to fail. Previous changes up to this point merit a public | |
51 | release, pending the fixing of afforementioned bug, hence this release. | |
52 | ||
53 | 3.20_2 | |
54 | Mon May 21 16:15:23 CDT 2007 | |
55 | Fixed small but important incompatibility with some versions of | |
56 | Exception::Handler | |
57 | ||
58 | 3.20_1 | |
59 | Fri May 18 15:42:01 CDT 2007 | |
60 | Improved error handling mechanism even more, and created 31 new test | |
61 | scenarios to make sure that any failure events are handled correctly. | |
62 | ||
63 | Fixed some small latent bugs, for example, corrected file handle | |
64 | reference verification error handling--checking for validity of | |
65 | file handle references. | |
66 | ||
67 | 3.19 | |
68 | Wed May 16 18:07:49 CDT 2007 | |
69 | Documentation. Documentation. Documentation. Small corrections and | |
70 | several enhancements. More examples. | |
71 | ||
72 | Improved error-handling mechanism by adding cascading logic to prioritize | |
73 | fatality-handling rules of failed calls over the rules of the File::Util | |
74 | object, whether they be defaults or manually set up via File::Util::new() | |
75 | ||
76 | 3.18 | |
77 | Tue Feb 27 15:54:51 CST 2007 | |
78 | Finished documentation for ALL methods. Whew! That was a lot of | |
79 | writing. The documentation will continue to evolve. | |
80 | ||
81 | Implemented the --use-sysopen flag for File::Util::open_handle() | |
82 | and thereafter the following extra open modes for it (only valid if | |
83 | the --use-sysopen flag is used): | |
84 | rwcreate | |
85 | rwupdate | |
86 | rwclobber | |
87 | rwappend | |
88 | ||
89 | (See the documentation for more details about this new feature). | |
90 | ||
91 | Added new method File::Util::release_open_file() for the purpose | |
92 | of releasing file locks placed on file handles by the | |
93 | File::Util::open_file() method, that is, when file locking is | |
94 | NOT turned off. If file locking is disabled by the user, this new | |
95 | method has no effect. | |
96 | ||
97 | 3.17_* | |
98 | Fri Feb 23 - Mon Feb 26 | |
99 | Developer's releases (testing); not released to the public. | |
100 | ||
101 | 3.16 | |
102 | Tue Feb 20 14:16:45 CST 2007 | |
103 | Fixed problem with method File::Util::make_dir() when used with | |
104 | absolute pathnames (path names starting with "/", for example). | |
105 | ||
106 | Fixed documentation error concerning the File::Util::list_dir method, | |
107 | specifically regarding the "--pattern" option flag. | |
108 | ||
109 | Method File::Util::make_dir() now enforces the policy of failing when | |
110 | asked to create a directory that already exists as a file of any kind. | |
111 | Use the "--if-not-exists" flag if you are counting on the old behavior | |
112 | or if you want to create directories which could possibly exist already. | |
113 | ||
114 | More documentation added. | |
115 | ||
116 | ||
117 | 3.15 | |
118 | Fri Dec 22 14:12:45 CST 2006 | |
119 | Fixed broken test suite that was causing `make test` to fail falsely. | |
120 | Revisited documentation, adding a little, and various small improvements. | |
121 | ||
122 | 3.14_8 | |
123 | Thu Dec 14 20:13:03 CST 2006 | |
124 | Fixed some error messages to be more clear. Tweaked the | |
125 | File::Util::readlimit() method to provide better error messages if | |
126 | called incorrectly. Modified File::Util::make_dir() to include | |
127 | the --if-not-exists option. | |
128 | ||
129 | More documentation added for various methods whose documentation had | |
130 | yet to be written. | |
131 | ||
132 | Fixed a broken test case in "make test" that was causing it to fail | |
133 | falsely. | |
134 | ||
135 | Releasing this version as an official release and NOT a developer's | |
136 | release only. | |
137 | ||
138 | ||
139 | 3.14_7 | |
140 | Sat Jan 31 13:36:24 CST 2004 | |
141 | Changes to method File::Util::flock_rules() to output helpful error | |
142 | message if specification of invalid file locking policy attempted. | |
143 | ||
144 | flock_rules parameter for File::Util::new() constructor method no | |
145 | longer accepted or recognized in the interest of speed and efficiency. | |
146 | If you want to change the default flock rules for the File::Util object, | |
147 | then call File::Util::flock_rules() with your desired ruleset as | |
148 | specified in the documentation for this method. | |
149 | ||
150 | Changed default max_dives number to 1000. (See documentation for the | |
151 | File::Util::max_dives() method.) | |
152 | ||
153 | Much more documentation added for various methods whose documentation | |
154 | had yet to be written. | |
155 | ||
156 | 3.14_6 | |
157 | Mon Sep 22 11:10:46 CDT 2003 | |
158 | Changes to methods File::Util::list_dir() and | |
159 | File::Util::escape_filename() increase efficiency and fix some bugs. | |
160 | Both methods retain the same interface and return values in the same | |
161 | manner. | |
162 | ||
163 | Added new method File::Util::return_path() (see documentation). | |
164 | ||
165 | Method File::Util::last_mod changed to File::Util::last_modified for | |
166 | clarity, better readability, and consistency with other similar methods | |
167 | in the File::Util namespace. (eg- File::Util::last_access, etc) | |
168 | ||
169 | Added the following methods to @EXPORT_OK | |
170 | File::Util::return_path() | |
171 | File::Util::created() | |
172 | File::Util::last_access() | |
173 | File::Util::last_modified() | |
174 | ||
175 | Much more documentation added. Test suite revisited to reflect changes | |
176 | to the methods mentioned above. | |
177 | ||
178 | 3.14_2 | |
179 | 1/14/03, 12:05 am | |
180 | Much more documentation added. Various methods slightly altered to stay | |
181 | in keeping with the docs and with standard conventions. Test suite | |
182 | revisited somewhat. | |
183 | ||
184 | 3.14_1 | |
185 | 1/2/03, 3:47 am | |
186 | Added a substantial amount of new documentation. Spelling errors in | |
187 | documentation files corrected. | |
188 | ||
189 | Previously available method, File::Util::os(), has been dropped from the | |
190 | namespace and is no longer part of the module. | |
191 | ||
192 | Method File::Util::file_type() no longer includes the 'tty' keyword among | |
193 | its list of recognized file types, as the native Perl file test for | |
194 | divining a TTY file can only be used on open file handles. | |
195 | ||
196 | The keywords returned by this method are all upper case strings as of | |
197 | version 3.13_9, though the release notes for that version errantly did | |
198 | not include this statement. The list of keywords otherwise remains | |
199 | unchanged: | |
200 | PLAIN TEXT | |
201 | BINARY DIRECTORY | |
202 | SYMLINK PIPE | |
203 | SOCKET BLOCK | |
204 | CHARACTER | |
205 | ||
206 | 3.14_0 | |
207 | 12/27/02, 5:50 pm | |
208 | ||
209 | File::Util no longer @ISA Handy::Dandy, and no longer includes it | |
210 | as a prerequisite dependency. Added a little more documentation, | |
211 | but it has a _long_ way to go as yet. | |
212 | ||
213 | 3.13_9 | |
214 | 12/23/02, 3:22 pm | |
215 | ||
216 | A few small changes; no longer lists Handy::Dandy::TimeTools as a | |
217 | prerequisite dependency. | |
218 | ||
219 | 3.13_8 | |
220 | 12/22/02, 11:31 pm | |
221 | ||
222 | Method File::Util::file_type() now returns a list instead of a single | |
223 | string of concatenated keyword substrings, the file type keywords being: | |
224 | plain text | |
225 | binary directory | |
226 | symlink pipe | |
227 | socket block | |
228 | character tty | |
229 | ||
230 | Methods File::Util::load_file() and File::Util::open_handle() both will | |
231 | truly guarantee the uniqueness of the underlying file handle which is | |
232 | auto-generated, whereas before measures to achieve the uniqueness of | |
233 | the file handles were taken, but not verified. | |
234 | ||
235 | POD documentation got a big update. | |
236 | ||
237 | 3.13_7 | |
238 | 12/6/02, 2:56 pm | |
239 | Almost ready for CPAN! | |
240 | ||
241 | License changed from the GNU LGPL to Perl's own licensing scheme. | |
242 | ||
243 | Various tweaks to compile-time sequences. | |
244 | ||
245 | Previously subroutines, SL and NL are now constants. This makes them | |
246 | easier to use when importing them to your main program. Instead of | |
247 | having to type "print('foo' . NL . NL)", you can type the more intuitive | |
248 | "print('foo' . NL x 2)". The same applies for SL, though it's not likely | |
249 | you'll be wanting to print out more than one SL character in sequence. | |
250 | This shouldn't break previous usage of these exported names. | |
251 | ||
252 | Small reference material section appended to the general documentation | |
253 | file contained in 'docs-basic.txt' (part of this distribution) | |
254 | ||
255 | 3.13_4 | |
256 | 11/14/02, 1:22 pm | |
257 | ||
258 | Got rid of all variables in @EXPORT_OK, namely: | |
259 | $OS | |
260 | $EBCDIC | |
261 | $NL | |
262 | $SL | |
263 | ||
264 | I wanted to export only methods, seeing as exporting variables just isn't | |
265 | right, no matter how convenient it might be. There are two new methods, | |
266 | and they are both autoloaded, namely: | |
267 | File::Util::os() | |
268 | File::Util::ebcdic() | |
269 | ||
270 | These two methods take no arguments, and return only the value of the | |
271 | previously EXPORT_OK'ed "$OS" and "$EBCDIC" | |
272 | ||
273 | Added more thorough testing to distribution tests lineup, and an | |
274 | additional set of tests in an automated "empty subclass test" of the | |
275 | modules native methods and all those it inherits from its ancestral | |
276 | classes. | |
277 | ||
278 | More flock() related tweaking in private methods that implement | |
279 | File::Util's automatic, transparent file locking mechanism. | |
280 | ||
281 | 3.13_3 | |
282 | 11/13/02, 9:41 pm | |
283 | ||
284 | Slightly optimized recursive directory listing features of package method | |
285 | File::Util::list_dir() and moved less-used method File::Util::load_dir() | |
286 | to AUTOLOAD. | |
287 | ||
288 | Got rid of stupid method File::Util::EB which was previously | |
289 | used for error bracketing around dynamic values quoted in error messages; | |
290 | this has nothing to do with file handling -the purpose of this module. | |
291 | ||
292 | Global vars $AUTOLOAD and $ATL are gone, since moving to the use of Perl's | |
293 | native AUTOLOAD extension from the old autoloading mechanism. | |
294 | ||
295 | Added/removed functionality tests in the distribution installer according | |
296 | to these changes. | |
297 | ||
298 | 3.13_1 | |
299 | 11/13/02, 1:40 am | |
300 | ||
301 | Fixed problem that caused File::Util to not recognize its set flock | |
302 | usage policy, and flock failthrough rule set when either was manually | |
303 | set during runtime. Added more flock tests to distribution test scripts. | |
304 | ||
305 | 3.13_1 | |
306 | 11/4/02, 12:28 pm | |
307 | ||
308 | Further preparations made to ready the module for PAUSE upload. | |
309 | ||
310 | 3.13_0 | |
311 | Method 'list_dir()' now recognizes a new option, '--ignore-case'. When | |
312 | this option is included among the other arguments you pass in, the list | |
313 | of items returned will be sorted alphabetically from A to Z without | |
314 | respect to character case. | |
315 | ||
316 | Accordingly, when the '--ignore-case' option is used the contents of | |
317 | a directory that would normally appear ordered like the items in | |
318 | Example A would instead appear ordered like the items in the order of | |
319 | Example B. | |
320 | ||
321 | Example A. (default list order of directory contents) | |
322 | Changes COPYING MANIFEST Makefile.PL README test.pl | |
323 | ||
324 | ||
325 | Example B. (case insensitive order) | |
326 | COPYING Changes Makefile.PL MANIFEST README test.pl | |
327 | ||
328 | 3.12_9 | |
329 | 10/27/02, 1:54 pm | |
330 | Various places where warnings were surfacing undesirably have been | |
331 | corrected. General preparations made to upload File::Util to PAUSE and | |
332 | ultimately be included in the CPAN. | |
333 | ||
334 | 3.12_7 | |
335 | 10/10/02, 11:56 pm | |
336 | Method 'list_dir_a()' no longer suffixes directory items with the | |
337 | system path separator by force. | |
338 | ||
339 | 3.12_6 | |
340 | 10/4/02, 4:22 am | |
341 | Fixed serious problem with flock() wrapper which was previously not | |
342 | working at all when global setting '--fatals-as-status' or global | |
343 | setting '--fatals-as-warning' were used. An upgrade to the present | |
344 | release of File::Util from versions predating this release (3.12_6) is | |
345 | seriously recommended! | |
346 | ||
347 | 3.12_5 | |
348 | 10/1/02, 7:46 pm | |
349 | More performance improvements. | |
350 | ||
351 | New argument flags recognized by method 'new': | |
352 | '--fatals-as-warning' The new File::Util object will CORE::warn() | |
353 | about otherwise fatal errors instead of | |
354 | failing and exiting the process. | |
355 | ||
356 | '--fatals-as-status' The new File::Util object will return(undef) | |
357 | to method calls that would otherwise cause | |
358 | fatal errors. | |
359 | ||
360 | Method 'write_file' now recognizes the argument flag, | |
361 | '--empty-writes-OK', as an alternative means of allowing the | |
362 | creation of empty files without reaping a nasty fatal error. Up | |
363 | until now, setting $File::Util::empty_writes to a true value was the | |
364 | only way to accomplish this. | |
365 | ||
366 | 3.12_4 | |
367 | 9/23/02, 2:30 pm | |
368 | Fixed 'deep recursion' problem in AUTOLOAD | |
369 | ||
370 | 3.12_3 | |
371 | 9/23/02, 1:18 pm | |
372 | Added AUTOLOAD and moved lots of methods away into space. They get | |
373 | AUTOLOAD-ed when needed, but not compiled as routines in the module. | |
374 | This greatly improves compile-time and run-time performance now. | |
375 | Got rid of methods 'get()' and 'set()'; they're largely useless. | |
376 | Got rid of variable '$File::Util::canhackit'; no longer used. | |
377 | ||
378 | 3.12_2 | |
379 | 9/11/02, 12:35 am | |
380 | Moved to OOorNO interface design in order to provide both an Object- | |
381 | Oriented and a Procedural (non-Object-Oriented) programming style | |
382 | interface to File::Util. | |
383 | ||
384 | 1.10 | |
385 | Thursday, March 14, 2002, 1:29:55 AM | |
386 | Constants are now class attributes independent of the constructor method. | |
387 | File::Util objects should always get these constants regardless. | |
388 | ||
389 | Constants and OS identification extended upon code from CGI.pm v.2.78 | |
390 | (go Lincoln, it's your birthday, get busy...) as such, File::Util got path | |
391 | separator help to better support a wider variety of platforms. | |
392 | ||
393 | Additionally, constants contributed to a major overhaul of how File::Util | |
394 | handles newlines. | |
395 | ||
396 | 1.09 | |
397 | Thursday, March 14, 2002, 1:29:55 AM | |
398 | Error messages got their own place as predefined key-value pairs in an | |
399 | anonymous hash independent of any class methods. eg-they are committed to | |
400 | memory at compile time for speedy destruction of intentionally halted | |
401 | processes. | |
402 | ||
403 | 1.07 | |
404 | Saturday, February 9, 2002, 3:32:57 PM | |
405 | new method: File::Util::open_handle. This method lets user pass a | |
406 | typeglob reference (eg- *TYPG) and in return the user will get back a new | |
407 | file handle which is opened to the filename of their specifications. | |
408 | ||
409 | 1.06 | |
410 | Tuesday, February 5, 2002, 9:47:35 AM | |
411 | Fixed a bug in File::Util::stamp() which made times during the hour of | |
412 | 12:00 PM appear with the 'AM' suffix rather than the correct 'PM suffix. | |
413 | ||
414 | Added a new format type to File::Util::stamp() called 'file' or 'filename' | |
415 | which returns a timestamp suitable for placing into the name of a file | |
416 | in order to archive old files or versions of code with a time/date stamp | |
417 | embedded into the filename for easy lookup. | |
418 | ||
419 | 1.05 | |
420 | Wednesday, December 5, 2001, 1:36:48 AM | |
421 | Added a few more methods of the same nature as File::Util::size(). Passing | |
422 | in a format keyword argument returns a formatted timestamp. Format | |
423 | keywords described in detail within the overview entry for previous | |
424 | version 1.02. Now an overview of new methods: | |
425 | ||
426 | File::Util::created([filename][format]) | |
427 | ||
428 | returns the creation time of the file in seconds since the epoch. The | |
429 | value returned is then passed back in the same format as the value | |
430 | returned from a call to Perl's built-in function: time() | |
431 | ||
432 | consequently, the value returned is suitable for feeding to | |
433 | localtime, or any private methods and functions expecting the same | |
434 | type of input. | |
435 | ||
436 | As such, a call to this method on a file which was created at: | |
437 | Thursday, December 6, 2001, 4:27:57 PM | |
438 | ...would return the value: 1007684877 | |
439 | ||
440 | File::Util::last_mod([filename][format]) | |
441 | ||
442 | Returns the last modified time of the file you pass to it in seconds | |
443 | since the epoch. Just as with the new created() method described | |
444 | above, the value returned comes in the same format as the value | |
445 | returned from a call to time(), and is therefore suitable for feeding | |
446 | to localtime() or any other private function or method expecting input | |
447 | of the same type. | |
448 | ||
449 | As such, a call to this method on a file which was last modified at: | |
450 | Sunday, December 2, 2001, 12:05:21 AM | |
451 | ...would return the value: 1007280321 | |
452 | ||
453 | File::Util::last_access([filename][format]) | |
454 | ||
455 | Same as the two previously described methods, only this method returns | |
456 | the number of seconds since the epoch to the time when the specified | |
457 | file was last accessed. | |
458 | ||
459 | As such, a call to this method on a file which was last accessed at: | |
460 | Thursday, December 6, 2001, 12:00:00 AM | |
461 | ...would return the value: 1007625600 | |
462 | ||
463 | 1.04 | |
464 | Wednesday, December 5, 2001, 1:36:48 AM | |
465 | Fixed some of the checks on files for existence, added the | |
466 | File::Util::file_size([filename]) method which returns the size of the | |
467 | filename you pass as the only argument. | |
468 | ||
469 | 1.03 | |
470 | Thursday, November 29, 2001, 12:54:07 AM | |
471 | Re-visited the time/date methods to work out a bug which was causing file | |
472 | creation and last-modified times to be returned with incorrect values. | |
473 | ||
474 | 1.02 | |
475 | Tuesday, November 27, 2001, 2:23:55 PM | |
476 | More directory listing options. Method File::Util::stamp() now takes | |
477 | optional format keyword argument; it lets you choose between different | |
478 | output formats for the returned time stamp. Format keywords are thus: | |
479 | ||
480 | --short 5/15/02, 4:22 pm | |
481 | --formal Saturday, June 15, 2002, 4:22 pm | |
482 | --long same as '--formal' | |
483 | --succinct Sat 5/15/02 16:22:43 | |
484 | --ISO Sat, 15 Jun 2002 16.22.43 GMT | |
485 | --filename -June-15-2002-16.22.43 | |
486 | --file same as '--filename' | |
487 | --mdy 5/15/02 | |
488 | --hm 4:22 pm | |
489 | --hms 4:22:43 pm | |
490 | --24hms 16:22:43 | |
491 | --dayofmonth 15 | |
492 | --dayofyear 134 (1 - 365) | |
493 | --dayofweek Saturday | |
494 | --dayofweek, --num 7 | |
495 | --month June | |
496 | --month, --num 6 | |
497 | --year 2002 | |
498 | --shortyear 02 | |
499 | --minute 22 | |
500 | --hour 16 (0 - 24) | |
501 | --second 43 | |
502 | ||
503 | 1.01 | |
504 | Wednesday, November 21, 2001, 4:00:00 PM | |
505 | All methods now include very detailed error messages and a stack trace | |
506 | to help quickly track down mistakes. You can fix mistakes now without | |
507 | having to decipher some cryptic error message which no one can understand | |
508 | and whose origin one can guess :o( | |
509 | ||
510 | 1.00 | |
511 | Sunday, September 23, 2001 4:18:30 PM | |
512 | Initial release of File::Util.pm | |
513 |
0 | COPYING | |
1 | Changes | |
2 | MANIFEST | |
3 | Makefile.PL | |
4 | README | |
5 | Util.pm | |
6 | Util.pod | |
7 | t/001_canuseit.t | |
8 | t/002_isa.t | |
9 | t/003_can.t | |
10 | t/004_portable.t | |
11 | t/005_ftests.t | |
12 | t/006_io.t | |
13 | t/007_flock.t | |
14 | t/008_export_ok.t | |
15 | t/009_empty_subclass.t | |
16 | t/010_diesnice.t | |
17 | t/bin | |
18 | t/txt | |
19 | META.yml Module meta-data (added by MakeMaker) |
0 | # http://module-build.sourceforge.net/META-spec.html | |
1 | #XXXXXXX This is a prototype!!! It will change in the future!!! XXXXX# | |
2 | name: File-Util | |
3 | version: 3.27 | |
4 | version_from: Util.pm | |
5 | installdirs: site | |
6 | requires: | |
7 | Class::OOorNO: 0.01 | |
8 | Exception::Handler: 1 | |
9 | ||
10 | distribution_type: module | |
11 | generated_by: ExtUtils::MakeMaker version 6.30 |
0 | use ExtUtils::MakeMaker; | |
1 | require 5.006; | |
2 | ||
3 | # See lib/ExtUtils/MakeMaker.pm for details of how to influence | |
4 | # the contents of the Makefile that is written. | |
5 | WriteMakefile | |
6 | ( | |
7 | 'NAME' => 'File::Util', | |
8 | 'AUTHOR' => 'Tommy Butler <cpan@atrixnet.com>', | |
9 | 'ABSTRACT_FROM'=> 'Util.pod', | |
10 | 'VERSION_FROM' => 'Util.pm', | |
11 | 'INSTALLDIRS' => 'site', | |
12 | 'PREREQ_PM' => | |
13 | { | |
14 | 'Class::OOorNO' => 0.01_0, | |
15 | 'Exception::Handler' => 1.00_0, | |
16 | }, | |
17 | 'linkext' => { LINKTYPE => '' }, # no link needed | |
18 | 'dist' => | |
19 | { | |
20 | 'COMPRESS' => 'gzip -9f', | |
21 | 'SUFFIX' => 'gz', | |
22 | 'ZIP' => '/usr/bin/zip', | |
23 | 'ZIPFLAGS' => '-rl', | |
24 | } | |
25 | ); |
0 | File::Util | |
1 | ========================= | |
2 | ||
3 | DESCRIPTION | |
4 | File::Util provides a comprehensive toolbox of utilities to automate all | |
5 | kinds of common tasks on file / directories. Its purpose is to do so | |
6 | in the most portable manner possible so that users of this module won't | |
7 | have to worry about whether their programs will work on other OSes | |
8 | and machines. | |
9 | ||
10 | ||
11 | CHANGES IN LAST FEW RELEASES | |
12 | (listed in reverse chronological order by date and subversion) | |
13 | ||
14 | 2.27 | |
15 | Sat Dec 6 13:10:00 CST 2008 | |
16 | Fixed a bug that caused root directories using Micro$oft filesystem | |
17 | notation to be mis-read when using the '--dirs-only' flag for | |
18 | File::Util::list_dir() | |
19 | ||
20 | 3.26 | |
21 | Tue Dec 2 20:07:09 CST 2008 | |
22 | Added to test suite in order to avoid errant test failures | |
23 | when flock'ing on solaris. This is a big deal, since the point of | |
24 | File::Util is to be easy, and portable! | |
25 | ||
26 | Added some yet more extra examples in the documentation. | |
27 | ||
28 | 3.25 | |
29 | Mon Dec 1 15:11:20 CST 2008 | |
30 | Fixed a bug in File::Util::touch() | |
31 | ||
32 | Added some extra examples and corrected one minor error in the | |
33 | documentation. | |
34 | ||
35 | 3.24 | |
36 | Wed May 23 16:27:20 CDT 2007 | |
37 | **Don't use this version. It has a bug. Use 3.25 or greater. | |
38 | ||
39 | Added method File::Util::last_changed (get inode change time for a file) | |
40 | Added method File::Util::touch (works like *nix touch command) | |
41 | ||
42 | Both touch and last_changed are autoloaded methods | |
43 | ||
44 | Applied patch from S. Muskiewicz that fixes the File::Util::last_modified | |
45 | method that was using a similar but incorrect "-" file test operator. | |
46 | ||
47 | INSTALLATION | |
48 | To install this module type the following: | |
49 | ||
50 | perl Makefile.PL | |
51 | make | |
52 | make test | |
53 | make install | |
54 | ||
55 | On windows machines use nmake rather than make; those running cygwin don't have | |
56 | to worry about this. If you don't know what cygwin is, use nmake and check out | |
57 | <URL: http://cygwin.com/> after you're done installing this module if you want | |
58 | to find out. | |
59 | ||
60 | ||
61 | DEPENDENCIES | |
62 | This module requires these other modules and libraries: | |
63 | ||
64 | Class::OOorNO v0.01_0 or better | |
65 | Exception::Handler v1.00_0 or better | |
66 | ||
67 | ||
68 | AUTHOR | |
69 | Tommy Butler <cpan@atrixnet.com> | |
70 | ||
71 | ||
72 | COPYRIGHT | |
73 | Copyright (C) Tommy Butler 2001-2002, all rights reserved. | |
74 | ||
75 | ||
76 | LICENCE | |
77 | ||
78 | This library is free software, you may redistribute it and/or modify it | |
79 | under the same terms as Perl itself. | |
80 |
0 | package File::Util; | |
1 | use 5.006; | |
2 | use strict; | |
3 | use vars qw( | |
4 | $VERSION @ISA @EXPORT_OK %EXPORT_TAGS | |
5 | $OS $MODES $READLIMIT $MAXDIVES $EMPTY_WRITES_OK | |
6 | $USE_FLOCK @ONLOCKFAIL $ILLEGAL_CHR $CAN_FLOCK | |
7 | $NEEDS_BINMODE $EBCDIC $DIRSPLIT $SL $NL $_LOCKS | |
8 | ); | |
9 | use Exporter; | |
10 | use AutoLoader qw( AUTOLOAD ); | |
11 | use Class::OOorNO qw( :all ); | |
12 | $VERSION = 3.27; # Sat Dec 6 13:10:00 CST 2008 | |
13 | @ISA = qw( Exporter Class::OOorNO ); | |
14 | @EXPORT_OK = ( | |
15 | @Class::OOorNO::EXPORT_OK, qw( | |
16 | can_flock ebcdic existent isbin bitmask NL SL | |
17 | strip_path can_read can_write file_type needs_binmode | |
18 | valid_filename size escape_filename return_path | |
19 | created last_access last_changed last_modified OS | |
20 | ) | |
21 | ); | |
22 | %EXPORT_TAGS = ( 'all' => [ @EXPORT_OK ] ); | |
23 | ||
24 | BEGIN { | |
25 | ||
26 | # Some OS logic. | |
27 | unless ($OS = $^O) { require Config; eval(q[$OS=$Config::Config{osname}]) } | |
28 | ||
29 | if ($OS =~ /^darwin/i) { $OS = 'UNIX' } | |
30 | elsif ($OS =~ /^cygwin/i) { $OS = 'CYGWIN' } | |
31 | elsif ($OS =~ /^MSWin/i) { $OS = 'WINDOWS' } | |
32 | elsif ($OS =~ /^vms/i) { $OS = 'VMS' } | |
33 | elsif ($OS =~ /^bsdos/i) { $OS = 'UNIX' } | |
34 | elsif ($OS =~ /^dos/i) { $OS = 'DOS' } | |
35 | elsif ($OS =~ /^MacOS/i) { $OS = 'MACINTOSH' } | |
36 | elsif ($OS =~ /^epoc/) { $OS = 'EPOC' } | |
37 | elsif ($OS =~ /^os2/i) { $OS = 'OS2' } | |
38 | else { $OS = 'UNIX' } | |
39 | ||
40 | $EBCDIC = qq[\t] ne qq[\011] ? 1 : 0; | |
41 | $NEEDS_BINMODE = $OS =~ /WINDOWS|DOS|OS2|MSWin/ ? 1 : 0; | |
42 | $NL = | |
43 | $NEEDS_BINMODE ? qq[\015\012] | |
44 | : $EBCDIC || $OS eq 'VMS' ? qq[\n] | |
45 | : $OS eq 'MACINTOSH' ? qq[\015] | |
46 | : qq[\012]; | |
47 | $SL = | |
48 | { 'DOS' => '\\', 'EPOC' => '/', 'MACINTOSH' => ':', | |
49 | 'OS2' => '\\', 'UNIX' => '/', 'WINDOWS' => chr(92), | |
50 | 'VMS' => '/', 'CYGWIN' => '/', }->{ $OS }||'/'; | |
51 | ||
52 | $_LOCKS = {}; | |
53 | ||
54 | } BEGIN { | |
55 | use constant NL => $NL; | |
56 | use constant SL => $SL; | |
57 | use constant OS => $OS; | |
58 | } | |
59 | ||
60 | $DIRSPLIT = qr/[\x5C\/\:]/; | |
61 | $ILLEGAL_CHR = qr/[\x5C\/\|$NL\r\n\t\013\*\"\?\<\:\>]/; | |
62 | ||
63 | $READLIMIT = 52428800; # set readlimit to a default of 50 megabytes | |
64 | $MAXDIVES = 1000; # maximum depth for recursive list_dir calls | |
65 | ||
66 | use Fcntl qw( ); | |
67 | ||
68 | { local($@); eval <<'__canflock__'; $CAN_FLOCK = $@ ? 0 : 1; } | |
69 | flock(STDOUT, &Fcntl::LOCK_SH); | |
70 | flock(STDOUT, &Fcntl::LOCK_UN); | |
71 | __canflock__ | |
72 | ||
73 | # try to use file locking, define flock race conditions policy | |
74 | $USE_FLOCK = 1; @ONLOCKFAIL = qw( NOBLOCKEX FAIL ); | |
75 | ||
76 | $MODES->{'popen'} = { | |
77 | 'write' => '>', 'trunc' => '>', 'rwupdate' => '+<', | |
78 | 'append' => '>>', 'read' => '<', 'rwclobber' => '+>', | |
79 | 'rwcreate' => '+>', 'rwappend' => '+>>', | |
80 | }; | |
81 | ||
82 | $MODES->{'sysopen'} = { | |
83 | 'read' => '&Fcntl::O_RDONLY', | |
84 | 'write' => '&Fcntl::O_WRONLY | &Fcntl::O_CREAT', | |
85 | 'append' => '&Fcntl::O_WRONLY | &Fcntl::O_APPEND | &Fcntl::O_CREAT', | |
86 | 'trunc' => '&Fcntl::O_WRONLY | &Fcntl::O_CREAT | &Fcntl::O_TRUNC', | |
87 | 'rwcreate' => '&Fcntl::O_RDWR | &Fcntl::O_CREAT', | |
88 | 'rwupdate' => '&Fcntl::O_RDWR', | |
89 | 'rwclobber' => '&Fcntl::O_RDWR | &Fcntl::O_TRUNC | &Fcntl::O_CREAT', | |
90 | 'rwappend' => '&Fcntl::O_RDWR | &Fcntl::O_APPEND | &Fcntl::O_CREAT', | |
91 | }; | |
92 | ||
93 | ||
94 | # -------------------------------------------------------- | |
95 | # Constructor | |
96 | # -------------------------------------------------------- | |
97 | sub new { | |
98 | my($this) = {}; bless($this, shift(@_)); | |
99 | my($in) = $this->coerce_array(@_); | |
100 | ||
101 | my($opts) = $this->shave_opts(\@_); $this->{'opts'} = $opts || {}; | |
102 | ||
103 | $USE_FLOCK = $in->{'use_flock'} | |
104 | if exists $in->{'use_flock'} && $in->{'use_flock'}; | |
105 | ||
106 | $READLIMIT = $in->{'readlimit'} | |
107 | if defined $in->{'readlimit'} | |
108 | && $$in{'readlimit'} !~ /\D/; | |
109 | ||
110 | $MAXDIVES = $in->{'max_dives'} | |
111 | if defined $in->{'max_dives'} | |
112 | && $$in{'max_dives'} !~ /\D/; | |
113 | ||
114 | return $this; | |
115 | } | |
116 | ||
117 | ||
118 | # -------------------------------------------------------- | |
119 | # File::Util::list_dir() | |
120 | # -------------------------------------------------------- | |
121 | sub list_dir { | |
122 | my($this) = shift(@_); | |
123 | my($opts) = $this->shave_opts(\@_); | |
124 | my($dir) = shift(@_)||'.'; | |
125 | my($path) = $dir; | |
126 | my($maxd) = $opts->{'--max-dives'} || $MAXDIVES; | |
127 | my($r) = 0; | |
128 | my(@dirs) = (); my(@files) = (); my(@items) = (); | |
129 | ||
130 | return | |
131 | $this->_throw | |
132 | ( | |
133 | 'no input', | |
134 | { | |
135 | 'meth' => 'list_dir', | |
136 | 'missing' => 'a directory name', | |
137 | 'opts' => $opts, | |
138 | } | |
139 | ) | |
140 | unless length($dir); | |
141 | ||
142 | return($this->_throw('no such file', {'filename' => $dir})) unless -e $dir; | |
143 | ||
144 | # whack off any trailing directory separator, except for root directories | |
145 | # -account for both posix filesystem AND micro$oft directory notation | |
146 | unless ( length($dir) == 1 || $dir =~ /^(?:[[:alpha:]]:)(?:\\|\/)$/o ) { | |
147 | # removes one or more dirsep at the end of $dir | |
148 | $dir =~ s/(?:$DIRSPLIT){1,}$//o; | |
149 | } | |
150 | ||
151 | return | |
152 | $this->_throw | |
153 | ( | |
154 | 'called opendir on a file', | |
155 | { | |
156 | 'filename' => $dir, | |
157 | 'opts' => $opts, | |
158 | } | |
159 | ) | |
160 | unless (-d $dir); | |
161 | ||
162 | # this directory recursion method keeps track of dives based on the parent | |
163 | # directory of $dir, rather than on $dir itself so that multiple | |
164 | # subdirectories within the same parent directory don't improperly increment | |
165 | # the number of dives made | |
166 | if ($opts->{'--recursing'}) { | |
167 | ||
168 | my($pdir) = $dir; $pdir =~ s/(^.*)$DIRSPLIT.*/$1/; | |
169 | ||
170 | $this->{'traversed'}{ $pdir } = $pdir; | |
171 | } | |
172 | else { $this->{'traversed'} = {} } | |
173 | ||
174 | if (scalar keys %{ $this->{'traversed'} } >= $maxd) { | |
175 | ||
176 | return $this->_throw | |
177 | ( | |
178 | 'maxdives exceeded', | |
179 | { | |
180 | 'meth' => 'list_dir', | |
181 | 'maxdives' => $maxd, | |
182 | 'opts' => $opts, | |
183 | } | |
184 | ) | |
185 | } | |
186 | ||
187 | $r = 1 if ($opts->{'--follow'} || $opts->{'--recurse'}); | |
188 | ||
189 | local(*DIR); | |
190 | ||
191 | opendir(DIR, $dir) or | |
192 | return | |
193 | $this->_throw | |
194 | ( | |
195 | 'bad opendir', | |
196 | { | |
197 | 'dirname' => $dir, | |
198 | 'exception' => $!, | |
199 | 'opts' => $opts, | |
200 | } | |
201 | ); | |
202 | ||
203 | # read from beginning of the directory (doesn't seem necessary on any | |
204 | # platforms I've run code on, but just in case...) | |
205 | rewinddir(DIR); | |
206 | ||
207 | @files = exists($opts->{'--pattern'}) | |
208 | ? grep(/$opts->{'--pattern'}/, readdir(DIR)) | |
209 | : readdir(DIR); | |
210 | ||
211 | closedir(DIR) or return $this->_throw( | |
212 | 'close dir', | |
213 | { | |
214 | 'dir' => $dir, | |
215 | 'exception' => $!, | |
216 | 'opts' => $opts, | |
217 | } | |
218 | ); | |
219 | ||
220 | if ($opts->{'--no-fsdots'}) { | |
221 | ||
222 | my(@shadow) = @files; @files = (); | |
223 | ||
224 | while (@shadow) { | |
225 | ||
226 | my($f) = shift(@shadow); | |
227 | ||
228 | push(@files,$f) unless ( | |
229 | $this->strip_path($f) eq '.' | |
230 | or | |
231 | $this->strip_path($f) eq '..' | |
232 | ); | |
233 | } | |
234 | } | |
235 | ||
236 | for (my($i) = 0; $i < @files; ++$i) { | |
237 | ||
238 | my($listing) = ($opts->{'--with-paths'} or ($r==1)) | |
239 | ? $path . SL . $files[$i] | |
240 | : $files[$i]; | |
241 | ||
242 | if (-d $path . SL . $files[$i]) { push(@dirs, $listing) } | |
243 | else { push(@items, $listing) } | |
244 | } | |
245 | ||
246 | if (($r) and (not $opts->{'--override-follow'})) { | |
247 | ||
248 | my(@shadow) = @dirs; @dirs = (); | |
249 | ||
250 | while (@shadow) { | |
251 | ||
252 | my($f) = shift(@shadow); | |
253 | ||
254 | push(@dirs,$f) | |
255 | unless | |
256 | ( | |
257 | $this->strip_path($f) eq '.' | |
258 | or | |
259 | $this->strip_path($f) eq '..' | |
260 | ); | |
261 | } | |
262 | ||
263 | for (my($i) = 0; $i < @dirs; ++$i) { | |
264 | ||
265 | my(@lsts) = $this->list_dir | |
266 | ( | |
267 | $dirs[$i], | |
268 | '--with-paths', '--dirs-as-ref', | |
269 | '--files-as-ref', '--recursing', | |
270 | '--no-fsdots', '--max-dives=' . $maxd | |
271 | ); | |
272 | ||
273 | push(@dirs,@{$lsts[0]}); push(@items,@{$lsts[1]}); | |
274 | } | |
275 | } | |
276 | ||
277 | if ($opts->{'--sl-after-dirs'}) { | |
278 | ||
279 | @dirs = $this->_dropdots(@dirs,'--save-dots'); | |
280 | my($dots) = shift(@dirs); | |
281 | @dirs = map ( ($_ .= SL), @dirs ); | |
282 | @dirs = (@{$dots},@dirs); | |
283 | } | |
284 | ||
285 | my($reta) = []; my($retb) = []; | |
286 | ||
287 | if ($opts->{'--ignore-case'}) { | |
288 | ||
289 | $reta = [ sort {uc $a cmp uc $b} @dirs ]; | |
290 | $retb = [ sort {uc $a cmp uc $b} @items ]; | |
291 | } | |
292 | else { | |
293 | ||
294 | $reta = [ sort {$a cmp $b} @dirs ]; | |
295 | $retb = [ sort {$a cmp $b} @items ]; | |
296 | } | |
297 | ||
298 | return(scalar(@$reta)) | |
299 | if $opts->{'--dirs-only'} && $opts->{'--count-only'}; | |
300 | ||
301 | return(scalar(@$retb)) | |
302 | if $opts->{'--files-only'} && $opts->{'--count-only'}; | |
303 | ||
304 | return(scalar(@$reta) + scalar(@$retb)) if $opts->{'--count-only'}; | |
305 | ||
306 | return($reta,$retb) if $opts->{'--as-ref'}; | |
307 | ||
308 | $reta=[$reta] if $opts->{'--dirs-as-ref'}; | |
309 | $retb=[$retb] if $opts->{'--files-as-ref'}; | |
310 | ||
311 | return(@$reta) if $opts->{'--dirs-only'}; | |
312 | return(@$retb) if $opts->{'--files-only'}; | |
313 | ||
314 | return(@$reta,@$retb); | |
315 | } | |
316 | ||
317 | ||
318 | # -------------------------------------------------------- | |
319 | # File::Util::_dropdots() | |
320 | # -------------------------------------------------------- | |
321 | sub _dropdots { | |
322 | my($this) = shift(@_); my(@out) = (); my($opts) = $this->shave_opts(\@_); | |
323 | my(@shadow) = @_; my(@dots) = (); my($gottadot) = 0; | |
324 | ||
325 | while (@shadow) { | |
326 | ||
327 | if ($gottadot == 2){ push(@out,@shadow) and last } | |
328 | ||
329 | my($thing) = shift(@shadow); | |
330 | ||
331 | if ($thing eq '.') {++$gottadot;push(@dots,$thing);next} | |
332 | if ($thing eq '..') {++$gottadot;push(@dots,$thing);next} | |
333 | ||
334 | push(@out,$thing); | |
335 | } | |
336 | ||
337 | return([@dots],@out) if ($opts->{'--save-dots'}); @out; | |
338 | } | |
339 | ||
340 | ||
341 | # -------------------------------------------------------- | |
342 | # File::Util::load_file() | |
343 | # -------------------------------------------------------- | |
344 | sub load_file { | |
345 | my($this) = shift(@_); my($opts) = $this->shave_opts(\@_); | |
346 | my($in) = $this->coerce_array(@_); my(@dirs) = (); | |
347 | my($blocksize) = 1024; # 1.24 kb | |
348 | my($FH_passed) = 0; my($fh) = undef; my($file) = ''; my($path) = ''; | |
349 | my($content) = ''; my($FHstatus) = ''; my($mode) = 'read'; | |
350 | ||
351 | if (scalar(@_) == 1) { | |
352 | ||
353 | $file = shift(@_)||''; | |
354 | ||
355 | @dirs = split(/$DIRSPLIT/, $file); | |
356 | ||
357 | if (scalar(@dirs) > 0) { | |
358 | ||
359 | $file = pop(@dirs); $path = join(SL, @dirs); | |
360 | } | |
361 | ||
362 | if (length($path) > 0) { | |
363 | ||
364 | $path = '.' . SL . $path if ($path !~ /(?:^\/)|(?:^\w\:)/o); | |
365 | } | |
366 | else { $path = '.'; } | |
367 | ||
368 | return $this->_throw | |
369 | ( | |
370 | 'no input', | |
371 | { | |
372 | 'meth' => 'load_file', | |
373 | 'missing' => 'a file name or file handle reference', | |
374 | 'opts' => $opts, | |
375 | } | |
376 | ) | |
377 | if (length($path . SL . $file) == 0); | |
378 | } | |
379 | else { | |
380 | $fh = $in->{'FH'}||''; $FHstatus = $in->{'FH_status'}||''; | |
381 | ||
382 | # did we get a filehandle? | |
383 | if (length($fh) > 0) { $FH_passed = 1; } else { | |
384 | return $this->_throw( | |
385 | 'no input', | |
386 | { | |
387 | 'meth' => 'load_file', | |
388 | 'missing' => 'a file name or file handle reference', | |
389 | 'opts' => $opts, | |
390 | } | |
391 | ); | |
392 | } | |
393 | } | |
394 | ||
395 | if ($FH_passed) { | |
396 | my($buff) = 0; my($bytes_read) = 0; | |
397 | ||
398 | while (<$fh>) { | |
399 | if ($buff < $READLIMIT) { | |
400 | $bytes_read = read($fh,$content,$blocksize); $buff += $bytes_read; | |
401 | } | |
402 | else { | |
403 | return $this->_throw( | |
404 | 'readlimit exceeded', | |
405 | { | |
406 | 'filename' => '<FH>', | |
407 | 'size' => qq[[truncated at $bytes_read]], | |
408 | 'opts' => $opts, | |
409 | } | |
410 | ); | |
411 | } | |
412 | } | |
413 | ||
414 | # return an array of all lines in the file if the call to this method/ | |
415 | # subroutine asked for an array eg- my(@file) = load_file('file'); | |
416 | # otherwise, return a scalar value containing all of the file's content | |
417 | return(split(/$NL|\r|\n/o,$content)) if $opts->{'--as-list'}; | |
418 | ||
419 | return($content); | |
420 | } | |
421 | ||
422 | # if the file doesn't exist, send back an error | |
423 | return $this->_throw( | |
424 | 'no such file', | |
425 | { | |
426 | 'filename' => $path . SL . $file, | |
427 | 'opts' => $opts, | |
428 | } | |
429 | ) unless -e $path . SL . $file; | |
430 | ||
431 | # it's good to know beforehand whether or not we have permission to open | |
432 | # and read from this file allowing us to handle such an exception before | |
433 | # it handles us. | |
434 | ||
435 | # first check the readability of the file's housing dir | |
436 | return $this->_throw( | |
437 | 'cant dread', | |
438 | { | |
439 | 'filename' => $path . SL . $file, | |
440 | 'dirname' => $path . SL, | |
441 | 'opts' => $opts, | |
442 | } | |
443 | ) unless (-r $path . SL); | |
444 | ||
445 | # now check the readability of the file itself | |
446 | return $this->_throw( | |
447 | 'cant fread', | |
448 | { | |
449 | 'filename' => $path . SL . $file, | |
450 | 'dirname' => $path . SL, | |
451 | 'opts' => $opts, | |
452 | } | |
453 | ) unless (-r $path . SL . $file); | |
454 | ||
455 | # if the file is a directory it will not be opened | |
456 | return $this->_throw( | |
457 | 'called open on a dir', | |
458 | { | |
459 | 'filename' => $path . SL . $file, | |
460 | 'opts' => $opts, | |
461 | } | |
462 | ) if -d $path . SL . $file; | |
463 | ||
464 | my($fsize) = -s $path . SL . $file; | |
465 | ||
466 | return $this->_throw( | |
467 | 'readlimit exceeded', | |
468 | { | |
469 | 'filename' => $path . SL . $file, | |
470 | 'size' => $fsize, | |
471 | 'opts' => $opts, | |
472 | } | |
473 | ) if ($fsize > $READLIMIT); | |
474 | ||
475 | # we need a unique filehandle | |
476 | do { $fh = int(rand(time)) . $$; $fh = eval('*' . 'LOAD_FILE' . $fh) } | |
477 | while fileno($fh); | |
478 | ||
479 | # localize the global output record separator so we can slurp it all | |
480 | # in one quick read. We fail if the filesize exceeds our limit. | |
481 | local($/); | |
482 | ||
483 | # open the file for reading (note the '<' syntax there) or fail with a | |
484 | # error message if our attempt to open the file was unsuccessful | |
485 | my($cmd) = '<' . $path . SL . $file; | |
486 | ||
487 | # lock file before I/O on platforms that support it | |
488 | if ($$opts{'--no-lock'} || $$this{'opts'}{'--no-lock'}) { | |
489 | ||
490 | # if you use the '--no-lock' option you are probably inefficient | |
491 | open($fh, $cmd) or return $this->_throw( | |
492 | 'bad open', | |
493 | { | |
494 | 'filename' => $path . SL . $file, | |
495 | 'mode' => $mode, | |
496 | 'exception' => $!, | |
497 | 'cmd' => $cmd, | |
498 | 'opts' => $opts, | |
499 | } | |
500 | ); | |
501 | } | |
502 | else { | |
503 | open($fh, $cmd) or return $this->_throw( | |
504 | 'bad open', | |
505 | { | |
506 | 'filename' => $path . SL . $file, | |
507 | 'mode' => $mode, | |
508 | 'exception' => $!, | |
509 | 'cmd' => $cmd, | |
510 | 'opts' => $opts, | |
511 | } | |
512 | ); | |
513 | ||
514 | $this->_seize($path . SL . $file, $fh); | |
515 | } | |
516 | ||
517 | # call binmode on binary files for portability accross platforms such | |
518 | # as MS flavor OS family | |
519 | CORE::binmode($fh) if (-B $path . SL . $file); | |
520 | ||
521 | # assign the content of the file to this lexically scoped scalar variable | |
522 | # (memory for *that* variable will be freed when execution leaves this | |
523 | # method / sub | |
524 | $content = <$fh>; | |
525 | ||
526 | if ($$opts{'--no-lock'} || $$this{'opts'}{'--no-lock'}) { | |
527 | ||
528 | # if execution gets here, you used the '--no-lock' option, and you | |
529 | # are probably inefficient | |
530 | close($fh) or return $this->_throw( | |
531 | 'bad close', | |
532 | { | |
533 | 'filename' => $path . SL . $file, | |
534 | 'mode' => $mode, | |
535 | 'exception' => $!, | |
536 | 'opts' => $opts, | |
537 | } | |
538 | ); | |
539 | } | |
540 | else { | |
541 | # release shadow-ed locks on the file | |
542 | $this->_release($fh); | |
543 | ||
544 | close($fh) or return $this->_throw( | |
545 | 'bad close', | |
546 | { | |
547 | 'filename' => $path . SL . $file, | |
548 | 'mode' => $mode, | |
549 | 'exception' => $!, | |
550 | 'opts' => $opts, | |
551 | } | |
552 | ); | |
553 | } | |
554 | ||
555 | # return an array of all lines in the file if the call to this method/ | |
556 | # subroutine asked for an array eg- my(@file) = load_file('file'); | |
557 | # otherwise, return a scalar value containing all of the file's content | |
558 | return(split(/$NL|\r|\n/o,$content)) if $opts->{'--as-lines'}; | |
559 | ||
560 | $content; | |
561 | } | |
562 | ||
563 | ||
564 | # -------------------------------------------------------- | |
565 | # File::Util::write_file() | |
566 | # -------------------------------------------------------- | |
567 | sub write_file { | |
568 | my($this) = shift(@_); | |
569 | my($opts) = $this->shave_opts(\@_); | |
570 | my($in) = $this->coerce_array(@_); | |
571 | my($filename) = $in->{'file'} || $in->{'filename'} || ''; | |
572 | my($content) = $in->{'content'} || ''; | |
573 | my($mode) = $in->{'mode'} || 'write'; | |
574 | my($bitmask) = _bitmaskify($in->{'bitmask'}) || 0777; | |
575 | my($path) = ''; | |
576 | my(@dirs) = (); | |
577 | ||
578 | $path = $filename; | |
579 | ||
580 | local(*WRITE_FILE); $mode = 'trunc' if ($mode eq 'truncate'); | |
581 | ||
582 | # if the call to this method didn't include a filename to which the caller | |
583 | # wants us to write, then complain about it | |
584 | return $this->_throw( | |
585 | 'no input', | |
586 | { | |
587 | 'meth' => 'write_file', | |
588 | 'missing' => 'a file name to create, write, or append', | |
589 | 'opts' => $opts, | |
590 | } | |
591 | ) unless length($filename); | |
592 | ||
593 | # if prospective filename contains 2+ dir separators in sequence then | |
594 | # this is a syntax error we need to whine about | |
595 | return $this->_throw( | |
596 | 'bad chars', | |
597 | { | |
598 | 'string' => $filename, | |
599 | 'purpose' => 'the name of a file or directory', | |
600 | 'opts' => $opts, | |
601 | } | |
602 | ) if ($filename =~ /(?:$DIRSPLIT){2,}/); | |
603 | ||
604 | # if the call to this method didn't include any data which the caller | |
605 | # wants us to write or append to the file, then complain about it | |
606 | return $this->_throw( | |
607 | 'no input', | |
608 | { | |
609 | 'meth' => 'write_file', | |
610 | 'missing' => 'the content you want to write or append', | |
611 | 'opts' => $opts, | |
612 | } | |
613 | ) if ( | |
614 | (length($content) == 0) | |
615 | and | |
616 | ($mode ne 'trunc') | |
617 | and | |
618 | (!$EMPTY_WRITES_OK) | |
619 | and | |
620 | (!$opts->{'--empty-writes-OK'}) | |
621 | ); | |
622 | ||
623 | # remove any possible trailing directory seperator | |
624 | $filename =~ s/$DIRSPLIT$//; | |
625 | ||
626 | # check if file already exists in the form of a directory | |
627 | return $this->_throw( | |
628 | 'cant write_file on a dir', | |
629 | { | |
630 | 'filename' => $filename, | |
631 | 'opts' => $opts, | |
632 | } | |
633 | ) if (-d $filename); | |
634 | ||
635 | # determine existance of the file path, make directory(ies) for the | |
636 | # path if the full directory path doesn't exist | |
637 | @dirs = split(/$DIRSPLIT/, $filename); | |
638 | ||
639 | # if prospective file name has illegal chars then complain | |
640 | foreach (@dirs) { | |
641 | return $this->_throw( | |
642 | 'bad chars', | |
643 | { | |
644 | 'string' => $_, | |
645 | 'purpose' => 'the name of a file or directory', | |
646 | 'opts' => $opts, | |
647 | } | |
648 | ) if (!$this->valid_filename($_)); | |
649 | } | |
650 | ||
651 | # make sure that open mode is a valid mode | |
652 | unless ($mode eq 'write' || $mode eq 'append' || $mode eq 'trunc') { | |
653 | return $this->_throw( | |
654 | 'bad openmode popen', | |
655 | { | |
656 | 'meth' => 'write_file', | |
657 | 'filename' => $filename, | |
658 | 'badmode' => $mode, | |
659 | 'opts' => $opts, | |
660 | } | |
661 | ) | |
662 | } | |
663 | ||
664 | if (scalar(@dirs) > 0) { $filename = pop(@dirs); $path = join(SL, @dirs); } | |
665 | ||
666 | if (length($path) > 0) { | |
667 | $path = '.' . SL . $path if ($path !~ /(?:^\/)|(?:^\w\:)/o); | |
668 | } | |
669 | else { $path = '.'; } | |
670 | ||
671 | # create path preceding file if path doesn't exist | |
672 | $this->make_dir( | |
673 | $path, | |
674 | exists $in->{'dbitmask'} ? _bitmaskify($in->{'dbitmask'}) : 0777 | |
675 | ) unless -e $path; | |
676 | ||
677 | my($openarg) = qq[$path$SL$filename]; | |
678 | ||
679 | if (-e $openarg) { | |
680 | return $this->_throw( | |
681 | 'cant fwrite', | |
682 | { | |
683 | 'filename' => $openarg, | |
684 | 'dirname' => $path, | |
685 | 'opts' => $opts, | |
686 | } | |
687 | ) unless (-w $openarg); | |
688 | } | |
689 | else { | |
690 | # if file doesn't exist, the error is one of creation | |
691 | return $this->_throw( | |
692 | 'cant fcreate', | |
693 | { | |
694 | 'filename' => $openarg, | |
695 | 'dirname' => $path, | |
696 | 'opts' => $opts, | |
697 | } | |
698 | ) unless (-w $path . SL); | |
699 | } | |
700 | ||
701 | # if you use the '--no-lock' option you are probably inefficient | |
702 | if ($$opts{'--no-lock'} || !$USE_FLOCK) { | |
703 | ||
704 | # get open mode | |
705 | $mode = $$MODES{'popen'}{ $mode }; | |
706 | ||
707 | # only non-existent files get bitmask arguments | |
708 | if (-e $openarg) { | |
709 | sysopen(WRITE_FILE, $openarg, eval($$MODES{'sysopen'}{ $mode })) or | |
710 | return $this->_throw( | |
711 | 'bad open', | |
712 | { | |
713 | 'filename' => $openarg, | |
714 | 'mode' => $mode, | |
715 | 'exception' => $!, | |
716 | 'cmd' => qq{$openarg, $$MODES{'sysopen'}{ $mode }}, | |
717 | 'opts' => $opts, | |
718 | } | |
719 | ); | |
720 | } | |
721 | else { | |
722 | sysopen( | |
723 | WRITE_FILE, | |
724 | $openarg, | |
725 | eval($$MODES{'sysopen'}{ $mode }), | |
726 | $bitmask | |
727 | ) or return $this->_throw( | |
728 | 'bad open', | |
729 | { | |
730 | 'filename' => $openarg, | |
731 | 'mode' => $mode, | |
732 | 'exception' => $!, | |
733 | 'cmd' => qq{$openarg, $$MODES{'sysopen'}{$mode}, $bitmask}, | |
734 | 'opts' => $opts, | |
735 | } | |
736 | ); | |
737 | } | |
738 | } | |
739 | else { | |
740 | # open read-only first to safely check if we can get a lock. | |
741 | if (-e $openarg) { | |
742 | ||
743 | open(WRITE_FILE, '<' . $openarg) or | |
744 | return $this->_throw( | |
745 | 'bad open', | |
746 | { | |
747 | 'filename' => $openarg, | |
748 | 'mode' => 'read', | |
749 | 'exception' => $!, | |
750 | 'cmd' => $mode . $openarg, | |
751 | 'opts' => $opts, | |
752 | } | |
753 | ); | |
754 | ||
755 | # lock file before I/O on platforms that support it | |
756 | my($lockstat) = $this->_seize($openarg, *WRITE_FILE); | |
757 | ||
758 | return($lockstat) unless $lockstat; | |
759 | ||
760 | sysopen(WRITE_FILE, $openarg, eval($$MODES{'sysopen'}{ $mode })) | |
761 | or return $this->_throw( | |
762 | 'bad open', | |
763 | { | |
764 | 'filename' => $openarg, | |
765 | 'mode' => $mode, | |
766 | 'opts' => $opts, | |
767 | 'exception' => $!, | |
768 | 'cmd' => qq[$openarg, $$MODES{'sysopen'}{ $mode }], | |
769 | } | |
770 | ); | |
771 | } | |
772 | else { # only non-existent files get bitmask arguments | |
773 | sysopen( | |
774 | WRITE_FILE, | |
775 | $openarg, | |
776 | eval($$MODES{'sysopen'}{ $mode }), | |
777 | $bitmask | |
778 | ) or return $this->_throw( | |
779 | 'bad open', | |
780 | { | |
781 | 'filename' => $openarg, | |
782 | 'mode' => $mode, | |
783 | 'opts' => $opts, | |
784 | 'exception' => $!, | |
785 | 'cmd' => qq{$openarg, $$MODES{'sysopen'}{$mode}, $bitmask}, | |
786 | } | |
787 | ); | |
788 | ||
789 | # lock file before I/O on platforms that support it | |
790 | my($lockstat) = $this->_seize($openarg, *WRITE_FILE); | |
791 | ||
792 | return($lockstat) unless $lockstat; | |
793 | } | |
794 | ||
795 | # now truncate | |
796 | if ($mode ne 'append') { | |
797 | truncate(WRITE_FILE,0) or return $this->_throw( | |
798 | 'bad systrunc', | |
799 | { | |
800 | 'filename' => $openarg, | |
801 | 'exception' => $!, | |
802 | 'opts' => $opts, | |
803 | } | |
804 | ); | |
805 | } | |
806 | } | |
807 | ||
808 | CORE::binmode(WRITE_FILE) if $in->{'binmode'} || $opts->{'--binmode'}; | |
809 | ||
810 | $in->{'content'}||=''; syswrite(WRITE_FILE, $in->{'content'}); | |
811 | ||
812 | # release lock on the file | |
813 | unless ($$opts{'--no-lock'} || !$USE_FLOCK) { $this->_release(*WRITE_FILE) } | |
814 | ||
815 | close(WRITE_FILE) or | |
816 | return $this->_throw( | |
817 | 'bad close', | |
818 | { | |
819 | 'filename' => $openarg, | |
820 | 'mode' => $mode, | |
821 | 'exception' => $!, | |
822 | 'opts' => $opts, | |
823 | } | |
824 | ); | |
825 | ||
826 | return(1); | |
827 | } | |
828 | ||
829 | ||
830 | # -------------------------------------------------------- | |
831 | # %$File::Util::LOCKS | |
832 | # -------------------------------------------------------- | |
833 | $_LOCKS->{'IGNORE'} = sub { $_[2] }; | |
834 | $_LOCKS->{'ZERO'} = sub { 0 }; | |
835 | $_LOCKS->{'UNDEF'} = sub { undef }; | |
836 | $_LOCKS->{'NOBLOCKEX'} = sub { | |
837 | return $_[2] if flock($_[2], &Fcntl::LOCK_EX | &Fcntl::LOCK_NB); undef | |
838 | }; | |
839 | $_LOCKS->{'NOBLOCKSH'} = sub { | |
840 | return $_[2] if flock($_[2], &Fcntl::LOCK_SH | &Fcntl::LOCK_NB); undef | |
841 | }; | |
842 | $_LOCKS->{'BLOCKEX'} = sub { | |
843 | return $_[2] if flock($_[2], &Fcntl::LOCK_EX); undef | |
844 | }; | |
845 | $_LOCKS->{'BLOCKSH'} = sub { | |
846 | return $_[2] if flock($_[2], &Fcntl::LOCK_SH); undef | |
847 | }; | |
848 | $_LOCKS->{'WARN'} = sub { | |
849 | $_[0]->_throw( | |
850 | 'bad flock', | |
851 | { | |
852 | 'filename' => $_[1], | |
853 | 'exception' => $!, | |
854 | }, | |
855 | '--as-warning', | |
856 | ); undef | |
857 | }; | |
858 | $_LOCKS->{'FAIL'} = sub { | |
859 | $_[0]->_throw( | |
860 | 'bad flock', | |
861 | { | |
862 | 'filename' => $_[1], | |
863 | 'exception' => $!, | |
864 | }, | |
865 | ); 0 | |
866 | }; | |
867 | ||
868 | ||
869 | # -------------------------------------------------------- | |
870 | # File::Util::_seize() | |
871 | # -------------------------------------------------------- | |
872 | sub _seize { | |
873 | my($this) = shift(@_); my($file) = shift(@_)||''; my($fh) = shift(@_)||''; | |
874 | my(@policy) = @ONLOCKFAIL; | |
875 | my($policy) = {}; | |
876 | ||
877 | # seize filehandle, return it if lock is successful | |
878 | ||
879 | # forget seizing if system can't flock | |
880 | return($fh) if !$CAN_FLOCK; | |
881 | ||
882 | return($this->_throw(q{no file name passed to _seize.})) unless length $file; | |
883 | return($this->_throw(q{no handle passed to _seize.})) unless $fh; | |
884 | ||
885 | while (@policy) { | |
886 | my($fh) = &{ $_LOCKS->{ shift @policy } }($this,$file,$fh); | |
887 | return $fh if ($fh || !scalar @policy) | |
888 | } | |
889 | ||
890 | $fh; | |
891 | } | |
892 | ||
893 | ||
894 | # -------------------------------------------------------- | |
895 | # File::Util::_release() | |
896 | # -------------------------------------------------------- | |
897 | sub _release { | |
898 | my($this,$fh) = @_; | |
899 | ||
900 | return($this->_throw('not a filehandle.', {'argtype' => ref(\$fh||'')})) | |
901 | unless ($fh && ref(\$fh||'') eq 'GLOB'); | |
902 | ||
903 | if ($CAN_FLOCK) { flock($fh, &Fcntl::LOCK_UN) } 1; | |
904 | } | |
905 | ||
906 | ||
907 | # -------------------------------------------------------- | |
908 | # File::Util::valid_filename() | |
909 | # -------------------------------------------------------- | |
910 | sub valid_filename { | |
911 | my($f) = myargs(@_); | |
912 | ||
913 | $f !~ /$ILLEGAL_CHR/ ? 1 : undef | |
914 | } | |
915 | ||
916 | ||
917 | # -------------------------------------------------------- | |
918 | # File::Util::strip_path() | |
919 | # -------------------------------------------------------- | |
920 | sub strip_path { my($f) = myargs(@_); pop @{['', split(/$DIRSPLIT/,$f)]}||'' } | |
921 | ||
922 | ||
923 | # -------------------------------------------------------- | |
924 | # File::Util::line_count() | |
925 | # -------------------------------------------------------- | |
926 | sub line_count { | |
927 | my($this,$file) = @_; | |
928 | my($buff) = ''; | |
929 | my($lines) = 0; | |
930 | my($cmd) = '<' . $file; | |
931 | ||
932 | local(*LINES); | |
933 | ||
934 | open(LINES, $file) or | |
935 | return $this->_throw( | |
936 | 'bad open', | |
937 | { | |
938 | 'filename' => $file, | |
939 | 'mode' => 'read', | |
940 | 'exception' => $!, | |
941 | 'cmd' => $cmd, | |
942 | } | |
943 | ); | |
944 | ||
945 | while (sysread(LINES, $buff, 4096)) { | |
946 | $lines += $buff =~ tr/\n//; $buff = ''; | |
947 | } | |
948 | ||
949 | close(LINES); $lines; | |
950 | } | |
951 | ||
952 | ||
953 | # -------------------------------------------------------- | |
954 | # File::Util::_bitmaskify() | |
955 | # -------------------------------------------------------- | |
956 | sub _bitmaskify { | |
957 | # save users who mistakenly pass in string values when bitmasks are | |
958 | # required (bitmasks must always be octal numbers) | |
959 | ||
960 | my($bmsk) = @_; | |
961 | ||
962 | return unless (defined($bmsk) && length($bmsk)); | |
963 | ||
964 | $bmsk == eval($bmsk) ? $bmsk : oct($bmsk); | |
965 | } | |
966 | ||
967 | ||
968 | # -------------------------------------------------------- | |
969 | # File::Util::DESTROY(), end File::Util class definition | |
970 | # -------------------------------------------------------- | |
971 | sub DESTROY {} | |
972 | 1; | |
973 | ||
974 | __END__ | |
975 | ||
976 | # -------------------------------------------------------- | |
977 | # File::Util::bitmask() | |
978 | # -------------------------------------------------------- | |
979 | sub bitmask { | |
980 | my($f) = myargs(@_); | |
981 | ||
982 | defined $f and -e $f ? sprintf('%04o',(stat($f))[2] & 0777) : undef | |
983 | } | |
984 | ||
985 | ||
986 | # -------------------------------------------------------- | |
987 | # File::Util::can_flock() | |
988 | # -------------------------------------------------------- | |
989 | sub can_flock { $CAN_FLOCK } | |
990 | ||
991 | ||
992 | # File::Util::-------------------------------------------- | |
993 | # can_read(), can_write() | |
994 | # -------------------------------------------------------- | |
995 | sub can_read { my($f) = myargs(@_); defined $f ? -r $f : undef } | |
996 | sub can_write { my($f) = myargs(@_); defined $f ? -w $f : undef } | |
997 | ||
998 | ||
999 | # -------------------------------------------------------- | |
1000 | # File::Util::created() | |
1001 | # -------------------------------------------------------- | |
1002 | sub created { | |
1003 | my($f) = myargs(@_); | |
1004 | ||
1005 | defined $f and -e $f ? $^T - ((-M $f) * 60 * 60 * 24) : undef | |
1006 | } | |
1007 | ||
1008 | ||
1009 | # -------------------------------------------------------- | |
1010 | # File::Util::ebcdic() | |
1011 | # -------------------------------------------------------- | |
1012 | sub ebcdic { $EBCDIC } | |
1013 | ||
1014 | ||
1015 | # -------------------------------------------------------- | |
1016 | # File::Util::escape_filename() | |
1017 | # -------------------------------------------------------- | |
1018 | sub escape_filename { | |
1019 | my($opts) = shave_opts(\@_); | |
1020 | my($file,$escape,$also) = myargs(@_); | |
1021 | ||
1022 | return '' unless defined $file; | |
1023 | ||
1024 | $escape = '_' if !defined($escape); | |
1025 | ||
1026 | $file = strip_path($file) if $opts->{'--strip-path'}; | |
1027 | ||
1028 | if ($also) { $file =~ s/\Q$also\E/$escape/g } | |
1029 | ||
1030 | $file =~ s/$ILLEGAL_CHR/$escape/g; | |
1031 | $file =~ s/$DIRSPLIT/$escape/g; | |
1032 | ||
1033 | $file | |
1034 | } | |
1035 | ||
1036 | ||
1037 | # -------------------------------------------------------- | |
1038 | # File::Util::existent() | |
1039 | # -------------------------------------------------------- | |
1040 | sub existent { my($f) = myargs(@_); defined $f ? -e $f : undef } | |
1041 | ||
1042 | ||
1043 | # -------------------------------------------------------- | |
1044 | # File::Util::touch() | |
1045 | # -------------------------------------------------------- | |
1046 | sub touch { | |
1047 | my($this) = shift(@_); my($opts) = $this->shave_opts(\@_); | |
1048 | my($in) = $this->coerce_array(@_); my(@dirs) = (); | |
1049 | my($file) = ''; my($path) = ''; | |
1050 | my($mode) = 'read'; | |
1051 | ||
1052 | $file = shift(@_)||''; | |
1053 | ||
1054 | @dirs = split(/$DIRSPLIT/, $file); | |
1055 | ||
1056 | if (scalar(@dirs) > 0) { | |
1057 | ||
1058 | $file = pop(@dirs); $path = join(SL, @dirs); | |
1059 | } | |
1060 | ||
1061 | if (length($path) > 0) { | |
1062 | $path = '.' . SL . $path if ($path !~ /(?:^\/)|(?:^\w\:)/o); | |
1063 | } | |
1064 | else { $path = '.'; } | |
1065 | ||
1066 | return $this->_throw( | |
1067 | 'no input', | |
1068 | { | |
1069 | 'meth' => 'touch', | |
1070 | 'missing' => 'a file name or file handle reference', | |
1071 | 'opts' => $opts, | |
1072 | } | |
1073 | ) if (length($path . SL . $file) == 0); | |
1074 | ||
1075 | # see if the file exists already and is a directory | |
1076 | return $this->_throw( | |
1077 | 'cant touch on a dir', | |
1078 | { | |
1079 | 'filename' => $path . SL . $file, | |
1080 | 'dirname' => $path . SL, | |
1081 | 'opts' => $opts, | |
1082 | } | |
1083 | ) if (-e $path . SL . $file && -d $path . SL . $file); | |
1084 | ||
1085 | # if the path doesn't exist, make it | |
1086 | $this->make_dir($path) unless -e $path . SL; | |
1087 | ||
1088 | # it's good to know beforehand whether or not we have permission to open | |
1089 | # and read from this file allowing us to handle such an exception before | |
1090 | # it handles us. | |
1091 | ||
1092 | # first check the readability of the file's housing dir | |
1093 | return $this->_throw( | |
1094 | 'cant dread', | |
1095 | { | |
1096 | 'filename' => $path . SL . $file, | |
1097 | 'dirname' => $path . SL, | |
1098 | 'opts' => $opts, | |
1099 | } | |
1100 | ) unless (-r $path . SL); | |
1101 | ||
1102 | # now check the writability of the file itself | |
1103 | return $this->_throw( | |
1104 | 'cant fwrite', | |
1105 | { | |
1106 | 'filename' => $path . SL . $file, | |
1107 | 'dirname' => $path . SL, | |
1108 | 'opts' => $opts, | |
1109 | } | |
1110 | ) if (-e $path . SL . $file && !-w $path . SL . $file); | |
1111 | ||
1112 | # create the file if it doesn't exist (like the *nix touch command does) | |
1113 | $this->write_file( | |
1114 | 'filename' => $path . SL . $file, | |
1115 | 'content' => '', | |
1116 | '--empty-writes-OK' | |
1117 | ) if !-e $path . SL . $file; | |
1118 | ||
1119 | my($now) = time(); | |
1120 | ||
1121 | # return | |
1122 | return utime $now, $now, $path . SL . $file; | |
1123 | } | |
1124 | ||
1125 | ||
1126 | # -------------------------------------------------------- | |
1127 | # File::Util::file_type() | |
1128 | # -------------------------------------------------------- | |
1129 | sub file_type { | |
1130 | my($f) = myargs(@_); | |
1131 | ||
1132 | return undef unless defined $f and -e $f; | |
1133 | ||
1134 | my(@ret) = (); | |
1135 | ||
1136 | push @ret, 'PLAIN' if (-f $f); push @ret, 'TEXT' if (-T $f); | |
1137 | push @ret, 'BINARY' if (-B $f); push @ret, 'DIRECTORY' if (-d $f); | |
1138 | push @ret, 'SYMLINK' if (-l $f); push @ret, 'PIPE' if (-p $f); | |
1139 | push @ret, 'SOCKET' if (-S $f); push @ret, 'BLOCK' if (-b $f); | |
1140 | push @ret, 'CHARACTER' if (-c $f); push @ret, 'TTY' if (-t $f); | |
1141 | ||
1142 | push(@ret,'Error: cannot determine file type') unless @ret; @ret | |
1143 | } | |
1144 | ||
1145 | ||
1146 | # -------------------------------------------------------- | |
1147 | # File::Util::flock_rules() | |
1148 | # -------------------------------------------------------- | |
1149 | sub flock_rules { | |
1150 | my($this) = shift(@_); | |
1151 | my(@rules) = myargs(@_); | |
1152 | ||
1153 | return @ONLOCKFAIL unless defined scalar @rules; | |
1154 | ||
1155 | my(%valid) = qw/ | |
1156 | NOBLOCKEX NOBLOCKEX | |
1157 | NOBLOCKSH NOBLOCKSH | |
1158 | BLOCKEX BLOCKEX | |
1159 | BLOCKSH BLOCKSH | |
1160 | FAIL FAIL | |
1161 | WARN WARN | |
1162 | IGNORE IGNORE | |
1163 | UNDEF UNDEF | |
1164 | ZERO ZERO /; | |
1165 | ||
1166 | map { | |
1167 | return $this->_throw('bad flock rules', { 'bad' => $_, 'all' => \@rules }) | |
1168 | unless exists $valid{ $_ } | |
1169 | } @rules; | |
1170 | ||
1171 | @ONLOCKFAIL = @rules; | |
1172 | ||
1173 | @ONLOCKFAIL | |
1174 | } | |
1175 | ||
1176 | ||
1177 | # -------------------------------------------------------- | |
1178 | # File::Util::isbin() | |
1179 | # -------------------------------------------------------- | |
1180 | sub isbin { my($f) = myargs(@_); defined $f ? -B $f : undef } | |
1181 | ||
1182 | ||
1183 | # -------------------------------------------------------- | |
1184 | # File::Util::last_access() | |
1185 | # -------------------------------------------------------- | |
1186 | sub last_access { | |
1187 | my($f) = myargs(@_); $f ||= ''; | |
1188 | ||
1189 | return undef unless -e $f; | |
1190 | ||
1191 | # return the last accessed time of $f | |
1192 | $^T - ((-A $f) * 60 * 60 * 24) | |
1193 | } | |
1194 | ||
1195 | ||
1196 | # -------------------------------------------------------- | |
1197 | # File::Util::last_modified() | |
1198 | # -------------------------------------------------------- | |
1199 | sub last_modified { | |
1200 | my($f) = myargs(@_); $f ||= ''; | |
1201 | ||
1202 | return undef unless -e $f; | |
1203 | ||
1204 | # return the last modified time of $f | |
1205 | $^T - ((-M $f) * 60 * 60 * 24) | |
1206 | } | |
1207 | ||
1208 | ||
1209 | # -------------------------------------------------------- | |
1210 | # File::Util::last_changed() | |
1211 | # -------------------------------------------------------- | |
1212 | sub last_changed { | |
1213 | my($f) = myargs(@_); $f ||= ''; | |
1214 | ||
1215 | return undef unless -e $f; | |
1216 | ||
1217 | # return the last changed time of $f | |
1218 | $^T - ((-C $f) * 60 * 60 * 24) | |
1219 | } | |
1220 | ||
1221 | ||
1222 | # -------------------------------------------------------- | |
1223 | # File::Util::load_dir() | |
1224 | # -------------------------------------------------------- | |
1225 | sub load_dir { | |
1226 | my($this) = shift(@_); my($opts) = $this->shave_opts(\@_); | |
1227 | my($dir) = shift(@_)||''; my(@files) = (); | |
1228 | my($dir_hash) = {}; my($dir_list) = []; | |
1229 | ||
1230 | return $this->_throw | |
1231 | ( | |
1232 | 'no input', | |
1233 | { | |
1234 | 'meth' => 'load_dir', | |
1235 | 'missing' => 'a directory name', | |
1236 | 'opts' => $opts, | |
1237 | } | |
1238 | ) | |
1239 | unless length($dir); | |
1240 | ||
1241 | @files = $this->list_dir($dir,'--files-only'); | |
1242 | ||
1243 | # map the content of each file into a hash key-value element where the | |
1244 | # key name for each file is the name of the file | |
1245 | if (!$opts->{'--as-list'} and !$opts->{'--as-listref'}) { | |
1246 | ||
1247 | foreach (@files) { | |
1248 | ||
1249 | $dir_hash->{ $_ } = $this->load_file( $dir . SL . $_ ); | |
1250 | } | |
1251 | ||
1252 | return($dir_hash); | |
1253 | } | |
1254 | else { | |
1255 | ||
1256 | foreach (@files) { | |
1257 | ||
1258 | push(@{$dir_list},$this->load_file( $dir . SL . $_ )); | |
1259 | } | |
1260 | ||
1261 | return($dir_list) if ($opts->{'--as-listref'}); return(@{$dir_list}); | |
1262 | } | |
1263 | ||
1264 | $dir_hash; | |
1265 | } | |
1266 | ||
1267 | ||
1268 | # -------------------------------------------------------- | |
1269 | # File::Util::make_dir() | |
1270 | # -------------------------------------------------------- | |
1271 | sub make_dir { | |
1272 | my($this) = shift(@_); | |
1273 | my($opts) = $this->shave_opts(\@_); | |
1274 | my($dir,$bitmask) = @_; $bitmask = _bitmaskify($bitmask) || 0777; | |
1275 | ||
1276 | if ($$opts{'--if-not-exists'}) { | |
1277 | if (-e $dir) { | |
1278 | return $dir if -d $dir; | |
1279 | ||
1280 | return $this->_throw( | |
1281 | 'called mkdir on a file', | |
1282 | { | |
1283 | 'filename' => $dir, | |
1284 | 'dirname' => join(SL,(split(/$DIRSPLIT/,$dir))[0 .. -1]) . SL | |
1285 | } | |
1286 | ); | |
1287 | } | |
1288 | } | |
1289 | else { | |
1290 | if (-e $dir) { | |
1291 | return $this->_throw( | |
1292 | 'called mkdir on a file', | |
1293 | { | |
1294 | 'filename' => $dir, | |
1295 | 'dirname' => join(SL,(split(/$DIRSPLIT/,$dir))[0 .. -1]) . SL | |
1296 | } | |
1297 | ) unless -d $dir; | |
1298 | ||
1299 | return $this->_throw( | |
1300 | 'make_dir target exists', | |
1301 | { | |
1302 | 'dirname' => $dir, | |
1303 | 'filetype' => [ $this->file_type($dir) ], | |
1304 | } | |
1305 | ); | |
1306 | } | |
1307 | } | |
1308 | ||
1309 | # if the call to this method didn't include a directory name to create, | |
1310 | # then complain about it | |
1311 | return $this->_throw( | |
1312 | 'no input', | |
1313 | { | |
1314 | 'meth' => 'make_dir', | |
1315 | 'missing' => 'a directory name', | |
1316 | } | |
1317 | ) unless (defined($dir) && length($dir)); | |
1318 | ||
1319 | # if prospective directory name contains 2+ dir separators in sequence then | |
1320 | # this is a syntax error we need to whine about | |
1321 | return $this->_throw( | |
1322 | 'bad chars', | |
1323 | { | |
1324 | 'string' => $dir, | |
1325 | 'purpose' => 'the name of a directory', | |
1326 | } | |
1327 | ) if ($dir =~ /$DIRSPLIT{2,}/); | |
1328 | ||
1329 | $dir =~ s/$DIRSPLIT$// unless $dir eq $DIRSPLIT; | |
1330 | ||
1331 | my(@dirs_in_path) = split(/$DIRSPLIT/, $dir); | |
1332 | ||
1333 | # for absolute pathnames | |
1334 | if (substr($dir,0,1) eq SL) { | |
1335 | $dirs_in_path[0] = SL; | |
1336 | } | |
1337 | ||
1338 | for (my($i) = 0; $i < scalar @dirs_in_path; ++$i) { | |
1339 | next if $i == 0 && $dirs_in_path[$i] eq SL; | |
1340 | ||
1341 | # if prospective directory name contains illegal chars then complain | |
1342 | return $this->_throw( | |
1343 | 'bad chars', | |
1344 | { | |
1345 | 'string' => $dirs_in_path[$i], | |
1346 | 'purpose' => 'the name of a directory', | |
1347 | } | |
1348 | ) unless $this->valid_filename($dirs_in_path[$i]) | |
1349 | } | |
1350 | ||
1351 | # qualify each subdir in @dirs_in_path by prepending its preceeding dir | |
1352 | # names to it. Above, "/foo/bar/baz" becomes ("/", "foo", "bar", "baz") | |
1353 | # and below it becomes ("/", "/foo", "/foo/bar", "/foo/bar/baz") | |
1354 | ||
1355 | if (scalar(@dirs_in_path) > 1) { | |
1356 | for (my($depth) = 1; $depth < scalar @dirs_in_path; ++$depth) { | |
1357 | if ($dirs_in_path[$depth-1] eq SL) { | |
1358 | $dirs_in_path[$depth] = SL . $dirs_in_path[$depth] | |
1359 | } | |
1360 | else { | |
1361 | $dirs_in_path[$depth] = join(SL, @dirs_in_path[($depth-1)..$depth]) | |
1362 | } | |
1363 | } | |
1364 | } | |
1365 | ||
1366 | my($i) = 0; | |
1367 | ||
1368 | foreach (@dirs_in_path) { | |
1369 | my($dir) = $_; | |
1370 | my($up) = ($i > 0) ? $dirs_in_path[$i-1] : '..'; | |
1371 | ||
1372 | ++$i; | |
1373 | ||
1374 | if (-e $dir and !-d $dir) { | |
1375 | return $this->_throw( | |
1376 | 'called mkdir on a file', | |
1377 | { | |
1378 | 'filename' => $dir, | |
1379 | 'dirname' => $up . SL, | |
1380 | } | |
1381 | ); | |
1382 | } | |
1383 | ||
1384 | next if -e $dir; | |
1385 | ||
1386 | # it's good to know beforehand whether or not we have permission to | |
1387 | # create dirs here, which allows us to handle such an exception | |
1388 | # before it handles us. | |
1389 | return $this->_throw( | |
1390 | 'cant dcreate', | |
1391 | { | |
1392 | 'dirname' => $dir, | |
1393 | 'parentd' => $up, | |
1394 | } | |
1395 | ) unless -w $up; | |
1396 | ||
1397 | mkdir($dir, $bitmask) or | |
1398 | return $this->_throw( | |
1399 | 'bad make_dir', | |
1400 | { | |
1401 | 'exception' => $!, | |
1402 | 'dirname' => $dir, | |
1403 | 'bitmask' => $bitmask, | |
1404 | } | |
1405 | ); | |
1406 | } | |
1407 | ||
1408 | $dir; | |
1409 | } | |
1410 | ||
1411 | ||
1412 | # -------------------------------------------------------- | |
1413 | # File::Util::max_dives() | |
1414 | # -------------------------------------------------------- | |
1415 | sub max_dives { | |
1416 | my($arg) = myargs(@_); | |
1417 | ||
1418 | if (defined($arg)) { | |
1419 | return $this->_throw('bad maxdives') if $arg !~ /\D/o; | |
1420 | $MAXDIVES = $arg; | |
1421 | } | |
1422 | ||
1423 | $MAXDIVES | |
1424 | } | |
1425 | ||
1426 | ||
1427 | # -------------------------------------------------------- | |
1428 | # File::Util::readlimt() | |
1429 | # -------------------------------------------------------- | |
1430 | sub readlimit { | |
1431 | my($arg) = myargs(@_); | |
1432 | ||
1433 | if (defined($arg)) { | |
1434 | return $this->_throw | |
1435 | ( | |
1436 | 'bad readlimit', | |
1437 | { | |
1438 | 'bad' => $arg, | |
1439 | } | |
1440 | ) if $arg !~ /\D/o; | |
1441 | ||
1442 | $READLIMIT = $arg; | |
1443 | } | |
1444 | ||
1445 | $READLIMIT | |
1446 | } | |
1447 | ||
1448 | ||
1449 | # -------------------------------------------------------- | |
1450 | # File::Util::needs_binmode() | |
1451 | # -------------------------------------------------------- | |
1452 | sub needs_binmode { $NEEDS_BINMODE } | |
1453 | ||
1454 | ||
1455 | # -------------------------------------------------------- | |
1456 | # File::Util::open_handle() | |
1457 | # -------------------------------------------------------- | |
1458 | sub open_handle { | |
1459 | my($this) = shift(@_); | |
1460 | my($opts) = $this->shave_opts(\@_); | |
1461 | my($in) = $this->coerce_array(@_); | |
1462 | my($filename) = $in->{'file'} || $in->{'filename'} || ''; | |
1463 | my($mode) = $in->{'mode'} || 'write'; | |
1464 | my($bitmask) = _bitmaskify($in->{'bitmask'}) || 0777; | |
1465 | my($fh) = undef; | |
1466 | my($path) = ''; | |
1467 | my(@dirs) = (); | |
1468 | ||
1469 | $path = $filename; | |
1470 | ||
1471 | # begin user input validation/sanitation sequence | |
1472 | ||
1473 | # if the call to this method didn't include a filename to which the caller | |
1474 | # wants us to write, then complain about it | |
1475 | return $this->_throw( | |
1476 | 'no input', | |
1477 | { | |
1478 | 'meth' => 'open_handle', | |
1479 | 'missing' => 'a file name to create, write, read/write, or append', | |
1480 | 'opts' => $opts, | |
1481 | } | |
1482 | ) unless length($filename); | |
1483 | ||
1484 | # if prospective filename contains 2+ dir separators in sequence then | |
1485 | # this is a syntax error we need to whine about | |
1486 | return $this->_throw( | |
1487 | 'bad chars', | |
1488 | { | |
1489 | 'string' => $filename, | |
1490 | 'purpose' => 'the name of a file or directory', | |
1491 | 'opts' => $opts, | |
1492 | } | |
1493 | ) if ($filename =~ /(?:$DIRSPLIT){2,}/); | |
1494 | ||
1495 | # remove trailing directory seperator | |
1496 | $filename =~ s/$DIRSPLIT$//; | |
1497 | ||
1498 | # determine existance of the file path, make directory(ies) for the | |
1499 | # path if the full directory path doesn't exist | |
1500 | @dirs = split(/$DIRSPLIT/, $filename); | |
1501 | ||
1502 | # if prospective file name has illegal chars then complain | |
1503 | foreach (@dirs) { | |
1504 | return $this->_throw( | |
1505 | 'bad chars', | |
1506 | { | |
1507 | 'string' => $_, | |
1508 | 'purpose' => 'the name of a file or directory', | |
1509 | 'opts' => $opts, | |
1510 | } | |
1511 | ) if (!$this->valid_filename($_)); | |
1512 | } | |
1513 | ||
1514 | # make sure that open mode is a valid mode | |
1515 | if ( | |
1516 | !exists($opts->{'--use-sysopen'}) && | |
1517 | !defined($opts->{'--use-sysopen'}) | |
1518 | ) { | |
1519 | # native Perl open modes | |
1520 | unless ( | |
1521 | exists($$MODES{'popen'}{ $mode }) && | |
1522 | defined($$MODES{'popen'}{ $mode }) | |
1523 | ) { | |
1524 | return $this->_throw( | |
1525 | 'bad openmode popen', | |
1526 | { | |
1527 | 'meth' => 'open_handle', | |
1528 | 'filename' => $filename, | |
1529 | 'badmode' => $mode, | |
1530 | 'opts' => $opts, | |
1531 | } | |
1532 | ) | |
1533 | } | |
1534 | } | |
1535 | else { | |
1536 | # system open modes | |
1537 | unless ( | |
1538 | exists($$MODES{'sysopen'}{ $mode }) && | |
1539 | defined($$MODES{'sysopen'}{ $mode }) | |
1540 | ) { | |
1541 | return $this->_throw( | |
1542 | 'bad openmode sysopen', | |
1543 | { | |
1544 | 'meth' => 'open_handle', | |
1545 | 'filename' => $filename, | |
1546 | 'badmode' => $mode, | |
1547 | 'opts' => $opts, | |
1548 | } | |
1549 | ) | |
1550 | } | |
1551 | } | |
1552 | ||
1553 | if (scalar(@dirs) > 0) { $filename = pop(@dirs); $path = join(SL, @dirs); } | |
1554 | ||
1555 | if (length($path) > 0) { | |
1556 | $path = '.' . SL . $path if ($path !~ /(?:^\/)|(?:^\w\:)/o); | |
1557 | } | |
1558 | else { $path = '.'; } | |
1559 | ||
1560 | # create path preceding file if path doesn't exist | |
1561 | $this->make_dir( | |
1562 | $path, | |
1563 | exists $in->{'dbitmask'} ? _bitmaskify($in->{'dbitmask'}) : 0777 | |
1564 | ) unless -e $path; | |
1565 | ||
1566 | my($openarg) = qq[$path$SL$filename]; | |
1567 | ||
1568 | # sanity checks based on requested mode | |
1569 | if ( | |
1570 | $mode eq 'write' || | |
1571 | $mode eq 'append' || | |
1572 | $mode eq 'rwcreate' || | |
1573 | $mode eq 'rwclobber' || | |
1574 | $mode eq 'rwappend' | |
1575 | ) { | |
1576 | # Check whether or not we have permission to open and perform writes | |
1577 | # on this file. | |
1578 | ||
1579 | if (-e $openarg) { | |
1580 | return $this->_throw( | |
1581 | 'cant fwrite', | |
1582 | { | |
1583 | 'filename' => $openarg, | |
1584 | 'dirname' => $path, | |
1585 | 'opts' => $opts, | |
1586 | } | |
1587 | ) unless (-w $openarg); | |
1588 | } | |
1589 | else { | |
1590 | # If file doesn't exist and the path isn't writable, the error is | |
1591 | # one of unallowed creation. | |
1592 | return $this->_throw( | |
1593 | 'cant fcreate', | |
1594 | { | |
1595 | 'filename' => $openarg, | |
1596 | 'dirname' => $path, | |
1597 | 'opts' => $opts, | |
1598 | } | |
1599 | ) unless (-w $path . SL); | |
1600 | } | |
1601 | } | |
1602 | elsif ($mode eq 'read' || $mode eq 'rwupdate') { | |
1603 | # Check whether or not we have permission to open and perform reads | |
1604 | # on this file, starting with file's housing directory. | |
1605 | return $this->_throw( | |
1606 | 'cant dread', | |
1607 | { | |
1608 | 'filename' => $path . SL . $filename, | |
1609 | 'dirname' => $path, | |
1610 | 'opts' => $opts, | |
1611 | } | |
1612 | ) unless (-r $path . SL); | |
1613 | ||
1614 | # Seems obvious, but we can't read non-existent files | |
1615 | return $this->_throw( | |
1616 | 'cant fread not found', | |
1617 | { | |
1618 | 'filename' => $path . SL . $filename, | |
1619 | 'dirname' => $path, | |
1620 | 'opts' => $opts, | |
1621 | } | |
1622 | ) unless (-e $path . SL . $filename); | |
1623 | ||
1624 | # Check the readability of the file itself | |
1625 | return $this->_throw( | |
1626 | 'cant fread', | |
1627 | { | |
1628 | 'filename' => $path . SL . $filename, | |
1629 | 'dirname' => $path, | |
1630 | 'opts' => $opts, | |
1631 | } | |
1632 | ) unless (-r $path . SL . $filename); | |
1633 | } | |
1634 | else { | |
1635 | return $this->_throw( | |
1636 | 'no input', | |
1637 | { | |
1638 | 'meth' => 'open_handle', | |
1639 | 'missing' => q{a valid IO mode. (eg- 'read', 'write'...)}, | |
1640 | 'opts' => $opts, | |
1641 | } | |
1642 | ) | |
1643 | } | |
1644 | # input validation sequence finished | |
1645 | ||
1646 | # we need a unique filehandle | |
1647 | do { $fh = int(rand(time)) . $$; $fh = eval('*' . 'OPEN_TO_FH' . $fh) } | |
1648 | while ( fileno($fh) ); | |
1649 | ||
1650 | # if you use the '--no-lock' option you are probably inefficient | |
1651 | if ($$opts{'--no-lock'} || !$USE_FLOCK) { | |
1652 | if ( | |
1653 | !exists($opts->{'--use-sysopen'}) && | |
1654 | !defined($opts->{'--use-sysopen'}) | |
1655 | ) { # perl open | |
1656 | # get open mode | |
1657 | $mode = $$MODES{'popen'}{ $mode }; | |
1658 | ||
1659 | open($fh, $mode . $openarg) or | |
1660 | return $this->_throw( | |
1661 | 'bad open', | |
1662 | { | |
1663 | 'filename' => $openarg, | |
1664 | 'mode' => $mode, | |
1665 | 'exception' => $!, | |
1666 | 'cmd' => $mode . $openarg, | |
1667 | 'opts' => $opts, | |
1668 | } | |
1669 | ); | |
1670 | } | |
1671 | else { # sysopen | |
1672 | # get open mode | |
1673 | $mode = $$MODES{'sysopen'}{ $mode }; | |
1674 | ||
1675 | sysopen($fh, $openarg, eval($$MODES{'sysopen'}{ $mode })) or | |
1676 | return $this->_throw( | |
1677 | 'bad open', | |
1678 | { | |
1679 | 'filename' => $openarg, | |
1680 | 'mode' => $mode, | |
1681 | 'exception' => $!, | |
1682 | 'cmd' => qq{$openarg, $$MODES{'sysopen'}{ $mode }}, | |
1683 | 'opts' => $opts, | |
1684 | } | |
1685 | ); | |
1686 | } | |
1687 | } | |
1688 | else { | |
1689 | if ( | |
1690 | !exists($opts->{'--use-sysopen'}) && | |
1691 | !defined($opts->{'--use-sysopen'}) | |
1692 | ) { # perl open | |
1693 | # open read-only first to safely check if we can get a lock. | |
1694 | if (-e $openarg) { | |
1695 | ||
1696 | open($fh, '<' . $openarg) or | |
1697 | return $this->_throw( | |
1698 | 'bad open', | |
1699 | { | |
1700 | 'filename' => $openarg, | |
1701 | 'mode' => 'read', | |
1702 | 'exception' => $!, | |
1703 | 'cmd' => $mode . $openarg, | |
1704 | 'opts' => $opts, | |
1705 | } | |
1706 | ); | |
1707 | ||
1708 | # lock file before I/O on platforms that support it | |
1709 | my($lockstat) = $this->_seize($openarg, $fh); | |
1710 | ||
1711 | return($lockstat) unless $lockstat; | |
1712 | ||
1713 | if ($mode ne 'read') { | |
1714 | open($fh, $$MODES{'popen'}{ $mode } . $openarg) or | |
1715 | return $this->_throw( | |
1716 | 'bad open', | |
1717 | { | |
1718 | 'exception' => $!, | |
1719 | 'filename' => $openarg, | |
1720 | 'mode' => $mode, | |
1721 | 'opts' => $opts, | |
1722 | 'cmd' => $$MODES{'popen'}{ $mode } . $openarg, | |
1723 | } | |
1724 | ); | |
1725 | } | |
1726 | } | |
1727 | else { | |
1728 | open($fh, $$MODES{'popen'}{ $mode } . $openarg) or | |
1729 | return $this->_throw( | |
1730 | 'bad open', | |
1731 | { | |
1732 | 'exception' => $!, | |
1733 | 'filename' => $openarg, | |
1734 | 'mode' => $mode, | |
1735 | 'opts' => $opts, | |
1736 | 'cmd' => $$MODES{'popen'}{ $mode } . $openarg, | |
1737 | } | |
1738 | ); | |
1739 | ||
1740 | # lock file before I/O on platforms that support it | |
1741 | my($lockstat) = $this->_seize($openarg, $fh); | |
1742 | ||
1743 | return($lockstat) unless $lockstat; | |
1744 | } | |
1745 | } | |
1746 | else { # sysopen | |
1747 | # open read-only first to safely check if we can get a lock. | |
1748 | if (-e $openarg) { | |
1749 | ||
1750 | open($fh, '<' . $openarg) or | |
1751 | return $this->_throw( | |
1752 | 'bad open', | |
1753 | { | |
1754 | 'filename' => $openarg, | |
1755 | 'mode' => 'read', | |
1756 | 'exception' => $!, | |
1757 | 'cmd' => $mode . $openarg, | |
1758 | 'opts' => $opts, | |
1759 | } | |
1760 | ); | |
1761 | ||
1762 | # lock file before I/O on platforms that support it | |
1763 | my($lockstat) = $this->_seize($openarg, $fh); | |
1764 | ||
1765 | return($lockstat) unless $lockstat; | |
1766 | ||
1767 | sysopen($fh, $openarg, eval($$MODES{'sysopen'}{ $mode })) | |
1768 | or return $this->_throw( | |
1769 | 'bad open', | |
1770 | { | |
1771 | 'filename' => $openarg, | |
1772 | 'mode' => $mode, | |
1773 | 'opts' => $opts, | |
1774 | 'exception' => $!, | |
1775 | 'cmd' => qq{$openarg, $$MODES{'sysopen'}{ $mode }}, | |
1776 | } | |
1777 | ); | |
1778 | } | |
1779 | else { # only non-existent files get bitmask arguments | |
1780 | sysopen( | |
1781 | $fh, | |
1782 | $openarg, | |
1783 | eval($$MODES{'sysopen'}{ $mode }), | |
1784 | $bitmask | |
1785 | ) or return $this->_throw( | |
1786 | 'bad open', | |
1787 | { | |
1788 | 'filename' => $openarg, | |
1789 | 'mode' => $mode, | |
1790 | 'opts' => $opts, | |
1791 | 'exception' => $!, | |
1792 | 'cmd' => qq{$openarg, $$MODES{'sysopen'}{$mode}, $bitmask}, | |
1793 | } | |
1794 | ); | |
1795 | ||
1796 | # lock file before I/O on platforms that support it | |
1797 | my($lockstat) = $this->_seize($openarg, $fh); | |
1798 | ||
1799 | return($lockstat) unless $lockstat; | |
1800 | } | |
1801 | } | |
1802 | } | |
1803 | ||
1804 | # call binmode on the filehandle if it was requested | |
1805 | CORE::binmode($fh) if $in->{'binmode'} || $opts->{'--binmode'}; | |
1806 | ||
1807 | # return file handle reference to the caller | |
1808 | $fh; | |
1809 | } | |
1810 | ||
1811 | ||
1812 | # -------------------------------------------------------- | |
1813 | # File::Util::unlock_open_handle() | |
1814 | # -------------------------------------------------------- | |
1815 | sub unlock_open_handle { | |
1816 | my($this,$fh) = @_; | |
1817 | ||
1818 | return 1 if !$USE_FLOCK; | |
1819 | ||
1820 | return($this->_throw('not a filehandle.', {'argtype' => ref(\$fh||'')})) | |
1821 | unless ($fh && ref(\$fh||'') eq 'GLOB'); | |
1822 | ||
1823 | if ($CAN_FLOCK) { return flock($fh, &Fcntl::LOCK_UN) } 1; | |
1824 | } | |
1825 | ||
1826 | ||
1827 | # -------------------------------------------------------- | |
1828 | # File::Util::return_path() | |
1829 | # -------------------------------------------------------- | |
1830 | sub return_path { my($f) = myargs(@_); $f =~ s/(^.*)$DIRSPLIT.*/$1/o; $f } | |
1831 | ||
1832 | ||
1833 | # -------------------------------------------------------- | |
1834 | # File::Util::size() | |
1835 | # -------------------------------------------------------- | |
1836 | sub size { my($f) = myargs(@_); $f ||= ''; return undef unless -e $f; -s $f } | |
1837 | ||
1838 | ||
1839 | # -------------------------------------------------------- | |
1840 | # File::Util::trunc() | |
1841 | # -------------------------------------------------------- | |
1842 | sub trunc { $_[0]->write_file('mode' => 'trunc', 'file' => $_[1]) } | |
1843 | ||
1844 | ||
1845 | # -------------------------------------------------------- | |
1846 | # File::Util::use_flock() | |
1847 | # -------------------------------------------------------- | |
1848 | sub use_flock { | |
1849 | my($arg) = myargs(@_); | |
1850 | ||
1851 | if (defined($arg)) { $USE_FLOCK = $arg } | |
1852 | ||
1853 | $USE_FLOCK | |
1854 | } | |
1855 | ||
1856 | ||
1857 | # -------------------------------------------------------- | |
1858 | # File::Util::_throw | |
1859 | # -------------------------------------------------------- | |
1860 | sub _throw { | |
1861 | my($this) = shift(@_); my($opts) = $this->shave_opts(\@_); | |
1862 | my(%fatal_rules) = (); | |
1863 | ||
1864 | # fatalality-handling rules passed to the failing caller trump the | |
1865 | # rules set up in the attributes of the object; the mechanism below | |
1866 | # also allows for the implicit handling of '--fatals-are-fatal' | |
1867 | map { $fatal_rules{ $_ } = $_ } | |
1868 | grep(/^--fatals/o, values %$opts); | |
1869 | ||
1870 | unless (scalar keys %fatal_rules) { | |
1871 | map { $fatal_rules{ $_ } = $_ } | |
1872 | grep(/^--fatals/o, keys %{ $this->{'opts'} }) | |
1873 | } | |
1874 | ||
1875 | return(0) if $fatal_rules{'--fatals-as-status'}; | |
1876 | ||
1877 | $this->{'expt'}||={}; | |
1878 | ||
1879 | unless (UNIVERSAL::isa($this->{'expt'},'Exception::Handler')) { | |
1880 | require Exception::Handler; | |
1881 | $this->{'expt'} = Exception::Handler->new(); | |
1882 | } | |
1883 | ||
1884 | my($error) = ''; my($in) = {}; | |
1885 | ||
1886 | if (@_ == 1) { | |
1887 | ||
1888 | if (defined($_[0])) { $error = 'plain error'; goto PLAIN_ERRORS } | |
1889 | } | |
1890 | else { $error = shift(@_) || 'empty error' } | |
1891 | ||
1892 | $in = shift(@_)||{}; $in->{'_pak'} = __PACKAGE__; | |
1893 | ||
1894 | map { $_ = defined($_) ? $_ : 'undefined value' } keys(%$in); | |
1895 | ||
1896 | PLAIN_ERRORS: | |
1897 | ||
1898 | my($bad_news) = | |
1899 | CORE::eval | |
1900 | ( | |
1901 | q{<<__ERRORBLOCK__} | |
1902 | . &NL . &_errors($error) | |
1903 | . &NL . q{__ERRORBLOCK__} | |
1904 | ); | |
1905 | ||
1906 | ## for debugging only | |
1907 | # if ($@) { return $this->{'expt'}->trace($@) } | |
1908 | ||
1909 | if ($fatal_rules{'--fatals-as-warning'}) { | |
1910 | ||
1911 | warn($this->{'expt'}->trace(($@ || $bad_news))) and return | |
1912 | } | |
1913 | elsif ( $fatal_rules{'--fatals-as-errmsg'} || $opts->{'--return'}) { | |
1914 | ||
1915 | return($this->{'expt'}->trace(($@ || $bad_news))) | |
1916 | } | |
1917 | ||
1918 | foreach (keys(%{$in})) { | |
1919 | ||
1920 | next if ($_ eq 'opts'); | |
1921 | ||
1922 | $bad_news .= qq[ARG $_ = $in->{$_}] . $NL; | |
1923 | } | |
1924 | ||
1925 | if ($in->{'opts'}) { | |
1926 | ||
1927 | foreach (keys(%{$$in{'opts'}})) { | |
1928 | ||
1929 | $_ = (defined($_)) ? $_ : 'empty value'; | |
1930 | ||
1931 | $bad_news .= qq[OPT $_] . $NL; | |
1932 | } | |
1933 | } | |
1934 | ||
1935 | warn($this->{'expt'}->trace(($@ || $bad_news))) if ($opts->{'--warn-also'}); | |
1936 | ||
1937 | $this->{'expt'}->fail(($@ || $bad_news)); | |
1938 | ||
1939 | ''; | |
1940 | } | |
1941 | ||
1942 | ||
1943 | #%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%# | |
1944 | # ERROR MESSAGES | |
1945 | #%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%# | |
1946 | sub _errors { | |
1947 | use vars qw($EBL $EBR); | |
1948 | ($EBL,$EBR) = (chr(187), chr(171)); | |
1949 | ($EBL,$EBR) = ('{','}') if ($OS eq 'DOS'); | |
1950 | my($error_thrown) = shift(@_); | |
1951 | ||
1952 | # begin long table of helpful diag error messages | |
1953 | my(%error_msg_table) = ( | |
1954 | # NO SUCH FILE | |
1955 | 'no such file' => <<'__bad_open__', | |
1956 | $in->{'_pak'} can't open | |
1957 | $EBL$in->{'filename'}$EBR | |
1958 | because no such file or directory exists. | |
1959 | ||
1960 | Origin: This is *most likely* due to human error. | |
1961 | Solution: Cannot diagnose. A human must investigate the problem. | |
1962 | __bad_open__ | |
1963 | ||
1964 | ||
1965 | # BAD FLOCK RULE POLICY | |
1966 | 'bad flock rules' => <<'__bad_lockrules__', | |
1967 | Invalid file locking policy can not be implemented. $in->{'_pak'}::flock_rules | |
1968 | does not accept one or more of the policy keywords passed to this method. | |
1969 | ||
1970 | Invalid Policy specified: $EBL@{[ | |
1971 | join ' ', map { '[undef]' unless defined $_ } @{ $in->{'all'} } ]}$EBR | |
1972 | ||
1973 | flock_rules policy in effect before invalid policy failed: | |
1974 | $EBL@ONLOCKFAIL$EBR | |
1975 | ||
1976 | Proper flock_rules policy includes one or more of the following recognized | |
1977 | keywords specified in order of precedence: | |
1978 | BLOCK waits to try getting an exclusive lock | |
1979 | FAIL dies with stack trace | |
1980 | WARN warn()s about the error with a stack trace | |
1981 | IGNORE ignores the failure to get an exclusive lock | |
1982 | UNDEF returns undef | |
1983 | ZERO returns 0 | |
1984 | ||
1985 | Origin: This is a human error. | |
1986 | Solution: A human must fix the programming flaw. | |
1987 | __bad_lockrules__ | |
1988 | ||
1989 | ||
1990 | # CAN'T READ FILE - PERMISSIONS | |
1991 | 'cant fread' => <<'__cant_read__', | |
1992 | Permissions conflict. $in->{'_pak'} can't read the contents of this file: | |
1993 | $EBL$in->{'filename'}$EBR | |
1994 | ||
1995 | Due to insufficient permissions, the system has denied Perl the right to | |
1996 | view the contents of this file. It has a bitmask of: (octal number) | |
1997 | $EBL@{[ sprintf('%04o',(stat($in->{'filename'}))[2] & 0777) ]}$EBR | |
1998 | ||
1999 | The directory housing it has a bitmask of: (octal number) | |
2000 | $EBL@{[ sprintf('%04o',(stat($in->{'dirname'}))[2] & 0777) ]}$EBR | |
2001 | ||
2002 | Current flock_rules policy: | |
2003 | $EBL@ONLOCKFAIL$EBR | |
2004 | ||
2005 | Origin: This is *most likely* due to human error. External system errors | |
2006 | can occur however, but this doesn't have to do with $in->{'_pak'}. | |
2007 | Solution: A human must fix the conflict by adjusting the file permissions | |
2008 | of directories where a program asks $in->{'_pak'} to perform I/O. | |
2009 | Try using Perl's chmod command, or the native system chmod() | |
2010 | command from a shell. | |
2011 | __cant_read__ | |
2012 | ||
2013 | ||
2014 | # CAN'T READ FILE - NOT EXISTENT | |
2015 | 'cant fread not found' => <<'__cant_read__', | |
2016 | File not found. $in->{'_pak'} can't read the contents of this file: | |
2017 | $EBL$in->{'filename'}$EBR | |
2018 | ||
2019 | The file specified does not exist. It can not be opened or read from. | |
2020 | ||
2021 | Origin: This is *most likely* due to human error. External system errors | |
2022 | can occur however, but this doesn't have to do with $in->{'_pak'}. | |
2023 | Solution: A human must investigate why the application tried to open a | |
2024 | non-existent file, and/or why the file is expected to exist and | |
2025 | is not found. | |
2026 | __cant_read__ | |
2027 | ||
2028 | ||
2029 | # CAN'T CREATE FILE - PERMISSIONS | |
2030 | 'cant fcreate' => <<'__cant_write__', | |
2031 | Permissions conflict. $in->{'_pak'} can't create this file: | |
2032 | $EBL$in->{'filename'}$EBR | |
2033 | ||
2034 | $in->{'_pak'} can't create this file because the system has denied Perl | |
2035 | the right to create files in the parent directory. | |
2036 | ||
2037 | The -e test returns $EBL@{[-e $in->{'dirname'} ]}$EBR for the directory. | |
2038 | The -r test returns $EBL@{[-r $in->{'dirname'} ]}$EBR for the directory. | |
2039 | The -R test returns $EBL@{[-R $in->{'dirname'} ]}$EBR for the directory. | |
2040 | The -w test returns $EBL@{[-w $in->{'dirname'} ]}$EBR for the directory | |
2041 | The -W test returns $EBL@{[-w $in->{'dirname'} ]}$EBR for the directory | |
2042 | ||
2043 | Parent directory: (path may be relative and/or redundant) | |
2044 | $EBL$in->{'dirname'}$EBR | |
2045 | ||
2046 | Parent directory has a bitmask of: (octal number) | |
2047 | $EBL@{[ sprintf('%04o',(stat($in->{'dirname'}))[2] & 0777) ]}$EBR | |
2048 | ||
2049 | Current flock_rules policy: | |
2050 | $EBL@ONLOCKFAIL$EBR | |
2051 | ||
2052 | Origin: This is *most likely* due to human error. External system errors | |
2053 | can occur however, but this doesn't have to do with $in->{'_pak'}. | |
2054 | Solution: A human must fix the conflict by adjusting the file permissions | |
2055 | of directories where a program asks $in->{'_pak'} to perform I/O. | |
2056 | Try using Perl's chmod command, or the native system chmod() | |
2057 | command from a shell. | |
2058 | __cant_write__ | |
2059 | ||
2060 | ||
2061 | # CAN'T WRITE TO FILE - EXISTS AS DIRECTORY | |
2062 | 'cant write_file on a dir' => <<'__bad_writefile__', | |
2063 | $in->{'_pak'} can't write to the specified file because it already exists | |
2064 | as a directory. | |
2065 | $EBL$in->{'filename'}$EBR | |
2066 | ||
2067 | Origin: This is a human error. | |
2068 | Solution: Resolve naming issue between the existent directory and the file | |
2069 | you wish to create/write/append. | |
2070 | __bad_writefile__ | |
2071 | ||
2072 | ||
2073 | # CAN'T TOUCH A FILE - EXISTS AS DIRECTORY | |
2074 | 'cant touch on a dir' => <<'__bad_touchfile__', | |
2075 | $in->{'_pak'} can't touch the specified file because it already exists | |
2076 | as a directory. | |
2077 | $EBL$in->{'filename'}$EBR | |
2078 | ||
2079 | Origin: This is a human error. | |
2080 | Solution: Resolve naming issue between the existent directory and the file | |
2081 | you wish to touch. | |
2082 | __bad_touchfile__ | |
2083 | ||
2084 | ||
2085 | # CAN'T WRITE TO FILE | |
2086 | 'cant fwrite' => <<'__cant_write__', | |
2087 | Permissions conflict. $in->{'_pak'} can't write to this file: | |
2088 | $EBL$in->{'filename'}$EBR | |
2089 | ||
2090 | Due to insufficient permissions, the system has denied Perl the right | |
2091 | to modify the contents of this file. It has a bitmask of: (octal number) | |
2092 | $EBL@{[ sprintf('%04o',(stat($in->{'filename'}))[2] & 0777) ]}$EBR | |
2093 | ||
2094 | Parent directory has a bitmask of: (octal number) | |
2095 | $EBL@{[ sprintf('%04o',(stat($in->{'dirname'}))[2] & 0777) ]}$EBR | |
2096 | ||
2097 | Current flock_rules policy: | |
2098 | $EBL@ONLOCKFAIL$EBR | |
2099 | ||
2100 | Origin: This is *most likely* due to human error. External system errors | |
2101 | can occur however, but this doesn't have to do with $in->{'_pak'}. | |
2102 | Solution: A human must fix the conflict by adjusting the file permissions | |
2103 | of directories where a program asks $in->{'_pak'} to perform I/O. | |
2104 | Try using Perl's chmod command, or the native system chmod() | |
2105 | command from a shell. | |
2106 | __cant_write__ | |
2107 | ||
2108 | ||
2109 | # BAD OPEN MODE - PERL | |
2110 | 'bad openmode popen' => <<'__bad_openmode__', | |
2111 | Illegal mode specified for file open. $in->{'_pak'} can't open this file: | |
2112 | $EBL$in->{'filename'}$EBR | |
2113 | ||
2114 | When calling $in->{'_pak'}::$in->{'meth'}() you specified that the file | |
2115 | opened in this I/O operation should be opened in $EBL$in->{'badmode'}$EBR | |
2116 | but that is not a recognized open mode. | |
2117 | ||
2118 | Supported open modes for $in->{'_pak'}::write_file() are: | |
2119 | write - open the file in write mode, creating it if necessary, and | |
2120 | overwriting any existing contents of the file. | |
2121 | append - open the file in append mode | |
2122 | ||
2123 | Supported open modes for $in->{'_pak'}::open_handle() are the same as above, but | |
2124 | also include the following: | |
2125 | read - open the file in read-only mode | |
2126 | ||
2127 | (and if the --use-sysopen flag is used): | |
2128 | rwcreate - open the file for update (read+write), creating it if necessary | |
2129 | rwupdate - open the file for update (read+write). Causes fatal error if | |
2130 | the file doesn't yet exist | |
2131 | rwappend - open the file for update in append mode | |
2132 | rwclobber - open the file for update, erasing all contents (truncating, | |
2133 | i.e- "clobbering" the file first) | |
2134 | ||
2135 | Origin: This is a human error. | |
2136 | Solution: A human must fix the programming flaw by specifying the desired | |
2137 | open mode from the list above. | |
2138 | __bad_openmode__ | |
2139 | ||
2140 | ||
2141 | # BAD OPEN MODE - SYSOPEN | |
2142 | 'bad openmode sysopen' => <<'__bad_openmode__', | |
2143 | Illegal mode specified for file sysopen. $in->{'_pak'} can't sysopen this file: | |
2144 | $EBL$in->{'filename'}$EBR | |
2145 | ||
2146 | When calling $in->{'_pak'}::$in->{'meth'}() you specified that the file | |
2147 | opened in this I/O operation should be sysopen()'d in $EBL$in->{'badmode'}$EBR | |
2148 | but that is not a recognized open mode. | |
2149 | ||
2150 | Supported open modes for $in->{'_pak'}::write_file() are: | |
2151 | write - open the file in write mode, creating it if necessary, and | |
2152 | overwriting any existing contents of the file. | |
2153 | append - open the file in append mode | |
2154 | ||
2155 | Supported open modes for $in->{'_pak'}::open_handle() are the same as above, but | |
2156 | also include the following: | |
2157 | read - open the file in read-only mode | |
2158 | ||
2159 | (and if the --use-sysopen flag is used, as the application JUST did): | |
2160 | rwcreate - open the file for update (read+write), creating it if necessary | |
2161 | rwupdate - open the file for update (read+write). Causes fatal error if | |
2162 | the file doesn't yet exist | |
2163 | rwappend - open the file for update in append mode | |
2164 | rwclobber - open the file for update, erasing all contents (truncating, | |
2165 | i.e- "clobbering" the file first) | |
2166 | ||
2167 | Origin: This is a human error. | |
2168 | Solution: A human must fix the programming flaw by specifying the desired | |
2169 | sysopen mode from the list above. | |
2170 | __bad_openmode__ | |
2171 | ||
2172 | ||
2173 | # CAN'T LIST DIRECTORY | |
2174 | 'cant dread' => <<'__cant_read__', | |
2175 | Permissions conflict. $in->{'_pak'} can't list the contents of this directory: | |
2176 | $EBL$in->{'dirname'}$EBR | |
2177 | ||
2178 | Due to insufficient permissions, the system has denied Perl the right to | |
2179 | view the contents of this directory. It has a bitmask of: (octal number) | |
2180 | $EBL@{[ sprintf('%04o',(stat($in->{'dirname'}))[2] & 0777) ]}$EBR | |
2181 | ||
2182 | Origin: This is *most likely* due to human error. External system errors | |
2183 | can occur however, but this doesn't have to do with $in->{'_pak'}. | |
2184 | Solution: A human must fix the conflict by adjusting the file permissions | |
2185 | of directories where a program asks $in->{'_pak'} to perform I/O. | |
2186 | Try using Perl's chmod command, or the native system chmod() | |
2187 | command from a shell. | |
2188 | __cant_read__ | |
2189 | ||
2190 | ||
2191 | # CAN'T CREATE DIRECTORY - PERMISSIONS | |
2192 | 'cant dcreate' => <<'__cant_dcreate__', | |
2193 | Permissions conflict. $in->{'_pak'} can't create: | |
2194 | $EBL$in->{'dirname'}$EBR | |
2195 | ||
2196 | $in->{'_pak'} can't create this directory because the system has denied | |
2197 | Perl the right to create files in the parent directory. | |
2198 | ||
2199 | Parent directory: (path may be relative and/or redundant) | |
2200 | $EBL$in->{'parentd'}$EBR | |
2201 | ||
2202 | Parent directory has a bitmask of: (octal number) | |
2203 | $EBL@{[ sprintf('%04o',(stat($in->{'parentd'}))[2] & 0777) ]}$EBR | |
2204 | ||
2205 | Origin: This is *most likely* due to human error. External system errors | |
2206 | can occur however, but this doesn't have to do with $in->{'_pak'}. | |
2207 | Solution: A human must fix the conflict by adjusting the file permissions | |
2208 | of directories where a program asks $in->{'_pak'} to perform I/O. | |
2209 | Try using Perl's chmod command, or the native system chmod() | |
2210 | command from a shell. | |
2211 | __cant_dcreate__ | |
2212 | ||
2213 | ||
2214 | # CAN'T CREATE DIRECTORY - TARGET EXISTS | |
2215 | 'make_dir target exists' => <<'__cant_dcreate__', | |
2216 | make_dir target already exists. | |
2217 | $EBL$in->{'dirname'}$EBR | |
2218 | ||
2219 | $in->{'_pak'} can't create the directory you specified because that | |
2220 | directory already exists, with filetype attributes of | |
2221 | @{[join(', ', @{ $in->{'filetype'} })]} and permissions | |
2222 | set to $EBL@{[ sprintf('%04o',(stat($in->{'dirname'}))[2] & 0777) ]}$EBR | |
2223 | ||
2224 | Origin: This is *most likely* due to human error. The program has tried | |
2225 | to make a directory where a directory already exists. | |
2226 | Solution: Weaken the requirement somewhat by using the "--if-not-exists" | |
2227 | flag when calling the make_dir object method. This option | |
2228 | will cause $in->{'_pak'} to ignore attempts to create directories | |
2229 | that already exist, while still creating the ones that don't. | |
2230 | __cant_dcreate__ | |
2231 | ||
2232 | ||
2233 | # CAN'T OPEN | |
2234 | 'bad open' => <<'__bad_open__', | |
2235 | $in->{'_pak'} can't open this file for $EBL$in->{'mode'}$EBR: | |
2236 | $EBL$in->{'filename'}$EBR | |
2237 | ||
2238 | The system returned this error: | |
2239 | $EBL$in->{'exception'}$EBR | |
2240 | ||
2241 | $in->{'_pak'} used this directive in its attempt to open the file | |
2242 | $EBL$in->{'cmd'}$EBR | |
2243 | ||
2244 | Current flock_rules policy: | |
2245 | $EBL@ONLOCKFAIL$EBR | |
2246 | ||
2247 | Origin: This is *most likely* due to human error. | |
2248 | Solution: Cannot diagnose. A Human must investigate the problem. | |
2249 | __bad_open__ | |
2250 | ||
2251 | ||
2252 | # BAD CLOSE | |
2253 | 'bad close' => <<'__bad_close__', | |
2254 | $in->{'_pak'} couldn't close this file after $EBL$in->{'mode'}$EBR | |
2255 | $EBL$in->{'filename'}$EBR | |
2256 | ||
2257 | The system returned this error: | |
2258 | $EBL$in->{'exception'}$EBR | |
2259 | ||
2260 | Current flock_rules policy: | |
2261 | $EBL@ONLOCKFAIL$EBR | |
2262 | ||
2263 | Origin: Could be either human _or_ system error. | |
2264 | Solution: Cannot diagnose. A Human must investigate the problem. | |
2265 | __bad_close__ | |
2266 | ||
2267 | ||
2268 | # CAN'T TRUNCATE | |
2269 | 'bad systrunc' => <<'__bad_systrunc__', | |
2270 | $in->{'_pak'} couldn't truncate() on $EBL$in->{'filename'}$EBR after having | |
2271 | successfully opened the file in write mode. | |
2272 | ||
2273 | The system returned this error: | |
2274 | $EBL$in->{'exception'}$EBR | |
2275 | ||
2276 | Current flock_rules policy: | |
2277 | $EBL@ONLOCKFAIL$EBR | |
2278 | ||
2279 | This is most likely _not_ a human error, but has to do with your system's | |
2280 | support for the C truncate() function. | |
2281 | __bad_systrunc__ | |
2282 | ||
2283 | ||
2284 | # CAN'T GET FLOCK AFTER BLOCKING | |
2285 | 'bad flock' => <<'__bad_lock__', | |
2286 | $in->{'_pak'} can't get a lock on the file | |
2287 | $EBL$in->{'filename'}$EBR | |
2288 | ||
2289 | The system returned this error: | |
2290 | $EBL$in->{'exception'}$EBR | |
2291 | ||
2292 | Current flock_rules policy: | |
2293 | $EBL@ONLOCKFAIL$EBR | |
2294 | ||
2295 | Origin: Could be either human _or_ system error. | |
2296 | Solution: Investigate the reason why you can't get a lock on the file, | |
2297 | it is usually because of improper programming which causes | |
2298 | race conditions on one or more files. | |
2299 | __bad_lock__ | |
2300 | ||
2301 | ||
2302 | # CAN'T OPEN ON A DIRECTORY | |
2303 | 'called open on a dir' => <<'__bad_open__', | |
2304 | $in->{'_pak'} can't call open() on this file because it is a directory | |
2305 | $EBL$in->{'filename'}$EBR | |
2306 | ||
2307 | Origin: This is a human error. | |
2308 | Solution: Use $in->{'_pak'}::load_file() to load the contents of a file | |
2309 | Use $in->{'_pak'}::list_dir() to list the contents of a directory | |
2310 | __bad_open__ | |
2311 | ||
2312 | ||
2313 | # CAN'T OPENDIR ON A FILE | |
2314 | 'called opendir on a file' => <<'__bad_open__', | |
2315 | $in->{'_pak'} can't opendir() on this file because it is not a directory. | |
2316 | $EBL$in->{'filename'}$EBR | |
2317 | ||
2318 | Use $in->{'_pak'}::load_file() to load the contents of a file | |
2319 | Use $in->{'_pak'}::list_dir() to list the contents of a directory | |
2320 | ||
2321 | Origin: This is a human error. | |
2322 | Solution: Use $in->{'_pak'}::load_file() to load the contents of a file | |
2323 | Use $in->{'_pak'}::list_dir() to list the contents of a directory | |
2324 | __bad_open__ | |
2325 | ||
2326 | ||
2327 | # CAN'T MKDIR ON A FILE | |
2328 | 'called mkdir on a file' => <<'__bad_open__', | |
2329 | $in->{'_pak'} can't auto-create a directory for this path name because it | |
2330 | already exists as a file. | |
2331 | $EBL$in->{'filename'}$EBR | |
2332 | ||
2333 | Origin: This is a human error. | |
2334 | Solution: Resolve naming issue between the existent file and the directory | |
2335 | you wish to create. | |
2336 | __bad_open__ | |
2337 | ||
2338 | ||
2339 | # BAD CALL TO File::Util::readlimit | |
2340 | 'bad readlimit' => <<'__maxdives__', | |
2341 | Bad call to $in->{'_pak'}::readlimit(). This method can only be called with | |
2342 | a numeric value (bytes). Non-integer numbers will be converted to integer | |
2343 | format if specified (numbers like 5.2), but don't do that, it's inefficient. | |
2344 | ||
2345 | This operation aborted. | |
2346 | ||
2347 | Origin: This is a human error. | |
2348 | Solution: A human must fix the programming flaw. | |
2349 | __maxdives__ | |
2350 | ||
2351 | ||
2352 | # EXCEEDED READLIMIT | |
2353 | 'readlimit exceeded' => <<'__readlimit__', | |
2354 | $in->{'_pak'} can't load file: $EBL$in->{'filename'}$EBR | |
2355 | into memory because its size exceeds the maximum file size allowed | |
2356 | for a read. | |
2357 | ||
2358 | The size of this file is $EBL$in->{'size'}$EBR bytes. | |
2359 | ||
2360 | Currently the read limit is set at $EBL$READLIMIT$EBR bytes. | |
2361 | ||
2362 | Origin: This is a human error. | |
2363 | Solution: Consider setting the limit to a higher number of bytes. | |
2364 | __readlimit__ | |
2365 | ||
2366 | ||
2367 | # BAD CALL TO File::Util::max_dives | |
2368 | 'bad maxdives' => <<'__maxdives__', | |
2369 | Bad call to $in->{'_pak'}::max_dives(). This method can only be called with | |
2370 | a numeric value (bytes). Non-integer numbers will be converted to integer | |
2371 | format if specified (numbers like 5.2), but don't do that, it's inefficient. | |
2372 | ||
2373 | This operation aborted. | |
2374 | ||
2375 | Origin: This is a human error. | |
2376 | Solution: A human must fix the programming flaw. | |
2377 | __maxdives__ | |
2378 | ||
2379 | ||
2380 | # EXCEEDED MAXDIVES | |
2381 | 'maxdives exceeded' => <<'__maxdives__', | |
2382 | Recursion limit reached at $EBL${\ scalar( | |
2383 | (exists $in->{'maxdives'} && defined $in->{'maxdives'}) ? | |
2384 | $in->{'maxdives'} : $MAXDIVES) }$EBR dives. Maximum number of subdirectory dives is set to the value returned by | |
2385 | $in->{'_pak'}::max_dives(). Try manually setting the value to a higher number | |
2386 | before calling list_dir() with option --follow or --recurse (synonymous). Do | |
2387 | so by calling $in->{'_pak'}::max_dives() with the numeric argument corresponding | |
2388 | to the maximum number of subdirectory dives you want to allow when traversing | |
2389 | directories recursively. | |
2390 | ||
2391 | This operation aborted. | |
2392 | ||
2393 | Origin: This is a human error. | |
2394 | Solution: Consider setting the limit to a higher number. | |
2395 | __maxdives__ | |
2396 | ||
2397 | ||
2398 | # BAD OPENDIR | |
2399 | 'bad opendir' => <<'__bad_opendir__', | |
2400 | $in->{'_pak'} can't opendir on directory: | |
2401 | $EBL$in->{'dirname'}$EBR | |
2402 | ||
2403 | The system returned this error: | |
2404 | $EBL$in->{'exception'}$EBR | |
2405 | ||
2406 | Origin: Could be either human _or_ system error. | |
2407 | Solution: Cannot diagnose. A Human must investigate the problem. | |
2408 | __bad_opendir__ | |
2409 | ||
2410 | ||
2411 | # BAD MAKEDIR | |
2412 | 'bad make_dir' => <<'__bad_make_dir__', | |
2413 | $in->{'_pak'} had a problem with the system while attempting to create the | |
2414 | directory you specified with a bitmask of $EBL$in->{'bitmask'}$EBR | |
2415 | ||
2416 | directory: $EBL$in->{'dirname'}$EBR | |
2417 | ||
2418 | The system returned this error: | |
2419 | $EBL$in->{'exception'}$EBR | |
2420 | ||
2421 | Origin: Could be either human _or_ system error. | |
2422 | Solution: Cannot diagnose. A Human must investigate the problem. | |
2423 | __bad_make_dir__ | |
2424 | ||
2425 | ||
2426 | # BAD CHARS | |
2427 | 'bad chars' => <<'__bad_chars__', | |
2428 | $in->{'_pak'} can't use this string for $EBL$in->{'purpose'}$EBR. | |
2429 | $EBL$in->{'string'}$EBR | |
2430 | It contains illegal characters. | |
2431 | ||
2432 | Illegal characters are: | |
2433 | \\ (backslash) | |
2434 | / (forward slash) | |
2435 | : (colon) | |
2436 | | (pipe) | |
2437 | * (asterisk) | |
2438 | ? (question mark) | |
2439 | " (double quote) | |
2440 | < (less than) | |
2441 | > (greater than) | |
2442 | \\t (tab) | |
2443 | \\ck (vertical tabulator) | |
2444 | \\r (newline CR) | |
2445 | \\n (newline LF) | |
2446 | ||
2447 | Origin: This is a human error. | |
2448 | Solution: A human must remove the illegal characters from this string. | |
2449 | __bad_chars__ | |
2450 | ||
2451 | ||
2452 | # NOT A VALID FILEHANDLE | |
2453 | 'not a filehandle' => <<'__bad_handle__', | |
2454 | $in->{'_pak'} can't unlock file with an invalid file handle reference: | |
2455 | $EBL$in->{'argtype'}$EBR is not a valid filehandle | |
2456 | ||
2457 | Origin: This is most likely a human error, although it is remotely possible | |
2458 | that this message is the result of an internal error in the | |
2459 | $in->{'_pak'} module, but this is not likely if you called | |
2460 | $in->{'_pak'}'s internal ::_release() method directly on your own. | |
2461 | Solution: A human must fix the programming flaw. Alternatively, in the | |
2462 | second listed scenario, the package maintainer must investigate the | |
2463 | problem. Please send a usenet post with this error message in its | |
2464 | entirety to Tommy Butler <tommy\@atrixnet.com>, or to usenet group: | |
2465 | $EBL news://comp.lang.perl.modules $EBR | |
2466 | __bad_handle__ | |
2467 | ||
2468 | ||
2469 | # BAD CALL TO METHOD FOO | |
2470 | 'no input' => <<'__no_input__', | |
2471 | $in->{'_pak'} can't honor your call to $EBL$in->{'_pak'}::$in->{'meth'}()$EBR | |
2472 | because you didn't provide $EBL@{[$in->{'missing'}||'the required input']}$EBR | |
2473 | ||
2474 | Origin: This is a human error. | |
2475 | Solution: A human must fix the programming flaw. | |
2476 | __no_input__ | |
2477 | ||
2478 | ||
2479 | # PLAIN ERROR TYPE | |
2480 | 'plain error' => <<'__plain_error__', | |
2481 | $in->{'_pak'} failed with the following message: | |
2482 | ${\ scalar ($_[0] || ((exists $in->{'error'} && defined $in->{'error'}) ? | |
2483 | $in->{'error'} : '[error unspecified]')) } | |
2484 | __plain_error__ | |
2485 | ||
2486 | ||
2487 | # INVALID ERROR TYPE | |
2488 | 'unknown error message' => <<'__foobar_input__', | |
2489 | $in->{'_pak'} failed with an invalid error-type designation. | |
2490 | ||
2491 | Origin: This is a bug! Please inform Tommy Butler <tommy\@atrixnet.com> | |
2492 | Solution: A human must fix the programming flaw. | |
2493 | __foobar_input__ | |
2494 | ||
2495 | ||
2496 | # EMPTY ERROR TYPE | |
2497 | 'empty error' => <<'__no_input__', | |
2498 | $in->{'_pak'} failed with an empty error-type designation. | |
2499 | ||
2500 | Origin: This is a human error. | |
2501 | Solution: A human must fix the programming flaw. | |
2502 | __no_input__ | |
2503 | ||
2504 | ); # end of error message table | |
2505 | ||
2506 | exists $error_msg_table{ $error_thrown } | |
2507 | ? $error_msg_table{ $error_thrown } | |
2508 | : $error_msg_table{'unknown error message'} | |
2509 | } | |
2510 |
0 | =head1 NAME | |
1 | ||
2 | File::Util - Easy, versatile, portable file handling | |
3 | ||
4 | =head1 DESCRIPTION | |
5 | ||
6 | File::Util provides a comprehensive toolbox of utilities to automate all | |
7 | kinds of common tasks on file / directories. Its purpose is to do so | |
8 | in the most portable manner possible so that users of this module won't | |
9 | have to worry about whether their programs will work on other OSes | |
10 | and machines. | |
11 | ||
12 | =head1 SYNOPSIS | |
13 | ||
14 | use File::Util; | |
15 | my($f) = File::Util->new(); | |
16 | ||
17 | my($content) = $f->load_file('foo.txt'); | |
18 | ||
19 | $content =~ s/this/that/g; | |
20 | ||
21 | $f->write_file( | |
22 | 'file' => 'bar.txt', | |
23 | 'content' => $content, | |
24 | 'bitmask' => 0644 | |
25 | ); | |
26 | ||
27 | $f->write_file( | |
28 | 'file' => 'file.bin', 'content' => $binary_content, '--binmode' | |
29 | ); | |
30 | ||
31 | my(@lines) = $f->load_file('randomquote.txt', '--as-lines'); | |
32 | my($line) = int(rand(scalar @lines)); | |
33 | ||
34 | print $lines[$line]; | |
35 | ||
36 | my(@files) = $f->list_dir('/var/tmp', qw/ --files-only --recurse /); | |
37 | my(@textfiles) = $f->list_dir('/var/tmp', '--pattern=\.txt$'); | |
38 | ||
39 | if ($f->can_write('wibble.log')) { | |
40 | ||
41 | my($HANDLE) = $f->open_handle( | |
42 | 'file' => 'wibble.log', | |
43 | 'mode' => 'append' | |
44 | ); | |
45 | ||
46 | print $HANDLE "Hello World! It's ", scalar localtime; | |
47 | ||
48 | close $HANDLE | |
49 | } | |
50 | ||
51 | my($log_line_count) = $f->line_count('/var/log/httpd/access_log'); | |
52 | ||
53 | print "My file has a bitmask of " . $f->bitmask('my.file'); | |
54 | ||
55 | print "My file is a " . join(', ', $f->file_type('my.file')) . " file." | |
56 | ||
57 | warn 'This file is binary!' if $f->isbin('my.file'); | |
58 | ||
59 | print "My file was last modified on " . | |
60 | scalar localtime($f->last_modified('my.file')); | |
61 | ||
62 | # ...and _lots_ more | |
63 | ||
64 | =head1 INSTALLATION | |
65 | ||
66 | To install this module type the following at the command prompt: | |
67 | ||
68 | perl Makefile.PL | |
69 | make | |
70 | make test | |
71 | make install | |
72 | ||
73 | On windows machines use nmake rather than make; those running cygwin don't have | |
74 | to worry about this. If you don't know what cygwin is, use nmake and check out | |
75 | http://cygwin.com/ after you're done installing this module if you want to | |
76 | find out. | |
77 | ||
78 | =head1 ISA | |
79 | ||
80 | =over | |
81 | ||
82 | =item L<Exporter> | |
83 | ||
84 | =item L<Class::OOorNO> | |
85 | ||
86 | =back | |
87 | ||
88 | =head1 EXPORTED SYMBOLS | |
89 | ||
90 | Exports nothing by default. | |
91 | ||
92 | =head2 EXPORT_OK | |
93 | ||
94 | The following symbols comprise C<@File::Util::EXPORT_OK>), and as such are | |
95 | available for import to your namespace only upon request. | |
96 | ||
97 | C<bitmask> I<(see L<bitmask|/bitmask>)> | |
98 | ||
99 | C<can_flock> I<(see L<can_flock|/can_flock>)> | |
100 | ||
101 | C<can_read> I<(see L<can_read|/can_read>)> | |
102 | ||
103 | C<can_write> I<(see L<can_write|/can_write>)> | |
104 | ||
105 | C<created> I<(see L<created|/created>)> | |
106 | ||
107 | C<ebcdic> I<(see L<ebcdic|/ebcdic>)> | |
108 | ||
109 | C<escape_filename> I<(see L<escape_filename|/escape_filename>)> | |
110 | ||
111 | C<existent> I<(see L<existent|/existent>)> | |
112 | ||
113 | C<file_type> I<(see L<file_type|/file_type>)> | |
114 | ||
115 | C<isbin> I<(see L<isbin|/isbin>)> | |
116 | ||
117 | C<last_access> I<(see L<last_access|/last_access>)> | |
118 | ||
119 | C<last_changed> I<(see L<last_changed|/last_changed>)> | |
120 | ||
121 | C<last_modified> I<(see L<last_modified|/last_modified>)> | |
122 | ||
123 | C<NL> I<(see L<NL|/NL>)> | |
124 | ||
125 | C<needs_binmode> I<(see L<needs_binmode|/needs_binmode>)> | |
126 | ||
127 | C<return_path> I<(see L<return_path|/return_path>)> | |
128 | ||
129 | C<size> I<(see L<size|/size>)> | |
130 | ||
131 | C<SL> I<(see L<SL|/SL>)> | |
132 | ||
133 | C<strip_path> I<(see L<strip_path|/strip_path>)> | |
134 | ||
135 | C<valid_filename> I<(see L<valid_filename|/valid_filename>)> | |
136 | ||
137 | B<Note:> Symbols in C<@L<Class::OOorNO|Class::OOorNO>::EXPORT_OK> are also | |
138 | available for import. | |
139 | ||
140 | =head2 EXPORT_TAGS | |
141 | ||
142 | :all (exports all of @File::Util::EXPORT_OK) | |
143 | ||
144 | =head1 METHODS | |
145 | ||
146 | B<Note:> Some of the methods listed will state that they are autoloaded methods. | |
147 | Autloaded methods are not compiled at runtime as part of your process and only | |
148 | get created if called somewhere in your program. I<(see L<AutoLoader>.)> | |
149 | ||
150 | Methods listed in alphabetical order. | |
151 | ||
152 | =head2 C<bitmask> | |
153 | ||
154 | =over | |
155 | ||
156 | =item I<Syntax:> C<bitmask( [file name] )> | |
157 | ||
158 | Gets the bitmask of the named file, provided the file exists. If the file | |
159 | exists, the bitmask of the named file is returned in four digit octal | |
160 | notation e.g.- C<0644>. Otherwise, returns C<undef> if the file does I<not> | |
161 | exist. This is an autoloaded method. | |
162 | ||
163 | =back | |
164 | ||
165 | =head2 C<can_flock> | |
166 | ||
167 | =over | |
168 | ||
169 | =item I<Syntax:> C<can_flock> | |
170 | ||
171 | Returns 1 if the current system claims to support C<flock()> I<and> if the | |
172 | Perl process can successfully call it. I<(see L<perlfunc/flock>.)> Unless | |
173 | both of these conditions are true a zero value (0) is returned. This is | |
174 | an autoloaded method. This is a constant subroutine. It accepts no arguments | |
175 | and will always return the same value for the system on which it is executed. | |
176 | ||
177 | B<Note:> Perl will try to support or emulate flock whenever it can via | |
178 | available system calls, namely C<flock>; C<lockf>; or with C<fcntl>. | |
179 | ||
180 | =back | |
181 | ||
182 | =head2 C<can_read> | |
183 | ||
184 | =over | |
185 | ||
186 | =item I<Syntax:> C<can_read( [file name] )> | |
187 | ||
188 | Returns 1 if the named file (or directory) is B<readable> by your program | |
189 | according to the applied permissions of the file system on which the file | |
190 | resides. Otherwise a value of undef is returned. | |
191 | ||
192 | This works the same as Perl's built-in C<-r> file test operator, | |
193 | I<(see L<perlfunc/-X>)>, it's just easier for some people to remember. This | |
194 | is an autoloaded method. | |
195 | ||
196 | =back | |
197 | ||
198 | =head2 C<can_write> | |
199 | ||
200 | =over | |
201 | ||
202 | =item I<Syntax:> C<can_write( [file name] )> | |
203 | ||
204 | Returns 1 if the named file (or directory) is B<writable> by your program | |
205 | according to the applied permissions of the file system on which the file | |
206 | resides. Otherwise a value of undef is returned. | |
207 | ||
208 | This works the same as Perl's built-in C<-w> file test operator, | |
209 | I<(see L<perlfunc/-X>)>, it's just easier for some people to remember. This | |
210 | is an autoloaded method. | |
211 | ||
212 | =back | |
213 | ||
214 | =head2 C<created> | |
215 | ||
216 | =over | |
217 | ||
218 | =item I<Syntax:> C<created( [file name] )> | |
219 | ||
220 | Returns the time of creation for the named file in non-leap seconds since | |
221 | whatever your system considers to be the epoch. Suitable for feeding to | |
222 | Perl's built-in functions "gmtime" and "localtime". I<(see L<perlfunc/time>.)> | |
223 | This is an autoloaded method. | |
224 | ||
225 | =back | |
226 | ||
227 | =head2 C<ebcdic> | |
228 | ||
229 | =over | |
230 | ||
231 | =item I<Syntax:> C<ebcdic> | |
232 | ||
233 | Returns 1 if the machine on which the code is running uses EBCDIC, or returns | |
234 | 0 if not. I<(see L<perlebcdic>.)> This is an autoloaded method. This is a | |
235 | constant subroutine. It accepts no arguments and will always return the same | |
236 | value for the system on which it is executed. | |
237 | ||
238 | =back | |
239 | ||
240 | =head2 C<escape_filename> | |
241 | ||
242 | =over | |
243 | ||
244 | =item I<Syntax:> C<escape_filename( [string], [escape char] )> | |
245 | ||
246 | Returns it's argument in an escaped form that is suitable for use as a filename. | |
247 | Illegal characters (i.e.- any type of newline character, tab, vtab, and the | |
248 | following C<< / | * " ? < : > \ >>), are replaced with [escape char] or | |
249 | "B<_>" if no [escape char] is specified. Returns an empty string if no | |
250 | arguments are provided. This is an autoloaded method. | |
251 | ||
252 | =back | |
253 | ||
254 | =head2 C<existent> | |
255 | ||
256 | =over | |
257 | ||
258 | =item I<Syntax:> C<existent( [file name] )> | |
259 | ||
260 | Returns 1 if the named file (or directory) exists. Otherwise a value of | |
261 | undef is returned. | |
262 | ||
263 | This works the same as Perl's built-in C<-e> file test operator, | |
264 | I<(see L<perlfunc/-X>)>, it's just easier for some people to remember. This | |
265 | is an autoloaded method. | |
266 | ||
267 | =back | |
268 | ||
269 | =head2 C<file_type> | |
270 | ||
271 | =over | |
272 | ||
273 | =item I<Syntax:> C<file_type( [file name] )> | |
274 | ||
275 | Returns a list of keywords corresponding to each of Perl's built in file tests | |
276 | (those specific to file types) for which the named file returns true. | |
277 | I<(see L<perlfunc/-X>.)> This is an autoloaded method. | |
278 | ||
279 | The keywords and their definitions appear below; the order of keywords returned | |
280 | is the same as the order in which the are listed here: | |
281 | ||
282 | =over | |
283 | ||
284 | =item C<PLAIN File is a plain file.> | |
285 | ||
286 | =item C<TEXT File is a text file.> | |
287 | ||
288 | =item C<BINARY File is a binary file.> | |
289 | ||
290 | =item C<DIRECTORY File is a directory.> | |
291 | ||
292 | =item C<SYMLINK File is a symbolic link.> | |
293 | ||
294 | =item C<PIPE File is a named pipe (FIFO).> | |
295 | ||
296 | =item C<SOCKET File is a socket.> | |
297 | ||
298 | =item C<BLOCK File is a block special file.> | |
299 | ||
300 | =item C<CHARACTER File is a character special file.> | |
301 | ||
302 | =back | |
303 | ||
304 | =back | |
305 | ||
306 | =head2 C<flock_rules> | |
307 | ||
308 | =over | |
309 | ||
310 | =item I<Syntax:> C<flock_rules( [keyword list] )> | |
311 | ||
312 | Sets I/O race condition policy, or tells File::Util how it should handle race | |
313 | conditions created when a file can't be locked because it is already locked | |
314 | somewhere else (usually by another process). | |
315 | ||
316 | An empty call to this method returns a list of keywords representing the rules | |
317 | that are currently in effect for the object. | |
318 | ||
319 | Otherwise, a call should include a list with array containing your chosen | |
320 | directive keywords in order of precedence. The rules will be applied in | |
321 | cascading order when a File::Util object attempts to lock a file, so if the | |
322 | actions specified by the first rule don't result in success, the second rule | |
323 | is applied, and so on. | |
324 | ||
325 | Recognized keywords: | |
326 | ||
327 | =over | |
328 | ||
329 | =item C<NOBLOCKEX> | |
330 | ||
331 | tries to get an exclusive lock on the file without blocking (waiting) | |
332 | ||
333 | =item C<NOBLOCKSH> | |
334 | ||
335 | tries to get a shared lock on the file without blocking | |
336 | ||
337 | =item C<BLOCKEX> | |
338 | ||
339 | waits to try getting an exclusive lock | |
340 | ||
341 | =item C<BLOCKSH> | |
342 | ||
343 | waits to try getting a shared lock | |
344 | ||
345 | =item C<FAIL> | |
346 | ||
347 | dies with stack trace | |
348 | ||
349 | =item C<WARN> | |
350 | ||
351 | warn()s about the error with a stack trace and returns undef | |
352 | ||
353 | =item C<IGNORE> | |
354 | ||
355 | ignores the failure to get an exclusive lock | |
356 | ||
357 | =item C<UNDEF> | |
358 | ||
359 | returns undef | |
360 | ||
361 | =item C<ZERO> | |
362 | ||
363 | returns 0 | |
364 | ||
365 | =back | |
366 | ||
367 | Examples: | |
368 | ||
369 | =over | |
370 | ||
371 | =item ex- C<flock_rules( qw/ NOBLOCKEX FAIL / );> | |
372 | ||
373 | This is the default policy. When in effect, the File::Util object will first | |
374 | attempt to get a non-blocking exclusive lock on the file. If that attempt | |
375 | fails the File::Util object will call die() with a detailed error message and | |
376 | a stack trace. | |
377 | ||
378 | =item ex- C<flock_rules( qw/ NOBLOCKEX BLOCKEX FAIL / );> | |
379 | ||
380 | The File::Util object will first attempt to get a non-blocking exclusive lock | |
381 | on the file. If that attempt fails it falls back to the second policy rule | |
382 | "BLOCKEX" and tries again to get an exclusive lock on the file, but this time | |
383 | by blocking (waiting for its turn). If that second attempt fails, the | |
384 | File::Util object will fail with a detailed error message and a stack trace. | |
385 | ||
386 | =item ex- C<flock_rules( qw/ BLOCKEX IGNORE / );> | |
387 | ||
388 | The File::Util object will first attempt to get a file non-blocking lock on | |
389 | the file. If that attempt fails it will ignore the error, and go on to open | |
390 | the file anyway and no failures will occur or warings be issued. | |
391 | ||
392 | =back | |
393 | ||
394 | This is an autoloaded method. | |
395 | ||
396 | =back | |
397 | ||
398 | =head2 C<isbin> | |
399 | ||
400 | =over | |
401 | ||
402 | =item I<Syntax:> C<isbin( [file name] )> | |
403 | ||
404 | Returns 1 if the named file (or directory) exists. Otherwise a value of undef | |
405 | is returned, indicating that the named file either does not exist or is of | |
406 | another file type. | |
407 | ||
408 | This works the same as Perl's built-in C<-B> file test operator, | |
409 | I<(see L<perlfunc/-X>)>, it's just easier for some people to remember. This | |
410 | is an autoloaded method. | |
411 | ||
412 | =back | |
413 | ||
414 | =head2 C<last_access> | |
415 | ||
416 | =over | |
417 | ||
418 | =item I<Syntax:> C<last_access( [file name] )> | |
419 | ||
420 | Returns the last accessed time for the named file in non-leap seconds since | |
421 | whatever your system considers to be the epoch. Suitable for feeding to | |
422 | Perl's built-in functions "gmtime" and "localtime". I<(see L<perlfunc/time>.)> | |
423 | This is an autoloaded method. | |
424 | ||
425 | =back | |
426 | ||
427 | =head2 C<last_changed> | |
428 | ||
429 | =over | |
430 | ||
431 | =item I<Syntax:> C<last_changed( [file name] )> | |
432 | ||
433 | Returns the inode change time for the named file in non-leap seconds since | |
434 | whatever your system considers to be the epoch. Suitable for feeding to | |
435 | Perl's built-in functions "gmtime" and "localtime". I<(see L<perlfunc/time>.)> | |
436 | This is an autoloaded method. | |
437 | ||
438 | =back | |
439 | ||
440 | =head2 C<last_modified> | |
441 | ||
442 | =over | |
443 | ||
444 | =item I<Syntax:> C<last_modified( [file name] )> | |
445 | ||
446 | Returns the last modified time for the named file in non-leap seconds since | |
447 | whatever your system considers to be the epoch. Suitable for feeding to | |
448 | Perl's built-in functions "gmtime" and "localtime". I<(see L<perlfunc/time>.)> | |
449 | This is an autoloaded method. | |
450 | ||
451 | =back | |
452 | ||
453 | =head2 C<line_count> | |
454 | ||
455 | =over | |
456 | ||
457 | =item I<Syntax:> C<line_count( [file name] )> | |
458 | ||
459 | Returns the number of lines in the named file. Fails with an error if the | |
460 | named file does not exist. | |
461 | ||
462 | =back | |
463 | ||
464 | =head2 C<list_dir> | |
465 | ||
466 | =over | |
467 | ||
468 | =item I<Syntax:> C<list_dir( [directory name] , [--opts] )> | |
469 | ||
470 | Returns alphabetically sorted all file names in the directory specified if it | |
471 | exists. Fails with an error message if no such directory is found. | |
472 | ||
473 | =over | |
474 | ||
475 | =item B<Flags accepted by C<list_dir()>> | |
476 | ||
477 | =over | |
478 | ||
479 | =item C<--dirs-only> | |
480 | ||
481 | return only directory contents which are directories | |
482 | ||
483 | =item C<--files-only> | |
484 | ||
485 | return only directory contents which are files | |
486 | ||
487 | =item C<--no-fsdots> | |
488 | ||
489 | do not include "." and ".." in the list of directory contents | |
490 | ||
491 | =item C<--pattern> | |
492 | ||
493 | return only files/directories matching pattern provided. argument | |
494 | should be plain text string. It will be converted to a perl regex and passed | |
495 | to CORE::grep as the method scans through directory listings for a match. | |
496 | ||
497 | (ex- C<'--pattern=\.txt$'> returns all file/directory names ending in ".txt". | |
498 | It will match "foo.txt", but not "foo.txt.gz" because of the "$" anchor in the | |
499 | regular expression passed in.) | |
500 | ||
501 | or for the opposite effect, C<< '--pattern=.*(?<!\.txt)$' >> returns all | |
502 | file/directory names that don't end in ".txt" | |
503 | ||
504 | =item C<--with-paths> | |
505 | ||
506 | Include file paths with the contents of the directory list, relative | |
507 | to the directory named in the call. | |
508 | ||
509 | =item C<--recurse> | |
510 | ||
511 | Recurse subdirectories | |
512 | ||
513 | =item C<--follow> | |
514 | ||
515 | Recurse subdirectories, same as C<--recurse> | |
516 | ||
517 | =item C<--dirs-as-ref> | |
518 | ||
519 | When returning directory listing, include first a reference to the list | |
520 | of subdirectories found, followed by anything else returned by the call. | |
521 | ||
522 | =item C<--files-as-ref> | |
523 | ||
524 | When returning directory listing, include last a reference to the list | |
525 | of files found, preceded by a list of subdirectories found (or preceeded | |
526 | by a list reference to subdirectories found if C<--dirs-as-ref> was also used). | |
527 | ||
528 | =item C<--as-ref> | |
529 | ||
530 | Return a pair list references: the first is a reference to any subdirectories | |
531 | found by the call, the second is a reference to any files found by the call. | |
532 | ||
533 | =item C<--sl-after-dirs> | |
534 | ||
535 | Append a directory seperator ("/, "\", or ":" depending on your system) | |
536 | to all directories found by the call. Useful in visual displays for quick | |
537 | differentiation between subdirectories and files. | |
538 | ||
539 | =item C<--ignore-case> | |
540 | ||
541 | Items returned by the call to this method are sorted alphabetically by | |
542 | default, so "Zoo.txt" comes before "alligator.txt" because the alphabetical | |
543 | sort is case-sensitive. This is also the way directories are listed at the | |
544 | system level on most operating systems. | |
545 | ||
546 | If you'd like the directory contents returned by this method to be | |
547 | sorted without regard to case , use this flag. | |
548 | ||
549 | =item C<--count-only> | |
550 | ||
551 | Returns a single value: an integer reflecting the number of items | |
552 | found in the directory after applying the filter criteria specified by any | |
553 | other flags (ie- "--dirs-only", "--recurse", etc.) that may have been passed | |
554 | in as well. | |
555 | ||
556 | =back | |
557 | ||
558 | =back | |
559 | ||
560 | =back | |
561 | ||
562 | =head2 C<load_dir> | |
563 | ||
564 | =over | |
565 | ||
566 | =item I<Syntax:> C<load_dir( [directory name] , [--ds-type] )> | |
567 | ||
568 | Returns a data structure containing the contents of each file present in the | |
569 | named directory. This is an autoloaded method. | |
570 | ||
571 | The type of data structure returned is determined by the optional data-type | |
572 | switch. Only one option may be used for a given call to this method. | |
573 | Recognized options are listed below. | |
574 | ||
575 | =over | |
576 | ||
577 | =item B<Flags accepted by C<load_dir()>> | |
578 | ||
579 | =over | |
580 | ||
581 | =item C<--as-list> | |
582 | ||
583 | Causes the method to return a list comprised of the contents loaded from | |
584 | each file (in case-sensitive order) located in the named directory. | |
585 | ||
586 | =item C<--as-listref> | |
587 | ||
588 | Same as above, except an array reference to the list of items is returned | |
589 | rather than the list itself. | |
590 | ||
591 | =item C<--as-hashref> *(default) | |
592 | ||
593 | Implicit. If no option is passed in, the default behavior is to return a | |
594 | reference to an anonymous hash whose keys are the names of each file in the | |
595 | specified directory; the hash values for contain the contents of the file | |
596 | represented by its corresponding key. | |
597 | ||
598 | =back | |
599 | ||
600 | =back | |
601 | ||
602 | B<Note:> This method does not distinguish between plain files and other file | |
603 | types such as binaries, FIFOs, sockets, etc. | |
604 | ||
605 | Restrictions imposed by the current "read limit" | |
606 | I<(see the L<readlimit()|/readlimit>) entry below> will be applied to the | |
607 | files opened by this method as well. Adjust the readlimit as necessary. | |
608 | ||
609 | my($files) = $fu->load_dir('directory/to/load/'); | |
610 | ||
611 | The above code creates an anonymous hash reference that is stored in the | |
612 | variable named "C<$files>". The keys and values of the hash referenced by | |
613 | "C<$files>" would resemble those of the following code snippet (given that | |
614 | the files in the named directory were the files 'a.txt', 'b.html', 'c.dat', | |
615 | and 'd.conf') | |
616 | ||
617 | my($files) = | |
618 | { | |
619 | 'a.txt' => "the contents of file a.txt", | |
620 | 'b.html' => "the contents of file b.html", | |
621 | 'c.dat' => "the contents of file c.dat", | |
622 | 'd.conf' => "the contents of file d.conf", | |
623 | }; | |
624 | ||
625 | =back | |
626 | ||
627 | =head2 C<load_file> | |
628 | ||
629 | =over | |
630 | ||
631 | =item I<Syntax:> C<load_file( [file name] , [--opts] )> | |
632 | ||
633 | =item I<OR:> C<< load_file( 'FH' => [file handle reference] , [--opts] ) >> | |
634 | ||
635 | If [file name] is passed, returns the contents of [file name] in a string. | |
636 | If a [file handle reference] is passed instead, the filehandle will be | |
637 | C<CORE::read()> and the data obtained by the read will be returned in a string. | |
638 | ||
639 | If you desire the contents of the file (or file handle data) in a list of | |
640 | lines instead of a single string, this can be accomplished through the use | |
641 | of the C<--as-lines> flag (see below). | |
642 | ||
643 | =over | |
644 | ||
645 | =item B<Flags accepted by C<load_file()>> | |
646 | ||
647 | =over | |
648 | ||
649 | =item C<--as-lines> | |
650 | ||
651 | If this flag is passed then your call to C<load_file> will return an ordered | |
652 | list of strings, each of which is a line from the file [file name]. The lines | |
653 | are returned in the order they are read, from the beginning of the file to the | |
654 | end. | |
655 | ||
656 | This is not the default behavior. The default behavior is for C<load_file> to | |
657 | return a single string containing the entire contents of the file, including | |
658 | line break characters. | |
659 | ||
660 | =item C<--no-lock> | |
661 | ||
662 | By default this method will attempt to get a lock on the file while it is | |
663 | being read, following whatever rules are in place for the flock policy | |
664 | established either by default (implicitly) or changed by you in a call to | |
665 | File::Util::flock_rules() | |
666 | I<(see the L<flock_rules()|/flock_rules>) entry below>. | |
667 | ||
668 | This method will not try to get a lock on the file if the File::Util object was | |
669 | created with the option C<--no-lock> or if the method was called with the | |
670 | option C<--no-lock>. | |
671 | ||
672 | This method will automatically call binmode() on binary files for you. If you | |
673 | pass in a filehandle instead of a file name you do not get this automatic | |
674 | check performed for you. In such a case, you'll have to call binmode() on | |
675 | the filehandle yourself. Once you pass a filehandle to this method it has no | |
676 | way of telling if the file opened to that filehandle is binary or not. | |
677 | ||
678 | B<Notes:> This method does not distinguish between plain files and other file | |
679 | types such as binaries, FIFOs, sockets, etc. | |
680 | ||
681 | Restrictions imposed by the current "read limit" | |
682 | I<(see the L<readlimit()|/readlimit>) entry below> will be applied to the | |
683 | files opened by this method as well. Adjust the readlimit as necessary. | |
684 | ||
685 | =back | |
686 | ||
687 | =back | |
688 | ||
689 | =back | |
690 | ||
691 | =head2 C<make_dir> | |
692 | ||
693 | =over | |
694 | ||
695 | =item I<Syntax:> C<make_dir( [new directory name] , [bitmask], [--opts] )> | |
696 | ||
697 | Attempts to create (recursively) a directory as [new directory name] with | |
698 | the [bitmask] provided. The bitmask is an optional argument and defaults to | |
699 | 0777. If specified, the bitmask must be supplied in the form required by the | |
700 | native perl umask function. I<see L<perlfunc/"umask">> for more information | |
701 | about the format of the bitmask argument. | |
702 | ||
703 | As mentioned above, the recursive creation of directories is transparently | |
704 | handled for you. This means that if the name of the directory you pass in | |
705 | contains a parent directory that does not exist, the parent directory(ies) will | |
706 | be created for you automatically and silently in order to create the final | |
707 | directory in the [new directory name]. | |
708 | ||
709 | Simply put, if [new directory] is "/path/to/directory" and the directory | |
710 | "/path/to" does not exist, the directory "/path/to" will be created and the | |
711 | "/path/to/directory" directory will be created thereafter. All directories | |
712 | created will be created with the [bitmask] you specify, or with the default | |
713 | of 0777. | |
714 | ||
715 | Upon successful creation of the [new directory name], the [new directory name] | |
716 | is returned to the caller. | |
717 | ||
718 | =over | |
719 | ||
720 | =item B<Flags accepted by C<make_dir()>> | |
721 | ||
722 | =over | |
723 | ||
724 | =item C<--if-not-exists> | |
725 | ||
726 | If this flag is passed in then make_dir will not attempt to create the directory | |
727 | if it already exists. Rather it will return the name of the directory as it | |
728 | normally would if the directory did not exist previous to calling this method. | |
729 | ||
730 | If a call to this method is made without the C<--if-not-exists> flag and the | |
731 | directory specified as [new directory name] does in fact exist, an error will | |
732 | result as it is impossible to create a directory that already exists. | |
733 | ||
734 | =back | |
735 | ||
736 | =back | |
737 | ||
738 | This is an autoloaded method. | |
739 | ||
740 | =back | |
741 | ||
742 | =head2 C<max_dives> | |
743 | ||
744 | =over | |
745 | ||
746 | =item I<Syntax:> C<max_dives( [integer] )> | |
747 | ||
748 | When called without any arguments, this method returns an integer reflecting | |
749 | the current number of times the File::Util object will dive into the | |
750 | subdirectories it discovers when recursively listing directory contents from | |
751 | a call to C<File::Util::list_dir()>. The default is 1000. If the number is | |
752 | exceeded, the File::Util object will fail with a diagnostic error message. | |
753 | ||
754 | When called with an argument, it sets the maximum number of times a File::Util | |
755 | object will recurse into subdirectories before failing with an error message. | |
756 | ||
757 | This method can only be called with a numeric integer value. Passing a bad | |
758 | argument to this method will cause it to fail with an error message. | |
759 | ||
760 | I<(see L<list_dir|/list_dir>)> | |
761 | ||
762 | This is an autoloaded method. | |
763 | ||
764 | =back | |
765 | ||
766 | =head2 C<needs_binmode> | |
767 | ||
768 | =over | |
769 | ||
770 | =item I<Syntax:> C<needs_binmode> | |
771 | ||
772 | Returns 1 if the machine on which the code is running requires that C<binmode()> | |
773 | I<(a built-in function)> be called on open file handles, or returns 0 if not. | |
774 | I<(see L<perlfunc/binmode>.)> This is an autoloaded method. This is a constant | |
775 | subroutine. It accepts no arguments and will always return the same value for | |
776 | the system on which it is executed. | |
777 | ||
778 | =back | |
779 | ||
780 | =head2 C<new> | |
781 | ||
782 | =over | |
783 | ||
784 | =item I<Syntax:> C<< new( ['parameters' => 'values', etc], [--flags] ) >> | |
785 | ||
786 | This is the File::Util constructor method. eg- It returns a new File::Util | |
787 | object reference when you call it. It recognizes various parameters and flags | |
788 | that govern the behavior of the new File::Util object. | |
789 | ||
790 | =over | |
791 | ||
792 | =item B<Parameters accepted by C<new()>> | |
793 | ||
794 | =over | |
795 | ||
796 | =item use_flock => true/false value | |
797 | ||
798 | Optionally specify this option to the C<File::Util::new> method instruct the | |
799 | new object that it should never attempt to use C<flock()> in it's I/O | |
800 | operations. The default is to use C<flock()> when available on your system. | |
801 | Specify this option with a true or false value, true to use C<flock()>, false | |
802 | to not use it. | |
803 | ||
804 | =item readlimit => positive integer | |
805 | ||
806 | Optionally specify this option to the File::Util::new method to instruct the | |
807 | new object that it should never attempt to open and read in a file greater | |
808 | than the number of bytes you specify. Obviously this argument can only be | |
809 | a numeric integer value, otherwise it will be silently ignored. The default | |
810 | readlimit for File::Util objects is 52428800 bytes (50 megabytes). | |
811 | ||
812 | =item max_dives => positive integer | |
813 | ||
814 | Optionally specify this option to the File::Util::new method to instruct the | |
815 | new object to set the maximum number of times it will recurse into | |
816 | subdirectories while performing directory listing operations before failing | |
817 | with an error message. This argument can only be a numeric integer value, | |
818 | otherwise it will be silently ignored. | |
819 | ||
820 | =back | |
821 | ||
822 | =item B<Flags accepted by C<new()>> | |
823 | ||
824 | =over | |
825 | ||
826 | =item C<--fatals-as-warning> | |
827 | ||
828 | Directive to instruct the new File::Util object that when any call to one of | |
829 | its methods results in a fatal error that it should return B<C<undef>> | |
830 | instead of the value(s) that would normally be returned by the call, and to | |
831 | send an error message to STDERR as well. | |
832 | ||
833 | =item C<--fatals-as-status> | |
834 | ||
835 | Directive to instruct the new File::Util object that when any call to one of | |
836 | its methods results in a fatal error that it should return B<C<undef>> | |
837 | instead of the value(s) that would normally be returned by the call. | |
838 | ||
839 | =item C<--fatals-as-errmsg> | |
840 | ||
841 | Directive to instruct the new File::Util object that when any call to one of | |
842 | its methods results in a fatal error that it should return B<an error message> | |
843 | instead of the value(s) that would normally be returned by the call. | |
844 | ||
845 | =back | |
846 | ||
847 | =back | |
848 | ||
849 | =back | |
850 | ||
851 | =head2 C<open_handle> | |
852 | ||
853 | =over | |
854 | ||
855 | =item I<Syntax:> C<< open_handle('file' => [file name], [--opts]) >> | |
856 | ||
857 | =item I<OR:> C<< open_handle('file' => [file name], 'mode' => [mode], [--opts]) >> | |
858 | ||
859 | =item I<OR:> C<< open_handle('file' => [file name], 'mode' => [mode], 'bitmask' => [bitmask], [--opts]) >> | |
860 | ||
861 | =item I<OR:> C<< open_handle('file' => [file name], 'mode' => [mode], 'bitmask' => [bitmask], 'dbitmask' => [bitmask], [--opts]) >> | |
862 | ||
863 | Attempts to get a unique open file handle on [file name] in [mode] mode. | |
864 | Returns the file handle if successful or generates a fatal error with a | |
865 | diagnostic message if the operation fails. | |
866 | ||
867 | You will need to remember to call C<close()> on the filehandle yourself, at | |
868 | your own discretion. Leaving filehandles open is not a good practice, and | |
869 | is not recommended. I<see L<perlfunc/close>>). | |
870 | ||
871 | Once you have the file handle you would use it as you would use any file handle. | |
872 | Remember that unless you specifically turn file locking off when the | |
873 | C<File::Util> object is created (see I<(see L<new|/new>)> or by using the | |
874 | C<--no-lock> flag when calling C<open_handle>, that file locking is going to | |
875 | automagically be handled for you behind the scenes, so long as your OS supports | |
876 | file locking of any kind at all. Great! It's very convenient for you to not | |
877 | have to worry about portably taking care of file locking between one | |
878 | application and the next; by using C<File::Util> in all of them, you know | |
879 | that you're covered. | |
880 | ||
881 | A slight inconvenience for the price of a larger set of features (compare | |
882 | L<write_file|/write_file> to this method) | |
883 | I<B<you will have to release the file lock on the open handle yourself.>> | |
884 | C<File::Util> can't manage it for you anymore once it hands the handle over | |
885 | to you. At that point, it's all yours. In order to release the file lock | |
886 | on your file handle, call L<unlock_open_handle()|/unlock_open_handle> on it. | |
887 | Otherwise the lock will remain for the life of your process. If you don't | |
888 | want to use the free portable file locking, remember the C<--no-lock> flag, | |
889 | which will turn off file locking for your open handle. Seldom, however, should | |
890 | you ever opt to not use file locking unless you really know what you are doing. | |
891 | ||
892 | If the file does not yet exist it will be created, and it will be created | |
893 | with a bitmask of [bitmask] if you specify a file creation bitmask using | |
894 | the C<'bitmask'> option, otherwise the file will be created with the default | |
895 | bitmask of 0777. | |
896 | ||
897 | If specified, the bitmask must be supplied in the form required by the | |
898 | native perl umask function. I<see L<perlfunc/"umask">> for more information | |
899 | about the format of the bitmask argument. If the file [file name] already | |
900 | exists then the bitmask argument has no effect and is silently ignored. | |
901 | ||
902 | Any non-existent directories in the path preceeding the actual file name will | |
903 | be automatically (and silently - no warnings) created for you and any new | |
904 | directories will be created with a bitmask of [dbitmask], provided you specify | |
905 | a directory creation bitmask with the C<'dbitmask'> option. | |
906 | ||
907 | If specified, the directory creation bitmask [dbitmask] must be supplied in | |
908 | the form required by the native perl umask function. | |
909 | ||
910 | If there is an error while trying to create any preceeding directories, the | |
911 | failure results in a fatal error with a diagnostic error message. If all | |
912 | directories preceeding the name of the file already exist, the dbitmask | |
913 | argument has no effect and is silently ignored. | |
914 | ||
915 | =back | |
916 | ||
917 | =over | |
918 | ||
919 | =item B<Native Perl open modes> | |
920 | ||
921 | The default behavior of C<open_handle()> is to open file handles using Perl's | |
922 | native C<open()> I<(see L<perlfunc/open>)>. Unless you use the | |
923 | C<--use-sysopen> flag, the following modes and only these modes are valid. | |
924 | ||
925 | =over | |
926 | ||
927 | =item C<< 'mode' => 'read' >> | |
928 | ||
929 | [file name] is opened in read-only mode. If the file does not yet exist then | |
930 | a fatal error will occur with a diagnostic help message to help you troubleshoot | |
931 | the problem. | |
932 | ||
933 | =item C<< 'mode' => 'write' >> (this is the default mode) | |
934 | ||
935 | [file name] is created if it does not yet exist. If [file name] already exists | |
936 | then its contents are overwritten with the new content provided. | |
937 | ||
938 | =item C<< 'mode' => 'append' >> | |
939 | ||
940 | [file name] is created if it does not yet exist. If [file name] already exists | |
941 | its contents will be preserved and the new content you provide will be appended | |
942 | to the end of the file. | |
943 | ||
944 | =back | |
945 | ||
946 | =back | |
947 | ||
948 | =over | |
949 | ||
950 | =item B<System level open modes ("open a la C")> | |
951 | ||
952 | Optionally you can ask C<File::Util> to open your handle using C<CORE::sysopen> | |
953 | instead of using the native Perl C<CORE::open()>. This is accomplished by | |
954 | passing in the C<--use-sysopen> flag. Using this feature opens up more | |
955 | possibilities as far as the open modes you can choose from, but also carries | |
956 | with it a few caveats so you have to be careful, just as you'd have to be a | |
957 | little more careful when using C<sysopen()> anyway. | |
958 | ||
959 | Specifically you need to remember that when using this feature you must NOT | |
960 | mix different types of I/O when working with the file handle. You can't go | |
961 | opening file handles with C<sysopen()> and print to them as you normally | |
962 | would print to a file handle. You have to use C<syswrite()> instead. The | |
963 | same applies here. If you get a C<sysopen()>'d filehandle from C<open_handle()> | |
964 | it is imperative that you use C<syswrite()> on it. You'll also need to use | |
965 | C<sysseek()> and other type of C<sys>* commands on the filehandle instead of | |
966 | their native Perl equivalents. | |
967 | ||
968 | (see L<perlfunc/sysopen>, L<perlfunc/syswrite>, L<perlfunc/sysseek>, | |
969 | L<perlfunc/sysread>) | |
970 | ||
971 | That said, here are the different modes you can choose from to get a file handle | |
972 | when using the C<--use-sysopen> flag. Remember that these won't work unless | |
973 | you use the flag, and will generate an error if you try using them without it. | |
974 | The standard C<'read'>, C<'write'>, and C<'append'> modes are already available | |
975 | to you by default. These are the extended modes: | |
976 | ||
977 | =over | |
978 | ||
979 | =item C<< 'mode' => 'rwcreate' >> | |
980 | ||
981 | [file name] is opened in read-write mode, and will be created for you if it | |
982 | does not already exist. | |
983 | ||
984 | =item C<< 'mode' => 'rwupdate' >> | |
985 | ||
986 | [file name] is opened for you in read-write mode, but must already exist. If | |
987 | it does not exist, a fatal error will result and a diagnostic help message will | |
988 | be printed out to help you troubleshoot the problem. | |
989 | ||
990 | =item C<< 'mode' => 'rwclobber' >> | |
991 | ||
992 | [file name] is opened for you in read-write mode. If the file already exists | |
993 | it's contents will be "clobbered" or wiped out. The file will then be empty | |
994 | and you will be working with the then-truncated file. This can not be undone. | |
995 | Once you call C<open_handle()> using this option, your file WILL be wiped out. | |
996 | If the file does not exist yet, it will be created for you. | |
997 | ||
998 | =item C<< 'mode' => 'rwappend' >> | |
999 | ||
1000 | [file name] will be opened for you in read-write mode ready for appending. The | |
1001 | file's contents will not be wiped out; they will be preserved and you will be | |
1002 | working in append fashion. You will only be able to write starting at the end | |
1003 | of the file. If the file does not exist, it will be created for you. | |
1004 | ||
1005 | =back | |
1006 | ||
1007 | Remember to use C<sysread()> and not plain C<read()> when reading those | |
1008 | C<sysopen()>'d filehandles! | |
1009 | ||
1010 | =back | |
1011 | ||
1012 | =over | |
1013 | ||
1014 | =item B<Flags accepted by C<open_handle()>> | |
1015 | ||
1016 | =over | |
1017 | ||
1018 | =item C<--binmode> | |
1019 | ||
1020 | Makes sure that CORE::binmode() is called on the filehandle when your content | |
1021 | is written. This is useful for times when the content you are writing to file | |
1022 | is a binary stream. I<(see L<perlfunc/binmode>)>. | |
1023 | ||
1024 | =item C<--no-lock> | |
1025 | ||
1026 | By default this method will attempt to get a lock on the file while it is | |
1027 | being read, following whatever rules are in place for the flock policy | |
1028 | established either by default (implicitly) or changed by you in a call to | |
1029 | File::Util::flock_rules() | |
1030 | I<(see the L<flock_rules()|/flock_rules>) entry below>. | |
1031 | ||
1032 | This method will not try to get a lock on the file if the File::Util object was | |
1033 | created with the option C<--no-lock> or if this method is called with the | |
1034 | option C<--no-lock>. | |
1035 | ||
1036 | =item C<--use-sysopen> | |
1037 | ||
1038 | Instead of opening the file using Perl's native C<open()> command, C<File::Util> | |
1039 | will open the file with the C<sysopen()> command. You will have to remember | |
1040 | that your filehandle is a C<sysopen()>'d one, and that you will not be able to | |
1041 | use native Perl I/O functions on it. You will have to use the C<sys>* | |
1042 | equivalents. See L<perlopentut> for a more in-depth explanation of why you | |
1043 | can't mix native Perl I/O with system I/O. | |
1044 | ||
1045 | =back | |
1046 | ||
1047 | This is an autoloaded method. | |
1048 | ||
1049 | =back | |
1050 | ||
1051 | =head2 C<readlimit> | |
1052 | ||
1053 | =over | |
1054 | ||
1055 | =item I<Syntax:> C<readlimit( [integer] )> | |
1056 | ||
1057 | By default, the largest size file that File::Util will read into memory and | |
1058 | return via the L<load_file|/load_file> is 52428800 byptes (50 megabytes). | |
1059 | ||
1060 | This value can be modified by calling this method with an integer value | |
1061 | reflecting the new limit you want to impose, in bytes. For example, if you want | |
1062 | to set the limit to 10 megabytes, call the method with an argument of 10485760. | |
1063 | ||
1064 | If this method is called without an argument, the read limit currently in force | |
1065 | for the File::Util object will be returned. | |
1066 | ||
1067 | This is an autoloaded method. | |
1068 | ||
1069 | =back | |
1070 | ||
1071 | =head2 C<return_path> | |
1072 | ||
1073 | =over | |
1074 | ||
1075 | =item I<Syntax:> C<return_path( [string] )> | |
1076 | ||
1077 | Takes the file path from the file name provided and returns it such that | |
1078 | "/foo/bar/baz.txt" is returned "/foo/bar". | |
1079 | ||
1080 | This is an autoloaded method. | |
1081 | ||
1082 | =back | |
1083 | ||
1084 | =head2 C<size> | |
1085 | ||
1086 | =over | |
1087 | ||
1088 | =item I<Syntax:> C<size( [file name] )> | |
1089 | ||
1090 | Returns the file size of [file name] in bytes. Returns C<0> if the file is | |
1091 | empty, returns C<undef> if the file does not exist. | |
1092 | ||
1093 | This is an autoloaded method. | |
1094 | ||
1095 | =back | |
1096 | ||
1097 | =head2 C<strip_path> | |
1098 | ||
1099 | =over | |
1100 | ||
1101 | =item I<Syntax:> C<strip_path( [string] )> | |
1102 | ||
1103 | Strips the file path from the file name provided and returns the file name only. | |
1104 | ||
1105 | =back | |
1106 | ||
1107 | =head2 C<touch> | |
1108 | ||
1109 | =over | |
1110 | ||
1111 | =item I<Syntax:> C<touch( [file name] )> | |
1112 | ||
1113 | Behaves like the *nix C<touch> command; Updates the access and modification | |
1114 | times of the specified file to the current time. If the file does not exist, | |
1115 | C<File::Util> tries to create it empty. This method will fail with a fatal | |
1116 | error if system permissions deny alterations to or creation of the file. | |
1117 | ||
1118 | Returns C<1> if successful. If unsuccessful, fails with a descriptive error | |
1119 | message about what went wrong. | |
1120 | ||
1121 | This is an autoloaded method. | |
1122 | ||
1123 | =back | |
1124 | ||
1125 | =head2 C<trunc> | |
1126 | ||
1127 | =over | |
1128 | ||
1129 | =item I<Syntax:> C<trunc( [file name] )> | |
1130 | ||
1131 | Truncates [file name] (i.e.- wipes out, or "clobbers" the contents of the | |
1132 | specified file. Returns C<1> if successful. If unsuccessful, fails with a | |
1133 | descriptive error message about what went wrong. | |
1134 | ||
1135 | This is an autoloaded method. | |
1136 | ||
1137 | =back | |
1138 | ||
1139 | =head2 C<unlock_open_handle> | |
1140 | ||
1141 | =over | |
1142 | ||
1143 | =item I<Syntax:> C<unlock_open_handle([file handle])> | |
1144 | ||
1145 | Release the flock on a file handle you opened with L<open_handle|/open_handle>. | |
1146 | ||
1147 | Returns true on success, false on failure. Will not raise a fatal error if | |
1148 | the unlock operation fails. You can capture the return value from your call | |
1149 | to this method and C<die()> if you so desire. Failure is not ever very likely, | |
1150 | or C<File::Util> wouldn't have been able to get a portable lock on the file | |
1151 | in the first place. | |
1152 | ||
1153 | If C<File::Util> wasn't able to ever lock the file due to limitations of your | |
1154 | operating system, a call to this method will return a true value. | |
1155 | ||
1156 | If file locking has been disabled on the file handle via the C<--no-lock> flag | |
1157 | at the time L<open_handle|/open_handle> was called, or if file locking was | |
1158 | disabled using the L<use_flock|/use_flock> method, or if file locking was | |
1159 | disabled on the entire C<File::Util> object at the time of its creation | |
1160 | I<(see L<new()|/new>)>, calling this method will have no effect and a true value | |
1161 | will be returned. | |
1162 | ||
1163 | This is an autoloaded method, due to L<open_handle|open_handle> also being | |
1164 | autoloaded. | |
1165 | ||
1166 | =back | |
1167 | ||
1168 | =head2 C<use_flock> | |
1169 | ||
1170 | =over | |
1171 | ||
1172 | =item I<Syntax:> C<use_flock( [true / false value] )> | |
1173 | ||
1174 | When called without any arguments, this method returns a true or false value | |
1175 | to reflect the current use of C<flock()> within the File::Util object. | |
1176 | ||
1177 | When called with a true or false value as its single argument, this method | |
1178 | will tell the File::Util object whether or not it should attempt to use | |
1179 | C<flock()> in its I/O operations. A true value indicates that the File::Util | |
1180 | object will use C<flock()> if available, a false value indicates that it will | |
1181 | not. The default is to use C<flock()> when available on your system. | |
1182 | ||
1183 | This is an autoloaded method. | |
1184 | ||
1185 | =back | |
1186 | ||
1187 | =head2 C<write_file> | |
1188 | ||
1189 | =over | |
1190 | ||
1191 | =item I<Syntax:> C<< write_file('file' => [file name], 'content' => [string], [--opts]) >> | |
1192 | ||
1193 | =item I<OR:> C<< write_file('file' => [file name], 'content' => [string], 'mode' => [mode], [--opts]) >> | |
1194 | ||
1195 | =item I<OR:> C<< write_file('file' => [file name], 'content' => [string], 'mode' => [mode], 'bitmask' => [bitmask], [--opts]) >> | |
1196 | ||
1197 | =item I<OR:> C<< write_file('file' => [file name], 'content' => [string], 'mode' => [mode], 'bitmask' => [bitmask], 'dbitmask' => [bitmask], [--opts]) >> | |
1198 | ||
1199 | Attempts to write [string] to [file name] in mode [mode]. If the file does | |
1200 | not yet exist it will be created, and it will be created with a bitmask of | |
1201 | [bitmask] if you specify a file creation bitmask using the C<'bitmask'> option, | |
1202 | otherwise the file will be created with the default bitmask of 0777. | |
1203 | ||
1204 | [string] should be a string or a scalar variable containing a string. The | |
1205 | string can be any type of data, such as a binary stream, or ascii text with | |
1206 | line breaks, etc. Be sure to pass in the C<--binmode> flag for binary streams. | |
1207 | ||
1208 | If specified, the bitmask must be supplied in the form required by the | |
1209 | native perl umask function. I<see L<perlfunc/"umask">> for more information | |
1210 | about the format of the bitmask argument. If the file [file name] already | |
1211 | exists then the bitmask argument has no effect and is silently ignored. | |
1212 | ||
1213 | Returns 1 if successful or fails (fatal) with an error message if not | |
1214 | successful. | |
1215 | ||
1216 | Any non-existent directories in the path preceeding the actual file name will | |
1217 | be automatically (and silently - no warnings) created for you and any new | |
1218 | directories will be created with a bitmask of [dbitmask], provided you specify | |
1219 | a directory creation bitmask with the C<'dbitmask'> option. | |
1220 | ||
1221 | If specified, the directory creation bitmask [dbitmask] must be supplied in | |
1222 | the form required by the native perl umask function. | |
1223 | ||
1224 | If there is an error while trying to create any preceeding directories, the | |
1225 | failure results in a fatal error with a diagnostic error message. If all | |
1226 | directories preceeding the name of the file already exist, the dbitmask | |
1227 | argument has no effect and is silently ignored. | |
1228 | ||
1229 | =over | |
1230 | ||
1231 | =item C<< 'mode' => 'write' >> (this is the default mode) | |
1232 | ||
1233 | [file name] is created if it does not yet exist. If [file name] already exists | |
1234 | then its contents are overwritten with the new content provided. | |
1235 | ||
1236 | =item C<< 'mode' => 'append' >> | |
1237 | ||
1238 | [file name] is created if it does not yet exist. If [file name] already exists | |
1239 | its contents will be preserved and the new content you provide will be appended | |
1240 | to the end of the file. | |
1241 | ||
1242 | =back | |
1243 | ||
1244 | =over | |
1245 | ||
1246 | =item B<Flags accepted by C<write_file()>> | |
1247 | ||
1248 | =over | |
1249 | ||
1250 | =item C<--binmode> | |
1251 | ||
1252 | Makes sure that CORE::binmode() is called on the filehandle when your content | |
1253 | is written. This is useful for times when the content you are writing to file | |
1254 | is a binary stream. | |
1255 | ||
1256 | =item C<--empty-writes-OK> | |
1257 | ||
1258 | Allows you to call this method without providing a content argument (it lets | |
1259 | you create an empty file without warning you or failing. Be advised that | |
1260 | if you use this flag, it will have the same effect as truncating a file | |
1261 | that already has content in it (i.e.- it will "clobber" non-empty files) | |
1262 | ||
1263 | =item C<--no-lock> | |
1264 | ||
1265 | By default this method will attempt to get a lock on the file while it is | |
1266 | being read, following whatever rules are in place for the flock policy | |
1267 | established either by default (implicitly) or changed by you in a call to | |
1268 | File::Util::flock_rules() | |
1269 | I<(see the L<flock_rules()|/flock_rules>) entry below>. | |
1270 | ||
1271 | This method will not try to get a lock on the file if the File::Util object was | |
1272 | created with the option C<--no-lock> or if this method is called with the | |
1273 | option C<--no-lock>. | |
1274 | ||
1275 | =back | |
1276 | ||
1277 | =back | |
1278 | ||
1279 | =back | |
1280 | ||
1281 | =head2 C<valid_filename> | |
1282 | ||
1283 | =over | |
1284 | ||
1285 | =item I<Syntax:> C<valid_filename( [string] )> | |
1286 | ||
1287 | For the given string, returns 1 if the string is a legal file name for the | |
1288 | system on which the program is running, or returns undef if it is not. This | |
1289 | method does not test for the validity of file paths! It tests for the validity | |
1290 | of file names only. (It is used internally to check beforehand if a file name | |
1291 | is useable when creating new files, but is also a public method available for | |
1292 | external use.) | |
1293 | ||
1294 | =back | |
1295 | ||
1296 | =head1 CONSTANTS | |
1297 | ||
1298 | =head2 C<NL> | |
1299 | ||
1300 | =over | |
1301 | ||
1302 | =item I<Syntax:> C<NL> | |
1303 | ||
1304 | Returns the correct new line character (or character sequence) for the system | |
1305 | on which your program runs. | |
1306 | ||
1307 | =back | |
1308 | ||
1309 | =head2 C<SL> | |
1310 | ||
1311 | =over | |
1312 | ||
1313 | =item I<Syntax:> C<SL> | |
1314 | ||
1315 | Returns the correct directory path seperator for the system on which your | |
1316 | program runs. | |
1317 | ||
1318 | =back | |
1319 | ||
1320 | =head2 C<OS> | |
1321 | ||
1322 | =over | |
1323 | ||
1324 | =item I<Syntax:> C<OS> | |
1325 | ||
1326 | Returns the File::Util keyword for the operating system FAMILY it detected. The | |
1327 | keyword for the detected operating system will be one of the following, derived | |
1328 | from the conents of C<$^O>, or if C<$^O> can not be found, from the contents of | |
1329 | C<$Config::Config{osname}> (see native L<Config> library), or if that | |
1330 | doesn't contain a recognizable value, finally falls back to C<UNIX>. | |
1331 | ||
1332 | Generally speaking, Linux operating systems are going to be detected as C<UNIX>. | |
1333 | This isn't a bug. The OS FAMILY to which it belongs uses C<UNIX> style | |
1334 | filesystem conventions and line endings, which are the relevant things to | |
1335 | file handling operations. | |
1336 | ||
1337 | =over | |
1338 | ||
1339 | =item UNIX | |
1340 | ||
1341 | Specifics: OS name =~ /^(?:darwin|bsdos)/i | |
1342 | ||
1343 | =item CYGWIN | |
1344 | ||
1345 | Specifics: OS name =~ /^cygwin/i | |
1346 | ||
1347 | =item WINDOWS | |
1348 | ||
1349 | Specifics: OS name =~ /^MSWin/i | |
1350 | ||
1351 | =item VMS | |
1352 | ||
1353 | Specifics: OS name =~ /^vms/i | |
1354 | ||
1355 | =item DOS | |
1356 | ||
1357 | Specifics: OS name =~ /^dos/i | |
1358 | ||
1359 | =item MACINTOSH | |
1360 | ||
1361 | Specifics: OS name =~ /^MacOS/i | |
1362 | ||
1363 | =item EPOC | |
1364 | ||
1365 | Specifics: OS name =~ /^epoc/i | |
1366 | ||
1367 | =item OS2 | |
1368 | ||
1369 | Specifics: OS name =~ /^os2/i | |
1370 | ||
1371 | =back | |
1372 | ||
1373 | =back | |
1374 | ||
1375 | =head1 PREREQUISITES | |
1376 | ||
1377 | =over | |
1378 | ||
1379 | =item L<Perl|perl> 5.006 or better | |
1380 | ||
1381 | =item L<Class::OOorNO> v0.01_1 or better | |
1382 | ||
1383 | =item L<Exception::Handler> v1.00_0 or better | |
1384 | ||
1385 | =back | |
1386 | ||
1387 | =head1 EXAMPLES | |
1388 | ||
1389 | =head2 Get the names of all files and subdirectories in a directory | |
1390 | ||
1391 | use File::Util; | |
1392 | my($f) = File::Util->new(); | |
1393 | # option --no-fsdots excludes "." and ".." from the list | |
1394 | my(@dirs_and_files) = $f->list_dir('/foo','--no-fsdots'); | |
1395 | ||
1396 | =head2 Get the names of all files and subdirectories in a directory, recursively | |
1397 | ||
1398 | use File::Util; | |
1399 | my($f) = File::Util->new(); | |
1400 | my(@dirs_and_files) = $f->list_dir('/foo','--recurse'); | |
1401 | ||
1402 | =head2 Get the names of all files (no subdirectories) in a directory | |
1403 | ||
1404 | use File::Util; | |
1405 | my($f) = File::Util->new(); | |
1406 | my(@dirs_and_files) = $f->list_dir('/foo','--files-only'); | |
1407 | ||
1408 | =head2 Get the names of all subdirectories (no files) in a directory | |
1409 | ||
1410 | use File::Util; | |
1411 | my($f) = File::Util->new(); | |
1412 | my(@dirs_and_files) = $f->list_dir('/foo','--dirs-only'); | |
1413 | ||
1414 | =head2 Get the number of files and subdirectories in a directory | |
1415 | ||
1416 | use File::Util; | |
1417 | my($f) = File::Util->new(); | |
1418 | my(@dirs_and_files) = $f->list_dir('/foo', qw/--no-fsdots --count-only/); | |
1419 | ||
1420 | =head2 Get the names of files and subdirs in a directory as seperate array refs | |
1421 | ||
1422 | use File::Util; | |
1423 | my($f) = File::Util->new(); | |
1424 | my($dirs,$files) = $f->list_dir('/foo', '--as-ref'); | |
1425 | ||
1426 | -OR- | |
1427 | my($dirs,$files) = $f->list_dir('.', qw/--dirs-as-ref --files-as-ref/); | |
1428 | ||
1429 | =head2 Get the contents of a file in a string | |
1430 | ||
1431 | use File::Util; | |
1432 | my($f) = File::Util->new(); | |
1433 | my($contents) = $f->load_file('filename'); | |
1434 | ||
1435 | =head2 Get the contents of a file in an array of lines in the file | |
1436 | ||
1437 | use File::Util; | |
1438 | my($f) = File::Util->new(); | |
1439 | my(@contents) = $f->load_file('filename','--as-lines'); | |
1440 | ||
1441 | =head2 Get an open file handle for reading | |
1442 | ||
1443 | use File::Util; | |
1444 | my($f) = File::Util->new(); | |
1445 | my($FH_REF) = $f->open_handle( | |
1446 | 'file' => 'new_filename', | |
1447 | 'mode' => 'read' | |
1448 | ); | |
1449 | ||
1450 | =head2 Get an open file handle for writing | |
1451 | ||
1452 | use File::Util; | |
1453 | my($f) = File::Util->new(); | |
1454 | my($FH_REF) = $f->open_handle( | |
1455 | 'file' => 'new_filename', | |
1456 | 'mode' => 'write' | |
1457 | ); | |
1458 | ||
1459 | =head2 Write to a new or existing file | |
1460 | ||
1461 | use File::Util; | |
1462 | my($content) = 'Pathelogically Eclectic Rubbish Lister'; | |
1463 | my($f) = File::Util->new(); | |
1464 | $f->write_file('file' => 'a new file.txt', 'content' => $content); | |
1465 | ||
1466 | # optionally specify a creation bitmask when writing to a new file | |
1467 | $f->write_file( | |
1468 | 'file' => 'a new file.txt', | |
1469 | 'bitmask' => 0777, | |
1470 | 'content' => $content | |
1471 | ); | |
1472 | ||
1473 | =head2 Append to a new or existing file | |
1474 | ||
1475 | use File::Util; | |
1476 | my($content) = 'Pathelogically Eclectic Rubbish Lister'; | |
1477 | my($f) = File::Util->new(); | |
1478 | $f->write_file( | |
1479 | 'file' => 'a new file.txt', | |
1480 | 'mode' => 'append', | |
1481 | 'content' => $content | |
1482 | ); | |
1483 | ||
1484 | =head2 Determine if something is a valid file name | |
1485 | ||
1486 | use File::Util qw( valid_filename ); | |
1487 | ||
1488 | if (valid_filename("foo?+/bar~@/#baz.txt")) { | |
1489 | print "file name is valid" | |
1490 | else { | |
1491 | print "file name contains illegal characters" | |
1492 | } | |
1493 | ||
1494 | -OR- | |
1495 | use File::Util; | |
1496 | print File::Util->valid_filename("foo?+/bar~@/#baz.txt") ? 'ok' : 'bad'; | |
1497 | ||
1498 | -OR- | |
1499 | use File::Util; | |
1500 | my($f) = File::Util->new(); | |
1501 | print $f->valid_filename("foo?+/bar~@/#baz.txt") ? 'ok' : 'bad'; | |
1502 | ||
1503 | =head2 Get the number of lines in a file | |
1504 | ||
1505 | use File::Util; | |
1506 | my($f) = File::Util->new(); | |
1507 | my($linecount) = $f->line_count('foo.txt'); | |
1508 | ||
1509 | =head2 Strip the path from a file name | |
1510 | ||
1511 | use File::Util; | |
1512 | my($f) = File::Util->new(); | |
1513 | ||
1514 | # On Windows | |
1515 | # (prints "hosts") | |
1516 | my($path) = $f->strip_path('C:\WINDOWS\system32\drivers\etc\hosts'); | |
1517 | ||
1518 | # On Linux/Unix | |
1519 | # (prints "perl") | |
1520 | print $f->strip_path('/usr/bin/perl'); | |
1521 | ||
1522 | # On a Mac | |
1523 | # (prints "baz") | |
1524 | print $f->strip_path('foo:bar:baz'); | |
1525 | ||
1526 | =head2 Get the path preceeding a file name | |
1527 | ||
1528 | use File::Util; | |
1529 | my($f) = File::Util->new(); | |
1530 | ||
1531 | # On Windows | |
1532 | # (prints "C:\WINDOWS\system32\drivers\etc") | |
1533 | my($path) = $f->return_path('C:\WINDOWS\system32\drivers\etc\hosts'); | |
1534 | ||
1535 | # On Linux/Unix | |
1536 | # (prints "/usr/bin") | |
1537 | print $f->return_path('/usr/bin/perl'); | |
1538 | ||
1539 | # On a Mac | |
1540 | # (prints "foo:bar") | |
1541 | print $f->return_path('foo:bar:baz'); | |
1542 | ||
1543 | =head2 Find out if the host system can use flock | |
1544 | ||
1545 | use File::Util qw( can_flock ); | |
1546 | print can_flock; | |
1547 | ||
1548 | -OR- | |
1549 | print File::Util->can_flock; | |
1550 | ||
1551 | -OR- | |
1552 | my($f) = File::Util->new(); | |
1553 | print $f->can_flock; | |
1554 | ||
1555 | =head2 Find out if the host system needs to call binmode on binary files | |
1556 | ||
1557 | use File::Util qw( needs_binmode ); | |
1558 | print needs_binmode; | |
1559 | ||
1560 | -OR- | |
1561 | use File::Util; | |
1562 | print File::Util->needs_binmode; | |
1563 | ||
1564 | -OR- | |
1565 | use File::Util; | |
1566 | my($f) = File::Util->new(); | |
1567 | print $f->needs_binmode; | |
1568 | ||
1569 | =head2 Find out if a file can be opened for read (based on file permissions) | |
1570 | ||
1571 | use File::Util; | |
1572 | my($f) = File::Util->new(); | |
1573 | my($is_readable) = $f->can_read('foo.txt'); | |
1574 | ||
1575 | =head2 Find out if a file can be opened for write (based on file permissions) | |
1576 | ||
1577 | use File::Util; | |
1578 | my($f) = File::Util->new(); | |
1579 | my($is_writable) = $f->can_write('foo.txt'); | |
1580 | ||
1581 | =head2 Escape illegal characters in a potential file name (and its path) | |
1582 | ||
1583 | use File::Util; | |
1584 | my($f) = File::Util->new(); | |
1585 | ||
1586 | # prints "C__WINDOWS_system32_drivers_etc_hosts" | |
1587 | print $f->escape_filename('C:\WINDOWS\system32\drivers\etc\hosts'); | |
1588 | ||
1589 | # prints "baz)__@^" | |
1590 | # (strips the file path from the file name, then escapes it | |
1591 | print $f->escape_filename( | |
1592 | '/foo/bar/baz)?*@^', | |
1593 | '--strip-path' | |
1594 | ); | |
1595 | ||
1596 | # prints "_foo_!_@so~me#illegal$_file&(name" | |
1597 | # (yes, that is a legal filename) | |
1598 | print $f->escape_filename(q[\foo*!_@so~me#illegal$*file&(name]); | |
1599 | ||
1600 | =head2 Find out if the host system uses EBCDIC | |
1601 | ||
1602 | use File::Util qw( ebcdic ); | |
1603 | print ebcdic; | |
1604 | ||
1605 | -OR- | |
1606 | use File::Util; | |
1607 | print File::Util->ebcdic; | |
1608 | ||
1609 | -OR- | |
1610 | use File::Util; | |
1611 | my($f) = File::Util->new(); | |
1612 | print $f->ebcdic; | |
1613 | ||
1614 | =head2 Get the type(s) of an existent file | |
1615 | ||
1616 | use File::Util qw( file_type ); | |
1617 | print file_type('foo.exe'); | |
1618 | ||
1619 | -OR- | |
1620 | use File::Util; | |
1621 | print File::Util->file_type('bar.txt'); | |
1622 | ||
1623 | -OR- | |
1624 | use File::Util; | |
1625 | my($f) = File::Util->new(); | |
1626 | print $f->file_type('/dev/null'); | |
1627 | ||
1628 | =head2 Get the bitmask of an existent file | |
1629 | ||
1630 | use File::Util qw( bitmask ); | |
1631 | print bitmask('/usr/sbin/sendmail'); | |
1632 | ||
1633 | -OR- | |
1634 | use File::Util; | |
1635 | print File::Util->bitmask('C:\COMMAND.COM'); | |
1636 | ||
1637 | -OR- | |
1638 | use File::Util; | |
1639 | my($f) = File::Util->new(); | |
1640 | print $f->bitmask('/dev/null'); | |
1641 | ||
1642 | =head2 Get time of creation for a file | |
1643 | ||
1644 | use File::Util qw( created ); | |
1645 | print scalar localtime created('/usr/bin/exim'); | |
1646 | ||
1647 | -OR- | |
1648 | use File::Util; | |
1649 | print scalar localtime File::Util->created('C:\COMMAND.COM'); | |
1650 | ||
1651 | -OR- | |
1652 | use File::Util; | |
1653 | my($f) = File::Util->new(); | |
1654 | print scalar localtime $f->created('/bin/less'); | |
1655 | ||
1656 | =head2 Get the last access time for a file | |
1657 | ||
1658 | use File::Util qw( last_access ); | |
1659 | print scalar localtime last_access('/usr/bin/exim'); | |
1660 | ||
1661 | -OR- | |
1662 | use File::Util; | |
1663 | print scalar localtime File::Util->last_access('C:\COMMAND.COM'); | |
1664 | ||
1665 | -OR- | |
1666 | use File::Util; | |
1667 | my($f) = File::Util->new(); | |
1668 | print scalar localtime $f->last_access('/bin/less'); | |
1669 | ||
1670 | =head2 Get the inode change time for a file | |
1671 | ||
1672 | use File::Util qw( last_changed ); | |
1673 | print scalar localtime last_changed('/usr/bin/vim'); | |
1674 | ||
1675 | -OR- | |
1676 | use File::Util; | |
1677 | print scalar localtime File::Util->last_changed('C:\COMMAND.COM'); | |
1678 | ||
1679 | -OR- | |
1680 | use File::Util; | |
1681 | my($f) = File::Util->new(); | |
1682 | print scalar localtime $f->last_changed('/bin/cpio'); | |
1683 | ||
1684 | =head2 Get the last modified time for a file | |
1685 | ||
1686 | use File::Util qw( last_modified ); | |
1687 | print scalar localtime last_modified('/usr/bin/exim'); | |
1688 | ||
1689 | -OR- | |
1690 | use File::Util; | |
1691 | print scalar localtime File::Util->last_modified('C:\COMMAND.COM'); | |
1692 | ||
1693 | -OR- | |
1694 | use File::Util; | |
1695 | my($f) = File::Util->new(); | |
1696 | print scalar localtime $f->last_modified('/bin/less'); | |
1697 | ||
1698 | =head2 Make a new directory, recursively if neccessary | |
1699 | ||
1700 | use File::Util; | |
1701 | my($f) = File::Util->new(); | |
1702 | $f->make_dir('/var/tmp/tempfiles/foo/bar/'); | |
1703 | ||
1704 | # optionally specify a creation bitmask to be used in directory creations | |
1705 | $f->make_dir('/var/tmp/tempfiles/foo/bar/',0755); | |
1706 | ||
1707 | =head2 Touch a file | |
1708 | ||
1709 | use File::Util qw( touch ); | |
1710 | touch('somefile.txt'); | |
1711 | ||
1712 | -OR- | |
1713 | use File::Util; | |
1714 | my($f) = File::Util->new(); | |
1715 | $f->touch('/foo/bar/baz.tmp'); | |
1716 | ||
1717 | =head2 Truncate a file | |
1718 | ||
1719 | use File::Util; | |
1720 | my($f) = File::Util->new(); | |
1721 | $f->trunc('/wibble/wombat/noot.tmp'); | |
1722 | ||
1723 | =head2 Get the correct path seperator for the host system | |
1724 | ||
1725 | use File::Util qw( SL ); | |
1726 | print SL; | |
1727 | ||
1728 | -OR- | |
1729 | use File::Util; | |
1730 | print File::Util->SL; | |
1731 | ||
1732 | -OR- | |
1733 | use File::Util; | |
1734 | my($f) = File::Util->new(); | |
1735 | print $f->SL; | |
1736 | ||
1737 | =head2 Get the correct newline character for the host system | |
1738 | ||
1739 | use File::Util qw( NL ); | |
1740 | print NL; | |
1741 | ||
1742 | -OR- | |
1743 | use File::Util; | |
1744 | print File::Util->NL; | |
1745 | ||
1746 | -OR- | |
1747 | use File::Util; | |
1748 | my($f) = File::Util->new(); | |
1749 | print $f->NL; | |
1750 | ||
1751 | =head1 EXAMPLES (Full Programs) | |
1752 | ||
1753 | =head2 Batch File Rename | |
1754 | ||
1755 | # Code changes the file suffix of all files in a directory ending in | |
1756 | # *.foo so that they afterward end in *.bar | |
1757 | ||
1758 | use strict; | |
1759 | use vars qw( $dir ); | |
1760 | use File::Util qw( NL SL ); | |
1761 | ||
1762 | my($f) = File::Util->new(); | |
1763 | my($dir) = '../wibble'; | |
1764 | my($old) = 'foo'; | |
1765 | my($new) = 'bar'; | |
1766 | my(@files) = $f->list_dir($dir, '--files-only'); | |
1767 | ||
1768 | foreach (@files) { | |
1769 | ||
1770 | # don't change the file suffix unless it is *.foo | |
1771 | if ($_ =~ /\.$old$/o) { | |
1772 | ||
1773 | my($newname) = $_; $newname =~ s/\.$old/\.$new/; | |
1774 | ||
1775 | if (rename($dir . SL . $_, $dir . SL . $newname)) { | |
1776 | ||
1777 | print qq[$_ -> $newname], NL | |
1778 | } | |
1779 | else { warn <<__ERR__ } | |
1780 | Couldn't rename "$_" to "$newname"! | |
1781 | __ERR__ | |
1782 | } | |
1783 | else { print <<__NOCHANGE__ } | |
1784 | File retained as "$_" | |
1785 | __NOCHANGE__ | |
1786 | } | |
1787 | ||
1788 | =head2 Recursively remove a directory and all its contents | |
1789 | ||
1790 | # This code removes a directory and everything in it | |
1791 | ||
1792 | use strict; # always | |
1793 | ||
1794 | use File::Util qw( NL ); | |
1795 | ||
1796 | my($f) = File::Util->new(); | |
1797 | my($removedir) = '/path/to/directory/youwanttodelete'; | |
1798 | ||
1799 | my(@gonners) = $f->list_dir($removedir, '--follow'); | |
1800 | ||
1801 | # remove directory and everything in it | |
1802 | my($a, $b); | |
1803 | foreach (reverse(sort({ length($a) <=> length($b) } @gonners)), $removedir) { | |
1804 | print "Removing $_ ..." . NL; | |
1805 | -d $_ ? rmdir($_) || die $! : unlink($_) || die $!; | |
1806 | } | |
1807 | ||
1808 | print 'Done. w00T!', NL x 2; | |
1809 | ||
1810 | ||
1811 | =head2 Wrap the lines in a file at 72 columns, then save it | |
1812 | ||
1813 | # This code opens a file, wraps its lines, and saves the file with | |
1814 | # the newly formatted content | |
1815 | ||
1816 | use strict; # always | |
1817 | ||
1818 | use File::Util qw( NL ); | |
1819 | use Text::Wrap qw( wrap ); | |
1820 | ||
1821 | $Text::Wrap::columns = 72; # wrap text at this many columns | |
1822 | ||
1823 | my($f) = File::Util->new(); | |
1824 | my($textfile) = 'myreport.txt'; # file to wrap and save | |
1825 | ||
1826 | $f->write_file( | |
1827 | 'filename' => $textfile, | |
1828 | 'content' => wrap('', '', $f->load_file($textfile)) | |
1829 | ); | |
1830 | ||
1831 | print 'Done.', NL x 2; | |
1832 | ||
1833 | =head2 Read and increment a counter file, then save it | |
1834 | ||
1835 | # This code opens a file, reads a number value, increments it, | |
1836 | # then saves the newly incremented value back to the file | |
1837 | ||
1838 | use strict; # always | |
1839 | ||
1840 | use File::Util; | |
1841 | ||
1842 | my($f) = File::Util->new(); | |
1843 | my($counterfile) = 'counter.txt'; | |
1844 | ||
1845 | # if the counter file doesn't exist, let's make one | |
1846 | if (! $f->existent($counterfile)) { | |
1847 | $f->touch($counterfile); | |
1848 | } | |
1849 | ||
1850 | my($count) = $f->load_file($counterfile); | |
1851 | ||
1852 | # convert textual number to in-memory int type, -this will default | |
1853 | # to a zero if it encounters non-numerical or empty content | |
1854 | chomp($count); # strip off any trailing lines | |
1855 | $count =~ s/[^[:digit:]]//g; # remove non-numeric data | |
1856 | $count = 0 if "$count" eq ''; # set count to 0 if empty string | |
1857 | $count = int($count); # numberify $count | |
1858 | ||
1859 | print 'Count value from file: ' . $f->load_file($counterfile), $f->NL; | |
1860 | ||
1861 | $count++; # increment the counter value by 1 | |
1862 | ||
1863 | # save the incremented count back to the counter file | |
1864 | $f->write_file( 'filename' => $counterfile, 'content' => $count); | |
1865 | ||
1866 | # verify that "it worked" | |
1867 | print 'Count is now: ' . $f->load_file($counterfile), $f->NL; | |
1868 | print 'Done.', $f->NL x 2; | |
1869 | ||
1870 | =head2 Batch Search & Replace | |
1871 | ||
1872 | # Code does a batch find or search and replace for all files in a given | |
1873 | # directory, recursively or non-recursively based on choices set forth | |
1874 | # in the code. | |
1875 | ||
1876 | use strict; | |
1877 | use File::Util qw( NL SL ); | |
1878 | ||
1879 | # will get search pattern from file named below | |
1880 | use constant SFILE => './sr/searchfor'; | |
1881 | ||
1882 | # will get replace pattern from file named below | |
1883 | use constant RFILE => './sr/replacewith'; | |
1884 | ||
1885 | # will perform batch operation in directory named below | |
1886 | use constant INDIR => '/foo/bar/baz'; | |
1887 | ||
1888 | # specify whether the operation will do a find or a search and replace | |
1889 | use constant RMODE => [qw| read-only write |]->[1]; | |
1890 | ||
1891 | # set the options for the search (will or will not recurse, etc) | |
1892 | my(@opts) = [qw/ --files-only --with-paths --recurse /]->[0,1]; | |
1893 | ||
1894 | # create new File::Util object, set File::Util to send a warning for | |
1895 | # fatal errors instead of dieing | |
1896 | my($f) = File::Util->new('--fatals-as-warning'); | |
1897 | my($rstr) = $f->load_file(RFILE); | |
1898 | my($spat) = quotemeta($f->load_file(SFILE)); $spat = qr/$spat/; | |
1899 | my($gsbt) = 0; | |
1900 | my($action) = RMODE eq 'read-only' ? 'detections' : 'substitutions'; | |
1901 | my(@files) = $f->list_dir(INDIR, @opts); | |
1902 | ||
1903 | for (my($i) = 0; $i < @files; ++$i) { | |
1904 | ||
1905 | next if $f->isbin($files[$i]); | |
1906 | ||
1907 | my($sbt) = 0; my($file) = $f->load_file($files[$i]); | |
1908 | ||
1909 | $file =~ s/$spat/++$sbt;++$gsbt;$rstr/ge; | |
1910 | ||
1911 | $f->write_file('file' => $files[$i], 'content' => $file) | |
1912 | if RMODE eq 'write'; | |
1913 | ||
1914 | print $sbt ? (qq[$sbt $action in $files[$i]] . NL) : ''; | |
1915 | } | |
1916 | ||
1917 | print( NL . <<__DONE__ . NL x 2) and exit; | |
1918 | $gsbt $action in ${\scalar(@files)} files. | |
1919 | __DONE__ | |
1920 | ||
1921 | =head2 Pretty-Print A Directory Recursively | |
1922 | ||
1923 | use strict; | |
1924 | use vars qw( $a $b ); | |
1925 | ||
1926 | use File::Util qw( NL ); | |
1927 | my($ind) = ''; | |
1928 | my($f) = File::Util->new(); | |
1929 | my(@o) = qw( | |
1930 | --with-paths | |
1931 | --sl-after-dirs | |
1932 | --no-fsdots | |
1933 | --files-as-ref | |
1934 | --dirs-as-ref | |
1935 | ); | |
1936 | ||
1937 | my($filetree) = {}; | |
1938 | my($treetrunk) = '/var/'; | |
1939 | my($subdirs,$sfiles) = $f->list_dir($treetrunk, @o); | |
1940 | ||
1941 | $filetree = [{ | |
1942 | $treetrunk => [ sort({ uc $a cmp uc $b } @$subdirs, @$sfiles) ] | |
1943 | }]; | |
1944 | ||
1945 | descend($filetree->[0]{ $treetrunk },scalar(@$subdirs)); | |
1946 | walk(@$filetree); | |
1947 | ||
1948 | sub descend { | |
1949 | my($parent,$dirnum) = @_; | |
1950 | for (my($i) = 0; $i < $dirnum; ++$i) { | |
1951 | my($current) = $parent->[$i]; next unless -d $current; | |
1952 | my($subdirs,$sfiles) = $f->list_dir($current, @o); | |
1953 | map { $_ = $f->strip_path($_) } @$sfiles; | |
1954 | splice(@$parent,$i,1,{ | |
1955 | $current => [ sort({ uc $a cmp uc $b } @$subdirs, @$sfiles) ] | |
1956 | }); | |
1957 | descend($parent->[$i]{ $current },scalar(@$subdirs)); | |
1958 | } | |
1959 | $parent | |
1960 | } | |
1961 | ||
1962 | sub walk { | |
1963 | my($dir) = shift(@_); | |
1964 | foreach (@{ [ %$dir ]->[1] }) { | |
1965 | my($mem) = $_; | |
1966 | if (ref($mem) eq 'HASH') { | |
1967 | print($ind . $f->strip_path([ %$mem ]->[0]) . '/',NL); | |
1968 | $ind .= ' ' x 3; | |
1969 | walk($mem); | |
1970 | $ind = substr($ind,3); | |
1971 | } else { print($ind . $mem,NL) } | |
1972 | } | |
1973 | } | |
1974 | ||
1975 | =head1 BUGS | |
1976 | ||
1977 | Send bug reports to the AUTHOR. There are no known bugs at this time. | |
1978 | ||
1979 | =head1 TODO | |
1980 | ||
1981 | Add full support for PerlIO layers in C<File::Util::open_handle()> and possibly | |
1982 | C<File::Util::write_file()>. | |
1983 | ||
1984 | =head1 AUTHOR | |
1985 | ||
1986 | Tommy Butler <L<cpan@atrixnet.com|mailto:cpan@atrixnet.com>> | |
1987 | ||
1988 | =head1 COPYRIGHT | |
1989 | ||
1990 | Copyright(C) 2001-2007, Tommy Butler. All rights reserved. | |
1991 | ||
1992 | =head1 LICENSE | |
1993 | ||
1994 | This library is free software, you may redistribute and/or modify it under | |
1995 | the same terms as Perl itself. | |
1996 | ||
1997 | =head1 SEE ALSO | |
1998 | ||
1999 | L<File::Slurp>, L<Exception::Handler>, L<Class::OOorNO> |
0 | ||
1 | use strict; | |
2 | use Test; | |
3 | ||
4 | # use a BEGIN block so we print our plan before MyModule is loaded | |
5 | BEGIN { plan tests => 1, todo => [] } | |
6 | ||
7 | # load your module... | |
8 | use lib './'; | |
9 | use File::Util; | |
10 | ||
11 | # check object constructor | |
12 | ok(ref(File::Util->new()),'File::Util'); | |
13 | ||
14 | exit;⏎ |
0 | ||
1 | use strict; | |
2 | use Test; | |
3 | ||
4 | # use a BEGIN block so we print our plan before MyModule is loaded | |
5 | BEGIN { plan tests => 2, todo => [] } | |
6 | BEGIN { $| = 1 } | |
7 | ||
8 | # load your module... | |
9 | use lib './'; | |
10 | use File::Util; | |
11 | ||
12 | my($f) = File::Util->new(); | |
13 | ||
14 | # check to see if File::Util ISA [foo, etc.] | |
15 | ok(UNIVERSAL::isa($f,'File::Util')); | |
16 | ok(UNIVERSAL::isa($f,'Class::OOorNO')); | |
17 | ||
18 | exit;⏎ |
0 | ||
1 | use strict; | |
2 | use Test; | |
3 | ||
4 | # use a BEGIN block so we print our plan before MyModule is loaded | |
5 | BEGIN { plan tests => 37, todo => [] } | |
6 | BEGIN { $| = 1 } | |
7 | ||
8 | # load your module... | |
9 | use lib './'; | |
10 | use File::Util; | |
11 | ||
12 | my($f) = File::Util->new(); | |
13 | ||
14 | # check to see if non-autoloaded File::Util methods are can-able ;O) | |
15 | map { ok(ref(UNIVERSAL::can($f,$_)),'CODE') } qw | |
16 | ( | |
17 | _dropdots | |
18 | _errors | |
19 | _release | |
20 | _seize | |
21 | _throw | |
22 | bitmask | |
23 | can_flock | |
24 | can_read | |
25 | can_write | |
26 | created | |
27 | ebcdic | |
28 | escape_filename | |
29 | existent | |
30 | file_type | |
31 | isbin | |
32 | last_access | |
33 | last_modified | |
34 | line_count | |
35 | list_dir | |
36 | load_dir | |
37 | load_file | |
38 | flock_rules | |
39 | make_dir | |
40 | max_dives | |
41 | needs_binmode | |
42 | new | |
43 | open_handle | |
44 | readlimit | |
45 | size | |
46 | strip_path | |
47 | trunc | |
48 | use_flock | |
49 | write_file | |
50 | valid_filename | |
51 | VERSION | |
52 | DESTROY | |
53 | AUTOLOAD | |
54 | ); | |
55 | ||
56 | exit; |
0 | ||
1 | use strict; | |
2 | use Test; | |
3 | ||
4 | # use a BEGIN block so we print our plan before MyModule is loaded | |
5 | BEGIN { plan tests => 46, todo => [] } | |
6 | BEGIN { $| = 1 } | |
7 | ||
8 | # load your module... | |
9 | use lib './'; | |
10 | use File::Util qw | |
11 | ( | |
12 | SL NL escape_filename | |
13 | valid_filename strip_path needs_binmode | |
14 | ); | |
15 | ||
16 | my($f) = File::Util->new(); | |
17 | ||
18 | # check asignability | |
19 | my($NL) = NL; my($SL) = SL; | |
20 | ||
21 | # newlines | |
22 | ok(NL eq $NL); # test 1 | |
23 | ||
24 | # binmode necessary? | |
25 | ok(needs_binmode, NL eq qq[\015\012] ? 1 : 0); # test 2 | |
26 | ||
27 | # path seperator | |
28 | ok(SL eq $SL); # test 3 | |
29 | ||
30 | # test file escaping with substitute escape char | |
31 | # with additional char to escape as well. | |
32 | ok # test 4 | |
33 | ( | |
34 | escape_filename(q[./foo/bar/baz.t/], '+','.'), | |
35 | '++foo+bar+baz+t+' | |
36 | ); | |
37 | ||
38 | # test file escaping with defaults | |
39 | ok # test 5 | |
40 | ( | |
41 | escape_filename(q[.\foo\bar\baz.t]), | |
42 | '._foo_bar_baz.t' | |
43 | ); | |
44 | ||
45 | # test file escaping with option "--strip-path" | |
46 | ok # test 6 | |
47 | ( | |
48 | escape_filename | |
49 | ( | |
50 | q[.:foo:bar:baz.t], | |
51 | '--strip-path' | |
52 | ), | |
53 | 'baz.t' | |
54 | ); | |
55 | ||
56 | # path stripping in general | |
57 | ok(strip_path(__FILE__),'004_portable.t'); # test 7 | |
58 | ||
59 | # illegal filename character intolerance | |
60 | ok(!valid_filename(qq[?foo])); # question mark | |
61 | ok(!valid_filename(qq[>foo])); # greater than | |
62 | ok(!valid_filename(qq[<foo])); # less than | |
63 | ok(!valid_filename(qq[<foo])); # less than | |
64 | ok(!valid_filename(qq[<foo])); # less than | |
65 | ok(!valid_filename(qq[<foo])); # less than | |
66 | ok(!valid_filename(qq[:foo])); # colon | |
67 | ok(!valid_filename(qq[*foo])); # asterisk | |
68 | ok(!valid_filename(qq[/foo])); # forward slash | |
69 | ok(!valid_filename(qq[\\foo])); # back slash | |
70 | ok(!valid_filename(qq["foo])); # double quotation mark | |
71 | ok(!valid_filename(qq[\tfoo])); # tab | |
72 | ok(!valid_filename(qq[\013foo])); # vertical tab | |
73 | ok(!valid_filename(qq[\012foo])); # newline | |
74 | ok(!valid_filename(qq[\015foo])); # form feed | |
75 | ||
76 | # strange but legal filename character tolerance | |
77 | ok(valid_filename(q['foo])); | |
78 | ok(valid_filename(';foo')); | |
79 | ok(valid_filename('$foo')); | |
80 | ok(valid_filename('%foo')); | |
81 | ok(valid_filename('`foo')); | |
82 | ok(valid_filename('!foo')); | |
83 | ok(valid_filename('@foo')); | |
84 | ok(valid_filename('#foo')); | |
85 | ok(valid_filename('^foo')); | |
86 | ok(valid_filename('&foo')); | |
87 | ok(valid_filename('-foo')); | |
88 | ok(valid_filename('_foo')); | |
89 | ok(valid_filename('+foo')); | |
90 | ok(valid_filename('=foo')); | |
91 | ok(valid_filename('(foo')); | |
92 | ok(valid_filename(')foo')); | |
93 | ok(valid_filename('{foo')); | |
94 | ok(valid_filename('}foo')); | |
95 | ok(valid_filename('[foo')); | |
96 | ok(valid_filename(']foo')); | |
97 | ok(valid_filename('~foo')); | |
98 | ok(valid_filename('.foo')); | |
99 | ok(valid_filename(q/;$%`!@#^&-_+=(){}[]~baz.foo'/)); | |
100 | ||
101 | # directory listing tests... | |
102 | # remove '.' and '..' directory entries | |
103 | ok(length(join('',$f->_dropdots(qw(. .. foo bar baz)))),9); | |
104 | ||
105 | exit; |
0 | ||
1 | use strict; | |
2 | use Test; | |
3 | ||
4 | # use a BEGIN block so we print our plan before MyModule is loaded | |
5 | BEGIN { plan tests => 35, todo => [] } | |
6 | BEGIN { $| = 1 } | |
7 | ||
8 | # load your module... | |
9 | use lib './'; | |
10 | use File::Util qw( SL OS ); | |
11 | ||
12 | my($f) = File::Util->new(); | |
13 | ||
14 | my(@fls) = ( qq[t${\SL}txt], qq[t${\SL}bin], 't', '.', '..' ); | |
15 | my($skip) = (OS eq 'WINDOWS') ? 'Running on window$' : 0; | |
16 | ||
17 | # types | |
18 | ok(join('',@{[$f->file_type($fls[0])]}), 'PLAINTEXT'); | |
19 | ok(join('',@{[$f->file_type($fls[1])]}), 'PLAINBINARY'); | |
20 | ||
21 | # skip if windows | |
22 | skip($skip, join('',@{[$f->file_type($fls[2])]}), 'BINARYDIRECTORY', $skip); | |
23 | skip($skip, join('',@{[$f->file_type($fls[3])]}), 'BINARYDIRECTORY', $skip); | |
24 | skip($skip, join('',@{[$f->file_type($fls[4])]}), 'BINARYDIRECTORY', $skip); | |
25 | ||
26 | # chk these on windows | |
27 | skip(!$skip, join('',@{[$f->file_type($fls[2])]}), 'DIRECTORY'); | |
28 | skip(!$skip, join('',@{[$f->file_type($fls[3])]}), 'DIRECTORY'); | |
29 | skip(!$skip, join('',@{[$f->file_type($fls[4])]}), 'DIRECTORY'); | |
30 | ||
31 | ||
32 | # file is/isn't binary | |
33 | ok($f->isbin($fls[1], 1)); | |
34 | ok(!$f->isbin(__FILE__)); | |
35 | ||
36 | foreach (@fls) { | |
37 | ||
38 | my($file) = $_; | |
39 | ||
40 | # get file size | |
41 | ok($f->size($file), -s $file); | |
42 | ||
43 | # get file creation time | |
44 | ok($f->created($file),$^T - ((-M $file) * 60 * 60 * 24)); | |
45 | ||
46 | # get file last access time | |
47 | ok($f->last_access($file),$^T - ((-A $file) * 60 * 60 * 24)); | |
48 | ||
49 | # get file last modified time | |
50 | ok($f->last_modified($file),$^T - ((-M $file) * 60 * 60 * 24)); | |
51 | ||
52 | # get file's bitmask | |
53 | ok($f->bitmask($file),sprintf('%04o',(stat($file))[2] & 0777)); | |
54 | } | |
55 | ||
56 | exit; |
0 | ||
1 | use strict; | |
2 | use Test; | |
3 | ||
4 | # use a BEGIN block so we print our plan before File::Util is loaded | |
5 | BEGIN { plan tests => 13, todo => [] } | |
6 | BEGIN { $| = 1 } | |
7 | ||
8 | # load your module... | |
9 | use lib './'; | |
10 | use File::Util qw( SL NL existent ); | |
11 | ||
12 | my($f) = File::Util->new('--fatals-as-status'); | |
13 | my($fh) = undef; | |
14 | my($testbed) = 't' . SL . $$; | |
15 | my($skip) = !$f->can_write('.') || | |
16 | !$f->can_write('t'); | |
17 | ||
18 | $skip = $skip ? &skipmsg() : $skip; | |
19 | ||
20 | sub skipmsg { <<'__WHYSKIP__' } | |
21 | Insufficient permissions to perform IO in this directory. Can't perform tests! | |
22 | __WHYSKIP__ | |
23 | ||
24 | # 1 | |
25 | # make a temporary testbed directory | |
26 | skip($skip, sub { $f->make_dir($testbed, '--if-not-exists') }, $testbed); | |
27 | ||
28 | # 2 | |
29 | # see if it's there | |
30 | skip($skip, -e $testbed, 1, $skip); | |
31 | ||
32 | # 3 | |
33 | # ...again | |
34 | skip($skip, sub { $f->existent($testbed) }, 1, $skip); | |
35 | ||
36 | # 4 | |
37 | # make a temporary file | |
38 | my($tmpf) = $testbed . SL . 'tmptst'; | |
39 | skip( | |
40 | $skip, | |
41 | sub { | |
42 | $f->write_file('file' => $tmpf, 'content' => $$ . NL), | |
43 | }, 1, $skip | |
44 | ); | |
45 | ||
46 | # 5 | |
47 | # File::Util::touch() a file, and see if it was created ok | |
48 | skip( | |
49 | $skip, | |
50 | sub { | |
51 | my($tmpf) = $testbed . SL . 'touched'; | |
52 | $f->touch($tmpf); | |
53 | my($return) = $f->existent($tmpf); | |
54 | unlink($tmpf); | |
55 | return($return); | |
56 | }, 1, $skip | |
57 | ); | |
58 | ||
59 | # 6 | |
60 | # get an open file handle | |
61 | $fh = ''; | |
62 | skip( | |
63 | $skip, | |
64 | sub { | |
65 | $fh = $f->open_handle( | |
66 | 'file' => $tmpf, | |
67 | 'mode' => 'append', | |
68 | qw(--fatals-as-errmsg --warn-also) | |
69 | ); | |
70 | $skip = &skipmsg() unless ($fh && length($fh) > 1); | |
71 | return 1; # stupid solaris testers won't play fair | |
72 | }, | |
73 | 1, | |
74 | $skip | |
75 | ); | |
76 | ||
77 | # 7 | |
78 | # make sure it's still open | |
79 | skip($skip, eval(q{fileno($fh)}), '/^\d/', $skip); | |
80 | ||
81 | # write to it, close it, write to it in append mode | |
82 | unless ($skip) { print( $fh 'Hello world!' . NL ); close($fh); } | |
83 | ||
84 | # 8 | |
85 | # load file | |
86 | skip($skip, sub { $f->load_file($tmpf),$f->load_file($tmpf) }); | |
87 | ||
88 | # 9 | |
89 | # write to it with method File::Util::write_file(), compare file contents | |
90 | # with the returned value | |
91 | skip ( | |
92 | $skip, | |
93 | sub { | |
94 | $f->write_file( | |
95 | 'filename' => $tmpf, | |
96 | 'content' => ( $^O || 'foo' ) . NL, | |
97 | 'mode' => 'append', | |
98 | ) | |
99 | }, 1, $skip | |
100 | ); | |
101 | ||
102 | # 10 | |
103 | # get line count of file | |
104 | skip($skip, sub { $f->line_count($tmpf) }, 3, $skip); | |
105 | ||
106 | # 11 | |
107 | # truncate file | |
108 | skip($skip, sub { $f->trunc($tmpf); -s $tmpf }, 0, $skip); | |
109 | ||
110 | # 12 | |
111 | # get line count of file | |
112 | skip($skip, sub { $f->line_count($tmpf)}, 0, $skip); | |
113 | ||
114 | # big directory creation / removal sequence | |
115 | my($newdir) = | |
116 | $testbed | |
117 | . SL . int(rand(time)) | |
118 | . SL . int(rand(time)) | |
119 | . SL . int(rand(time)) | |
120 | . SL . int(rand(time)); | |
121 | ||
122 | # 13 | |
123 | # make directories | |
124 | skip($skip, sub { $f->make_dir($newdir, '--if-not-exists') }, $newdir, $skip); | |
125 | ||
126 | # read directories | |
127 | unless ($skip) { | |
128 | my(@items) = $f->list_dir($testbed, '--follow'); | |
129 | ||
130 | # remove directories, temp file, testbed. | |
131 | foreach (reverse(sort({ length($a) <=> length($b) } @items)), $testbed) { | |
132 | ||
133 | -d $_ ? rmdir($_) || &_rmdie($!) : unlink($_) || &_uldie($!); | |
134 | } | |
135 | } | |
136 | ||
137 | exit; | |
138 | ||
139 | # ---- SUBS ----------------------------------------------- | |
140 | ||
141 | sub _uldie { die(<<__BADUNLINK__) } | |
142 | Can't unlink recently created temp file used in testing process. | |
143 | $! | |
144 | __BADUNLINK__ | |
145 | ||
146 | sub _rmdie { die(<<__BADRMDIR__) } | |
147 | Can't remove recently created temporary directory used in testing process. | |
148 | $! | |
149 | __BADRMDIR__ |
0 | ||
1 | use strict; | |
2 | use Test; | |
3 | ||
4 | # use a BEGIN block so we print our plan before MyModule is loaded | |
5 | BEGIN { plan tests => 12, todo => [] } | |
6 | BEGIN { $| = 1 } | |
7 | ||
8 | # load your module... | |
9 | use lib './'; | |
10 | use Fcntl qw( ); | |
11 | ||
12 | use File::Util qw( SL NL ); | |
13 | my($f) = File::Util->new(); | |
14 | my($tmpf) = 'flock_test'; | |
15 | my($probe_flock) = sub { local($@); eval(<<'__canflock__'); $@ ? 0 : 1 }; | |
16 | flock(STDIN, &Fcntl::LOCK_SH); | |
17 | flock(STDIN, &Fcntl::LOCK_UN); | |
18 | __canflock__ | |
19 | my($skip) = !$f->can_write('.') || !$f->can_write('t'); | |
20 | ||
21 | $skip = $skip ? &skipmsg() : $skip; | |
22 | ||
23 | # using flock? get/set flock-ing usage toggle | |
24 | ok($f->use_flock( ),1); # test 1 | |
25 | ok($f->use_flock(1),1); # test 2 | |
26 | ok($f->use_flock(0),0); # test 3 | |
27 | ok($f->use_flock( ),0); # test 4 | |
28 | ok($f->use_flock(1),1); # test 5 | |
29 | ||
30 | # get/set flock-ing failure policy | |
31 | ok(qq[@{[$f->flock_rules()]}],'NOBLOCKEX FAIL'); # test 6 | |
32 | ok(join(' ', $f->flock_rules(qw/ NOBLOCKEX ZERO /)),q[NOBLOCKEX ZERO]);# test 7 | |
33 | ||
34 | # can the system lock file IO? does it? | |
35 | skip(!$probe_flock, $f->can_flock, 1); # test 8 | |
36 | ||
37 | # does it really work? | |
38 | skip(!$probe_flock, &test_flock()); # test 9 | |
39 | ||
40 | exit; | |
41 | ||
42 | # put flock to the "test" | |
43 | sub test_flock { | |
44 | ||
45 | # lock file, keep open handle on it | |
46 | my($fh); | |
47 | ||
48 | unless ($skip) { | |
49 | $fh = $f->open_handle('file' => $tmpf); | |
50 | ||
51 | # write something into the file | |
52 | my($tstr) = 'Hello world!' . NL; | |
53 | print($fh $tstr x 50); | |
54 | ||
55 | } | |
56 | ||
57 | # try to $f->trunc locked file (should fail) | |
58 | skip( | |
59 | $skip, | |
60 | sub { # test 10 | |
61 | ||
62 | # FORKING!! | |
63 | my($pid) = fork; $| = 1; die(qq{Can't fork: $!}) unless defined($pid); | |
64 | ||
65 | if (!$pid) { $f->trunc($tmpf); exit } else { waitpid($pid, 0) } | |
66 | ||
67 | # DONE WITH THAT NOW. | |
68 | -s $tmpf | |
69 | }); | |
70 | ||
71 | # test 11 - try to $f->write_file on locked file (should fail) | |
72 | skip( | |
73 | $skip, | |
74 | sub { | |
75 | ||
76 | # FORKING!! | |
77 | my($pid) = fork; $| = 1; die(qq{Can't fork: $!}) unless defined($pid); | |
78 | ||
79 | if (!$pid) { | |
80 | ||
81 | $f->write_file( | |
82 | 'file' => $tmpf, | |
83 | 'content' => '', | |
84 | '--empty-writes-OK' | |
85 | ); | |
86 | ||
87 | exit | |
88 | } | |
89 | else { waitpid($pid, 0) } | |
90 | ||
91 | # DONE WITH THAT NOW. | |
92 | -s $tmpf | |
93 | }); | |
94 | ||
95 | # unlock file | |
96 | close($fh) unless $skip; | |
97 | ||
98 | # test 12 - try to trunc the file; should succeed | |
99 | # - skip this on solaris... | |
100 | if ($^O =~ /solaris/i) { | |
101 | skip(&skip_trunc_solaris(), 0, 0); | |
102 | } | |
103 | else { | |
104 | skip($skip, sub { $f->trunc($tmpf); return -s $tmpf }, 0); | |
105 | } | |
106 | ||
107 | # try to delete the file; should succeed | |
108 | unlink($tmpf) unless $skip; | |
109 | ||
110 | !-e $tmpf; | |
111 | } | |
112 | ||
113 | sub skipmsg { <<'__WHYSKIP__' } | |
114 | Insufficient permissions to perform IO in this directory. Can't perform tests! | |
115 | __WHYSKIP__ | |
116 | ||
117 | sub skip_trunc_solaris { <<'__WHYSKIP__' } | |
118 | Solaris can flock, but won't let go of discretionary lock yet. | |
119 | __WHYSKIP__ | |
120 |
0 | ||
1 | use strict; | |
2 | use Test; | |
3 | ||
4 | # use a BEGIN block so we print our plan before module is loaded | |
5 | BEGIN { use File::Util } | |
6 | BEGIN { plan tests => scalar(@File::Util::EXPORT_OK), todo => [] } | |
7 | BEGIN { $| = 1 } | |
8 | ||
9 | # load your module... | |
10 | use lib './'; | |
11 | ||
12 | # we gonna see if'n it cun export wut itz 'pose ta. this checks the | |
13 | # @EXPORT_OK of all packages in the inheritance cascade, which is the | |
14 | # only reason we're doing this. we already know that it UNIVERSAL::can do | |
15 | # all its own methods if this test is being run. test 3 ensures that. | |
16 | # this is just an automated non-empty superclass test | |
17 | use File::Util @File::Util::EXPORT_OK; | |
18 | ||
19 | map { | |
20 | ||
21 | ok ref(UNIVERSAL::can('File::Util', $_)) eq 'CODE' | |
22 | ||
23 | } @File::Util::EXPORT_OK; | |
24 | ||
25 | exit; |
0 | ||
1 | use strict; | |
2 | use Test; | |
3 | ||
4 | # use a BEGIN block so we print our plan before module is loaded | |
5 | BEGIN { use File::Util } | |
6 | BEGIN { plan tests => scalar(@File::Util::EXPORT_OK), todo => [] } | |
7 | BEGIN { $| = 1 } | |
8 | ||
9 | # load your module... | |
10 | use lib './'; | |
11 | ||
12 | # automated empty subclass test | |
13 | ||
14 | # subclass File::Util in package _Foo | |
15 | package _Foo; | |
16 | use strict; | |
17 | use warnings; | |
18 | use File::Util qw( :all ); | |
19 | $Foo::VERSION = 0.00_0; | |
20 | @_Foo::ISA = qw( File::Util ); | |
21 | 1; | |
22 | ||
23 | # switch back to main package | |
24 | package main; | |
25 | ||
26 | # see if _Foo can do everything that File::Util can do | |
27 | map { | |
28 | ||
29 | ok ref(UNIVERSAL::can('_Foo', $_)) eq 'CODE' | |
30 | ||
31 | } @File::Util::EXPORT_OK; | |
32 | ||
33 | ||
34 | exit; |
0 | ||
1 | use strict; | |
2 | use Test; | |
3 | ||
4 | # use a BEGIN block so we print our plan before MyModule is loaded | |
5 | BEGIN { plan tests => 31, todo => [] } | |
6 | BEGIN { $| = 1 } | |
7 | ||
8 | # load your module... | |
9 | use lib './'; | |
10 | use File::Util qw( SL NL existent ); | |
11 | ||
12 | my($f) = File::Util->new('--fatals-as-errmsg'); | |
13 | ||
14 | # start testing failure sequence | |
15 | ok($f->_throw('no such file' => { 'filename' => __FILE__ }, '--fatals-as-errmsg' ), | |
16 | q{/no such file or directory exists/}, | |
17 | q{Bad failure return code for error: "no such file"} | |
18 | ); | |
19 | ||
20 | ok( | |
21 | $f->_throw( | |
22 | 'bad flock rules' => { | |
23 | 'bad' => __FILE__, | |
24 | 'all' => [ $f->flock_rules() ], | |
25 | } | |
26 | ), | |
27 | q{/Invalid file locking policy/}, | |
28 | q{Bad failure return code for error: "bad flock rules"} | |
29 | ); | |
30 | ||
31 | ok( | |
32 | $f->_throw( | |
33 | 'cant fread' => { | |
34 | 'filename' => __FILE__, | |
35 | 'dirname' => '.', | |
36 | } | |
37 | ), | |
38 | q{/Permissions conflict\..+?can't read the contents of this file:/}, | |
39 | q{Bad failure return code for error: "cant fread"} | |
40 | ); | |
41 | ||
42 | ok($f->_throw('cant fread not found' => { 'filename' => __FILE__, }), | |
43 | q{/File not found\. .+?can't read the contents of this file\:/}, | |
44 | q{Bad failure return code for error: "cant fread no exists"} | |
45 | ); | |
46 | ||
47 | ok( | |
48 | $f->_throw( | |
49 | 'cant fcreate' => { | |
50 | 'filename' => __FILE__, | |
51 | 'dirname' => '.', | |
52 | } | |
53 | ), | |
54 | q{/Permissions conflict\..+?can't create this file:/}, | |
55 | q{Bad failure return code for error: "cant fcreate"} | |
56 | ); | |
57 | ||
58 | ok($f->_throw('cant write_file on a dir' => { 'filename' => __FILE__, }), | |
59 | q{/can't write to the specified file/}, | |
60 | q{Bad failure return code for error: "cant write_file on a dir"} | |
61 | ); | |
62 | ||
63 | ok( | |
64 | $f->_throw( | |
65 | 'cant fwrite' => { | |
66 | 'filename' => __FILE__, | |
67 | 'dirname' => '.', | |
68 | } | |
69 | ), | |
70 | q{/Permissions conflict\..+?can't write to this file:/}, | |
71 | q{Bad failure return code for error: "cant fwrite"} | |
72 | ); | |
73 | ||
74 | ok( | |
75 | $f->_throw( | |
76 | 'bad openmode popen' => { | |
77 | 'filename' => __FILE__, | |
78 | 'badmode' => 'illegal', | |
79 | 'meth' => 'anonymous', | |
80 | } | |
81 | ), | |
82 | q{/Illegal mode specified for file open\./}, | |
83 | q{Bad failure return code for error: "bad openmode popen"} | |
84 | ); | |
85 | ||
86 | ok( | |
87 | $f->_throw( | |
88 | 'bad openmode sysopen' => { | |
89 | 'filename' => __FILE__, | |
90 | 'badmode' => 'illegal', | |
91 | 'meth' => 'anonymous', | |
92 | } | |
93 | ), | |
94 | q{/Illegal mode specified for file sysopen/}, | |
95 | q{Bad failure return code for error: "bad openmode sysopen"} | |
96 | ); | |
97 | ||
98 | ok($f->_throw('cant dread' => { 'dirname' => '.' } ), | |
99 | q{/Permissions conflict\..+?can't list the contents of this/}, | |
100 | q{Bad failure return code for error: "cant dread"} | |
101 | ); | |
102 | ||
103 | ok( | |
104 | $f->_throw( | |
105 | 'cant dcreate' => { | |
106 | 'dirname' => '.', | |
107 | 'parentd' => '..', | |
108 | } | |
109 | ), | |
110 | q{/Permissions conflict\..+?can't create:/}, | |
111 | q{Bad failure return code for error: "cant dcreate"} | |
112 | ); | |
113 | ||
114 | ok( | |
115 | $f->_throw( | |
116 | 'make_dir target exists' => { | |
117 | 'dirname' => '.', | |
118 | 'filetype' => qq{@{[$f->file_type('.')]}}, | |
119 | } | |
120 | ), | |
121 | q{/make_dir target already exists\./}, | |
122 | q{Bad failure return code for error: "make_dir target exists"} | |
123 | ); | |
124 | ||
125 | ok( | |
126 | $f->_throw( | |
127 | 'bad open' => { | |
128 | 'mode' => 'illegal mode', | |
129 | 'filename' => __FILE__, | |
130 | 'exception' => 'dummy', | |
131 | 'cmd' => 'illegal cmd', | |
132 | } | |
133 | ), | |
134 | q{/can't open this file for .illegal mode.:/}, | |
135 | q{Bad failure return code for error: "bad open"} | |
136 | ); | |
137 | ||
138 | ok( | |
139 | $f->_throw( | |
140 | 'bad close' => { | |
141 | 'mode' => 'illegal mode', | |
142 | 'filename' => __FILE__, | |
143 | 'exception' => 'dummy', | |
144 | } | |
145 | ), | |
146 | q{/couldn't close this file after .illegal mode./}, | |
147 | q{Bad failure return code for error: "bad close"} | |
148 | ); | |
149 | ||
150 | ok( | |
151 | $f->_throw( | |
152 | 'bad systrunc' => { | |
153 | 'filename' => __FILE__, | |
154 | 'exception' => 'dummy', | |
155 | } | |
156 | ), | |
157 | q{/couldn't truncate\(\) on.+?after having/}, | |
158 | q{Bad failure return code for error: "bad systrunc"} | |
159 | ); | |
160 | ||
161 | ok( | |
162 | $f->_throw( | |
163 | 'bad flock' => { | |
164 | 'filename' => __FILE__, | |
165 | 'exception' => 'illegal', | |
166 | } | |
167 | ), | |
168 | q{/can't get a lock on the file/}, | |
169 | q{Bad failure return code for error: "bad flock"} | |
170 | ); | |
171 | ||
172 | ok($f->_throw('called open on a dir' => { 'filename' => __FILE__ }), | |
173 | q{/can't call open\(\) on this file because it is a directory/}, | |
174 | q{Bad failure return code for error: "called open on a dir"} | |
175 | ); | |
176 | ||
177 | ok($f->_throw('called opendir on a file' => { 'filename' => __FILE__ }), | |
178 | q{/can't opendir\(\) on this file because it is not a directory/}, | |
179 | q{Bad failure return code for error: "called opendir on a file"} | |
180 | ); | |
181 | ||
182 | ok($f->_throw('called mkdir on a file' => { 'filename' => __FILE__ }), | |
183 | q{/can't auto-create a directory for this path name because/}, | |
184 | q{Bad failure return code for error: "called mkdir on a file"} | |
185 | ); | |
186 | ||
187 | ok($f->_throw('bad readlimit' => {}), | |
188 | q{/Bad call to .+?\:\:readlimit\(\)\. This method can only be/}, | |
189 | q{Bad failure return code for error: "bad readlimit"} | |
190 | ); | |
191 | ok( | |
192 | $f->_throw( | |
193 | 'readlimit exceeded' => { | |
194 | 'filename' => __FILE__, | |
195 | 'size' => 'testtesttest', | |
196 | } | |
197 | ), | |
198 | q{/(?sm)can't load file.+?into memory because its size exceeds/}, | |
199 | q{Bad failure return code for error: "readlimit exceeded"} | |
200 | ); | |
201 | ||
202 | ok($f->_throw('bad maxdives' => {}), | |
203 | q{/Bad call to .+?\:\:max_dives\(\)\. This method can only be/}, | |
204 | q{Bad failure return code for error: "bad maxdives"} | |
205 | ); | |
206 | ||
207 | ok($f->_throw('maxdives exceeded' => {}), | |
208 | q{/Recursion limit reached at .+?dives\. Maximum number of/}, | |
209 | q{Bad failure return code for error: "maxdives exceeded"} | |
210 | ); | |
211 | ||
212 | ok( | |
213 | $f->_throw( | |
214 | 'bad opendir' => { | |
215 | 'dirname' => '.', | |
216 | 'exception' => 'illegal', | |
217 | } | |
218 | ), | |
219 | q{/can't opendir on directory\:/}, | |
220 | q{Bad failure return code for error: "bad opendir"} | |
221 | ); | |
222 | ||
223 | ok( | |
224 | $f->_throw( | |
225 | 'bad make_dir' => { | |
226 | 'dirname' => '.', | |
227 | 'bitmask' => 0777, | |
228 | 'exception' => 'illegal', | |
229 | 'meth' => 'anonymous', | |
230 | } | |
231 | ), | |
232 | q{/had a problem with the system while attempting to create/}, | |
233 | q{Bad failure return code for error: "bad make_dir"} | |
234 | ); | |
235 | ||
236 | ok( | |
237 | $f->_throw( | |
238 | 'bad chars' => { | |
239 | 'string' => 'illegal characters', | |
240 | 'purpose' => 'testing', | |
241 | } | |
242 | ), | |
243 | q{/(?sm)can't use this string.+?It contains illegal characters\./}, | |
244 | q{Bad failure return code for error: "bad chars"} | |
245 | ); | |
246 | ||
247 | ok($f->_throw('not a filehandle' => { 'argtype' => 'illegal', }), | |
248 | q{/can't unlock file with an invalid file handle reference\:/}, | |
249 | q{Bad failure return code for error: "not a filehandle"} | |
250 | ); | |
251 | ||
252 | ok($f->_throw('no input' => { 'meth' => 'anonymous' }), | |
253 | q{/(?sm)can't honor your call to.+?because you didn't provide/}, | |
254 | q{Bad failure return code for error: "no input"} | |
255 | ); | |
256 | ||
257 | ok($f->_throw('plain error' => 'testtesttest'), | |
258 | q{/failed with the following message\:/}, | |
259 | q{Bad failure return code for error: "plain error"} | |
260 | ); | |
261 | ||
262 | ok($f->_throw('unknown error message', => {}), | |
263 | q{/failed with an invalid error-type designation\./}, | |
264 | q{Bad failure return code for error: "unknown error message"} | |
265 | ); | |
266 | ||
267 | ok($f->_throw('empty error', => {}), | |
268 | q{/failed with an empty error-type designation\./}, | |
269 | q{Bad failure return code for error: "empty error"} | |
270 | ); | |
271 | ||
272 | exit; | |
273 |