Index: Source/NSArray.m
===================================================================
--- Source/NSArray.m	(revision 35406)
+++ Source/NSArray.m	(working copy)
@@ -53,6 +53,10 @@
 #import "GSPrivate.h"
 #import "GSFastEnumeration.h"
 #import "GSDispatch.h"
+
+NSArray *mergeSort(NSArray *a, NSComparator cmp);
+NSArray *merge(NSArray *a, NSArray *b, NSComparator cmp);
+
 static BOOL GSMacOSXCompatiblePropertyLists(void)
 {
   if (GSPrivateDefaultsFlag(NSWriteOldStylePropertyLists) == YES)
@@ -1838,6 +1842,81 @@
     indexOfObjectWithOptions: 0
     passingTest: predicate];
 }
+
+- (NSArray *)sortedArrayUsingComparator:(NSComparator)cmptr
+{
+  return [self sortedArrayWithOptions:0UL usingComparator:cmptr];
+}
+
+- (NSArray *)sortedArrayWithOptions:(NSSortOptions)opts usingComparator:(NSComparator)cmptr
+{
+  // We ignore the stable sorting flag and always use merge sort (which is stable)
+  /* TODO: Concurrency. */
+  return [[mergeSort(self, cmptr) copy] autorelease];
+}
+
+- (NSUInteger)indexOfObject:(id)obj
+              inSortedRange:(NSRange)r
+                    options:(NSBinarySearchingOptions)opts
+            usingComparator:(NSComparator)cmp
+{
+  if (r.length == 0)
+  {
+    return opts & NSBinarySearchingInsertionIndex ? r.location : NSNotFound;
+  }
+  
+  if (r.length == 1)
+  {
+    NSComparisonResult cr = cmp(obj, [self objectAtIndex:r.location]);
+    switch (cr)
+    {
+      case NSOrderedSame:
+        return r.location;
+      case NSOrderedAscending:
+        return opts & NSBinarySearchingInsertionIndex ? r.location : NSNotFound;
+      case NSOrderedDescending:
+        return opts & NSBinarySearchingInsertionIndex ? r.location + 1
+                                                      : NSNotFound;
+    }
+  }
+  
+  NSUInteger midPoint = r.length / 2;
+  NSComparisonResult cr = cmp(obj, [self objectAtIndex:r.location + midPoint]);
+  switch (cr)
+  {
+    case NSOrderedSame:
+      if (opts & NSBinarySearchingFirstEqual)
+      {
+        NSUInteger idx = [self indexOfObject:obj
+                               inSortedRange:NSMakeRange(r.location, midPoint)
+                                     options:opts
+                             usingComparator:cmp];
+        return idx == NSNotFound ? r.location + midPoint : idx;
+      }
+      else if (opts & NSBinarySearchingLastEqual)
+      {
+        return [self indexOfObject:obj
+                     inSortedRange:NSMakeRange(r.location + midPoint, r.length - midPoint)
+                           options:opts
+                   usingComparator:cmp];
+      }
+      else
+      {
+        return r.location + midPoint;
+      }
+    case NSOrderedAscending:
+      return [self indexOfObject:obj
+                   inSortedRange:NSMakeRange(r.location, midPoint)
+                         options:opts
+                 usingComparator:cmp];
+    case NSOrderedDescending:
+      return [self indexOfObject:obj
+                   inSortedRange:NSMakeRange(r.location + midPoint, r.length - midPoint)
+                         options:opts
+                 usingComparator:cmp];
+  }
+}
+
 @end
 
 

@@ -2581,3 +2660,57 @@
 }
 @end
 
+NSArray *mergeSort(NSArray *a, NSComparator cmp)
+{
+  NSUInteger l = [a count];
+  
+  if (l <= 1)
+  {
+    return [[a copy] autorelease];
+  }
+  
+  NSUInteger m = l / 2;
+  return merge(mergeSort([a subarrayWithRange:NSMakeRange(0, m    )], cmp),
+               mergeSort([a subarrayWithRange:NSMakeRange(m, l - m)], cmp),
+               cmp);
+}
+
+NSArray *merge(NSArray *a, NSArray *b, NSComparator cmp)
+{
+  NSUInteger al = [a count];
+  NSUInteger bl = [b count];
+  NSMutableArray *r = [NSMutableArray arrayWithCapacity:al + bl];
+  NSEnumerator *ae = [a objectEnumerator];
+  NSEnumerator *be = [b objectEnumerator];
+  id ao = [ae nextObject];
+  id bo = [be nextObject];
+  while (ao != nil && bo != nil)
+  {
+    NSComparisonResult cr = cmp(ao, bo);
+    if (cr == NSOrderedAscending)
+    {
+      [r addObject:ao];
+      ao = [ae nextObject];
+    }
+    else
+    {
+      [r addObject:bo];
+      bo = [be nextObject];
+    }
+  }
+  // We now drain both enumerators, as one of them is empty.
+   // We now drain both enumerators, as one of them is empty.
+  if (nil != ao)
+  {
+    [r addObject:ao];
+    [r addObjectsFromArray:[ae allObjects]];
+  }
+  else
+  {
+    [r addObject:bo];
+    [r addObjectsFromArray:[be allObjects]];
+  }
+ 
+  return r;
+}
+
Index: Headers/Foundation/NSArray.h
===================================================================
--- Headers/Foundation/NSArray.h	(revision 35406)
+++ Headers/Foundation/NSArray.h	(working copy)
@@ -212,6 +212,47 @@
 - (NSUInteger) indexOfObjectAtIndexes: (NSIndexSet*)indexSet
 			      options: (NSEnumerationOptions)opts
 			  passingTest: (GSPredicateBlock)predicate;
+
+/**
+ * Returns a sorted array using the block to determine the order of objects.
+ */
+- (NSArray *)sortedArrayUsingComparator:(NSComparator)cmptr;
+
+/**
+ * Returns a sorted array using the block to determine the order of objects.
+ *
+ * The opts argument is a bitfield.  Setting the NSSortConcurrent flag
+ * specifies that it is thread-safe.  The NSSortStable bit specifies that
+ * it should keep equal objects in the same order.
+ */
+- (NSArray *)sortedArrayWithOptions:(NSSortOptions)opts usingComparator:(NSComparator)cmptr;
+
+enum
+{
+  NSBinarySearchingFirstEqual = (1UL << 8), /** Specifies that the binary
+   * search should find the first object equal in the array.
+   */
+  NSBinarySearchingLastEqual = (1UL << 9), /** Specifies that the binary
+   * search should find the last object equal in the array.
+   */
+  NSBinarySearchingInsertionIndex = (1UL << 10), /** Specifies that the binary
+   * search should find the index at which an equal object should be inserted
+   * in order to keep the array sorted
+   */
+};
+
+typedef NSUInteger NSBinarySearchingOptions;
+
+/**
+ * Performs a binary search of the array within the specified range for the
+ * index of an object equal to obj according to cmp.
+ * If NSBinarySearchingInsertionIndex is specified, searches for the index
+ * at which such an object should be inserted.
+ */
+- (NSUInteger)indexOfObject:(id)obj
+              inSortedRange:(NSRange)r
+                    options:(NSBinarySearchingOptions)opts
+            usingComparator:(NSComparator)cmp;
 #endif
 /**
  * Accessor for subscripting.  This is called by the compiler when you write
Index: Headers/Foundation/NSObjCRuntime.h
===================================================================
--- Headers/Foundation/NSObjCRuntime.h	(revision 35406)
+++ Headers/Foundation/NSObjCRuntime.h	(working copy)
@@ -42,6 +42,7 @@
 
 #import	<GNUstepBase/GSVersionMacros.h>
 #import	<GNUstepBase/GSConfig.h>
+#import <GNUstepBase/GSBlocks.h>
 
 /* These typedefs must be in place before GSObjCRuntime.h is imported.
  */
@@ -99,6 +100,21 @@
  */
 typedef NSUInteger NSEnumerationOptions;
 
+enum
+{
+    NSSortConcurrent = (1UL << 0), /** Specifies that the sort
+     * is concurrency-safe.  Note that this does not mean that it will be
+     * carried out in a concurrent manner, only that it can be.
+     */
+    NSSortStable = (1UL << 4), /** Specifies that the sort should keep
+     * equal objects in the same order in the collection.
+     */
+};
+
+/** Bitfield used to specify options to control the sorting of collections.
+ */
+typedef NSUInteger NSSortOptions;
+
 #import <GNUstepBase/GSObjCRuntime.h>
 
 #if OS_API_VERSION(100500,GS_API_LATEST)
@@ -153,6 +169,7 @@
 
 enum {NSNotFound = NSIntegerMax};
 
+DEFINE_BLOCK_TYPE(NSComparator, NSComparisonResult, id, id);
 
 #ifdef __clang__
 #define NS_REQUIRES_NIL_TERMINATION __attribute__((sentinel))
Index: Tests/base/NSArray/blocks.m
===================================================================
--- Tests/base/NSArray/blocks.m	(revision 35406)
+++ Tests/base/NSArray/blocks.m	(working copy)
@@ -4,8 +4,8 @@
 #import <Foundation/NSIndexSet.h>
 #import <Foundation/NSString.h>
 #import <Foundation/NSEnumerator.h>
+#import <Foundation/NSValue.h>
 
-
 static NSUInteger fooCount = 0;
 static NSUInteger lastIndex = NSNotFound;
 int main()
@@ -50,6 +50,14 @@
     && (NO == [set containsIndex: 1])),
     "Can select object indices based on block predicate.");
   [arp release]; arp = nil;
+  
+  array = [NSArray arrayWithObjects:[NSNumber numberWithInteger:2], [NSNumber numberWithInteger:5], [NSNumber numberWithInteger:3], [NSNumber numberWithInteger:2], [NSNumber numberWithInteger:10], nil];
+  NSArray *sortedArray = [NSArray arrayWithObjects:[NSNumber numberWithInteger:2], [NSNumber numberWithInteger:2], [NSNumber numberWithInteger:3], [NSNumber numberWithInteger:5], [NSNumber numberWithInteger:10], nil];
+  PASS([sortedArray isEqualToArray:[array sortedArrayUsingComparator:^ NSComparisonResult (NSNumber *a, NSNumber *b) { return [a compare:b]; }]], "Can sort arrays with NSComparators.");
+  PASS(0 == [sortedArray indexOfObject:[NSNumber numberWithInteger:2] inSortedRange:NSMakeRange(0, [sortedArray count]) options:NSBinarySearchingFirstEqual usingComparator:^ NSComparisonResult (NSNumber *a, NSNumber *b) { return [a compare:b]; }], "Can find index of first object in sorted array");
+  PASS(1 == [sortedArray indexOfObject:[NSNumber numberWithInteger:2] inSortedRange:NSMakeRange(0, [sortedArray count]) options:NSBinarySearchingLastEqual usingComparator:^ NSComparisonResult (NSNumber *a, NSNumber *b) { return [a compare:b]; }], "Can find index of first object in sorted array");
+  PASS(3 == [sortedArray indexOfObject:[NSNumber numberWithInteger:4] inSortedRange:NSMakeRange(0, [sortedArray count]) options:NSBinarySearchingInsertionIndex usingComparator:^ NSComparisonResult (NSNumber *a, NSNumber *b) { return [a compare:b]; }], "Can find insertion index in sorted array");
+  PASS(NSNotFound == [sortedArray indexOfObject:[NSNumber numberWithInteger:4] inSortedRange:NSMakeRange(0, [sortedArray count]) options:0 usingComparator:^ NSComparisonResult (NSNumber *a, NSNumber *b) { return [a compare:b]; }], "Can not find non existant object in sorted array");
 # else
   SKIP("No Blocks support in the compiler.")
 # endif
