1#!/usr/local/bin/perl 2# 3# Heuristically converts line endings to the current OS's preferred format 4# 5# All existing line endings must be identical (e.g. lf's only, or even 6# the accedental cr.cr.lf sequence.) If some lines end lf, and others as 7# cr.lf, the file is presumed binary. If the cr character appears anywhere 8# except prefixed to an lf, the file is presumed binary. If there is no 9# change in the resulting file size, or the file is binary, the conversion 10# is discarded. 11# 12# Todo: Handle NULL stdin characters gracefully. 13# 14 15use IO::File; 16use File::Find; 17 18# The ignore list is '-' seperated, with this leading hyphen and 19# trailing hyphens in ever concatinated list below. 20$ignore = "-"; 21 22# Image formats 23$ignore .= "gif-jpg-jpeg-png-ico-bmp-"; 24 25# Archive formats 26$ignore .= "tar-gz-z-zip-jar-war-bz2-tgz-"; 27 28# Many document formats 29$ignore .= "eps-psd-pdf-chm-ai-"; 30 31# Some encodings 32$ignore .= "ucs2-ucs4-"; 33 34# Some binary objects 35$ignore .= "class-so-dll-exe-obj-lib-a-o-lo-slo-sl-dylib-"; 36 37# Some build env files 38$ignore .= "mcp-xdc-ncb-opt-pdb-ilk-exp-res-pch-idb-sbr-"; 39 40$preservedate = 1; 41 42$forceending = 0; 43 44$givenpaths = 0; 45 46$notnative = 0; 47 48while (defined @ARGV[0]) { 49 if (@ARGV[0] eq '--touch') { 50 $preservedate = 0; 51 } 52 elsif (@ARGV[0] eq '--nocr') { 53 $notnative = -1; 54 } 55 elsif (@ARGV[0] eq '--cr') { 56 $notnative = 1; 57 } 58 elsif (@ARGV[0] eq '--force') { 59 $forceending = 1; 60 } 61 elsif (@ARGV[0] eq '--FORCE') { 62 $forceending = 2; 63 } 64 elsif (@ARGV[0] =~ m/^-/) { 65 die "What is " . @ARGV[0] . " supposed to mean?\n\n" 66 . "Syntax:\t$0 [option()s] [path(s)]\n\n" . <<'OUTCH' 67Where: paths specifies the top level directory to convert (default of '.') 68 options are; 69 70 --cr keep/add one ^M 71 --nocr remove ^M's 72 --touch the datestamp (default: keeps date/attribs) 73 --force mismatched corrections (unbalanced ^M's) 74 --FORCE all files regardless of file name! 75 76OUTCH 77 } 78 else { 79 find(\&totxt, @ARGV[0]); 80 print "scanned " . @ARGV[0] . "\n"; 81 $givenpaths = 1; 82 } 83 shift @ARGV; 84} 85 86if (!$givenpaths) { 87 find(\&totxt, '.'); 88 print "did .\n"; 89} 90 91sub totxt { 92 $oname = $_; 93 $tname = '.#' . $_; 94 if (!-f) { 95 return; 96 } 97 @exts = split /\./; 98 if ($forceending < 2) { 99 while ($#exts && ($ext = pop(@exts))) { 100 if ($ignore =~ m|-$ext-|i) { 101 return; 102 } 103 } 104 } 105 return if ($File::Find::dir =~ m|^(.+/)?.svn(/.+)?$|); 106 @ostat = stat($oname); 107 $srcfl = new IO::File $oname, "r" or die; 108 $dstfl = new IO::File $tname, "w" or die; 109 binmode $srcfl; 110 if ($notnative) { 111 binmode $dstfl; 112 } 113 undef $t; 114 while (<$srcfl>) { 115 if (s/(\r*)\n$/\n/) { 116 $n = length $1; 117 if (!defined $t) { 118 $t = $n; 119 } 120 if (!$forceending && (($n != $t) || m/\r/)) { 121 print "mismatch in " .$oname. ":" .$n. " expected " .$t. "\n"; 122 undef $t; 123 last; 124 } 125 elsif ($notnative > 0) { 126 s/\n$/\r\n/; 127 } 128 } 129 print $dstfl $_; 130 } 131 if (defined $t && (tell $srcfl == tell $dstfl)) { 132 undef $t; 133 } 134 undef $srcfl; 135 undef $dstfl; 136 if (defined $t) { 137 unlink $oname or die; 138 rename $tname, $oname or die; 139 @anames = ($oname); 140 if ($preservedate) { 141 utime $ostat[9], $ostat[9], @anames; 142 } 143 chmod $ostat[2] & 07777, @anames; 144 chown $ostat[5], $ostat[6], @anames; 145 print "Converted file " . $oname . " to text in " . $File::Find::dir . "\n"; 146 } 147 else { 148 unlink $tname or die; 149 } 150} 151