#!/usr/bin/php
<?php

/*

UNIXCONV, Version 2009-08-05
(C) 2009 ViaThinkSoft

UNIXCONV wandelt alle Windows- und Macintosh-Zeilenumbrüche in das LF Unix-Format um.

Dieses Format ist z.B. bei *.sh dringend erforderlich.

Verwendung
	php unixconv.php <verzeichnis> [-fix] [-nolist]

Ohne die Angabe von -fix wird nur eine Auflistung durchgeführt.

*/

// Konfig

define('SHOW_OUTPUT', true); // gilt nicht für Fehler
define('RECURSIVE_DIR', true);

$allowed_ext = array();
$allowed_ext[] = "*.sh";

$exclude_ext = array();

$max_fsize = 2; // MB

/* ------------ */

if (isset($_SERVER["SERVER_NAME"]))
{
	die("Bitte f&uuml;hren Sie dieses Script separat &uuml;ber den PHP-Interpreter aus.\n");
}

if (($_SERVER['argc'] == 1) || ($_SERVER['argc'] > 4) ||
  (($_SERVER['argv'][2] != '') && ($_SERVER['argv'][2] != '-fix') && ($_SERVER['argv'][2] != '-nolist')) ||
  (($_SERVER['argv'][3] != '') && ($_SERVER['argv'][3] != '-fix') && ($_SERVER['argv'][3] != '-nolist')))
{
        die("Verwendung: php unixconv.php <verzeichnis> [-fix] [-nolist]\n");
}

$my_dir = $_SERVER['argv'][1];
$do_fix = ($_SERVER['argv'][2] == '-fix') || ($_SERVER['argv'][3] == '-fix');
$no_list = ($_SERVER['argv'][2] == '-nolist') || ($_SERVER['argv'][3] == '-nolist');

define('CR', "\r");
define('LF', "\n");
define('CRLF', CR.LF);

function normalizeToUnixLineBreaks($text, &$count_crlf=0, &$count_cr=0, &$count_lf=0) {
	$text = str_replace(CRLF, LF, $text, $count_crlf);
	$text = str_replace(CR, LF, $text, $count_cr);
	$count_lf = substr_count($text, LF) - $count_crlf - $count_cr;

	return $text;
}

/* function normalizeToWindowsLineBreaks($text, &$count_crlf=0, &$count_cr=0, &$count_lf=0) {
	$text = normalizeToUnixLineBreaks($text, $count_crlf, $count_cr, $count_lf);

	$text = str_replace(LF, CRLF, $text);

	return $text;
} */

/* function normalizeToMacintoshLineBreaks($text, &$count_crlf=0, &$count_cr=0, &$count_lf=0) {
	$text = normalizeToUnixLineBreaks($text, $count_crlf, $count_cr, $count_lf);

	$text = str_replace(LF, CR, $text);

	return $text;
} */

function is_binary_data($inp) {
	for ($i=0; $i<=31; $i++) {
		if ((strpos($inp, chr($i)) !== false) && ($i != 9) && ($i != 10) && ($i != 13)) {
			return true;
		}
	}
	return false;
}

function dir_add_trailing_slash($directory) {
	if (substr($directory, strlen($directory)-1, 1) != '/') $directory .= '/';
	return $directory;
}

$my_dir = dir_add_trailing_slash($my_dir);

if (!is_dir($my_dir)) die("UNIXCONV Fehler: Verzeichnis '$my_dir' existiert nicht!!\n");

$max_fsize = $max_fsize * 1024 * 1024;
$upd_count = 0;
$chk_count = 0;
$dir_count = 0;

$something_outputed = false;

function output($text) {
	global $something_outputed;
	echo $text."\n";
	$something_outputed = true;
}

function sucheLFUnkonformeDateien($verzeichnis, $do_fix = false) {
	global $allowed_ext, $exclude_ext, $max_fsize, $upd_count, $chk_count, $dir_count, $no_list;

	$handle = opendir($verzeichnis);
	while ($datei = readdir($handle))
	{
		unset($cont);
		if (($datei != '.') && ($datei != '..'))
		{
			$file = $verzeichnis.$datei;
			if (is_dir($file)) // Wenn Verzeichniseintrag ein Verzeichnis ist
			{
				// Erneuter Funktionsaufruf, um das aktuelle Verzeichnis auszulesen
				if (RECURSIVE_DIR) {
					sucheLFUnkonformeDateien($file.'/', $do_fix);
					$dir_count++;
				}
			} else {
				if (count($allowed_ext) > 0) {
					$ok = false;
					foreach ($allowed_ext as $pat) {
						if (fnmatch($pat, $datei)) {
							$ok = true;
							break;
						}
					}
					unset($pat);
					if (!$ok) continue;
				}

				if (count($exclude_ext) > 0) {
					$ok = true;
					foreach ($exclude_ext as $pat) {
						if (fnmatch($pat, $datei)) {
							$ok = false;
							break;
						}
					}
					unset($pat);
					if (!$ok) continue;
				}

				if (filesize($file) > $max_fsize) {
					output("UNIXCONV Fehler: Datei '$file' übersprungen. Zu groß!");
					continue;
				}

				if (!is_readable($file)) {
					output("UNIXCONV Fehler: Datei '$file' ist nicht lesbar!");
					continue;
				}

				$cont = file_get_contents($file);

				if (is_binary_data($cont)) {
					// output("UNIXCONV Fehler: Datei '$file' ist binär!");
					continue;
				}

				$chk_count++;

				$c_crlf = 0;
				$c_cr = 0;
				$c_lf = 0;

				$cont = normalizeToUnixLineBreaks($cont, $c_crlf, $c_cr, $c_lf);

				if ($c_crlf + $c_cr > 0) {
					if ((SHOW_OUTPUT) && (!$no_list)) {
						output("$file (CRLF=$c_crlf; LF=$c_lf; CR=$c_cr)");
					}

					if ($do_fix) {
						if (!is_writable($file)) {
							output("UNIXCONV Fehler: Datei '$file' kann nicht geschrieben werden!");
							continue;
						} else {
							$upd_count++;
							$h = fopen($file, 'w');
							fputs($h, $cont);
							fclose($h);
						}
					} else {
						$upd_count++;
					}
				}
			}
		}
	}
	closedir($handle);
}

sucheLFUnkonformeDateien($my_dir, $do_fix);

if (SHOW_OUTPUT) {
	if ($something_outputed) {
		output("--- --- --- --- --- --- ---");
	}
	output("UNIXCONV checked $chk_count files in $dir_count directories.");
	$output = "UNIXCONV ";
	if ($do_fix) {
		$output .= "fixed";
	} else {
		$output .= "found";
	}
	$output .= " $upd_count files with CRLF inside!";
	output($output);
	unset($output);
	if ((!$do_fix) && ($upd_count > 0)) {
		output("Please add the argument '-fix' to fix these files.");
	}
}

?>
