isFile()) { continue; } $path = $file->getPathName(); foreach ($excludes as $exclude) { if (strpos($path, $exclude) !== false) { continue 2; } } $lang = getLanguageFromExtension($file->getExtension()); if ($lang === null) { continue; } $origCode = $code = file_get_contents($path); if ($lang === 'c') { $code = stripTrailingWhitespace($code); // TODO: Avoid this for now. // $code = reindentToTabs($code); } else if ($lang === 'php') { $code = stripTrailingWhitespace($code); $code = reindentToSpaces($code); } else if ($lang === 'phpt') { // TODO: Don't reformat .phpt on PHP-7.4. /*$code = transformTestCode($code, function(string $code) { $code = stripTrailingWhitespace($code); $code = reindentToSpaces($code); return $code; });*/ } if ($origCode !== $code) { file_put_contents($path, $code); } } function stripTrailingWhitespace(string $code): string { return preg_replace('/\h+$/m', '', $code); } function reindentToTabs(string $code): string { return preg_replace_callback('/^ +/m', function(array $matches) { $tabSize = 4; $spaces = strlen($matches[0]); $tabs = intdiv($spaces, $tabSize); $spaces -= $tabs * $tabSize; return str_repeat("\t", $tabs) . str_repeat(" ", $spaces); }, $code); } function reindentToSpaces(string $code): string { return preg_replace_callback('/^[ \t]+/m', function(array $matches) { $tabSize = 4; $indent = 0; foreach (str_split($matches[0]) as $char) { if ($char === ' ') { $indent++; } else { $partialIndent = $indent % $tabSize; if ($partialIndent === 0) { $indent += $tabSize; } else { $indent += $tabSize - $partialIndent; } } } return str_repeat(" ", $indent); }, $code); } function transformTestCode(string $code, callable $transformer): string { // Don't transform whitespace-sensitive tests. if (strpos($code, '--WHITESPACE_SENSITIVE--') !== false) { return $code; } return preg_replace_callback( '/(--FILE--)(.+?)(--[A-Z_]+--)/s', function(array $matches) use($transformer) { return $matches[1] . $transformer($matches[2]) . $matches[3]; }, $code ); } function getLanguageFromExtension(string $ext): ?string { switch ($ext) { case 'c': case 'h': case 'cpp': case 'y': case 'l': case 're': return 'c'; case 'php': // TODO: Reformat .inc files. //case 'inc': return 'php'; case 'phpt': return 'phpt'; default: return null; } }