--- path_redirect/path_redirect.admin.inc.ORIGINAL	2009-12-02 12:19:15.000000000 +0100
+++ path_redirect/path_redirect.admin.inc		2009-12-09 16:54:48.000000000 +0100
@@ -448,6 +448,13 @@ function path_redirect_settings_form() {
     '#default_value' => variable_get('path_redirect_auto_redirect', 1),
     '#access' => module_exists('path'),
   );
+  $form['path_redirect_use_wildcards'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Enable use of wildcards (*) in redirects ("From:" and "To:" fields).'),
+    '#description' => t('<b>Check redirects carefully if you disable this option</b> once it has been used already, as <b>all redirects with wildcards will stop working</b>. This option is <b>disabled</b> for <b>PostgreSQL</b>.'),
+    '#default_value' => variable_get('path_redirect_use_wildcards', 0),
+    '#disabled' => $GLOBALS['db_type'] == 'pgsql',
+  );
   $form['path_redirect_purge_inactive'] = array(
     '#type' => 'select',
     '#title' => t('Discard redirects that have not been accessed for'),
--- path_redirect/path_redirect.module.ORIGINAL		2009-12-02 11:54:25.000000000 +0100
+++ path_redirect/path_redirect.module			2009-12-09 16:02:36.000000000 +0100
@@ -165,6 +165,28 @@ function path_redirect_goto($redirect = 
     else {
       // Perform the redirect.
       unset($_REQUEST['destination']);
+
+      if (($GLOBALS['db_type'] != 'pgsql') AND variable_get('path_redirect_use_wildcards', NULL) == 1) {
+        if (substr_count($redirect['source'], '*') > 0) {
+          $red_from_format = $redirect['source'];
+          $red_to_format = $redirect['redirect'];
+
+          $redirect['source'] = path_redirect_get_path();
+          $redirect['source_query'] = path_redirect_get_query();
+
+          $red_from = $redirect['source'];
+          $red_to = '';
+
+          $error = path_redirect_match_wildcards($red_from, $red_from_format, $red_to_format, $red_to);
+
+          if ($error == 0) {
+            $redirect['redirect'] = $red_to;
+          }
+          $redirect['query'] = $redirect['source_query'];
+          $redirect['redirect_url'] = url($redirect['redirect'], array('query' => $redirect['query'], 'fragment' => $redirect['fragment'], 'absolute' => TRUE));
+        }
+      }
+
       drupal_goto($redirect['redirect_url'], NULL, NULL, $redirect['type']);
     }
   }
@@ -432,8 +454,14 @@ function path_redirect_load($rid) {
  *   An optional query string to match.
  */
 function path_redirect_load_by_source($source, $language = '', $query = array()) {
-  $where = $query ? "(source = '%s' OR source LIKE '%s')" : "source = '%s'";
-  $args = ($query ? array($source, $source . '?%%') : array($source)) + array($language);
+  if (($GLOBALS['db_type'] != 'pgsql') AND variable_get('path_redirect_use_wildcards', NULL) == 1) {
+    $where = $query ? "(source = '%s' OR source LIKE '%s' OR (source LIKE '%%*%' AND '%s' REGEXP CONCAT('^', REPLACE(source, '*', '([[:alnum:]]|_|-)+'), '$')) OR (source LIKE '%%*' AND '%s' REGEXP CONCAT('^', source)))" : "(source = '%s' OR (source LIKE '%%*%' AND '%s' REGEXP CONCAT('^', REPLACE(source, '*', '([[:alnum:]]|_|-)+'), '$')) OR (source LIKE '%%*' AND '%s' REGEXP CONCAT('^', source)))";
+    $args = array_merge(($query ? array($source, $source . '?%%', $source, $source, $source) : array($source, $source, $source, $source)), array($language));
+  }
+  else {
+    $where = $query ? "(source = '%s' OR source LIKE '%s')" : "source = '%s'";
+    $args = ($query ? array($source, $source . '?%%') : array($source)) + array($language);
+  }
   $rid_query = db_query("SELECT rid FROM {path_redirect} WHERE $where AND language IN ('%s', '') ORDER BY language DESC, source DESC, rid DESC", $args);
   $rids = array();
   while ($rid = db_result($rid_query)) {
@@ -665,3 +693,178 @@ function path_redirect_variables() {
     'path_redirect_nodeapi_enabled' => NULL,
   );
 }
+
+function path_redirect_match_wildcards($in, $in_fmt, $out_fmt, &$out) {
+// -------------------------------------------------------------------------------------
+// Function parses input string ($in) according to input format string ($in_fmt), and
+// replaces corresponding wildcard characters (*) in output format string ($out_fmt)
+// with the first possible matches from input string ($in); if there are more wildcard
+// characters in input format string ($in_fmt) as in output format string ($out_fmt),
+// only replacements for the first matching ones are used to calculate the output string
+// -------------------------------------------------------------------------------------
+// Function returns calculated string setting the $out argument
+// -------------------------------------------------------------------------------------
+// Function returns the error code:
+// 0 => OK,
+// 1 => wildcard error,
+// > 1 => input string ($in) doesn't match input format string ($in_fmt)
+// -------------------------------------------------------------------------------------
+
+  $out = '';
+  $error = 0;
+
+  // Wildcards should not be repeated in $in_fmt (ambiguity)
+  while (substr_count($in_fmt, '**') > 0) {
+    $in_fmt = str_replace('**', '*', $in_fmt);
+  }
+
+  $wcif = substr_count($in_fmt, '*');
+  $wcof = substr_count($out_fmt, '*');
+
+  if ($wcif < $wcof) {
+    // ERROR #1: The number of wildcards in $in_fmt shall not
+    // be smaller than the number of wildcards in $out_fmt (as
+    // some of them could not be resolved in such a case):
+    $out = '';
+    $error = 1;
+  }
+
+  if ($error == 0) {
+    if ($wcif > 0) {
+    // There is at least one wildcard in $in_fmt:
+      $wpif = strpos($in_fmt, '*');
+
+      if ($wpif > 0) {
+        // If there is anything left to the first wildcard character in $in_fmt, the
+        // same substring ($match) shall be at the very beginning of $in as well;
+        // If so, we strip the matching part ($match) from the left of both strings,
+        // and proceed with the rest; otherwise, we set "INPUT DOESN'T MATCH" error
+        $match = substr($in_fmt, 0, $wpif);
+
+        if (substr($in, 0, $wpif) == $match) {
+          $in = substr($in, $wpif);
+          $in_fmt = substr($in_fmt, $wpif);
+        }
+        else {
+          // ERROR #2: $in doesn't match $in_fmt!!!
+          $out = '';
+          $error = 2;
+        }
+      }
+
+      if ($error == 0) {
+        // We have a wildcard character at the beginning of $in_fmt here for sure!
+        $in_fmt = substr($in_fmt, 1);
+        $wcif--;
+
+        if ($wcif > 0) {
+          // There is another wildcard somewhere in $in_fmt...
+          // We strip the substring found between both wildcards ($match) from $in_fmt
+
+          $wpif = strpos($in_fmt, '*');
+          $match = substr($in_fmt, 0, $wpif);
+          $in_fmt = substr($in_fmt, $wpif);
+
+          if (substr_count($in, $match) > 0) {
+            // There is at least one $match in $in; everything left to the first $match
+            // within $in is considered to be a replacement ($repl) for the first wildcard;
+            // we strip ($repl . $match) from $in, and proceed with the rest...
+            $wpi = strpos($in, $match);
+            $repl = substr($in, 0, $wpi);
+            $in = substr($in, $wpi + strlen($match));
+
+            if ($wcof > 0) {
+              // If there are any wildcards in $out_fmt left, we replace the first one
+              $wpof = strpos($out_fmt, '*');
+              $out_fmt = substr_replace($out_fmt, $repl, $wpof, 1);
+              $wcof--;
+            }
+          }
+          else {
+            // ERROR #3: $in doesn't match $in_fmt!!!
+            $out = '';
+            $error = 3;
+          }
+
+          if ($error == 0) {
+            if (strlen($in_fmt) > 0) {
+              // If there are more wildcards in $in_fmt,
+              // just recursively process the remaining...
+              $error = path_redirect_match_wildcards($in, $in_fmt, $out_fmt, $out);
+            }
+            else {
+              // We've done it...
+              $out = $out_fmt;
+            }
+          }
+        }
+        else {
+          // There is no wildcard in $in_fmt anymore...
+          // If there is anything in $in_fmt, it must match the right substring of $in
+          // (nothing should be right to the last $match within $in), and all the
+          // rest (before that $match) is considered as this last replacement ($repl)
+          $match = $in_fmt;
+
+          if ($match == '') {
+            // We've had only the wildcard character in $in_fmt here
+            // (the whole $in is a replacement $repl)
+            $repl = $in;
+
+            if ($wcof > 0) {
+            // If there are any wildcards in $out_fmt left, we replace the first one
+              $wpof = strpos($out_fmt, '*');
+              $out_fmt = substr_replace($out_fmt, $repl, $wpof, 1);
+              $wcof--;
+            }
+
+            // We've done it...
+            $out = $out_fmt;
+          }
+          elseif (substr_count($in, $match) > 0) {
+          // As stated above, there should be a match, and nothing right to it within $in
+          // (everything left to $match is considered as a replacement $repl)
+            $wpi = strrpos($in, $match);
+            $repl = substr($in, 0, $wpi);
+
+            if (strlen($in) > $wpi + strlen($match)) {
+            // ERROR #4: $in doesn't match $in_fmt!!!
+              $out = '';
+              $error = 4;
+            }
+            else {
+              if ($wcof > 0) {
+                // If there are any wildcards in $out_fmt left, we replace the first one
+                $wpof = strpos($out_fmt, '*');
+                $out_fmt = substr_replace($out_fmt, $repl, $wpof, 1);
+                $wcof--;
+              }
+
+              // We've done it...
+              $out = $out_fmt;
+            }
+          }
+          else {
+            // ERROR #5: $in doesn't match $in_fmt!!!
+            $out = '';
+            $error = 5;
+          }
+        }
+      }
+    }
+    else {
+    // There is no wildcard character in $in_fmt;
+    // if $in and $in_fmt do match, we've done it...
+      if (strcmp($in, $in_fmt) == 0) {
+        $out = $out_fmt;
+        $error = 0;
+      }
+      else {
+        // ERROR #6: $in doesn't match $in_fmt!!!
+        $out = '';
+        $error = 6;
+      }
+    }
+  }
+
+  return $error;
+}
