--- freelinking.module	2007-02-17 20:47:15.000000000 +0800
+++ freelinking.module	2007-09-10 12:05:37.000000000 +0800
@@ -250,48 +250,87 @@ function freelinking_form_alter($form_id
 */
 
 function _freelinking_do_filtering($text, $store = FALSE) {
-  $allowcamelcase = variable_get("freelinking_camelcase", TRUE);
-  $freelinkingregexp = '/\[\[.+]]/U'; // this finds [[links like this]], un-greedily
-  preg_match_all($freelinkingregexp, $text, $flmatches);
-  if ($allowcamelcase) {
-     $camelcaseregexp = '/\b([[:upper:]][[:lower:]]+){2,}\b/'; // this gets us close, but is not perfect. Example: ThisIsACamelCaseWord won't match (two caps in a row)
-     preg_match_all($camelcaseregexp, $text, $ccmatches);
-     $wikiwords = array_merge($ccmatches[0], $flmatches[0]);
-  }
-  else {
-     $wikiwords = $flmatches[0];
-  }
-  foreach (array_unique($wikiwords) as $wikiword) {
-    if (substr($wikiword, 0, 2) == '[[') { // if it's a freelink, the expressions are different
-      $phrase = substr($wikiword, 2, -2);
-      $freelink = $phrase;
-      $barpos = strpos($phrase, '|');
-      $pattern = '/\[\[' . preg_quote($phrase,'/') . ']]/';
-      if ($barpos) {
-         $freelink = substr($freelink, 0, $barpos);
-         $phrase = substr($phrase, $barpos + 1);
-      }
-      if (preg_match('/^(http|mailto|https|ftp):/', $freelink)) {
-         $replacement = '<a class="freelinking external" href="' . $freelink . '">' . $phrase . '</a>';
-      }
-      else {
-        $replacement = l($phrase, 'freelinking/' . rawurlencode(htmlspecialchars(rawurlencode($freelink))), array('class' => 'freelinking'));
-      }
-    }
-
-    else if ($allowcamelcase) { // it's a CamelCase, expressions are a bit simpler
-      $pattern = '/\b' . $wikiword . '\b(?![^<]*>)/';
-      $phrase = $wikiword; // consistency for the db
-      $freelink = $wikiword; // also for the db
-      $replacement = l($wikiword, 'freelinking/' . urlencode($wikiword));
-    }
-    $text = preg_replace($pattern, $replacement, $text, variable_get("freelinking_onceonly", 0) ? 1 : -1);
-    
-    if ($store) {
-      _freelinking_store($phrase, $replacement);
-    }
-  } // foreach wikiword
-  return $text;
+	// First pass. Only bracketed links
+	$freelinkingregexp = '/\[\[.+]]/U'; // this finds [[ links like this]], un-greedily
+	preg_match_all($freelinkingregexp, $text, $flmatches);
+	$wikiwords = $flmatches[0];
+
+	$tokens = $phrases = $replacements = array();
+	foreach (array_unique($wikiwords) as $wikiword) {
+		if (substr($wikiword, 0, 2) == '[[') { // if it's a freelink, the expressions are different
+			$phrase = substr($wikiword, 2, -2);
+			$freelink = $phrase;
+			$barpos = strpos($phrase, '|');
+			$pattern = '/\[\[' . preg_quote($phrase, '/') . ']]/';
+			if ($barpos) {
+				$freelink = substr($freelink, 0, $barpos);
+				$phrase = substr($phrase, $barpos + 1);
+			}
+			if (preg_match('/^(http|mailto|https|ftp):/', $freelink)) {
+				$replacement = '<a class="freelinking external" href="' . $freelink . '">' . $phrase . '</a>';
+			}
+			else {
+				$replacement = l($phrase, 'freelinking/' . rawurlencode($freelink), array('class' => 'freelinking'));
+			}
+		}
+		$index = count($tokens);
+		$token = '::TOKEN'.$index.'::';
+		$tokens[$index] = '/'.$token.'/';
+		$phrases[$index] = $phrase;
+		$replacements[$index] = $replacement;
+
+		$text = preg_replace($pattern, $token, $text);
+	} // foreach wikiword
+
+	// Second pass. CamelCase links (if required).
+	$allowcamelcase = variable_get("freelinking_camelcase", TRUE);
+
+	$cctokens = $ccphrases = $ccreplacements = array();
+	if ($allowcamelcase) {
+		// this gets us close, but is not perfect. Example: ThisIsACamelCaseWord won't match (two caps in a row)
+		$camelcaseregexp = '/\b([[:upper:]][[:lower:][:digit:]]+){2,}\b/';
+		preg_match_all($camelcaseregexp, $text, $ccmatches);
+		$wikiwords = $ccmatches[0];
+
+		foreach (array_unique($wikiwords) as $wikiword) {
+			$pattern = '/\b' . $wikiword . '\b(?![^<]*>)/';
+			$phrase = $wikiword; // consistency for the db
+			$freelink = $wikiword; // also for the db
+			$replacement = l($wikiword, 'freelinking/' . urlencode($wikiword));
+
+			$index = count($cctokens);
+			$token = '::CCTOKEN'.$index.'::';
+			$cctokens[$index] = '/'.$token.'/';
+			$ccphrases[$index] = $phrase;
+			$ccreplacements[$index] = $replacement;
+
+			$text = preg_replace($pattern, $token, $text);
+		} // foreach wikiword
+	}
+
+	// Replace the tokens
+	ksort($tokens);
+	ksort($replacements);
+	$text = preg_replace($tokens, $replacements, $text);
+	ksort($cctokens);
+	ksort($ccreplacements);
+	$text = preg_replace($cctokens, $ccreplacements, $text, variable_get("freelinking_onceonly", 0) ? 1 : -1);
+
+	if ($store) {
+		ksort($phrases);
+		foreach ($phrases as $key => $phrase) {
+			_freelinking_store($phrases[$key], $replacements[$key]);
+		}
+
+		if ($allowcamelcase) {
+			ksort($ccphrases);
+			foreach ($ccphrases as $key => $phrase) {
+				_freelinking_store($ccphrases[$key], $ccreplacements[$key]);
+			}
+		}
+	}
+
+	return $text;
 } // endfunction _freelinking_do_filtering
 
 function _freelinking_store($phrase, $path, $args=NULL) { // store freelinking pair in the db
