for a reference.
+
+ // Fetch token array.
+ list($id, $text) = $token;
+
+ // Debugging:
+ /*
+ if ($lasttoken[0] == T_WHITESPACE) {
+ $result .= token_name($id);
+ }
+ */
+
+
+ switch ($id) {
+ case T_ARRAY:
+ // Write array in lowercase.
+ $result .= strtolower(trim($text));
+ // Mark the next parenthesis level (we haven't consumed that token
+ // yet) as an array.
+ $in_array[$parenthesis + 1] = TRUE;
+ break;
+
+ case T_OPEN_TAG:
+ case T_OPEN_TAG_WITH_ECHO:
+ $in_php = TRUE;
+ // Add a line break between two PHP tags.
+ if (substr(rtrim($result), -2) == '?>' && !$after_php) {
+ coder_br($result);
+ }
+ $after_php = TRUE;
+ $nl = substr_count($text, "\n");
+ $result .= trim($text);
+ if ($first_php_tag) {
+ coder_br($result);
+ $first_php_tag = FALSE;
+ }
+ else {
+ if ($nl) {
+ coder_br($result, $parenthesis);
+ }
+ else {
+ $result .= ' ';
+ }
+ }
+ break;
+
+ case T_CLOSE_TAG:
+ $in_php = FALSE;
+ if ($after_php) {
+ $result = rtrim($result, ' ') . ' ';
+ $text = ltrim($text, ' ');
+ }
+ // Do not alter a closing PHP tag ($text includes trailing white-space)
+ // at all. Should allow to apply coder_format on phptemplate files.
+ $result .= $text;
+ break;
+
+ case T_OBJECT_OPERATOR:
+ $in_object = TRUE;
+ $result .= trim($text);
+ break;
+
+ case T_CONSTANT_ENCAPSED_STRING:
+ case T_STRING:
+ case T_VARIABLE:
+ // Boolean constants (TRUE, FALSE, NULL) are T_STRINGs, but must be
+ // written uppercase.
+ $text = trim($text);
+ if ($text == 'true' || $text == 'false' || $text == 'null') {
+ $text = strtoupper($text);
+ }
+ // No space after object operator ($foo->bar) and error suppression (@function()).
+ if ($in_object || $in_at) {
+ $result = rtrim($result) . $text;
+ $in_object = FALSE;
+ $in_at = FALSE;
+ }
+ else {
+ // Insert a space after right parenthesis, but not after type casts.
+ if (!in_array($lasttoken[0], array(T_ARRAY_CAST, T_BOOL_CAST, T_DOUBLE_CAST, T_INT_CAST, T_OBJECT_CAST, T_STRING_CAST, T_UNSET_CAST))) {
+ coder_add_space($result);
+ }
+ $result .= $text;
+ }
+ $in_variable = TRUE;
+ break;
+
+ case T_CONST:
+ // Constants are written uppercase.
+ $result = rtrim($result) . strtoupper(trim($text));
+ break;
+
+ case T_ENCAPSED_AND_WHITESPACE:
+ $result .= $text;
+ break;
+
+ case T_WHITESPACE:
+ // Avoid duplicate line feeds outside arrays.
+ $c = ($parenthesis || $after_comment) ? 0 : 1;
+
+ for ($c, $cc = substr_count($text, "\n"); $c < $cc; ++$c) {
+ // Newlines were added; not after semicolon anymore
+ coder_br($result, $parenthesis);
+ }
+
+ // If there were newlines present inside a parenthesis,
+ // turn on multiline mode.
+ if ($cc && $parenthesis) {
+ $in_multiline[$parenthesis] = TRUE;
+ }
+
+ // If there were newlines present, move inline comments above.
+ if ($cc) {
+ $after_semicolon = FALSE;
+ $after_case = FALSE;
+ $after_php = FALSE;
+ }
+
+ $in_variable = FALSE;
+ break;
+
+ case T_SWITCH:
+ ++$switches;
+ // Purposely fall through.
+ case T_IF:
+ case T_FOR:
+ case T_FOREACH:
+ case T_GLOBAL:
+ case T_STATIC:
+ case T_ECHO:
+ case T_PRINT:
+ case T_NEW:
+ case T_REQUIRE:
+ case T_REQUIRE_ONCE:
+ case T_INCLUDE:
+ case T_INCLUDE_ONCE:
+ case T_VAR:
+ coder_add_space($result);
+ // Append a space.
+ $result .= trim($text) . ' ';
+ break;
+
+ case T_DO:
+ $result .= trim($text);
+ $in_do_while = TRUE;
+ break;
+
+ case T_WHILE:
+ if ($in_do_while && substr(rtrim($result), -1) === '}') {
+ // Write while after right parenthesis for do {...} while().
+ $result = rtrim($result) . ' ';
+ $in_do_while = FALSE;
+ }
+ // Append a space.
+ $result .= trim($text) . ' ';
+ break;
+
+ case T_ELSE:
+ case T_ELSEIF:
+ // Write else and else if to a new line.
+ $result = rtrim($result);
+ coder_br($result);
+ $result .= trim($text) . ' ';
+ break;
+
+ case T_CASE:
+ case T_DEFAULT:
+ $braces_in_case[$switches] = 0;
+ $result = rtrim($result);
+ $after_case = TRUE;
+ if (!$in_case) {
+ $in_case = TRUE;
+ // Add a line break between cases.
+ if (substr($result, -1) != '{') {
+ coder_br($result);
+ }
+ }
+ else {
+ // Decrease current indent to align multiple cases.
+ --$_coder_indent;
+ }
+ coder_br($result);
+ $result .= trim($text) . ' ';
+ break;
+
+ case T_BREAK:
+ // Write break to a new line.
+ $result = rtrim($result);
+ coder_br($result);
+ // Trailing space needed for 'break 3;'.
+ $result .= trim($text) . ' ';
+ if ($in_case && !$braces_in_case[$switches]) {
+ --$_coder_indent;
+ $in_case = FALSE;
+ }
+ break;
+
+ case T_RETURN:
+ if ($in_case && !$braces_in_case[$switches]) {
+ // Defer reduction of indent for later.
+ ++$_coder_indent;
+ $after_return_in_case = TRUE;
+ }
+ case T_CONTINUE:
+ coder_add_space($result);
+ $result .= trim($text) . ' ';
+ // Decrease indent only if we're not in a control structure inside a case.
+ if ($in_case && !$braces_in_case[$switches]) {
+ --$_coder_indent;
+ $in_case = FALSE;
+ }
+ break;
+
+ case T_ABSTRACT:
+ case T_PRIVATE:
+ case T_PUBLIC:
+ case T_PROTECTED:
+ // Class member function properties must be treated similar to
+ // T_FUNCTION, but without line-break after the token. Because more
+ // than one of these tokens can appear in front of a function token,
+ // we need another white-space control variable.
+ $result .= trim($text) . ' ';
+ $after_visibility_modifier = TRUE;
+ break;
+
+ case T_FUNCTION:
+ $in_function_declaration = TRUE;
+ // Fall through.
+ case T_CLASS:
+ // Write function and class to new lines.
+ $result = rtrim($result);
+ if (substr($result, -1) == '}') {
+ coder_br($result);
+ }
+ if (!$after_visibility_modifier) {
+ coder_br($result);
+ }
+ else {
+ // This code only applies to T_FUNCTION; do not add a newline
+ // after public/protected/private/abstract.
+ $after_visibility_modifier = FALSE;
+ $result .= ' ';
+ }
+ $result .= trim($text) . ' ';
+ break;
+
+ case T_EXTENDS:
+ case T_INSTANCEOF:
+ // Add space before and after 'extends' and 'instanceof'.
+ $result = rtrim($result);
+ $result .= ' ' . trim($text) . ' ';
+ break;
+
+ case T_AND_EQUAL:
+ case T_AS:
+ case T_BOOLEAN_AND:
+ case T_BOOLEAN_OR:
+ case T_CONCAT_EQUAL:
+ case T_DIV_EQUAL:
+ case T_DOUBLE_ARROW:
+ case T_IS_EQUAL:
+ case T_IS_NOT_EQUAL:
+ case T_IS_IDENTICAL:
+ case T_IS_NOT_IDENTICAL:
+ case T_IS_GREATER_OR_EQUAL:
+ case T_IS_SMALLER_OR_EQUAL:
+ case T_LOGICAL_AND:
+ case T_LOGICAL_OR:
+ case T_LOGICAL_XOR:
+ case T_MINUS_EQUAL:
+ case T_MOD_EQUAL:
+ case T_MUL_EQUAL:
+ case T_OR_EQUAL:
+ case T_PLUS_EQUAL:
+ case T_SL:
+ case T_SL_EQUAL:
+ case T_SR:
+ case T_SR_EQUAL:
+ case T_XOR_EQUAL:
+ // Surround operators with spaces.
+ if (substr($result, -1) != ' ') {
+ // $result must not be trimmed to allow multi-line if-clauses.
+ $result .= ' ';
+ }
+ $result .= trim($text) . ' ';
+ break;
+
+ case T_COMMENT:
+ case T_ML_COMMENT:
+ case T_DOC_COMMENT:
+ if (substr($text, 0, 3) == '/**') {
+ // Prepend a new line.
+ $result = rtrim($result);
+ if (!$after_initial_comment) {
+ coder_br($result);
+ }
+ else {
+ // This probably will get set below, but it's good to
+ // explicitly turn it off after the initial comment has
+ // influenced behavior and now is not necessary.
+ $after_initial_comment = FALSE;
+ }
+ coder_br($result);
+
+ // Remove carriage returns.
+ $text = str_replace("\r", '', $text);
+
+ $lines = explode("\n", $text);
+ $params_fixed = FALSE;
+ for ($l = 0; $l < count($lines); ++$l) {
+ $lines[$l] = trim($lines[$l]);
+
+ // Add a new line between function description and first parameter description.
+ if (!$params_fixed && substr($lines[$l], 0, 8) == '* @param' && $lines[$l - 1] != '*') {
+ $result .= ' *';
+ coder_br($result);
+ $params_fixed = TRUE;
+ }
+ elseif (!$params_fixed && substr($lines[$l], 0, 8) == '* @param') {
+ // Do nothing if parameter description is properly formatted.
+ $params_fixed = TRUE;
+ }
+
+ // Add a new line between function params and return.
+ if (substr($lines[$l], 0, 9) == '* @return' && $lines[$l - 1] != '*') {
+ $result .= ' *';
+ coder_br($result);
+ }
+
+ // Add one space indent to get ' *[...]'.
+ if ($l > 0) {
+ $result .= ' ';
+ }
+ $result .= $lines[$l];
+ if ($l < count($lines)) {
+ coder_br($result);
+ }
+ }
+ }
+ else {
+ // Move the comment above if it's embedded.
+ $statement = FALSE;
+ // Some PHP versions throw a warning about wrong parameter count for
+ // substr_count().
+ $cc = substr_count(substr($result, $position_last_significant_token), "\n");
+ if ((!$cc || $after_semicolon) && !$after_case) {
+ $nl_position = strrpos(rtrim($result, " \n"), "\n");
+ $statement = substr($result, $nl_position);
+ $result = substr($result, 0, $nl_position);
+ $after_semicolon = FALSE;
+ coder_br($result, $parenthesis);
+ }
+ $result .= trim($text);
+ coder_br($result, $parenthesis);
+ if ($statement) {
+ // Newlines are automatically added, so remove these.
+ $result = rtrim($result, "\n ");
+ $result .= rtrim($statement, "\n ");
+ coder_br($result, $parenthesis);
+ // Need to update this, as our comment trickery has just
+ // reshuffled the index.
+ $position_last_significant_token = strlen(rtrim($result, " \n")) - 1;
+ }
+ else {
+ if (strpos($text, '$' . 'Id$') === FALSE) {
+ $after_comment = TRUE;
+ }
+ else {
+ // Is the number two so that our bottom code doesn't override
+ // our flag immediately.
+ $after_initial_comment = 2;
+ }
+ }
+ }
+ break;
+
+ case T_INLINE_HTML:
+ $result .= $text;
+ break;
+
+ case T_START_HEREDOC:
+ $result .= trim($text);
+ coder_br($result, FALSE, FALSE);
+ $in_heredoc = TRUE;
+ break;
+
+ case T_END_HEREDOC:
+ $result .= trim($text);
+ coder_br($result, FALSE, FALSE);
+ $in_heredoc = FALSE;
+ break;
+
+ default:
+ $result .= trim($text);
+ break;
+ }
+
+ // Store last token.
+ $lasttoken = $token;
+
+ // Excluding comments and whitespace, set the position of the
+ // last significant token's last character to the length of the
+ // string minus one.
+ switch ($id) {
+ case T_WHITESPACE:
+ case T_COMMENT:
+ case T_ML_COMMENT:
+ case T_DOC_COMMENT:
+ break;
+
+ default:
+ $position_last_significant_token = strlen(rtrim($result, " \n")) - 1;
+ break;
+ }
+
+ if ($id !== T_COMMENT && $id !== T_ML_COMMENT) {
+ $after_comment = FALSE;
+ }
+ if ($after_initial_comment && $id !== T_WHITESPACE) $after_initial_comment--;
+ }
+ }
+ return $result;
+}
+
+/**
+ * Generate a line feed including current line indent.
+ *
+ * This function will also remove all line indentation from the
+ * previous line if no text was added.
+ *
+ * @param &$result
+ * Result variable to append break and indent to, passed by reference.
+ * @param $parenthesis
+ * Optional integer of parentheses level for extra indents.
+ * @param $add_indent
+ * Whether to add current line indent after line feed.
+ */
+function coder_br(&$result, $parenthesis = FALSE, $add_indent = TRUE) {
+ global $_coder_indent;
+
+ // Scan result backwards for whitespace.
+ for ($i = strlen($result) - 1; $i >= 0; $i--) {
+ if ($result[$i] == ' ') {
+ continue;
+ }
+ if ($result[$i] == "\n") {
+ $result = rtrim($result, ' ');
+ break;
+ }
+ // Non-whitespace was encountered, no changes necessary.
+ break;
+ }
+
+ if ($parenthesis) {
+ // Add extra indent for each parenthesis in multiline definitions (f.e. arrays).
+ $_coder_indent = $_coder_indent + $parenthesis;
+ $result = rtrim($result);
+ // This recursive call will only be done once, as $parenthesis is
+ // set to false.
+ coder_br($result, FALSE, $add_indent);
+ $_coder_indent = $_coder_indent - $parenthesis;
+ }
+ else {
+ $output = "\n";
+ if ($add_indent && $_coder_indent >= 0) {
+ $output .= str_repeat(' ', $_coder_indent);
+ }
+ $result .= $output;
+ }
+}
+
+/**
+ * Write a space in certain conditions.
+ *
+ * A conditional space is needed after a right parenthesis of an if statement
+ * that is not followed by curly braces.
+ *
+ * @param $result
+ * Current result string that will be checked.
+ *
+ * @return
+ * Resulting string with or without an additional space.
+ */
+function coder_add_space(&$result) {
+ if (substr($result, -1) == ')') {
+ $result .= ' ';
+ }
+}
+
+/**
+ * Trim overall code.
+ *
+ * Strips whitespace at the beginning and end of code,
+ * removes the closing PHP tag and appends two empty lines.
+ */
+function coder_trim_php($code) {
+ // Remove surrounding whitespace.
+ $code = trim($code);
+
+ // Remove closing PHP tag.
+ if (substr($code, -2) == '?>') {
+ $code = rtrim($code, '?>');
+ }
+
+ // Append two empty lines.
+ $code .= str_repeat(chr(10), 2);
+
+ return $code;
+}
+
+/**
+ * Execute special tasks on source code.
+ *
+ * This function works similar to the Drupal hook and forms system. It searches
+ * for all defined functions with the given prefix and performs a preg_replace
+ * on the source code for each of these functions.
+ *
+ * Processor functions are defined with a associative array containing the
+ * following keys with the corresponding values:
+ * #title
+ * A human readable text describing what the processor actually does.
+ * #search
+ * The regular expression to search for.
+ * #replace
+ * The replacement text for each match.
+ *
+ * Optional definitions:
+ * #debug
+ * Set this to true to directly output the results of preg_match_all and
+ * exit script execution after this processor.
+ *
+ * @param string $code
+ * The source code to process.
+ * @param string $prefix
+ * Prefix of the functions to execute.
+ *
+ * @return
+ * The processed source code.
+ */
+function coder_exec_processors($code, $prefix = '') {
+ if (empty($prefix)) {
+ return;
+ }
+ $tasks = get_defined_functions();
+ $tasks = $tasks['user'];
+ for ($c = 0, $cc = count($tasks); $c < $cc; ++$c) {
+ if (strpos($tasks[$c], $prefix) === FALSE) {
+ unset($tasks[$c]);
+ }
+ else {
+ $tasks[$tasks[$c]] = call_user_func($tasks[$c]);
+ unset($tasks[$c]);
+ }
+ }
+ uasort($tasks, 'coder_order_processors');
+ foreach ($tasks as $func => $task) {
+ if (!isset($task['#search']) || (!isset($task['#replace']) && !isset($task['#replace_callback']))) {
+ continue;
+ }
+ if (isset($task['#debug'])) {
+ // Output regular expression results if debugging is enabled.
+ preg_match_all($task['#search'], $code, $matches, PREG_SET_ORDER);
+ echo "";
+ var_dump($matches);
+ echo "
\n";
+ // Exit immediately in debugging mode.
+ exit;
+ }
+ if (isset($task['#replace_callback'])) {
+ $code = preg_replace_callback($task['#search'], $task['#replace_callback'], $code);
+ }
+ else {
+ $code = preg_replace($task['#search'], $task['#replace'], $code);
+ }
+ }
+
+ return $code;
+}
+
+/**
+ * Orders preprocessors by weight.
+ *
+ * @see coder_exec_processors()
+ */
+function coder_order_processors($a, $b) {
+ if (isset($a['#weight']) && isset($b['#weight'])) {
+ return $a['#weight'] - $b['#weight'];
+ }
+ else {
+ return isset($a['#weight']) ? FALSE : TRUE;
+ }
+}
+
+/**
+ * @defgroup coder_preprocessor Preprocessors.
+ * @{
+ */
+function coder_preprocessor_line_breaks_win() {
+ return array(
+ '#title' => 'Convert Windows line breaks to Unix format.',
+ '#weight' => 1,
+ '#search' => "@\r\n@",
+ '#replace' => "\n",
+ );
+}
+
+function coder_preprocessor_line_breaks_mac() {
+ return array(
+ '#title' => 'Convert Macintosh line breaks to Unix format.',
+ '#weight' => 2,
+ '#search' => "@\r@",
+ '#replace' => "\n",
+ );
+}
+
+function coder_preprocessor_php() {
+ return array(
+ '#title' => 'Always use <?php ?> to delimit PHP code, not the <? ?> shorthands.',
+ '#search' => '@<\?(\s)@',
+ '#replace' => " 'Either exit a switch case with return *or* break.',
+ '#search' => '@
+ (return # match a return
+ \s+ # - followed by some white-space
+ .+ # - followed by any characters
+ ; # - followed by a semicolon
+ )
+ \s+ # match white-space (required)
+ break; # match a directly following "break;"
+ @mx',
+ '#replace' => '$1',
+ );
+}
+
+function coder_preprocessor_inline_comment() {
+ return array(
+ '#title' => 'Move inline comments above remarked line.',
+ '#weight' => 2,
+ '#search' => '@
+ ^([\040\t]*) # match spaces or tabs only.
+ (?!case) # do not match case statements.
+ (\S.+? # do not match lines containing only a comment.
+ [;,{] # match the TRICKY lines only.
+ )
+ [\040\t]* # match spaces or tabs only.
+ (?!:) # do not match URL protocols.
+ //\s* # match inline comment token.
+ ([^;\$]+?)$ # fetch comment, but do not match CVS keyword Id, nested comments, and comment tokens in quotes (f.e. "W3C//DTD").
+ @mx',
+ '#replace' => "$1// $3\n$1$2",
+ );
+}
+
+/**
+ * @} End of "defgroup coder_preprocessor".
+ */
+
+function coder_postprocessor_multiple_vars() {
+ return array(
+ '#title' => 'Align equal signs of multiple variable assignments in the same column.',
+ '#search' => '@
+ ^( # match start of a line
+ \n?\ * # match white-space, but only one new line
+ \$.+? # match a variable name
+ \ =\ # match a variable assignment
+ .+?$ # match a variable value
+ ){3,} # require the pattern to match at least 3 times
+ @mx',
+ '#replace_callback' => 'coder_replace_multiple_vars',
+ );
+}
+
+function coder_replace_multiple_vars($matches) {
+ // Retrieve all variable name = variable value pairs.
+ $regex = '@
+ ^ # match start of a line
+ (\s*) # match a single optional white-space char
+ (\$.+?) # match a variable name
+ \ (.?)=\ # match a variable assignment
+ (.+?$) # match a variable value including end of line
+ @mx';
+ preg_match_all($regex, $matches[0], $vars, PREG_SET_ORDER);
+
+ // Determine the longest variable name.
+ $maxlength = 0;
+ foreach ($vars as $var) {
+ if (strlen($var[2]) > $maxlength) {
+ $maxlength = strlen($var[2] . $var[3]);
+ }
+ }
+
+ // Realign variable values at the longest variable names.
+ $return = '';
+ $extra_spaces = 0;
+ for ($c = 0, $cc = count($vars); $c < $cc; ++$c) {
+ if ($maxlength <= 20) {
+ $extra_spaces = $maxlength - strlen($vars[$c][2] . $vars[$c][3]);
+ }
+ $return .= $vars[$c][1] . $vars[$c][2];
+ $return .= str_repeat(' ', $extra_spaces) . ' ' . $vars[$c][3] . '= ';
+ $return .= $vars[$c][4];
+ if ($c < $cc - 1) {
+ // Append a line break, but not to the last variable assignment.
+ $return .= "\n";
+ }
+ }
+
+ return $return;
+}
+
+function coder_postprocessor_indent_multiline_array() {
+ // Still buggy, disabled for now.
+ return array(
+ '#title' => 'Align equal signs of multiline array assignments in the same column.',
+ '#search' => '@
+ ^ # match start of a line
+ (?:\s* # require initial white-space
+ (?:
+ (?:
+ ([\'"]).+?\1 # capture a string key
+ |.+? # or any other key without white-space
+ )
+ \s*=>\s* # require associative array arrow syntax
+ .+? # match an array value
+ |\),\s? # or a closing brace followed by a comma and a single optional white-space char
+ )$ # require end of a line
+ ){3,} # require the pattern to match at least 3 times
+ @mix',
+ //'#replace_callback' => 'coder_replace_indent_multiline_array',
+ );
+}
+
+function coder_replace_indent_multiline_array($matches) {
+ // Separate out important components of the multiline array:
+ // (\s*) matches existing indent as \1
+ // (([\'"]).+?\2|\$.+?|[+\-]?(?:0x)?[0-9A-F]+) matches key as \2
+ // ([\'"]).+?\3 matches a quoted key, quote used is \3
+ // \.+? matches anything else
+ // \),\s*? matches a closing parenthesis in a nested array
+ // \s*=>\s* matches existing indentation and arrow to be discarded
+ // (.+?) matches value as \4
+ // {3,} requires three or more of these lines
+ // mi enables multiline and caseless mode
+ preg_match_all('/^(\s*)(?:(([\'"]).+?\3|\.+?)\s*=>\s*(.+?),?|\),)\s*?$/mi', $matches[0], $vars, PREG_SET_ORDER);
+ // Determine max key length for varying indentations.
+ $maxlengths = array();
+ foreach ($vars as $var) {
+ list(, $indent, $key) = $var;
+ if (!isset($maxlengths[$indent])) {
+ $maxlengths[$indent] = 0;
+ }
+ if (($t = strlen($key)) > $maxlengths[$indent]) {
+ $maxlengths[$indent] = $t;
+ }
+ }
+ // Reconstruct variable array declaration.
+ $return = '';
+ foreach ($vars as $var) {
+ list(, $indent, $key, , $value) = $var;
+ if ($key === NULL) {
+ $return .= "$indent),\n";
+ continue;
+ }
+ $spaces = str_repeat(' ', $maxlengths[$indent] - strlen($key));
+ if ($value !== 'array(') {
+ $comma = ',';
+ }
+ else {
+ $comma = '';
+ }
+ $return .= "$indent$key$spaces => $value$comma\n";
+ }
+ $return = rtrim($return, "\n");
+ return $return;
+}
+
+function coder_postprocessor_array_rearrange() {
+ // @bug common.inc, comment.module:
+ // Not yet working properly 25/03/2007 sun.
+ return array(
+ '#title' => 'Break array elements into separate lines, indented one level.',
+ // ([\040\t]*) matches blanks and tabs.
+ // (.*?array\() matches anything and 'array('.
+ // ((.+ => .+, ){3,}) matches all array items, except the last one.
+ // (.+ => ([^\(\)]+)) matches the last array item, excluding.
+ // arrays or functions (starting with a left parenthesis) (not supported yet).
+ //'#search' => '/^([\040\t]*)(.*?array\()((.+ => .+, ){3,})(.+ => ([^\(\)]+))\)/m',
+ '#replace_callback' => 'coder_replace_array_rearrange',
+ );
+}
+
+function coder_replace_array_rearrange($matches) {
+ // Retrieve all array items, except the last one.
+ preg_match_all('/(.+? => .+?,) /', $matches[3], $items);
+
+ // The original line including array(.
+ $return = $matches[1] . $matches[2] . "\n";
+ foreach ($items[1] as $item) {
+ // All array items, except the last one, with extra indent.
+ $return .= $matches[1] . ' ' . $item . "\n";
+ }
+ // Last array item, with extra indent and comma.
+ $return .= $matches[1] . ' ' . $matches[5] . ",\n";
+ // Closing parenthesis (on a new line).
+ $return .= $matches[1] . ')';
+
+ return $return;
+}
+
+function coder_postprocessor_if_curly_braces() {
+ // This post-processor relies on the fact that coder_format already
+ // re-formatted if statements without curly braces to be on one line.
+ return array(
+ '#title' => 'Use curly braces even in situations where they are technically optional.',
+ '#search' => '@
+ (\s*) # match leading white-space, including newline
+ (if\ \(.+\)\ ) # match if statement
+ ([^\{].+;) # match conditional executed code not starting with a curly brace, delimited by a semicolon.
+ @x',
+ '#replace' => '$1$2{$1 $3$1}',
+ );
+}
+
+function coder_postprocessor_elseif_not_else_if() {
+ // Replace all "else if" statements with "elseif"
+ return array(
+ '#title' => 'Use "elseif" in place of "else if".',
+ '#search' => '@
+ (else) # match an else statement followed by whitespace
+ \s+ # match whitespace
+ (if\ ?\() # match an if statement.
+ @x',
+ '#replace' => '$1$2',
+ );
+}
+
+/**
+ * @} End of "defgroup coder_postprocessor".
+ */
+
diff --git a/info.plist b/info.plist
index e0612c4..00912ea 100644
--- a/info.plist
+++ b/info.plist
@@ -1561,6 +1561,7 @@
F449D68D-FDF9-4121-9899-87C9F5321BF6
B9D08C39-CFA1-4CC1-B2D6-0AB1B1F980C4
74987B6D-0300-4625-80D7-A9F5BDA10C2E
+ 0C521CF6-7E58-47D9-B3F5-DB7B8CB529BD
355A91BB-BEE0-4E1B-98AC-35E30DDEEE47
2E8AFFB0-DC40-4E4B-A502-DA78AD1BC284
EE8AE645-959E-4F78-98E0-2987C73631E9