Index: coder.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/coder/coder.module,v
retrieving revision 1.88.2.32
diff -u -p -r1.88.2.32 coder.module
--- coder.module 29 Mar 2008 23:55:19 -0000 1.88.2.32
+++ coder.module 8 May 2008 10:47:41 -0000
@@ -130,6 +130,13 @@ function coder_menu() {
     'type' => MENU_LOCAL_TASK,
     'weight' => 1,
   );
+  $items['coder/patches'] = array(
+    'title' => t('Patches'),
+    'page callback' => 'coder_page',
+    'access arguments' => array('view code review'),
+    'type' => MENU_LOCAL_TASK,
+    'weight' => 2,
+  );
   $items['admin/settings/coder'] = array(
     'title' => t('Code review'),
     'description' => t('Select code review plugins and modules'),
@@ -236,153 +243,211 @@ function _coder_settings_form($settings,
     '#default_value' => $settings['coder_severity'],
   );

-  // Get the modules and theme.
-  $sql = 'SELECT name, filename, type, status FROM {system} WHERE type=\'module\' OR type=\'theme\' ORDER BY weight ASC, filename ASC';
-  $result = db_query($sql);
-  $system_modules = array();
-  $system_themes = array();
-  while ($system = db_fetch_object($result)) {
-    $display_name = $system->name;
-    if ($system->status) {
-      $display_name .= t(' (active)');
-      $system_active[$system->name] = $system->name;
-    }
-    if (_coder_is_drupal_core($system)) {
-      $display_name .= t(' (core)');
-      $system_core[$system->name] = $system->name;
-    }
-    if ($system->type == 'module') {
-      $system_modules[$system->name] = $system->name;
-    }
-    else {
-      $system_themes[$system->name] = $system->name;
+  if ($settings['coder_patches']) {
+    // Display what to review options.
+    $form['coder_what'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('What to review'),
+      '#collapsible' => true,
+      '#collapsed' => false,
+    );
+    $form['coder_what']['coder_patch_text'] = array(
+      '#type' => 'textarea',
+      '#title' => t('Patch to review'),
+      '#rows' => 10,
+      '#weight' => -1,
+      '#default_value' => isset($settings['coder_patch_text']) ? $settings['coder_patch_text'] : '',
+    );
+    $form['coder_patches'] = array(
+      '#type' => 'value',
+      '#value' => 1,
+    );
+
+    $in_patch = 0;
+    $patch_part = 1;
+    $patch = '';
+    $patches = array();
+    $lines = preg_split("/[\r\n|\n]/", $settings['coder_patch_text']);
+    foreach ($lines as $line) {
+      if ($line == '') {
+        continue;
+      }
+      if (preg_match("/^\+\+\+\s+([\w\.\-\/]+\s)/", $line, $matches)) {
+        $filename = $matches[1];
+      }
+      else if (preg_match("/^(@@\s+\-\d+,\d+\s+\+\d+,\d+\s+@@)/", $line, $matches)) {
+        $patch_line_numbers = $matches[1];
+        $patch_part = 1;
+      }
+      else if (preg_match("/^\+[^\+]+/", $line)) {
+        $patch .= ltrim($line, '+') ."\n";
+        $in_patch = 1;
+      }
+      else {
+        if ($in_patch) {
+          $part = '';
+          if ($patch_part > 1) {
+            $part = t(' (part @num)', array('@num' => $patch_part));
+          }
+          $patches[$filename .": ". $patch_line_numbers . $part] = $patch;
+          $system[$filename .": ". $patch_line_numbers . $part] = $filename;
+          $patch = '';
+          $patch_part++;
+        }
+        $in_patch = 0;
+      }
     }
-    $system_links[$system->name] = l($display_name, "coder/$system->name");
-    $files[$system->name] = $system->filename;
+    $files = $patches;
   }
-  asort($system_links);
+  else {
+    // Get the modules and theme.
+    $sql = 'SELECT name, filename, type, status FROM {system} WHERE type=\'module\' OR type=\'theme\' ORDER BY weight ASC, filename ASC';
+    $result = db_query($sql);
+    $system_modules = array();
+    $system_themes = array();
+    while ($system = db_fetch_object($result)) {
+      $display_name = $system->name;
+      if ($system->status) {
+        $display_name .= t(' (active)');
+        $system_active[$system->name] = $system->name;
+      }
+      if (_coder_is_drupal_core($system)) {
+        $display_name .= t(' (core)');
+        $system_core[$system->name] = $system->name;
+      }
+      if ($system->type == 'module') {
+        $system_modules[$system->name] = $system->name;
+      }
+      else {
+        $system_themes[$system->name] = $system->name;
+      }
+      $system_links[$system->name] = l($display_name, "coder/$system->name");
+      $files[$system->name] = $system->filename;
+    }
+    asort($system_links);

-  // Display what to review options.
-  $form['coder_what'] = array(
-    '#type' => 'fieldset',
-    '#title' => t('What to review'),
-    '#collapsible' => true,
-    '#collapsed' => false,
-  );
-  // NOTE: Should rename var.
-  $form['coder_what']['coder_active_modules'] = array(
-    '#type' => 'checkbox',
-    '#default_value' => isset($settings['coder_active_modules']) ? $settings['coder_active_modules'] : 0,
-    '#title' => t('active modules and themes'),
-  );
-  $form['coder_what']['coder_core'] = array(
-    '#type' => 'checkbox',
-    '#default_value' => isset($settings['coder_core']) ? $settings['coder_core'] : 0,
-    '#title' => t('core files (php, modules, and includes)'),
-  );
-  $form['coder_what']['coder_includes'] = array(
-    '#type' => 'checkbox',
-    '#default_value' => isset($settings['coder_includes']) ? $settings['coder_includes'] : 0,
-    '#title' => t('include files (.inc and .php files)'),
-  );
-  if (arg(0) == 'admin') {
-    $form['coder_what']['coder_cache'] = array(
+    // Display what to review options.
+    $form['coder_what'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('What to review'),
+      '#collapsible' => true,
+      '#collapsed' => false,
+    );
+    // NOTE: Should rename var.
+    $form['coder_what']['coder_active_modules'] = array(
       '#type' => 'checkbox',
-      '#default_value' => isset($settings['coder_cache']) ? $settings['coder_cache'] : 0,
-      '#title' => t('use the coder cache'),
+      '#default_value' => isset($settings['coder_active_modules']) ? $settings['coder_active_modules'] : 0,
+      '#title' => t('active modules and themes'),
     );
-  }
+    $form['coder_what']['coder_core'] = array(
+      '#type' => 'checkbox',
+      '#default_value' => isset($settings['coder_core']) ? $settings['coder_core'] : 0,
+      '#title' => t('core files (php, modules, and includes)'),
+    );
+    $form['coder_what']['coder_includes'] = array(
+      '#type' => 'checkbox',
+      '#default_value' => isset($settings['coder_includes']) ? $settings['coder_includes'] : 0,
+      '#title' => t('include files (.inc and .php files)'),
+    );
+    if (arg(0) == 'admin') {
+      $form['coder_what']['coder_cache'] = array(
+        '#type' => 'checkbox',
+        '#default_value' => isset($settings['coder_cache']) ? $settings['coder_cache'] : 0,
+        '#title' => t('use the coder cache'),
+      );
+    }

-  // Display the modules in a fieldset.
-  $form['coder_what']['coder_modules'] = array(
-    '#type' => 'fieldset',
-    '#title' => t('Select Specific Modules'),
-    '#collapsible' => true,
-    '#collapsed' => true,
-    'checkboxes' => array(
-      '#theme' => 'cols',
-      '#cols' => 2,
-    ),
-  );
-  if (isset($settings['coder_all'])) {
-    $modules = $system_modules;
-  }
-  elseif (isset($settings['coder_active_modules']) && $settings['coder_active_modules']) {
-    if (isset($settings['coder_core']) && $settings['coder_core']) {
-      $modules = array_intersect($system_active, $system_core);
-      $modules = array_intersect($modules, $system_modules);
+    // Display the modules in a fieldset.
+    $form['coder_what']['coder_modules'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('Select Specific Modules'),
+      '#collapsible' => true,
+      '#collapsed' => true,
+      'checkboxes' => array(
+        '#theme' => 'cols',
+        '#cols' => 2,
+      ),
+    );
+    if (isset($settings['coder_all'])) {
+      $modules = $system_modules;
     }
-    else {
-      $modules = array_intersect($system_active, $system_modules);
+    elseif (isset($settings['coder_active_modules']) && $settings['coder_active_modules']) {
+      if (isset($settings['coder_core']) && $settings['coder_core']) {
+        $modules = array_intersect($system_active, $system_core);
+        $modules = array_intersect($modules, $system_modules);
+      }
+      else {
+        $modules = array_intersect($system_active, $system_modules);
+      }
     }
-  }
-  elseif (isset($settings['coder_core']) && $settings['coder_core']) {
-    $modules = array_intersect($system_core, $system_modules);
-  }
-  elseif (isset($settings['coder_active_modules']) && $settings['coder_active_modules']) {
-    $modules = array_intersect($system_active, $system_modules);
-  }
-  else {
-    $modules = isset($settings['coder_modules']) && is_array($settings['coder_modules']) ? $settings['coder_modules'] : array();
-  }
-
-  // Display the themes in a fieldset.
-  $form['coder_what']['coder_themes'] = array(
-    '#type' => 'fieldset',
-    '#title' => t('Select Specific Themes'),
-    '#collapsible' => true,
-    '#collapsed' => true,
-    'checkboxes' => array(
-      '#theme' => 'cols',
-    ),
-  );
-  if (isset($settings['coder_all'])) {
-    $themes = $system_themes;
-  }
-  elseif (isset($settings['coder_active_modules']) && $settings['coder_active_modules']) {
-    if (isset($settings['coder_core']) && $settings['coder_core']) {
-      $themes = array_intersect($system_active, $system_core);
-      $themes = array_intersect($themes, $system_themes);
+    elseif (isset($settings['coder_core']) && $settings['coder_core']) {
+      $modules = array_intersect($system_core, $system_modules);
+    }
+    elseif (isset($settings['coder_active_modules']) && $settings['coder_active_modules']) {
+      $modules = array_intersect($system_active, $system_modules);
     }
     else {
-      $themes = array_intersect($system_active, $system_themes);
+      $modules = isset($settings['coder_modules']) && is_array($settings['coder_modules']) ? $settings['coder_modules'] : array();
     }
-  }
-  elseif (isset($settings['coder_core']) && $settings['coder_core']) {
-    $themes = array_intersect($system_core, $system_themes);
-  }
-  elseif (isset($settings['coder_active_modules']) && $settings['coder_active_modules']) {
-    $themes = array_intersect($system_active, $system_themes);
-  }
-  else {
-    $themes = isset($settings['coder_themes']) && is_array($settings['coder_themes']) ? $settings['coder_themes'] : array();
-  }

-  foreach ($system_links as $name => $link) {
-    $classes = array();
-    if (in_array($name, $system_active)) {
-      $classes[] = 'coder-active';
+    // Display the themes in a fieldset.
+    $form['coder_what']['coder_themes'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('Select Specific Themes'),
+      '#collapsible' => true,
+      '#collapsed' => true,
+      'checkboxes' => array(
+        '#theme' => 'cols',
+      ),
+    );
+    if (isset($settings['coder_all'])) {
+      $themes = $system_themes;
+    }
+    elseif (isset($settings['coder_active_modules']) && $settings['coder_active_modules']) {
+      if (isset($settings['coder_core']) && $settings['coder_core']) {
+        $themes = array_intersect($system_active, $system_core);
+        $themes = array_intersect($themes, $system_themes);
+      }
+      else {
+        $themes = array_intersect($system_active, $system_themes);
+      }
     }
-    if (in_array($name, $system_core)) {
-      $classes[] = 'coder-core';
+    elseif (isset($settings['coder_core']) && $settings['coder_core']) {
+      $themes = array_intersect($system_core, $system_themes);
     }
-    if (in_array($name, $system_themes)) {
-      $type = 'theme';
-      $default_value = isset($themes[$name]);
+    elseif (isset($settings['coder_active_modules']) && $settings['coder_active_modules']) {
+      $themes = array_intersect($system_active, $system_themes);
     }
     else {
-      $type = 'module';
-      $default_value = isset($modules[$name]);
+      $themes = isset($settings['coder_themes']) && is_array($settings['coder_themes']) ? $settings['coder_themes'] : array();
+    }
+
+    foreach ($system_links as $name => $link) {
+      $classes = array();
+      if (in_array($name, $system_active)) {
+        $classes[] = 'coder-active';
+      }
+      if (in_array($name, $system_core)) {
+        $classes[] = 'coder-core';
+      }
+      if (in_array($name, $system_themes)) {
+        $type = 'theme';
+        $default_value = isset($themes[$name]);
+      }
+      else {
+        $type = 'module';
+        $default_value = isset($modules[$name]);
+      }
+      $form['coder_what']["coder_${type}s"]['checkboxes']["coder_${type}s-$name"] = array(
+        '#type' => 'checkbox',
+        '#title' => $link,
+        '#default_value' => $default_value,
+        '#attributes' => array('class' => implode(' ', $classes)),
+      );
     }
-    $form['coder_what']["coder_${type}s"]['checkboxes']["coder_${type}s-$name"] = array(
-      '#type' => 'checkbox',
-      '#title' => $link,
-      '#default_value' => $default_value,
-      '#attributes' => array('class' => implode(' ', $classes)),
-    );
-  }

-  $system = array_merge($modules, $themes);
+    $system = array_merge($modules, $themes);
+  }
   return $form;
 }

@@ -516,6 +581,10 @@ function _coder_get_default_settings($ar
       $settings['coder_all'] = 1;
       break;

+    case 'patches':
+      $settings['coder_patches'] = 1;
+      break;
+
     case 'default':
       $settings['coder_active_modules'] = variable_get('coder_active_modules', 1);
       $settings['coder_core'] = variable_get('coder_core', 0);
@@ -611,6 +680,7 @@ function coder_page_form($form_state) {
       // Used to avoid duplicate includes.
       $dups = array();
       $stats = array();
+      $patch = '';
       foreach ($system as $name => $checked) {
         if ($checked) {
           // Process this one file.
@@ -619,10 +689,15 @@ function coder_page_form($form_state) {
             drupal_set_message(t('Code Review file for %module not found', array('%module' => $name)));
             continue;
           }
+          if ($settings['coder_patches']) {
+            $patch = $filename;
+            $filename = $name;
+          }
           $coder_args = array(
             '#reviews' => $reviews,
             '#severity' => $settings['coder_severity'],
             '#filename' => $filename,
+            '#patch' => $patch,
           );
           $results = do_coder_reviews($coder_args);
           $stats[$filename] = $results['#stats'];
@@ -679,8 +754,13 @@ function coder_page_form($form_state) {
           $summary['files'] ++;
         }
         $display = array();
-        $display[] = t('Coder found @count projects', array('@count' => count($stats)));
-        $display[] = t('@count files', array('@count' => $summary['files']));
+        if ($settings['coder_patches']) {
+          $display[] = t('Coder found @count patches', array('@count' => count($stats)));
+        }
+        else {
+          $display[] = t('Coder found @count projects', array('@count' => count($stats)));
+          $display[] = t('@count files', array('@count' => $summary['files']));
+        }
         foreach (array('critical', 'normal', 'minor') as $severity_name) {
           if ($summary[$severity_name] > 0) {
             $display[] = t('@count %severity_name warnings', array('@count' => $summary[$severity_name], '%severity_name' => $severity_name));
@@ -792,6 +872,7 @@ function _coder_modified() {
  *     - '#reviews' => array list of reviews to perform, see _coder_reviews();
  *     - '#severity' => integer magic number, see constants SEVERITY_*;
  *     - '#filename' => string filename to check,
+ *     - '#patch' => string patch lines to check,
  * @return
  *   Array of results, in form:
  *     - '#stats' => Array with error counts for all severities, in form
@@ -800,7 +881,7 @@ function _coder_modified() {
  *     - integer ID => HTML error for display.
  */
 function do_coder_reviews($coder_args) {
-  if ($use_cache = variable_get('coder_cache', 1)) {
+  if ($use_cache = variable_get('coder_cache', 1) && empty($coder_args['#patch'])) {
     // Load the cached results if they exist.
     $cache_key = 'coder:'.  implode(':', array_keys($coder_args['#reviews'])) .  $coder_args['#severity'] .':'. $coder_args['#filename'];
     $cache_mtime = filemtime(realpath($coder_args['#filename']));
@@ -867,15 +948,22 @@ function do_coder_reviews($coder_args) {
  */
 function _coder_read_and_parse_file(&$coder_args) {
   // Get the path to the module file.
-  if ($filepath = realpath($coder_args['#filename'])) {
-    // Read the file.
-    $content = file_get_contents($filepath) ."\n";
+  if (!empty($coder_args['#patch']) || $filepath = realpath($coder_args['#filename'])) {
+    $in_php = 0;
+    $in_allphp = 0;
+
+    if (empty($coder_args['#patch'])) {
+      $content = file_get_contents($filepath) ."\n";
+    }
+    else {
+      $content = $coder_args['#patch'];
+      $in_php = 1;
+      $in_allphp = 1;
+    }
     $content_length = drupal_strlen($content);

     $in_comment = 0;
     $beginning_of_line = 0;
-    $in_php = 0;
-    $in_allphp = 0;
     $in_quote_html = 0;
     $in_backslash = 0;
     $in_quote = 0;
