Index: wordpress/wp-includes/shortcodes.php
===================================================================
--- wordpress/wp-includes/shortcodes.php	(revision 7583)
+++ wordpress/wp-includes/shortcodes.php	(working copy)
@@ -75,23 +75,28 @@
 	$tagnames = array_keys($shortcode_tags);
 	$tagregexp = join( '|', array_map('preg_quote', $tagnames) );
 
-	$pattern = '/\[('.$tagregexp.')\b(.*?)(?:(\/))?\](?:(.+?)\[\/\1\])?/s';
+	$pattern = '/(.?)\[('.$tagregexp.')\b(.*?)(?:(\/))?\](?:(.+?)\[\/\2\])?(.?)/s';
 
 	return preg_replace_callback($pattern, 'do_shortcode_tag', $content);
 }
 
 function do_shortcode_tag($m) {
 	global $shortcode_tags;
+	
+	// allow [[foo]] syntax for escaping a tag
+	if ($m[1] == '[' && $m[6] == ']') {
+		return substr($m[0], 1, -1);
+	}
 
-	$tag = $m[1];
-	$attr = shortcode_parse_atts($m[2]);
+	$tag = $m[2];
+	$attr = shortcode_parse_atts($m[3]);
 
-	if ( isset($m[4]) ) {
+	if ( isset($m[5]) ) {
 		// enclosing tag - extra parameter
-		return call_user_func($shortcode_tags[$tag], $attr, $m[4]);
+		return $m[1] . call_user_func($shortcode_tags[$tag], $attr, $m[5]) . $m[6];
 	} else {
 		// self-closing tag
-		return call_user_func($shortcode_tags[$tag], $attr);
+		return $m[1] . call_user_func($shortcode_tags[$tag], $attr) . $m[6];
 	}
 }
 
