diff --git a/DDTemporaryDirectory.h b/DDTemporaryDirectory.h new file mode 100644 index 0000000..908f659 --- /dev/null +++ b/DDTemporaryDirectory.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2007-2008 Dave Dribin + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#import + + +@interface DDTemporaryDirectory : NSObject +{ + NSString * mFullPath; +} + + ++ (DDTemporaryDirectory *) temporaryDirectory; + +- (id) init; + +- (void) cleanup; + +- (NSString *) fullPath; + +@end diff --git a/DDTemporaryDirectory.m b/DDTemporaryDirectory.m new file mode 100644 index 0000000..98cb4f0 --- /dev/null +++ b/DDTemporaryDirectory.m @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2007-2008 Dave Dribin + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#import "DDTemporaryDirectory.h" +#include +#import "JRLog.h" + + +@implementation DDTemporaryDirectory + ++ (DDTemporaryDirectory *) temporaryDirectory; +{ + return [[[self alloc] init] autorelease]; +} + +- (id) init; +{ + self = [super init]; + if (self == nil) + return nil; + + NSString * tempDir = NSTemporaryDirectory(); + if (tempDir == nil) + tempDir = @"/tmp"; + + NSString * template = [tempDir stringByAppendingPathComponent: @"temp.XXXXXX"]; + JRLogDebug(@"Template: %@", template); + const char * fsTemplate = [template fileSystemRepresentation]; + NSMutableData * bufferData = [NSMutableData dataWithBytes: fsTemplate + length: strlen(fsTemplate)+1]; + char * buffer = [bufferData mutableBytes]; + JRLogDebug(@"FS Template: %s", buffer); + char * result = mkdtemp(buffer); + NSString * temporaryDirectory = [[NSFileManager defaultManager] + stringWithFileSystemRepresentation: buffer + length: strlen(buffer)]; + if (result == NULL) + { + JRLogWarn(@"Could not create temporary dir: %@, %s", temporaryDirectory, + strerror(errno)); + [self release]; + return nil; + } + + mFullPath = [temporaryDirectory retain]; + + return self; +} + +//=========================================================== +// dealloc +//=========================================================== +- (void) dealloc +{ + [self cleanup]; + [mFullPath release]; + + mFullPath = nil; + [super dealloc]; +} + +- (void) cleanup; +{ + [[NSFileManager defaultManager] removeFileAtPath: mFullPath + handler: nil]; +} + +- (NSString *) fullPath; +{ + return mFullPath; +} + +@end diff --git a/DDTemporaryFile.h b/DDTemporaryFile.h new file mode 100644 index 0000000..df19423 --- /dev/null +++ b/DDTemporaryFile.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2007-2008 Dave Dribin + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#import + +@class DDTemporaryDirectory; + +@interface DDTemporaryFile : NSObject +{ + DDTemporaryDirectory * mTemporaryDirectory; + NSString * mFullPath; +} + ++ (DDTemporaryFile *) temporaryFileWithName: (NSString *) name; + +- (id) initWithName: (NSString *) name; + +- (void) cleanup; + +- (NSString *) fullPath; + +@end diff --git a/DDTemporaryFile.m b/DDTemporaryFile.m new file mode 100644 index 0000000..9c61fa3 --- /dev/null +++ b/DDTemporaryFile.m @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2007-2008 Dave Dribin + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#import "DDTemporaryFile.h" +#import "DDTemporaryDirectory.h" + +@implementation DDTemporaryFile + ++ (DDTemporaryFile *) temporaryFileWithName: (NSString *) name; +{ + return [[[self alloc] initWithName: name] autorelease]; +} + +- (id) initWithName: (NSString *) name; +{ + self = [super init]; + if (self == nil) + return nil; + + mTemporaryDirectory = [[DDTemporaryDirectory alloc] init]; + mFullPath = [[[mTemporaryDirectory fullPath] + stringByAppendingPathComponent: name] retain]; + + return self; +} + +//=========================================================== +// dealloc +//=========================================================== +- (void) dealloc +{ + [self cleanup]; + [mTemporaryDirectory release]; + [mFullPath release]; + + mTemporaryDirectory = nil; + mFullPath = nil; + [super dealloc]; +} + +- (void) cleanup; +{ + [mTemporaryDirectory cleanup]; +} + +- (NSString *) fullPath; +{ + return mFullPath; +} + +@end diff --git a/JRLog.h b/JRLog.h new file mode 100644 index 0000000..e7d4915 --- /dev/null +++ b/JRLog.h @@ -0,0 +1,99 @@ +/******************************************************************************* + JRLog.h + Copyright (c) 2006-2007 Jonathan 'Wolf' Rentzsch: + Some rights reserved: + + ***************************************************************************/ + +#import + +// What you need to remember: Debug > Info > Warn > Error > Fatal. + +typedef enum { + JRLogLevel_UNSET, + JRLogLevel_Debug, + JRLogLevel_Info, + JRLogLevel_Warn, + JRLogLevel_Error, + JRLogLevel_Fatal, + JRLogLevel_Off, +} JRLogLevel; + +@protocol JRLogLogger + +- (void)logWithLevel:(JRLogLevel)callerLevel_ + instance:(NSString*)instance_ + file:(const char*)file_ + line:(unsigned)line_ + function:(const char*)function_ + message:(NSString*)message_; + +@end + +@interface NSObject (JRLogAdditions) ++ (JRLogLevel)classJRLogLevel; ++ (void)setClassJRLogLevel:(JRLogLevel)level_; + ++ (JRLogLevel)defaultJRLogLevel; ++ (void)setDefaultJRLogLevel:(JRLogLevel)level_; + ++ (void)setJRLogLogger: (id) logger_; ++ (id)JRLogLogger; ++ (id)defaultJRLogLogger; +@end + +BOOL IsJRLogLevelActive(id self_, JRLogLevel level_); +void JRLog(id self_, JRLogLevel level_, unsigned line_, const char *file_, const char *function_, NSString *format_, ...); + +#define JRLOG_CONDITIONALLY(sender,LEVEL,format,...) \ + do{if(IsJRLogLevelActive(sender,LEVEL)){JRLog(sender,LEVEL,__LINE__,__FILE__,__PRETTY_FUNCTION__,(format),##__VA_ARGS__);}}while(0) + +#if JRLogOverrideNSLog +id self; +#define NSLog JRLogInfo +#endif + +// +// Scary macros! +// The 1st #if is a filter, which you can read "IF any of the symbols are defined, THEN don't log for that level, ELSE log for that level." +// + +#if defined(JRLOGLEVEL_OFF) || defined(JRLOGLEVEL_FATAL) || defined(JRLOGLEVEL_ERROR) || defined(JRLOGLEVEL_WARN) || defined(JRLOGLEVEL_INFO) + #define JRLogDebug(format,...) + #define JRCLogDebug(format,...) +#else + #define JRLogDebug(format,...) JRLOG_CONDITIONALLY(self, JRLogLevel_Debug, format, ##__VA_ARGS__) + #define JRCLogDebug(format,...) JRLOG_CONDITIONALLY(nil, JRLogLevel_Debug, format, ##__VA_ARGS__) +#endif + +#if defined(JRLOGLEVEL_OFF) || defined(JRLOGLEVEL_FATAL) || defined(JRLOGLEVEL_ERROR) || defined(JRLOGLEVEL_WARN) + #define JRLogInfo(format,...) + #define JRCLogInfo(format,...) +#else + #define JRLogInfo(format,...) JRLOG_CONDITIONALLY(self, JRLogLevel_Info, format, ##__VA_ARGS__) + #define JRCLogInfo(format,...) JRLOG_CONDITIONALLY(nil, JRLogLevel_Info, format, ##__VA_ARGS__) +#endif + +#if defined(JRLOGLEVEL_OFF) || defined(JRLOGLEVEL_FATAL) || defined(JRLOGLEVEL_ERROR) + #define JRLogWarn(format,...) + #define JRCLogWarn(format,...) +#else + #define JRLogWarn(format,...) JRLOG_CONDITIONALLY(self, JRLogLevel_Warn, format, ##__VA_ARGS__) + #define JRCLogWarn(format,...) JRLOG_CONDITIONALLY(nil, JRLogLevel_Warn, format, ##__VA_ARGS__) +#endif + +#if defined(JRLOGLEVEL_OFF) || defined(JRLOGLEVEL_FATAL) + #define JRLogError(format,...) + #define JRCLogError(format,...) +#else + #define JRLogError(format,...) JRLOG_CONDITIONALLY(self, JRLogLevel_Error, format, ##__VA_ARGS__) + #define JRCLogError(format,...) JRLOG_CONDITIONALLY(nil, JRLogLevel_Error, format, ##__VA_ARGS__) +#endif + +#if defined(JRLOGLEVEL_OFF) + #define JRLogFatal(format,...) + #define JRCLogFatal(format,...) +#else + #define JRLogFatal(format,...) JRLOG_CONDITIONALLY(self, JRLogLevel_Fatal, format, ##__VA_ARGS__) + #define JCRLogFatal(format,...) JRLOG_CONDITIONALLY(nil, JRLogLevel_Fatal, format, ##__VA_ARGS__) +#endif diff --git a/JRLog.m b/JRLog.m new file mode 100644 index 0000000..4ab46d3 --- /dev/null +++ b/JRLog.m @@ -0,0 +1,284 @@ +/******************************************************************************* + JRLog.m + Copyright (c) 2006-2007 Jonathan 'Wolf' Rentzsch: + Some rights reserved: + + ***************************************************************************/ + +#import "JRLog.h" +#include + +#if JRLogOverrideNSLog +id self = nil; +#endif +#undef NSLog + +// +// Globals +// +#pragma mark Globals + +BOOL gLoadedJRLogSettings = NO; +JRLogLevel gDefaultJRLogLevel = JRLogLevel_Debug; + +// +// +// + +@protocol JRLogDestinationDO +- (oneway void)logWithDictionary:(bycopy NSDictionary*)dictionary_; +@end + +@interface JRLogOutput : NSObject { + NSString *sessionUUID; + BOOL tryDO; + id destination; +} ++ (id)sharedOutput; +- (void)destinationDOAvailable:(NSNotification*)notification_; +@end +@implementation JRLogOutput ++ (id)sharedOutput { + static JRLogOutput *output = nil; + if (!output) { + output = [[JRLogOutput alloc] init]; + } + return output; +} +- (id)init { + self = [super init]; + if (self) { + sessionUUID = (id)CFUUIDCreateString(kCFAllocatorDefault, CFUUIDCreate(kCFAllocatorDefault)); + [[NSDistributedNotificationCenter defaultCenter] addObserver:self + selector:@selector(destinationDOAvailable:) + name:@"JRLogDestinationDOAvailable" + object:nil]; + tryDO = YES; + } + return self; +} + +- (void)destinationDOAvailable:(NSNotification*)notification_ { + tryDO = YES; +} + +- (void)logWithLevel:(JRLogLevel)callerLevel_ + instance:(NSString*)instance_ + file:(const char*)file_ + line:(unsigned)line_ + function:(const char*)function_ + message:(NSString*)message_ +{ + if (tryDO) { + tryDO = NO; + destination = [[NSConnection rootProxyForConnectionWithRegisteredName:@"JRLogDestinationDO" host:nil] retain]; + } + if (destination) { + NS_DURING + [destination logWithDictionary:[NSDictionary dictionaryWithObjectsAndKeys: + [[NSBundle mainBundle] bundleIdentifier], @"bundleID", + sessionUUID, @"sessionUUID", + [NSNumber numberWithLong:getpid()], @"pid", + [NSDate date], @"date", + [NSNumber numberWithInt:callerLevel_], @"level", + instance_, @"instance", + [NSString stringWithUTF8String:file_], @"file", + [NSNumber numberWithUnsignedInt:line_], @"line", + [NSString stringWithUTF8String:function_], @"function", + message_, @"message", + nil]]; + NS_HANDLER + if ([[localException name] isEqualToString:NSObjectInaccessibleException]) { + destination = nil; + } else { + [localException raise]; + } + NS_ENDHANDLER + } else { + // "MyClass.m:123: blah blah" + NSLog(@"%@:%u: %@", + [[NSString stringWithUTF8String:file_] lastPathComponent], + line_, + message_); + } +} +@end + +// +// +// + +static JRLogLevel parseJRLogLevel(NSString *level_) { + static NSDictionary *levelLookup = nil; + if (!levelLookup) { + levelLookup = [NSDictionary dictionaryWithObjectsAndKeys: + [NSNumber numberWithInt:JRLogLevel_Debug], @"debug", + [NSNumber numberWithInt:JRLogLevel_Info], @"info", + [NSNumber numberWithInt:JRLogLevel_Warn], @"warn", + [NSNumber numberWithInt:JRLogLevel_Error], @"error", + [NSNumber numberWithInt:JRLogLevel_Fatal], @"fatal", + [NSNumber numberWithInt:JRLogLevel_Off], @"off", + nil]; + } + NSNumber *result = [levelLookup objectForKey:[level_ lowercaseString]]; + return result ? [result intValue] : JRLogLevel_UNSET; +} + +static void LoadJRLogSettings() { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + // Load+interpret the Info.plist-based settings. + NSMutableDictionary *settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[[NSBundle mainBundle] infoDictionary]]; + [settings addEntriesFromDictionary:[[NSUserDefaults standardUserDefaults] dictionaryRepresentation]]; + + NSArray *keys = [settings allKeys]; + unsigned keyIndex = 0, keyCount = [keys count]; + for(; keyIndex < keyCount; keyIndex++) { + NSString *key = [keys objectAtIndex:keyIndex]; + if ([key hasPrefix:@"JRLogLevel"]) { + JRLogLevel level = parseJRLogLevel([settings objectForKey:key]); + if (JRLogLevel_UNSET == level) { + NSLog(@"JRLog: can't parse \"%@\" JRLogLevel value for key \"%@\"", [settings objectForKey:key], key); + } else { + NSArray *keyNames = [key componentsSeparatedByString:@"."]; + if ([keyNames count] == 2) { + // It's a pseudo-keypath: JRLogLevel.MyClassName. + Class c = NSClassFromString([keyNames lastObject]); + if (c) { + [c setClassJRLogLevel:level]; + } else { + NSLog(@"JRLog: unknown class \"%@\"", [keyNames lastObject]); + } + } else { + // Just a plain "JRLogLevel": it's for the default level. + [NSObject setDefaultJRLogLevel:level]; + } + } + } + } + + [pool release]; +} + +BOOL IsJRLogLevelActive(id self_, JRLogLevel callerLevel_) { + assert(callerLevel_ >= JRLogLevel_Debug && callerLevel_ <= JRLogLevel_Fatal); + + if (!gLoadedJRLogSettings) { + gLoadedJRLogSettings = YES; + LoadJRLogSettings(); + } + + // Setting the default level to OFF disables all logging, regardless of everything else. + if (JRLogLevel_Off == gDefaultJRLogLevel) + return NO; + + JRLogLevel currentLevel; + if (self_) { + currentLevel = [[self_ class] classJRLogLevel]; + if (JRLogLevel_UNSET == currentLevel) { + currentLevel = gDefaultJRLogLevel; + } + } else { + currentLevel = gDefaultJRLogLevel; + // TODO It would be cool if we could use the file's name was a symbol to set logging levels for JRCLog... functions. + } + + return callerLevel_ >= currentLevel; +} + + void +JRLog( + id self_, + JRLogLevel callerLevel_, + unsigned line_, + const char *file_, + const char *function_, + NSString *format_, + ...) +{ + assert(callerLevel_ >= JRLogLevel_Debug && callerLevel_ <= JRLogLevel_Fatal); + assert(file_); + assert(function_); + assert(format_); + + // + va_list args; + va_start(args, format_); + NSString *message = [[[NSString alloc] initWithFormat:format_ arguments:args] autorelease]; + va_end(args); + + id logger = [JRLogOutput JRLogLogger]; + [logger logWithLevel:callerLevel_ + instance:self_ ? [NSString stringWithFormat:@"<%@: %p>", [self_ className], self_] : @"nil" + file:file_ + line:line_ + function:function_ + message:message]; + + if (JRLogLevel_Fatal == callerLevel_) { + exit(0); + } +} + +@implementation NSObject (JRLogAdditions) + +NSMapTable *gClassLoggingLevels = NULL; ++ (void)load { + if (!gClassLoggingLevels) { +#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 + gClassLoggingLevels = NSCreateMapTable(NSIntMapKeyCallBacks, NSIntMapValueCallBacks, 32); +#else + gClassLoggingLevels = NSCreateMapTable(NSIntegerMapKeyCallBacks, NSIntegerMapValueCallBacks, 32); +#endif + } +} + ++ (JRLogLevel)classJRLogLevel { + void *mapValue = NSMapGet(gClassLoggingLevels, self); + if (mapValue) { + return (JRLogLevel)mapValue; + } else { + Class superclass = [self superclass]; + return superclass ? [superclass classJRLogLevel] : JRLogLevel_UNSET; + } +} + ++ (void)setClassJRLogLevel:(JRLogLevel)level_ { + if (JRLogLevel_UNSET == level_) { + NSMapRemove(gClassLoggingLevels, self); + } else { + NSMapInsert(gClassLoggingLevels, self, (const void*)level_); + } +} + ++ (JRLogLevel)defaultJRLogLevel { + return gDefaultJRLogLevel; +} + ++ (void)setDefaultJRLogLevel:(JRLogLevel)level_ { + assert(level_ >= JRLogLevel_Debug && level_ <= JRLogLevel_Off); + gDefaultJRLogLevel = level_; +} + +static id sLogger = nil; + ++ (void)setJRLogLogger: (id) logger_; +{ + sLogger = logger_; +} + ++ (id)JRLogLogger; +{ + if (sLogger == nil) + return [JRLogOutput sharedOutput]; + else + return sLogger; +} + ++ (id)defaultJRLogLogger; +{ + return [JRLogOutput sharedOutput]; +} + +@end diff --git a/MarkdownLive.xcodeproj/project.pbxproj b/MarkdownLive.xcodeproj/project.pbxproj index aca2701..e4ade72 100644 --- a/MarkdownLive.xcodeproj/project.pbxproj +++ b/MarkdownLive.xcodeproj/project.pbxproj @@ -7,11 +7,12 @@ objects = { /* Begin PBXBuildFile section */ + 79252F250E8DF46200DFAD98 /* discountInclude.c in Sources */ = {isa = PBXBuildFile; fileRef = 79252F240E8DF46200DFAD98 /* discountInclude.c */; }; + 79252F560E8DFAF200DFAD98 /* DDTemporaryFile.m in Sources */ = {isa = PBXBuildFile; fileRef = 79252F520E8DFAF200DFAD98 /* DDTemporaryFile.m */; }; + 79252F570E8DFAF200DFAD98 /* DDTemporaryDirectory.m in Sources */ = {isa = PBXBuildFile; fileRef = 79252F540E8DFAF200DFAD98 /* DDTemporaryDirectory.m */; }; + 79252F5F0E8E017E00DFAD98 /* JRLog.m in Sources */ = {isa = PBXBuildFile; fileRef = 79252F5D0E8E017E00DFAD98 /* JRLog.m */; }; + 79252FF20E8E080100DFAD98 /* generate.c in Sources */ = {isa = PBXBuildFile; fileRef = 79252FF10E8E080100DFAD98 /* generate.c */; }; 796A2AD80A20DCEE00440275 /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 796A2AD70A20DCEE00440275 /* WebKit.framework */; }; - 7972D9090E42AF6100BF53B8 /* NSTask+runMaruku.m in Sources */ = {isa = PBXBuildFile; fileRef = 7972D9080E42AF6100BF53B8 /* NSTask+runMaruku.m */; }; - 7979D3260E8D4BFF00768BE3 /* markdown.c in Sources */ = {isa = PBXBuildFile; fileRef = 7979D2F20E8D4BFF00768BE3 /* markdown.c */; }; - 7979D32A0E8D4BFF00768BE3 /* mkdio.c in Sources */ = {isa = PBXBuildFile; fileRef = 7979D2F70E8D4BFF00768BE3 /* mkdio.c */; }; - 7979D32C0E8D4BFF00768BE3 /* resource.c in Sources */ = {isa = PBXBuildFile; fileRef = 7979D2FA0E8D4BFF00768BE3 /* resource.c */; }; 79F7EF740AC39638003DAB4E /* MarkdownLiveApp.icns in Resources */ = {isa = PBXBuildFile; fileRef = 79F7EF730AC39638003DAB4E /* MarkdownLiveApp.icns */; }; 8D15AC2C0486D014006FF6A4 /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 2A37F4B9FDCFA73011CA2CEA /* Credits.rtf */; }; 8D15AC2D0486D014006FF6A4 /* MainMenu.nib in Resources */ = {isa = PBXBuildFile; fileRef = 2A37F4B6FDCFA73011CA2CEA /* MainMenu.nib */; }; @@ -35,14 +36,16 @@ 2A37F4C4FDCFA73011CA2CEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = ""; }; 2A37F4C5FDCFA73011CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = ""; }; 32DBCF750370BD2300C91783 /* MarkdownLive_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MarkdownLive_Prefix.pch; sourceTree = ""; }; + 79252F230E8DF46200DFAD98 /* discountInclude.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = discountInclude.h; sourceTree = ""; }; + 79252F240E8DF46200DFAD98 /* discountInclude.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = discountInclude.c; sourceTree = ""; }; + 79252F520E8DFAF200DFAD98 /* DDTemporaryFile.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDTemporaryFile.m; sourceTree = ""; }; + 79252F530E8DFAF200DFAD98 /* DDTemporaryFile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDTemporaryFile.h; sourceTree = ""; }; + 79252F540E8DFAF200DFAD98 /* DDTemporaryDirectory.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDTemporaryDirectory.m; sourceTree = ""; }; + 79252F550E8DFAF200DFAD98 /* DDTemporaryDirectory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDTemporaryDirectory.h; sourceTree = ""; }; + 79252F5D0E8E017E00DFAD98 /* JRLog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JRLog.m; sourceTree = ""; }; + 79252F5E0E8E017E00DFAD98 /* JRLog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JRLog.h; sourceTree = ""; }; + 79252FF10E8E080100DFAD98 /* generate.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = generate.c; path = "discount-1.2.10/generate.c"; sourceTree = ""; }; 796A2AD70A20DCEE00440275 /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = /System/Library/Frameworks/WebKit.framework; sourceTree = ""; }; - 7972D9070E42AF6100BF53B8 /* NSTask+runMaruku.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSTask+runMaruku.h"; sourceTree = ""; }; - 7972D9080E42AF6100BF53B8 /* NSTask+runMaruku.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSTask+runMaruku.m"; sourceTree = ""; }; - 7979D2F20E8D4BFF00768BE3 /* markdown.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = markdown.c; sourceTree = ""; }; - 7979D2F30E8D4BFF00768BE3 /* markdown.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = markdown.h; sourceTree = ""; }; - 7979D2F70E8D4BFF00768BE3 /* mkdio.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mkdio.c; sourceTree = ""; }; - 7979D2F80E8D4BFF00768BE3 /* mkdio.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mkdio.h; sourceTree = ""; }; - 7979D2FA0E8D4BFF00768BE3 /* resource.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = resource.c; sourceTree = ""; }; 79F7EF730AC39638003DAB4E /* MarkdownLiveApp.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = MarkdownLiveApp.icns; sourceTree = ""; }; 8D15AC360486D014006FF6A4 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; 8D15AC370486D014006FF6A4 /* MarkdownLive.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MarkdownLive.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -92,7 +95,6 @@ isa = PBXGroup; children = ( 2A37F4ABFDCFA73011CA2CEA /* Classes */, - 7979D2E10E8D4BFF00768BE3 /* discount-1.2.10 */, 2A37F4AFFDCFA73011CA2CEA /* Other Sources */, 2A37F4B8FDCFA73011CA2CEA /* Resources */, 2A37F4C3FDCFA73011CA2CEA /* Frameworks */, @@ -106,8 +108,15 @@ children = ( 2A37F4AEFDCFA73011CA2CEA /* MyDocument.h */, 2A37F4ACFDCFA73011CA2CEA /* MyDocument.m */, - 7972D9070E42AF6100BF53B8 /* NSTask+runMaruku.h */, - 7972D9080E42AF6100BF53B8 /* NSTask+runMaruku.m */, + 79252F230E8DF46200DFAD98 /* discountInclude.h */, + 79252F240E8DF46200DFAD98 /* discountInclude.c */, + 79252F520E8DFAF200DFAD98 /* DDTemporaryFile.m */, + 79252F530E8DFAF200DFAD98 /* DDTemporaryFile.h */, + 79252F540E8DFAF200DFAD98 /* DDTemporaryDirectory.m */, + 79252F550E8DFAF200DFAD98 /* DDTemporaryDirectory.h */, + 79252F5D0E8E017E00DFAD98 /* JRLog.m */, + 79252F5E0E8E017E00DFAD98 /* JRLog.h */, + 79252FF10E8E080100DFAD98 /* generate.c */, ); name = Classes; sourceTree = ""; @@ -143,18 +152,6 @@ name = Frameworks; sourceTree = ""; }; - 7979D2E10E8D4BFF00768BE3 /* discount-1.2.10 */ = { - isa = PBXGroup; - children = ( - 7979D2F20E8D4BFF00768BE3 /* markdown.c */, - 7979D2F30E8D4BFF00768BE3 /* markdown.h */, - 7979D2F70E8D4BFF00768BE3 /* mkdio.c */, - 7979D2F80E8D4BFF00768BE3 /* mkdio.h */, - 7979D2FA0E8D4BFF00768BE3 /* resource.c */, - ); - path = "discount-1.2.10"; - sourceTree = ""; - }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -215,10 +212,11 @@ files = ( 8D15AC310486D014006FF6A4 /* MyDocument.m in Sources */, 8D15AC320486D014006FF6A4 /* main.m in Sources */, - 7972D9090E42AF6100BF53B8 /* NSTask+runMaruku.m in Sources */, - 7979D3260E8D4BFF00768BE3 /* markdown.c in Sources */, - 7979D32A0E8D4BFF00768BE3 /* mkdio.c in Sources */, - 7979D32C0E8D4BFF00768BE3 /* resource.c in Sources */, + 79252F250E8DF46200DFAD98 /* discountInclude.c in Sources */, + 79252F560E8DFAF200DFAD98 /* DDTemporaryFile.m in Sources */, + 79252F570E8DFAF200DFAD98 /* DDTemporaryDirectory.m in Sources */, + 79252F5F0E8E017E00DFAD98 /* JRLog.m in Sources */, + 79252FF20E8E080100DFAD98 /* generate.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/MyDocument.h b/MyDocument.h index 39ed7fa..94b57ed 100644 --- a/MyDocument.h +++ b/MyDocument.h @@ -1,5 +1,6 @@ #import #import +#import "DDTemporaryFile.h" @interface MyDocument : NSDocument { IBOutlet NSTextView *markdownSourceTextView; @@ -13,6 +14,8 @@ BOOL hasSavedOrigin; NSPoint savedOrigin; BOOL savedAtBottom; + DDTemporaryFile *markdownSourceTempFile; + DDTemporaryFile *htmlOutputTempFile; } - (IBAction)copyGeneratedHTMLAction:(id)sender; diff --git a/MyDocument.m b/MyDocument.m index 74809ab..7f1d134 100644 --- a/MyDocument.m +++ b/MyDocument.m @@ -1,6 +1,6 @@ #import "MyDocument.h" -#import "NSTask+runMaruku.h" -#include "markdown.h" +#include "discountInclude.h" +#import "JRLog.h" NSString *kMarkdownDocumentType = @"MarkdownDocumentType"; @@ -15,11 +15,28 @@ - (NSString*)markdown2html:(NSString*)markdown_ { return @""; NSError *error = nil; -#if 1 -#else - NSString *html = [NSTask runMarukuWithInput:markdown_ error:&error]; -#endif + [markdown_ writeToFile:[markdownSourceTempFile fullPath] + atomically:NO + encoding:NSUTF8StringEncoding + error:&error]; + NSString *html = @"an error occured"; + if (!error) { + FILE *markdownSourceTempFILE = fopen([[markdownSourceTempFile fullPath] fileSystemRepresentation], "r"); + Document *discountContext = mkd_in(markdownSourceTempFILE, 0); + assert(discountContext); + + FILE *htmlOutputTempFILE = fopen([[htmlOutputTempFile fullPath] fileSystemRepresentation], "w+"); + int markdown_result = markdown(discountContext, htmlOutputTempFILE, 0); + assert(markdown_result == 0); + fclose(markdownSourceTempFILE); + fclose(htmlOutputTempFILE); + html = [NSString stringWithContentsOfFile:[htmlOutputTempFile fullPath] + encoding:NSUTF8StringEncoding + error:&error]; + JRLogDebug(@"html: {%@}", html); + } + if (error) { [NSApp presentError:error]; } @@ -38,6 +55,10 @@ - (id)init { selector:@selector(htmlPreviewTimer:) userInfo:nil repeats:YES]; + markdownSourceTempFile = [[DDTemporaryFile alloc] initWithName:@"tmp.markdown"]; + JRLogDebug(@"markdownSourceTempFile: %@", [markdownSourceTempFile fullPath]); + htmlOutputTempFile = [[DDTemporaryFile alloc] initWithName:@"tmp.html"]; + JRLogDebug(@"htmlOutputTempFile: %@", [htmlOutputTempFile fullPath]); } return self; } @@ -45,6 +66,10 @@ - (id)init { - (void)dealloc { [htmlPreviewTimer invalidate]; htmlPreviewTimer = nil; [markdownSource release]; markdownSource = nil; + + [markdownSourceTempFile release]; + [htmlOutputTempFile release]; + [super dealloc]; } diff --git a/NSTask+runMaruku.h b/NSTask+runMaruku.h deleted file mode 100644 index 7997d9f..0000000 --- a/NSTask+runMaruku.h +++ /dev/null @@ -1,5 +0,0 @@ -#import - -@interface NSTask (runMaruku) -+ (NSString*)runMarukuWithInput:(NSString*)input_ error:(NSError**)error_; -@end diff --git a/NSTask+runMaruku.m b/NSTask+runMaruku.m deleted file mode 100644 index 9f5fb3f..0000000 --- a/NSTask+runMaruku.m +++ /dev/null @@ -1,62 +0,0 @@ -#import "NSTask+runMaruku.h" - -@implementation NSTask (runMaruku) - -+ (NSString*)runMarukuWithInput:(NSString*)input_ error:(NSError**)error_ { - NSString *result = nil; - NSError *error = nil; - - NSString *appResourcePath = [[NSBundle mainBundle] resourcePath]; - - NSArray *resources = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:appResourcePath - error:&error]; - - NSString *marukuDist = nil; - if (!error) { - for (NSString *resource in resources) { - if ([resource hasPrefix:@"maruku-"]) { - marukuDist = [appResourcePath stringByAppendingPathComponent:resource]; - break; - } - } - if (!marukuDist) { - error = [NSError errorWithDomain:NSCocoaErrorDomain - code:NSFileNoSuchFileError - userInfo:[NSDictionary dictionaryWithObject:[appResourcePath stringByAppendingPathComponent:@"maruku-*"] - forKey:NSFilePathErrorKey]]; - } - } - - if (!error) { - NSString *marukuBin = [marukuDist stringByAppendingPathComponent:@"bin/maruku"]; - NSString *marukuLib = [marukuDist stringByAppendingPathComponent:@"lib"]; - - //-- - NSPipe *inputPipe = [NSPipe pipe]; - NSPipe *outputPipe = [NSPipe pipe]; - NSPipe *errorPipe = [NSPipe pipe]; - - NSTask *scriptTask = [[[NSTask alloc] init] autorelease]; - [scriptTask setLaunchPath:@"/usr/bin/ruby"]; - [scriptTask setArguments:[NSArray arrayWithObject:marukuBin]]; - [scriptTask setCurrentDirectoryPath:marukuLib]; - [scriptTask setStandardInput:inputPipe]; - [scriptTask setStandardOutput:outputPipe]; - [scriptTask setStandardError:errorPipe]; - [scriptTask launch]; - - NS_DURING - [[inputPipe fileHandleForWriting] writeData:[input_ dataUsingEncoding:NSUTF8StringEncoding]]; - NS_HANDLER - // Catch Broken pipe exceptions in case the script for some reason doesn't read its STDIN. - NS_ENDHANDLER - [[inputPipe fileHandleForWriting] closeFile]; - result = [[[NSString alloc] initWithData:[[outputPipe fileHandleForReading] readDataToEndOfFile] - encoding:NSUTF8StringEncoding] autorelease]; - } - - if (error_ && error) *error_ = error; - return result; -} - -@end diff --git a/discountInclude.c b/discountInclude.c new file mode 100644 index 0000000..c60a500 --- /dev/null +++ b/discountInclude.c @@ -0,0 +1,9 @@ +#include +#include "discountInclude.h" + +// Work-around QuickDraw's declaration of Line. +#define Line discountLine + #include "discount-1.2.10/mkdio.c" + #include "discount-1.2.10/markdown.c" + #include "discount-1.2.10/resource.c" +#undef Line diff --git a/discountInclude.h b/discountInclude.h new file mode 100644 index 0000000..b3b87b0 --- /dev/null +++ b/discountInclude.h @@ -0,0 +1,6 @@ +// Work-around QuickDraw's declaration of Line. +#define Line discountLine + __BEGIN_DECLS + #include "discount-1.2.10/markdown.h" + __END_DECLS +#undef Line