diff --git a/.gitignore b/.gitignore
index 94061ea70..39b909942 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,7 @@
+.DS_Store
build
build/revision
+._*
*.xcodeproj/
!*.xcodeproj/project.pbxproj
Nightly.app.zip
diff --git a/.gitmodules b/.gitmodules
deleted file mode 100644
index 255017267..000000000
--- a/.gitmodules
+++ /dev/null
@@ -1,3 +0,0 @@
-[submodule "libgit2"]
- path = libgit2
- url = git://github.com/pieter/libgit2.git
diff --git a/AIURLAdditions.h b/AIURLAdditions.h
new file mode 100644
index 000000000..300da08ca
--- /dev/null
+++ b/AIURLAdditions.h
@@ -0,0 +1,44 @@
+/*
+ * Adium is the legal property of its developers, whose names are listed in the copyright file included
+ * with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License as published by the Free Software Foundation; either version 2 of the License,
+ * or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with this program; if not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+
+/*!
+ * Provides some additional functionality when working with \c NSURL objects.
+ */
+@interface NSURL (AIURLAdditions)
+
+/**
+ * @brief The length of the URL.
+ *
+ * @return The length (number of characters) of the absolute URL.
+ */
+@property (readonly, nonatomic) NSUInteger length;
+
+/*!
+ * @brief Returns the argument for the specified key in the query string component of
+ * the URL.
+ *
+ * The search is case-sensitive, and the caller is responsible for removing any
+ * percent escapes, as well as "+" escapes, too.
+ *
+ * @param key The key whose value should be located and returned.
+ * @return The argument for the specified key, or \c nil if the key could not
+ * be found in the query string.
+ */
+- (NSString *)queryArgumentForKey:(NSString *)key;
+- (NSString *)queryArgumentForKey:(NSString *)key withDelimiter:(NSString *)delimiter;
+
+@end
diff --git a/AIURLAdditions.m b/AIURLAdditions.m
new file mode 100644
index 000000000..2b99947cc
--- /dev/null
+++ b/AIURLAdditions.m
@@ -0,0 +1,55 @@
+/*
+ * Adium is the legal property of its developers, whose names are listed in the copyright file included
+ * with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License as published by the Free Software Foundation; either version 2 of the License,
+ * or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with this program; if not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#import "AIURLAdditions.h"
+
+@implementation NSURL (AIURLAdditions)
+
+- (NSUInteger)length
+{
+ return [[self absoluteString] length];
+}
+
+- (NSString *)queryArgumentForKey:(NSString *)key withDelimiter:(NSString *)delimiter
+{
+ for (NSString *obj in [[self query] componentsSeparatedByString:delimiter]) {
+ NSArray *keyAndValue = [obj componentsSeparatedByString:@"="];
+
+ if (([keyAndValue count] >= 2) && ([[keyAndValue objectAtIndex:0] caseInsensitiveCompare:key] == NSOrderedSame)) {
+ return [keyAndValue objectAtIndex:1];
+ }
+ }
+
+ return nil;
+}
+
+- (NSString *)queryArgumentForKey:(NSString *)key
+{
+ NSString *delimiter;
+
+ // The arguments in query strings can be delimited with a semicolon (';') or an ampersand ('&'). Since it's not
+ // likely a single URL would use both types of delimeters, we'll attempt to pick one and use it.
+ if ([[self query] rangeOfString:@";"].location != NSNotFound) {
+ delimiter = @";";
+ } else {
+ // Assume '&' by default, since that's more common
+ delimiter = @"&";
+ }
+
+ return [self queryArgumentForKey:key withDelimiter:delimiter];
+}
+
+@end
diff --git a/ApplicationController.h b/ApplicationController.h
index d611acbba..a417854df 100644
--- a/ApplicationController.h
+++ b/ApplicationController.h
@@ -7,7 +7,6 @@
//
#import
-#import "PBGitRepository.h"
@class PBCloneRepositoryPanel;
@@ -20,6 +19,8 @@
NSManagedObjectContext *managedObjectContext;
PBCloneRepositoryPanel *cloneRepositoryPanel;
+
+ NSDictionary *notificationUserInfo;
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator;
diff --git a/ApplicationController.m b/ApplicationController.m
index 6794b14d1..f8a5b8455 100644
--- a/ApplicationController.m
+++ b/ApplicationController.m
@@ -17,6 +17,13 @@
#import "PBGitDefaults.h"
#import "PBCloneRepositoryPanel.h"
#import "Sparkle/SUUpdater.h"
+#import "AIURLAdditions.h"
+#import "PBGitRepository.h"
+
+@interface ApplicationController ()
+- (void) cleanUpRemotesOnError;
+@end
+
@implementation ApplicationController
@@ -31,7 +38,7 @@ - (ApplicationController*)init
if(![[NSBundle bundleWithPath:@"/System/Library/Frameworks/Quartz.framework/Frameworks/QuickLookUI.framework"] load])
if(![[NSBundle bundleWithPath:@"/System/Library/PrivateFrameworks/QuickLookUI.framework"] load])
- NSLog(@"Could not load QuickLook");
+ DLog(@"Could not load QuickLook");
/* Value Transformers */
NSValueTransformer *transformer = [[PBNSURLPathUserDefaultsTransfomer alloc] init];
@@ -55,26 +62,39 @@ - (void)registerServices
int serviceVersion = [[NSUserDefaults standardUserDefaults] integerForKey:@"Services Version"];
if (serviceVersion < 2)
{
- NSLog(@"Updating services menu…");
+ DLog(@"Updating services menu…");
NSUpdateDynamicServices();
[[NSUserDefaults standardUserDefaults] setInteger:2 forKey:@"Services Version"];
}
}
+- (void)applicationWillFinishLaunching:(NSNotification*)notification
+{
+ [[NSAppleEventManager sharedAppleEventManager] setEventHandler:self
+ andSelector:@selector(getUrl:withReplyEvent:)
+ forEventClass:kInternetEventClass
+ andEventID:kAEGetURL];
+}
+
- (void)applicationDidFinishLaunching:(NSNotification*)notification
{
- [[SUUpdater sharedUpdater] setSendsSystemProfile:YES];
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(getArguments:) name:@"GitCommandSent" object:Nil];
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(cleanGitAfterErrorMessage:) name:@"ErrorMessageDidEnd" object:Nil];
+
+ [[SUUpdater sharedUpdater] setSendsSystemProfile:YES];
[[SUUpdater sharedUpdater] setDelegate:self];
+ if ([PBGitDefaults useAskPasswd]) {
// Make sure Git's SSH password requests get forwarded to our little UI tool:
setenv( "SSH_ASKPASS", [[[NSBundle mainBundle] pathForResource: @"gitx_askpasswd" ofType: @""] UTF8String], 1 );
setenv( "DISPLAY", "localhost:0", 1 );
-
+ }
+
[self registerServices];
BOOL hasOpenedDocuments = NO;
NSArray *launchedDocuments = [[[PBRepositoryDocumentController sharedDocumentController] documents] copy];
-
+
// Only try to open a default document if there are no documents open already.
// For example, the application might have been launched by double-clicking a .git repository,
// or by dragging a folder to the app icon
@@ -109,11 +129,21 @@ - (void)applicationDidFinishLaunching:(NSNotification*)notification
if (![[NSApplication sharedApplication] isActive])
return;
+}
- // The current directory was not enabled or could not be opened (most likely it’s not a git repository).
- // show an open panel for the user to select a repository to view
- if ([PBGitDefaults showOpenPanelOnLaunch] && !hasOpenedDocuments)
- [[PBRepositoryDocumentController sharedDocumentController] openDocument:self];
+- (void)getUrl:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent
+{
+ NSString *urlString = [[event paramDescriptorForKeyword:keyDirectObject] stringValue];
+ NSURL *url = [NSURL URLWithString:urlString];
+
+ if ([url.host isEqual:@"clone"]) {
+ NSString * repo = [[url queryArgumentForKey:@"repo"] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
+
+ [self showCloneRepository:self];
+
+ [cloneRepositoryPanel.repositoryURL setStringValue:repo];
+ }
+
}
- (void) windowWillClose: sender
@@ -133,6 +163,9 @@ - (IBAction)showAboutPanel:(id)sender
if (gitversion)
[dict addEntriesFromDictionary:[[NSDictionary alloc] initWithObjectsAndKeys:gitversion, @"Version", nil]];
+ [dict addEntriesFromDictionary:[[NSDictionary alloc] initWithObjectsAndKeys:@"GitX (L)", @"ApplicationName", nil]];
+ [dict addEntriesFromDictionary:[[NSDictionary alloc] initWithObjectsAndKeys:@"(c) Pieter de Bie,2008\n(c) German Laullon,2011\nAnd more...", @"Copyright", nil]];
+
#ifdef DEBUG_BUILD
[dict addEntriesFromDictionary:[[NSDictionary alloc] initWithObjectsAndKeys:@"GitX (DEBUG)", @"ApplicationName", nil]];
#endif
@@ -216,7 +249,7 @@ - (NSManagedObjectModel *)managedObjectModel {
return managedObjectModel;
}
- managedObjectModel = [[NSManagedObjectModel mergedModelFromBundles:nil] retain];
+ managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil];
return managedObjectModel;
}
@@ -242,7 +275,7 @@ - (NSPersistentStoreCoordinator *) persistentStoreCoordinator {
fileManager = [NSFileManager defaultManager];
applicationSupportFolder = [self applicationSupportFolder];
if ( ![fileManager fileExistsAtPath:applicationSupportFolder isDirectory:NULL] ) {
- [fileManager createDirectoryAtPath:applicationSupportFolder attributes:nil];
+ [fileManager createDirectoryAtPath:applicationSupportFolder withIntermediateDirectories:YES attributes:nil error:nil];
}
url = [NSURL fileURLWithPath: [applicationSupportFolder stringByAppendingPathComponent: @"GitTest.xml"]];
@@ -363,6 +396,21 @@ - (void)applicationWillTerminate:(NSNotification *)aNotification
[PBGitDefaults setPreviousDocumentPaths:paths];
}
}
+
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+}
+
+- (BOOL)applicationShouldOpenUntitledFile:(NSApplication *)sender
+{
+ id dc = [PBRepositoryDocumentController sharedDocumentController];
+
+ // Reopen last document if user prefers
+ if ([PBGitDefaults showOpenPanelOnLaunch])
+ {
+ [dc openDocument:self];
+ }
+
+ return NO;
}
/**
@@ -371,10 +419,9 @@ - (void)applicationWillTerminate:(NSNotification *)aNotification
- (void) dealloc {
- [managedObjectContext release], managedObjectContext = nil;
- [persistentStoreCoordinator release], persistentStoreCoordinator = nil;
- [managedObjectModel release], managedObjectModel = nil;
- [super dealloc];
+ managedObjectContext = nil;
+ persistentStoreCoordinator = nil;
+ managedObjectModel = nil;
}
@@ -411,9 +458,39 @@ - (IBAction)showHelp:(id)sender
- (IBAction)reportAProblem:(id)sender
{
- [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"http://gitx.lighthouseapp.com/tickets"]];
+ [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"https://github.com/laullon/gitx/issues"]];
}
+#pragma mark - Observer methods
+
+- (void)getArguments:(NSNotification*)notification
+{
+ notificationUserInfo = [notification userInfo];
+}
+
+
+- (void)cleanGitAfterErrorMessage:(NSNotification*)notification
+{
+ // When adding a remote occurs an error the remote
+ // will be set on git and has to be removed to clean the remotes list
+ [self cleanUpRemotesOnError];
+
+
+
+}
+
+#pragma mark - Extensions
+- (void) cleanUpRemotesOnError
+{
+ // check, if arguments was to add a remote
+ if ( ([(NSString*)[notificationUserInfo valueForKey:@"Arg0"] compare:@"remote"] == NSOrderedSame) &&
+ ([(NSString*)[notificationUserInfo valueForKey:@"Arg1"] compare:@"add"] == NSOrderedSame)
+ )
+ {
+ PBGitRef *remoteRef = [PBGitRef refFromString:[NSString stringWithFormat:@"%@%@", kGitXRemoteRefPrefix,[notificationUserInfo valueForKey:@"Arg3"]]];
+ [[notificationUserInfo valueForKey:@"Repository"] deleteRemote:remoteRef];
+ }
+}
@end
diff --git a/BMDefines.h b/BMDefines.h
new file mode 100644
index 000000000..02a874fab
--- /dev/null
+++ b/BMDefines.h
@@ -0,0 +1,298 @@
+//
+// BMDefines.h
+// BMScriptTest
+//
+// Created by Andre Berg on 27.09.09.
+// Copyright 2009 Berg Media. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/*!
+ * @file BMDefines.h
+ *
+ * Provides defines mostly for debugging.
+ * This file may be included by any project as it does not really contain project-specific symbols.
+ * Consists mainly of stuff I have gathered from multiple sources or defined in my own work to help
+ * ease debugging and/or cross-platform development.
+ */
+
+#import
+#import
+#import
+#include
+
+/// @cond HIDDEN
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _BM_DEFINES_H_
+#define _BM_DEFINES_H_ 1
+/// @endcond
+
+
+/*!
+ * @addtogroup project_defines Project Defines
+ * @{
+ */
+
+// Determine runtine environment
+#if !defined(__MACOSX_RUNTIME__) && !defined(__GNUSTEP_RUNTIME__)
+ #if defined(__APPLE__) && defined(__MACH__) && !defined(GNUSTEP)
+ /*!
+ * @def MACOSX_RUNTIME
+ * Determine runtime environment.
+ * Defined if running on Mac OS X. GNUStep will not have this defined.
+ */
+ #define __MACOSX_RUNTIME__
+ #endif // If not Mac OS X, GNUstep?
+ #if defined(GNUSTEP) && !defined(__MACOSX_RUNTIME__)
+ /*!
+ * @def __GNUSTEP_RUNTIME__
+ * Determine runtime environment.
+ * Defined if running GNUStep. Mac OS X will not have this defined.
+ */
+ #define __GNUSTEP_RUNTIME__
+ #endif // Not Mac OS X or GNUstep, that's a problem.
+#endif // !defined(__MACOSX_RUNTIME__) && !defined(__GNUSTEP_RUNTIME__)
+
+// If the above did not set the run time environment, error out.
+#if !defined(__MACOSX_RUNTIME__) && !defined(__GNUSTEP_RUNTIME__)
+ #error Unable to determine run time environment, automatic Mac OS X and GNUstep detection failed
+#endif
+
+/*!
+ * @def ENABLE_MACOSX_GARBAGE_COLLECTION
+ * Preprocessor definition to enable Mac OS X 10.5 (Leopard) Garbage Collection.
+ * This preprocessor define enables support for Garbage Collection on Mac OS X 10.5 (Leopard).
+ *
+ * Traditional retain / release functionality remains allowing the framework to be used in either
+ * Garbage Collected enabled applications or reference counting applications.
+ *
+ * The framework dynamically picks which mode to use at run-time base on whether or not the
+ * Garbage Collection system is active.
+ *
+ * @sa Garbage Collection Programming Guide
+ * @sa NSGarbageCollector Class Reference
+ */
+#if defined(__MACOSX_RUNTIME__) && defined(MAC_OS_X_VERSION_10_5) && defined(__OBJC_GC__)
+ #define ENABLE_MACOSX_GARBAGE_COLLECTION
+ #define BM_STRONG_REF __strong
+ #define BM_WEAK_REF __weak
+#else
+ #define BM_STRONG_REF
+ #define BM_WEAK_REF
+#endif
+
+#if defined(ENABLE_MACOSX_GARBAGE_COLLECTION) && !defined(MAC_OS_X_VERSION_10_5)
+#error The Mac OS X Garbage Collection feature requires at least Mac OS X 10.5
+#endif
+
+
+/*!
+ * A note to Clang's static analyzer.
+ * It tells about the returning onwnership intentions of methods.
+ * The header documentation of Apple follows:
+ * "Marks methods and functions which return an object that needs to be released by the caller but whose names are not consistent with Cocoa naming rules. The recommended fix to this is the rename the methods or functions, but this macro can be used to let the clang static analyzer know of any exceptions that cannot be fixed."
+ *
+ */
+#ifndef NS_RETURNS_RETAINED
+ #if defined(__clang__)
+ #define NS_RETURNS_RETAINED __attribute__((ns_returns_retained))
+ #else
+ #define NS_RETURNS_RETAINED
+ #endif
+#endif
+
+
+// To simplify support for 64bit (and Leopard in general),
+// provide the type defines for non Leopard SDKs
+#if !(MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
+
+ // NSInteger/NSUInteger and Max/Mins
+ #ifndef NSINTEGER_DEFINED
+ #if __LP64__ || NS_BUILD_32_LIKE_64
+ typedef long NSInteger;
+ typedef unsigned long NSUInteger;
+ #else
+ typedef int NSInteger;
+ typedef unsigned int NSUInteger;
+ #endif
+ #define NSIntegerMax LONG_MAX
+ #define NSIntegerMin LONG_MIN
+ #define NSUIntegerMax ULONG_MAX
+ #define NSINTEGER_DEFINED 1
+ #endif // NSINTEGER_DEFINED
+
+ // CGFloat
+ #ifndef CGFLOAT_DEFINED
+ #if defined(__LP64__) && __LP64__
+ // This really is an untested path (64bit on Tiger?)
+ typedef double CGFloat;
+ #define CGFLOAT_MIN DBL_MIN
+ #define CGFLOAT_MAX DBL_MAX
+ #define CGFLOAT_IS_DOUBLE 1
+ #else /* !defined(__LP64__) || !__LP64__ */
+ typedef float CGFloat;
+ #define CGFLOAT_MIN FLT_MIN
+ #define CGFLOAT_MAX FLT_MAX
+ #define CGFLOAT_IS_DOUBLE 0
+ #endif /* !defined(__LP64__) || !__LP64__ */
+ #define CGFLOAT_DEFINED 1
+ #endif // CGFLOAT_DEFINED
+
+ // NS_INLINE
+ #if !defined(NS_INLINE)
+ #if defined(__GNUC__)
+ #define NS_INLINE static __inline__ __attribute__((always_inline))
+ #elif defined(__MWERKS__) || defined(__cplusplus)
+ #define NS_INLINE static inline
+ #elif defined(_MSC_VER)
+ #define NS_INLINE static __inline
+ #elif defined(__WIN32__)
+ #define NS_INLINE static __inline__
+ #endif
+ #endif
+
+#endif // MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
+
+/*!
+ * @def BM_C99(keyword)
+ * C99 conformance defines.
+ * Make it possible to safely use keywords and features of the C99 standard.
+ * @param keyword a C99 keyword (e.g. restrict)
+ */
+#if __STDC_VERSION__ >= 199901L
+ #define BM_C99(keyword) keyword
+#else
+ #define BM_C99(keyword)
+#endif
+
+/*!
+ * @def BM_REQUIRES_NIL_TERMINATION
+ * Used to mark variadic methods and functions as requiring nil termination.
+ * Nil termination means the last argument of their variable argument list must be nil.
+ */
+#if !defined(BM_REQUIRES_NIL_TERMINATION)
+ #if TARGET_OS_WIN32
+ #define BM_REQUIRES_NIL_TERMINATION
+ #else
+ #if defined(__APPLE_CC__) && (__APPLE_CC__ >= 5549)
+ #define BM_REQUIRES_NIL_TERMINATION __attribute__((sentinel(0,1)))
+ #else
+ #define BM_REQUIRES_NIL_TERMINATION __attribute__((sentinel))
+ #endif
+ #endif
+#endif
+
+/*!
+ * @def BM_EXTERN
+ * Defines for the extern keyword.
+ * Makes it possible to use extern in the proper sense in C++ context included.
+ */
+/*!
+ * @def BM_PRIVATE_EXTERN
+ * Defines for the __private_extern__ Apple compiler directive.
+ * Makes a symbol public in the binrary (e.g. a library), but hidden outside of it.
+ */
+#ifdef __cplusplus
+ #define BM_EXTERN extern "C"
+ #define BM_PRIVATE_EXTERN __private_extern__
+#else
+ #define BM_EXTERN extern
+ #define BM_PRIVATE_EXTERN __private_extern__
+#endif
+
+/*!
+ * @def BM_ATTRIBUTES
+ * Macro wrapper around GCC __attribute__ syntax.
+ * @note When a compiler other than GCC 4+ is used, #BM_ATTRIBUTES evaluates to an empty string, removing itself and its arguments from the code to be compiled.
+ */
+/*!
+ * @def BM_EXPECTED
+ * Macro wrapper around GCC __builtin_expect syntax.
+ *
+ * From GCC docs: "You may use __builtin_expect to provide the compiler with branch prediction information. In general, you should prefer to use actual profile feedback for this (-fprofile-arcs), as programmers are notoriously bad at predicting how their programs actually perform. However, there are applications in which this data is hard to collect.
+ *
+ * The return value is the value of exp, which should be an integral expression. The value of c must be a compile-time constant. The semantics of the built-in are that it is expected that exp == c."
+ *
+ * And from RegexKit Framework docs (the origin of this macro):
+ *
+ *
Important:
BM_EXPECTED should only be used when the likelihood of the prediction is nearly certain. DO NOT GUESS.
+ *
+ * BM_EXPECTED [...] is used to provide the compiler with branch prediction information for conditional statements.
+ *
+ * An example of an appropriate use is parameter validation checks at the start of a function, such as (aPtr == NULL). Since callers are always expected to pass a valid pointer, the likelihood of the conditional evaluating to true is extremely unlikely. This allows the compiler to schedule instructions to minimize branch miss-prediction penalties. For example:
+
if(BM_EXPECTED((aPtr == NULL), 0)) { abort(); }
+ *
+ * @note If a compiler other than GCC 4+ is used then the macro leaves the conditional expression unaltered.
+ */
+#if defined (__GNUC__) && (__GNUC__ >= 4)
+ #define BM_STATIC_INLINE static __inline__ __attribute__((always_inline))
+ #define BM_STATIC_PURE_INLINE static __inline__ __attribute__((always_inline, pure))
+ #define BM_EXPECTED(cond, expect) __builtin_expect(cond, expect)
+ #define BM_ALIGNED(boundary) __attribute__ ((aligned(boundary)))
+ #define BM_ATTRIBUTES(attr, ...) __attribute__((attr, ##__VA_ARGS__))
+#else
+ #define BM_STATIC_INLINE static __inline__
+ #define BM_STATIC_PURE_INLINE static __inline__
+ #define BM_EXPECTED(cond, expect) cond
+ #define BM_ALIGNED(boundary)
+ #define BM_ATTRIBUTES(attr, ...)
+#endif
+
+
+/*!
+ * @def BM_DEBUG_RETAIN_INIT
+ * Defines a macro which supplies replacement methods for -[retain] and -[release].
+ * This macro is normally used in a global context (e.g. outside main) and followed by BM_DEBUG_RETAIN_SWIZZLE(className) in a local context, which then actually registers the replacement for the Class 'className' with the runtime.
+ * @attention This is only intended for debugging purposes. Has no effect if Garbage Collection is enabled.
+ */
+#define BM_DEBUG_RETAIN_INIT \
+ IMP oldRetain;\
+ IMP oldRelease;\
+ id newRetain(id self, SEL _cmd) {\
+ NSUInteger rc = [self retainCount];\
+ NSLog(@"%s[0x%x]: retain, rc = %d -> %d",\
+ class_getName([self class]), self, rc, rc + 1);\
+ return (*oldRetain)(self, _cmd);\
+ }\
+ void newRelease(id self, SEL _cmd) {\
+ NSUInteger rc = [self retainCount];\
+ NSLog(@"%s[0x%x]: retain, rc = %d -> %d", \
+ class_getName([self class]), self, rc, rc - 1);\
+ (*oldRetain)(self, _cmd);\
+ }
+
+/*!
+ * @def BM_DEBUG_RETAIN_SWIZZLE(className)
+ * Swizzles (or replaces) the methods defined by #BM_DEBUG_RETAIN_INIT for className.
+ * This macro is normally used in a (function) local scope, provided a #BM_DEBUG_RETAIN_INIT declaration at the beginning of the file (in global context). BM_DEBUG_RETAIN_SWIZZLE(className) then actually registers the replacements defined by #BM_DEBUG_RETAIN_INIT for the Class 'className' with the runtime.
+ * @attention This is only intended for debugging purposes. Has no effect if Garbage Collection is enabled.
+ * @param className the name of the class to replace the methods for (e.g. [SomeClass class]).
+ */
+#define BM_DEBUG_RETAIN_SWIZZLE(className) \
+ oldRetain = class_getMethodImplementation((className), @selector(retain));\
+ class_replaceMethod((className), @selector(retain), (IMP)&newRetain, "@@:");\
+ oldRelease = class_getMethodImplementation((className), @selector(release));\
+ class_replaceMethod((className), @selector(release), (IMP)&newRelease, "v@:");
+
+/*!
+ * @}
+ */
+
+#endif // _BM_DEFINES_H_
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
\ No newline at end of file
diff --git a/BMScript.h b/BMScript.h
new file mode 100644
index 000000000..9fa442852
--- /dev/null
+++ b/BMScript.h
@@ -0,0 +1,998 @@
+//
+// BMScript.h
+// BMScriptTest
+//
+// Created by Andre Berg on 11.09.09.
+// Copyright 2009 Berg Media. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// MARK: Docs: Mainpage
+
+/*!
+ * @mainpage BMScript: Harness The Power Of Shell Scripts
+ *
+ * @par Introduction
+ *
+ * BMScript is an Objective-C class set to make it easier to utilize the
+ * power and flexibility of a whole range of scripting languages that already
+ * come with modern Macs. BMScript does not favor any particular scripting
+ * language or UNIX™ command line tool for that matter, instead it was written
+ * as an abstraction layer to NSTask, and as such supports any command line tool,
+ * provided that it is available on the target system.
+ *
+ * @par Usage
+ *
+ * BMScript can be used in two ways:
+ *
+ * -# Use it directly
+ * -# Guided by the BMScriptLanguageProtocol, make a subclass from it
+ *
+ * The easiest way to use BMScript is, of course, to instanciate it directly:
+ *
+ * @include bmScriptCreationMethods.m
+ *
+ * You typically use the designated initializer for which you supply the script
+ * source and script options yourself.
+ * The options dictionary then looks like this:
+ *
+ * @include bmScriptOptionsDictionary.m
+ *
+ * There's two constant keys. These are the only keys you need to define values for.
+ * #BMScriptOptionsTaskLaunchPathKey stores the path to the tool's executable and
+ * #BMScriptOptionsTaskArgumentsKey is a nil-terminated variable list of parameters
+ * to be used as arguments to the task which will load and execute the tool found at
+ * the launch path specified for the other key.
+ *
+ * It is very important to note that the script source string should NOT be
+ * supplied in the array for the #BMScriptOptionsTaskArgumentsKey, as it will be added
+ * later by the class after performing tests and delegation which could alter the script
+ * in ways needed to safely execute it. This is in the delegate object's responsibility.
+ *
+ * A macro function called #BMSynthesizeOptions(path, args) is available to ease
+ * the declaration of the options.
+ * Here is the definition:
+ *
+ * @include bmScriptSynthesizeOptions.m
+ *
+ *
+ *
+ *
+ *
Important:
+ *
+ * Don't forget the nil at the end even
+ * if you don't need to supply any task arguments.
+ *
+ *
+ *
+ *
+ *
+ * If you initialize BMScript directly without specifying options and script source
+ * (e.g. using [[%BMScript alloc] init]) the options
+ * will default to BMSynthesizeOptions(@"/bin/echo", @"")
+ * and the script source will default to @"'
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-