@interface AppDelegate : NSObject
{
- IBOutlet DebuggerController* debugger;
- IBOutlet BreakpointController* breakpoint;
- IBOutlet LoggingController* loggingController_;
- PreferencesController* prefs;
+ IBOutlet DebuggerController* debugger;
+ IBOutlet BreakpointController* breakpoint;
+ IBOutlet LoggingController* loggingController_;
+ PreferencesController* prefs;
}
@property (readonly) DebuggerController* debugger;
*/
+ (void)load
{
- NSAutoreleasePool* pool = [NSAutoreleasePool new];
+ NSAutoreleasePool* pool = [NSAutoreleasePool new];
- NSDictionary* dict = [[NSDictionary alloc] initWithObjectsAndKeys:
- [NSNumber numberWithInt:9000], @"Port",
- [NSNumber numberWithBool:YES], @"BreakpointsWindowVisible",
- [NSNumber numberWithBool:YES], @"InspectorWindowVisible",
- [NSMutableArray array], @"PathReplacements",
- [NSNumber numberWithBool:YES], @"BreakOnFirstLine",
- [NSNumber numberWithBool:NO], @"AutoReconnect",
- nil
- ];
-
- [[NSUserDefaults standardUserDefaults] registerDefaults:dict];
+ NSDictionary* dict = [[NSDictionary alloc] initWithObjectsAndKeys:
+ [NSNumber numberWithInt:9000], @"Port",
+ [NSNumber numberWithBool:YES], @"BreakpointsWindowVisible",
+ [NSNumber numberWithBool:YES], @"InspectorWindowVisible",
+ [NSMutableArray array], @"PathReplacements",
+ [NSNumber numberWithBool:YES], @"BreakOnFirstLine",
+ [NSNumber numberWithBool:NO], @"AutoReconnect",
+ nil
+ ];
+
+ [[NSUserDefaults standardUserDefaults] registerDefaults:dict];
- [dict release];
+ [dict release];
- [pool release];
+ [pool release];
}
/**
*/
- (IBAction)showDebuggerWindow:(id)sender
{
- [[debugger window] makeKeyAndOrderFront:self];
- NSLog(@"logg %@", [loggingController_ window]);
+ [[debugger window] makeKeyAndOrderFront:self];
+ NSLog(@"logg %@", [loggingController_ window]);
}
/**
*/
- (IBAction)showBreakpointWindow:(id)sender
{
- if (![[breakpoint window] isVisible] || ![[breakpoint window] isKeyWindow])
- [[breakpoint window] makeKeyAndOrderFront:sender];
- else
- [[breakpoint window] orderOut:sender];
+ if (![[breakpoint window] isVisible] || ![[breakpoint window] isKeyWindow])
+ [[breakpoint window] makeKeyAndOrderFront:sender];
+ else
+ [[breakpoint window] orderOut:sender];
}
/**
*/
- (IBAction)showPreferences:(id)sender
{
- if (!prefs)
- prefs = [[PreferencesController alloc] init];
-
- [prefs showPreferencesWindow];
+ if (!prefs)
+ prefs = [[PreferencesController alloc] init];
+
+ [prefs showPreferencesWindow];
}
/**
*/
- (IBAction)openHelpPage:(id)sender
{
- [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"http://www.bluestatic.org/software/macgdbp/help.php"]];
+ [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"http://www.bluestatic.org/software/macgdbp/help.php"]];
}
@end
@interface BSLineNumberView : NSView
{
- BSSourceView* sourceView;
- NSRange lineNumberRange;
- NSSet* markers;
+ BSSourceView* sourceView;
+ NSRange lineNumberRange;
+ NSSet* markers;
}
@property(readwrite, assign) BSSourceView* sourceView;
*/
- (id)initWithFrame:(NSRect)frame
{
- if (self = [super initWithFrame:frame])
- {
- lineNumberRange = NSMakeRange(0, 0);
- }
- return self;
+ if (self = [super initWithFrame:frame])
+ {
+ lineNumberRange = NSMakeRange(0, 0);
+ }
+ return self;
}
/**
*/
- (BOOL)isFlipped
{
- return YES;
+ return YES;
}
/**
*/
- (void)drawRect:(NSRect)rect
{
- // background color
- [[NSColor colorWithDeviceRed:0.871 green:0.871 blue:0.871 alpha:1] set];
- [NSBezierPath fillRect:rect];
-
- [[NSColor blackColor] set];
- [NSBezierPath strokeLineFromPoint:NSMakePoint(rect.origin.x, rect.origin.y) toPoint:NSMakePoint(rect.origin.x + rect.size.width, rect.origin.y)];
-
- [[NSColor grayColor] set];
- [NSBezierPath strokeLineFromPoint:NSMakePoint(rect.origin.x, rect.size.height) toPoint:NSMakePoint(rect.origin.x + rect.size.width, rect.size.height)];
-
- // font attributes for the line number
- NSDictionary* attrs = [NSDictionary dictionaryWithObjectsAndKeys:[NSFont fontWithName:@"Monaco" size:9.0], NSFontAttributeName, [NSColor grayColor], NSForegroundColorAttributeName, nil];
-
- lineNumberRange = NSMakeRange(0, 0);
-
- unsigned i = 0, line = 1;
- while (i < [[[sourceView textView] layoutManager] numberOfGlyphs])
- {
- NSRange fragRange;
- NSRect fragRect = [self convertRect:[[[sourceView textView] layoutManager] lineFragmentRectForGlyphAtIndex:i effectiveRange:&fragRange] fromView:[sourceView textView]];
- fragRect.origin.x = rect.origin.x; // horizontal scrolling matters not
- fragRect.size.width = [self bounds].size.width;
-
- // we want to paint the top and bottom line number even if they're cut off
- NSRect testRect = rect;
- testRect.origin.y -= fragRect.size.height - 1;
- testRect.size.height += fragRect.size.height - 1;
- if (NSPointInRect(fragRect.origin, testRect))
- {
- lineNumberRange.location = (lineNumberRange.length == 0 ? line : lineNumberRange.location);
- lineNumberRange.length++;
- NSString* num = [NSString stringWithFormat:@"%u", line];
- NSSize strSize = [num sizeWithAttributes:attrs];
- [num drawAtPoint:NSMakePoint([self frame].size.width - strSize.width - 3, fragRect.origin.y + ((fragRect.size.height - strSize.height) / 2)) withAttributes:attrs];
- Breakpoint* test = [[Breakpoint alloc] initWithLine:line inFile:[sourceView file]];
- if ([markers containsObject:test])
- {
- [self drawMarkerInRect:fragRect];
- }
- [test release];
- }
-
- i += fragRange.length;
- line++;
- }
+ // background color
+ [[NSColor colorWithDeviceRed:0.871 green:0.871 blue:0.871 alpha:1] set];
+ [NSBezierPath fillRect:rect];
+
+ [[NSColor blackColor] set];
+ [NSBezierPath strokeLineFromPoint:NSMakePoint(rect.origin.x, rect.origin.y) toPoint:NSMakePoint(rect.origin.x + rect.size.width, rect.origin.y)];
+
+ [[NSColor grayColor] set];
+ [NSBezierPath strokeLineFromPoint:NSMakePoint(rect.origin.x, rect.size.height) toPoint:NSMakePoint(rect.origin.x + rect.size.width, rect.size.height)];
+
+ // font attributes for the line number
+ NSDictionary* attrs = [NSDictionary dictionaryWithObjectsAndKeys:[NSFont fontWithName:@"Monaco" size:9.0], NSFontAttributeName, [NSColor grayColor], NSForegroundColorAttributeName, nil];
+
+ lineNumberRange = NSMakeRange(0, 0);
+
+ unsigned i = 0, line = 1;
+ while (i < [[[sourceView textView] layoutManager] numberOfGlyphs])
+ {
+ NSRange fragRange;
+ NSRect fragRect = [self convertRect:[[[sourceView textView] layoutManager] lineFragmentRectForGlyphAtIndex:i effectiveRange:&fragRange] fromView:[sourceView textView]];
+ fragRect.origin.x = rect.origin.x; // horizontal scrolling matters not
+ fragRect.size.width = [self bounds].size.width;
+
+ // we want to paint the top and bottom line number even if they're cut off
+ NSRect testRect = rect;
+ testRect.origin.y -= fragRect.size.height - 1;
+ testRect.size.height += fragRect.size.height - 1;
+ if (NSPointInRect(fragRect.origin, testRect))
+ {
+ lineNumberRange.location = (lineNumberRange.length == 0 ? line : lineNumberRange.location);
+ lineNumberRange.length++;
+ NSString* num = [NSString stringWithFormat:@"%u", line];
+ NSSize strSize = [num sizeWithAttributes:attrs];
+ [num drawAtPoint:NSMakePoint([self frame].size.width - strSize.width - 3, fragRect.origin.y + ((fragRect.size.height - strSize.height) / 2)) withAttributes:attrs];
+ Breakpoint* test = [[Breakpoint alloc] initWithLine:line inFile:[sourceView file]];
+ if ([markers containsObject:test])
+ {
+ [self drawMarkerInRect:fragRect];
+ }
+ [test release];
+ }
+
+ i += fragRange.length;
+ line++;
+ }
}
/**
*/
- (void)mouseDown:(NSEvent*)event
{
- NSTextView* textView = [sourceView textView];
-
- NSPoint clickLoc = [self convertPoint:[event locationInWindow] fromView:nil];
-
- unsigned line = 1;
- unsigned i = 0;
- while (i < [[textView layoutManager] numberOfGlyphs])
- {
- NSRange fragRange;
- NSRect fragRect = [[textView layoutManager] lineFragmentRectForGlyphAtIndex:i effectiveRange:&fragRange];
- fragRect.size.width = [self bounds].size.width;
- if (NSPointInRect(clickLoc, fragRect))
- {
- [[sourceView delegate] gutterClickedAtLine:(line + lineNumberRange.location - 1) forFile:[sourceView file]];
- return;
- }
-
- i += fragRange.length;
- line++;
- }
+ NSTextView* textView = [sourceView textView];
+
+ NSPoint clickLoc = [self convertPoint:[event locationInWindow] fromView:nil];
+
+ unsigned line = 1;
+ unsigned i = 0;
+ while (i < [[textView layoutManager] numberOfGlyphs])
+ {
+ NSRange fragRange;
+ NSRect fragRect = [[textView layoutManager] lineFragmentRectForGlyphAtIndex:i effectiveRange:&fragRange];
+ fragRect.size.width = [self bounds].size.width;
+ if (NSPointInRect(clickLoc, fragRect))
+ {
+ [[sourceView delegate] gutterClickedAtLine:(line + lineNumberRange.location - 1) forFile:[sourceView file]];
+ return;
+ }
+
+ i += fragRange.length;
+ line++;
+ }
}
#pragma mark Private
*/
- (void)drawMarkerInRect:(NSRect)rect
{
- NSBezierPath* path = [NSBezierPath bezierPath];
-
- [path moveToPoint:NSMakePoint(rect.origin.x + 2, rect.origin.y + 2)]; // initial origin
- [path lineToPoint:NSMakePoint(rect.size.width - 7, rect.origin.y + 2)]; // upper right
- [path lineToPoint:NSMakePoint(rect.size.width - 2, rect.origin.y + (rect.size.height / 2))]; // point
- [path lineToPoint:NSMakePoint(rect.size.width - 7, rect.origin.y + rect.size.height - 2)]; // lower right
- [path lineToPoint:NSMakePoint(rect.origin.x + 2, rect.origin.y + rect.size.height - 2)]; // lower left
- [path lineToPoint:NSMakePoint(rect.origin.x + 2, rect.origin.y + 1)]; // upper left
-
- [[NSColor colorWithDeviceRed:0.004 green:0.557 blue:0.851 alpha:1.0] set];
- [path fill];
-
- [[NSColor colorWithDeviceRed:0.0 green:0.404 blue:0.804 alpha:1.0] set];
- [path setLineWidth:2];
- [path stroke];
+ NSBezierPath* path = [NSBezierPath bezierPath];
+
+ [path moveToPoint:NSMakePoint(rect.origin.x + 2, rect.origin.y + 2)]; // initial origin
+ [path lineToPoint:NSMakePoint(rect.size.width - 7, rect.origin.y + 2)]; // upper right
+ [path lineToPoint:NSMakePoint(rect.size.width - 2, rect.origin.y + (rect.size.height / 2))]; // point
+ [path lineToPoint:NSMakePoint(rect.size.width - 7, rect.origin.y + rect.size.height - 2)]; // lower right
+ [path lineToPoint:NSMakePoint(rect.origin.x + 2, rect.origin.y + rect.size.height - 2)]; // lower left
+ [path lineToPoint:NSMakePoint(rect.origin.x + 2, rect.origin.y + 1)]; // upper left
+
+ [[NSColor colorWithDeviceRed:0.004 green:0.557 blue:0.851 alpha:1.0] set];
+ [path fill];
+
+ [[NSColor colorWithDeviceRed:0.0 green:0.404 blue:0.804 alpha:1.0] set];
+ [path setLineWidth:2];
+ [path stroke];
}
@end
@interface BSSourceView : NSView
{
- BSLineNumberView* numberView;
- BSSourceViewTextView* textView;
- NSScrollView* scrollView;
-
- NSString* file;
- int markedLine;
-
- id delegate;
+ BSLineNumberView* numberView;
+ BSSourceViewTextView* textView;
+ NSScrollView* scrollView;
+
+ NSString* file;
+ int markedLine;
+
+ id delegate;
}
@property(readwrite, assign) BSLineNumberView* numberView;
*/
- (id)initWithFrame:(NSRect)frame
{
- if (self = [super initWithFrame:frame])
- {
- [self setupViews];
- [[NSNotificationCenter defaultCenter]
- addObserver:self
- selector:@selector(errorHighlightingFile:)
- name:NSFileHandleReadToEndOfFileCompletionNotification
- object:nil
- ];
- }
- return self;
+ if (self = [super initWithFrame:frame])
+ {
+ [self setupViews];
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(errorHighlightingFile:)
+ name:NSFileHandleReadToEndOfFileCompletionNotification
+ object:nil
+ ];
+ }
+ return self;
}
/**
*/
- (void)dealloc
{
- [file release];
-
- [numberView removeFromSuperview];
- [scrollView removeFromSuperview];
- [textView removeFromSuperview];
-
- [super dealloc];
+ [file release];
+
+ [numberView removeFromSuperview];
+ [scrollView removeFromSuperview];
+ [textView removeFromSuperview];
+
+ [super dealloc];
}
/**
*/
- (void)setFile:(NSString*)f
{
- if (file != f)
- {
- [file release];
- file = [f retain];
- }
-
- if (![[NSFileManager defaultManager] fileExistsAtPath:f])
- {
- [textView setString:@""];
- return;
- }
+ if (file != f)
+ {
+ [file release];
+ file = [f retain];
+ }
+
+ if (![[NSFileManager defaultManager] fileExistsAtPath:f])
+ {
+ [textView setString:@""];
+ return;
+ }
- @try
- {
- // Attempt to use the PHP CLI to highlight the source file as HTML
- NSPipe* outPipe = [NSPipe pipe];
- NSPipe* errPipe = [NSPipe pipe];
- NSTask* task = [[NSTask new] autorelease];
-
- [task setLaunchPath:@"/usr/bin/php"]; // This is the path to the default Leopard PHP executable
- [task setArguments:[NSArray arrayWithObjects:@"-s", f, nil]];
- [task setStandardOutput:outPipe];
- [task setStandardError:errPipe];
- [task launch];
-
- [[errPipe fileHandleForReading] readToEndOfFileInBackgroundAndNotify];
-
- NSData* data = [[outPipe fileHandleForReading] readDataToEndOfFile];
- NSAttributedString* source = [[NSAttributedString alloc] initWithHTML:data documentAttributes:NULL];
- [[textView textStorage] setAttributedString:source];
- [source release];
- }
- @catch (NSException* exception)
- {
- // If the PHP executable is not available then the NSTask will throw an exception
- [textView setString:[NSString stringWithContentsOfFile:f]];
- }
+ @try
+ {
+ // Attempt to use the PHP CLI to highlight the source file as HTML
+ NSPipe* outPipe = [NSPipe pipe];
+ NSPipe* errPipe = [NSPipe pipe];
+ NSTask* task = [[NSTask new] autorelease];
+
+ [task setLaunchPath:@"/usr/bin/php"]; // This is the path to the default Leopard PHP executable
+ [task setArguments:[NSArray arrayWithObjects:@"-s", f, nil]];
+ [task setStandardOutput:outPipe];
+ [task setStandardError:errPipe];
+ [task launch];
+
+ [[errPipe fileHandleForReading] readToEndOfFileInBackgroundAndNotify];
+
+ NSData* data = [[outPipe fileHandleForReading] readDataToEndOfFile];
+ NSAttributedString* source = [[NSAttributedString alloc] initWithHTML:data documentAttributes:NULL];
+ [[textView textStorage] setAttributedString:source];
+ [source release];
+ }
+ @catch (NSException* exception)
+ {
+ // If the PHP executable is not available then the NSTask will throw an exception
+ [textView setString:[NSString stringWithContentsOfFile:f]];
+ }
}
/**
*/
- (void)setString:(NSString*)source asFile:(NSString*)path
{
- // create the temp file
- NSError* error = nil;
- NSString* tmpPath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"MacGDBpHighlighter"];
- [source writeToFile:tmpPath atomically:NO encoding:NSUTF8StringEncoding error:&error];
- if (error)
- {
- [textView setString:source];
- return;
- }
-
- // highlight the temporary file
- [self setFile:tmpPath];
-
- // delete the temp file
- [[NSFileManager defaultManager] removeItemAtPath:tmpPath error:NULL];
-
- // plop in our fake path so nobody knows the difference
- if (path != file)
- {
- [file release];
- file = [path copy];
- }
+ // create the temp file
+ NSError* error = nil;
+ NSString* tmpPath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"MacGDBpHighlighter"];
+ [source writeToFile:tmpPath atomically:NO encoding:NSUTF8StringEncoding error:&error];
+ if (error)
+ {
+ [textView setString:source];
+ return;
+ }
+
+ // highlight the temporary file
+ [self setFile:tmpPath];
+
+ // delete the temp file
+ [[NSFileManager defaultManager] removeItemAtPath:tmpPath error:NULL];
+
+ // plop in our fake path so nobody knows the difference
+ if (path != file)
+ {
+ [file release];
+ file = [path copy];
+ }
}
/**
*/
- (void)errorHighlightingFile:(NSNotification*)notif
{
- NSData* data = [[notif userInfo] objectForKey:NSFileHandleNotificationDataItem];
- if ([data length] > 0) // there's something on stderr, so the PHP CLI failed
- [textView setString:[NSString stringWithContentsOfFile:file]];
+ NSData* data = [[notif userInfo] objectForKey:NSFileHandleNotificationDataItem];
+ if ([data length] > 0) // there's something on stderr, so the PHP CLI failed
+ [textView setString:[NSString stringWithContentsOfFile:file]];
}
/**
*/
- (BOOL)isFlipped
{
- return YES;
+ return YES;
}
/**
*/
- (void)scrollToLine:(int)line
{
- if ([[textView textStorage] length] == 0)
- return;
-
- // go through the document until we find the NSRange for the line we want
- int rangeIndex = 0;
- for (int i = 0; i < line; i++)
- {
- rangeIndex = NSMaxRange([[textView string] lineRangeForRange:NSMakeRange(rangeIndex, 0)]);
- }
-
- // now get the true start/end markers for it
- unsigned lineStart, lineEnd;
- [[textView string] getLineStart:&lineStart end:NULL contentsEnd:&lineEnd forRange:NSMakeRange(rangeIndex - 1, 0)];
- [textView scrollRangeToVisible:[[textView string] lineRangeForRange:NSMakeRange(lineStart, lineEnd - lineStart)]];
+ if ([[textView textStorage] length] == 0)
+ return;
+
+ // go through the document until we find the NSRange for the line we want
+ int rangeIndex = 0;
+ for (int i = 0; i < line; i++)
+ {
+ rangeIndex = NSMaxRange([[textView string] lineRangeForRange:NSMakeRange(rangeIndex, 0)]);
+ }
+
+ // now get the true start/end markers for it
+ unsigned lineStart, lineEnd;
+ [[textView string] getLineStart:&lineStart end:NULL contentsEnd:&lineEnd forRange:NSMakeRange(rangeIndex - 1, 0)];
+ [textView scrollRangeToVisible:[[textView string] lineRangeForRange:NSMakeRange(lineStart, lineEnd - lineStart)]];
}
/**
*/
- (void)setupViews
{
- int gutterWidth = 30;
-
- // setup the line number view
- NSRect numberFrame = [self bounds];
- numberFrame.origin = NSMakePoint(0.0, 0.0);
- numberFrame.size.width = gutterWidth;
- numberView = [[BSLineNumberView alloc] initWithFrame:numberFrame];
- [numberView setAutoresizingMask:NSViewHeightSizable];
- [numberView setSourceView:self];
- [self addSubview:numberView];
-
- // create the scroll view
- NSRect scrollFrame = [self bounds];
- scrollFrame.origin.x = gutterWidth;
- scrollFrame.size.width = scrollFrame.size.width - gutterWidth;
- scrollView = [[NSScrollView alloc] initWithFrame:scrollFrame];
- [scrollView setHasHorizontalScroller:YES];
- [scrollView setHasVerticalScroller:YES];
- [scrollView setAutohidesScrollers:YES];
- [scrollView setBorderType:NSBezelBorder];
- [scrollView setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
- [[scrollView contentView] setAutoresizesSubviews:YES];
- [self addSubview:scrollView];
-
- // add the text view to the scroll view
- NSRect textFrame;
- textFrame.origin = NSMakePoint(0.0, 0.0);
- textFrame.size = [scrollView contentSize];
- textView = [[BSSourceViewTextView alloc] initWithFrame:textFrame];
- [textView setSourceView:self];
- [textView setEditable:NO];
- [textView setFont:[NSFont fontWithName:@"Monaco" size:10.0]];
- [textView setHorizontallyResizable:YES];
- [textView setVerticallyResizable:YES];
- [textView setMinSize:textFrame.size];
- [textView setMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)];
- [[textView textContainer] setContainerSize:NSMakeSize(FLT_MAX, FLT_MAX)];
- [[textView textContainer] setWidthTracksTextView:NO];
- [[textView textContainer] setHeightTracksTextView:NO];
- [textView setAutoresizingMask:NSViewNotSizable];
- [scrollView setDocumentView:textView];
+ int gutterWidth = 30;
+
+ // setup the line number view
+ NSRect numberFrame = [self bounds];
+ numberFrame.origin = NSMakePoint(0.0, 0.0);
+ numberFrame.size.width = gutterWidth;
+ numberView = [[BSLineNumberView alloc] initWithFrame:numberFrame];
+ [numberView setAutoresizingMask:NSViewHeightSizable];
+ [numberView setSourceView:self];
+ [self addSubview:numberView];
+
+ // create the scroll view
+ NSRect scrollFrame = [self bounds];
+ scrollFrame.origin.x = gutterWidth;
+ scrollFrame.size.width = scrollFrame.size.width - gutterWidth;
+ scrollView = [[NSScrollView alloc] initWithFrame:scrollFrame];
+ [scrollView setHasHorizontalScroller:YES];
+ [scrollView setHasVerticalScroller:YES];
+ [scrollView setAutohidesScrollers:YES];
+ [scrollView setBorderType:NSBezelBorder];
+ [scrollView setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
+ [[scrollView contentView] setAutoresizesSubviews:YES];
+ [self addSubview:scrollView];
+
+ // add the text view to the scroll view
+ NSRect textFrame;
+ textFrame.origin = NSMakePoint(0.0, 0.0);
+ textFrame.size = [scrollView contentSize];
+ textView = [[BSSourceViewTextView alloc] initWithFrame:textFrame];
+ [textView setSourceView:self];
+ [textView setEditable:NO];
+ [textView setFont:[NSFont fontWithName:@"Monaco" size:10.0]];
+ [textView setHorizontallyResizable:YES];
+ [textView setVerticallyResizable:YES];
+ [textView setMinSize:textFrame.size];
+ [textView setMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)];
+ [[textView textContainer] setContainerSize:NSMakeSize(FLT_MAX, FLT_MAX)];
+ [[textView textContainer] setWidthTracksTextView:NO];
+ [[textView textContainer] setHeightTracksTextView:NO];
+ [textView setAutoresizingMask:NSViewNotSizable];
+ [scrollView setDocumentView:textView];
}
@end
@interface BSSourceViewTextView : NSTextView
{
- BSSourceView* sourceView;
+ BSSourceView* sourceView;
}
@property(readwrite, assign) BSSourceView* sourceView;
*/
- (void)drawRect:(NSRect)rect
{
- [super drawRect:rect];
-
- unsigned i = 0, line = 1;
- while (i < [[self layoutManager] numberOfGlyphs])
- {
- NSRange fragRange;
- NSRect fragRect = [self convertRect:[[self layoutManager] lineFragmentRectForGlyphAtIndex:i effectiveRange:&fragRange] fromView:self];
- fragRect.origin.x = rect.origin.x; // horizontal scrolling matters not
-
- if ([sourceView markedLine] == line)
- {
- [[[NSColor redColor] colorWithAlphaComponent:0.25] set];
- [NSBezierPath fillRect:fragRect];
- break;
- }
-
- i += fragRange.length;
- line++;
- }
-
- [[sourceView numberView] setNeedsDisplay:YES];
+ [super drawRect:rect];
+
+ unsigned i = 0, line = 1;
+ while (i < [[self layoutManager] numberOfGlyphs])
+ {
+ NSRange fragRange;
+ NSRect fragRect = [self convertRect:[[self layoutManager] lineFragmentRectForGlyphAtIndex:i effectiveRange:&fragRange] fromView:self];
+ fragRect.origin.x = rect.origin.x; // horizontal scrolling matters not
+
+ if ([sourceView markedLine] == line)
+ {
+ [[[NSColor redColor] colorWithAlphaComponent:0.25] set];
+ [NSBezierPath fillRect:fragRect];
+ break;
+ }
+
+ i += fragRange.length;
+ line++;
+ }
+
+ [[sourceView numberView] setNeedsDisplay:YES];
}
@end
*/
- (void)drawDividerInRect:(NSRect)rect
{
- // draw the gradient
- NSColor* startColor = [NSColor colorWithDeviceRed:0.875 green:0.875 blue:0.875 alpha:1.0];
- NSColor* endColor = [NSColor colorWithDeviceRed:0.812 green:0.812 blue:0.812 alpha:1.0];
- NSGradient* gradient = [[NSGradient alloc] initWithStartingColor:startColor endingColor:endColor];
- [gradient drawInRect:rect angle:([self isVertical] ? 0.0 : 90.0)];
- [gradient release];
-
- // draw the stroke
- [[NSColor colorWithDeviceRed:0.667 green:0.667 blue:0.667 alpha:1.0] setStroke];
- [NSBezierPath setDefaultLineWidth:0.5];
- [NSBezierPath strokeRect:rect];
-
- // draw the dimple
- NSImage* dimple = [NSImage imageNamed:@"dimple.png"];
- NSSize dmpSize = [dimple size];
- NSPoint origin = NSMakePoint((rect.size.width / 2) + rect.origin.x - (dmpSize.width / 2), (rect.size.height / 2) + rect.origin.y + (dmpSize.height / 2));
- [dimple compositeToPoint:origin operation:NSCompositeSourceOver];
+ // draw the gradient
+ NSColor* startColor = [NSColor colorWithDeviceRed:0.875 green:0.875 blue:0.875 alpha:1.0];
+ NSColor* endColor = [NSColor colorWithDeviceRed:0.812 green:0.812 blue:0.812 alpha:1.0];
+ NSGradient* gradient = [[NSGradient alloc] initWithStartingColor:startColor endingColor:endColor];
+ [gradient drawInRect:rect angle:([self isVertical] ? 0.0 : 90.0)];
+ [gradient release];
+
+ // draw the stroke
+ [[NSColor colorWithDeviceRed:0.667 green:0.667 blue:0.667 alpha:1.0] setStroke];
+ [NSBezierPath setDefaultLineWidth:0.5];
+ [NSBezierPath strokeRect:rect];
+
+ // draw the dimple
+ NSImage* dimple = [NSImage imageNamed:@"dimple.png"];
+ NSSize dmpSize = [dimple size];
+ NSPoint origin = NSMakePoint((rect.size.width / 2) + rect.origin.x - (dmpSize.width / 2), (rect.size.height / 2) + rect.origin.y + (dmpSize.height / 2));
+ [dimple compositeToPoint:origin operation:NSCompositeSourceOver];
}
/**
*/
- (CGFloat)dividerThickness;
{
- return 6.0;
+ return 6.0;
}
@end
@interface Breakpoint : NSObject
{
- NSString* file;
- int line;
- int debuggerId;
+ NSString* file;
+ int line;
+ int debuggerId;
}
@property(readonly) NSString* file;
*/
- (id)initWithLine:(int)l inFile:(NSString*)f
{
- if (self = [super init])
- {
- file = [f retain];
- line = l;
- }
- return self;
+ if (self = [super init])
+ {
+ file = [f retain];
+ line = l;
+ }
+ return self;
}
/**
*/
- (void)dealloc
{
- [file release];
- [super dealloc];
+ [file release];
+ [super dealloc];
}
/**
*/
- (id)initWithDictionary:(NSDictionary*)dict
{
- if (self = [super init])
- {
- file = [[dict valueForKey:@"file"] retain];
- line = [[dict valueForKey:@"line"] intValue];
- }
- return self;
+ if (self = [super init])
+ {
+ file = [[dict valueForKey:@"file"] retain];
+ line = [[dict valueForKey:@"line"] intValue];
+ }
+ return self;
}
/**
*/
- (NSString*)transformedPath
{
- NSString* path = self.file;
-
- NSMutableArray* transforms = [[NSUserDefaults standardUserDefaults] mutableArrayValueForKey:@"PathReplacements"];
- if (!transforms || [transforms count] < 1)
- return path;
-
- for (NSDictionary* replacement in transforms)
- {
- path = [path
- stringByReplacingOccurrencesOfString:[replacement valueForKey:@"local"]
- withString:[replacement valueForKey:@"remote"]
- ];
- }
-
- return path;
+ NSString* path = self.file;
+
+ NSMutableArray* transforms = [[NSUserDefaults standardUserDefaults] mutableArrayValueForKey:@"PathReplacements"];
+ if (!transforms || [transforms count] < 1)
+ return path;
+
+ for (NSDictionary* replacement in transforms)
+ {
+ path = [path
+ stringByReplacingOccurrencesOfString:[replacement valueForKey:@"local"]
+ withString:[replacement valueForKey:@"remote"]
+ ];
+ }
+
+ return path;
}
/**
*/
- (BOOL)isEqual:(id)obj
{
- return ([[obj file] isEqualToString:file] && [obj line] == line);
+ return ([[obj file] isEqualToString:file] && [obj line] == line);
}
/**
*/
- (NSUInteger)hash
{
- return ([file hash] << 8) + line;
+ return ([file hash] << 8) + line;
}
/**
*/
- (NSDictionary*)dictionary
{
- return [NSDictionary dictionaryWithObjectsAndKeys:file, @"file", [NSNumber numberWithInt:line], @"line", nil];
+ return [NSDictionary dictionaryWithObjectsAndKeys:file, @"file", [NSNumber numberWithInt:line], @"line", nil];
}
/**
*/
- (NSString*)description
{
- return [NSString stringWithFormat:@"%@:%i", file, line];
+ return [NSString stringWithFormat:@"%@:%i", file, line];
}
@end
@interface BreakpointController : NSWindowController
{
- BreakpointManager* manager;
-
- IBOutlet NSArrayController* arrayController;
- IBOutlet BSSourceView* sourceView;
+ BreakpointManager* manager;
+
+ IBOutlet NSArrayController* arrayController;
+ IBOutlet BSSourceView* sourceView;
}
@property(readonly) BSSourceView* sourceView;
*/
- (id)init
{
- if (self = [super initWithWindowNibName:@"Breakpoints"])
- {
- manager = [BreakpointManager sharedManager];
- if ([[NSUserDefaults standardUserDefaults] boolForKey:@"BreakpointsWindowVisible"])
- [[self window] orderBack:nil];
- }
- return self;
+ if (self = [super initWithWindowNibName:@"Breakpoints"])
+ {
+ manager = [BreakpointManager sharedManager];
+ if ([[NSUserDefaults standardUserDefaults] boolForKey:@"BreakpointsWindowVisible"])
+ [[self window] orderBack:nil];
+ }
+ return self;
}
/**
*/
- (IBAction)addBreakpoint:(id)sender
{
- NSOpenPanel* panel = [NSOpenPanel openPanel];
-
- if ([panel runModal] != NSOKButton)
- {
- return;
- }
-
- [sourceView setFile:[panel filename]];
+ NSOpenPanel* panel = [NSOpenPanel openPanel];
+
+ if ([panel runModal] != NSOKButton)
+ {
+ return;
+ }
+
+ [sourceView setFile:[panel filename]];
}
/**
*/
- (IBAction)removeBreakpoint:(id)sender
{
- NSArray* selection = [arrayController selectedObjects];
- if ([selection count] < 1)
- {
- return;
- }
-
- for (Breakpoint* bp in selection)
- {
- [manager removeBreakpointAt:[bp line] inFile:[bp file]];
- }
+ NSArray* selection = [arrayController selectedObjects];
+ if ([selection count] < 1)
+ {
+ return;
+ }
+
+ for (Breakpoint* bp in selection)
+ {
+ [manager removeBreakpointAt:[bp line] inFile:[bp file]];
+ }
}
#pragma mark NSTableView Delegate
*/
- (void)tableViewSelectionDidChange:(NSNotification*)notif
{
- NSArray* selection = [arrayController selectedObjects];
- if ([selection count] < 1)
- {
- return;
- }
-
- Breakpoint* bp = [selection objectAtIndex:0];
- [sourceView setFile:[bp file]];
- [sourceView scrollToLine:[bp line]];
- [[sourceView numberView] setMarkers:[NSSet setWithArray:[manager breakpointsForFile:[bp file]]]];
+ NSArray* selection = [arrayController selectedObjects];
+ if ([selection count] < 1)
+ {
+ return;
+ }
+
+ Breakpoint* bp = [selection objectAtIndex:0];
+ [sourceView setFile:[bp file]];
+ [sourceView scrollToLine:[bp line]];
+ [[sourceView numberView] setMarkers:[NSSet setWithArray:[manager breakpointsForFile:[bp file]]]];
}
#pragma mark BSSourceView Delegate
*/
- (void)gutterClickedAtLine:(int)line forFile:(NSString*)file
{
- if ([manager hasBreakpointAt:line inFile:file])
- {
- [manager removeBreakpointAt:line inFile:file];
- }
- else
- {
- Breakpoint* bp = [[Breakpoint alloc] initWithLine:line inFile:file];
- [manager addBreakpoint:bp];
- [bp release];
- }
-
- [[sourceView numberView] setMarkers:[NSSet setWithArray:[manager breakpointsForFile:file]]];
- [[sourceView numberView] setNeedsDisplay:YES];
+ if ([manager hasBreakpointAt:line inFile:file])
+ {
+ [manager removeBreakpointAt:line inFile:file];
+ }
+ else
+ {
+ Breakpoint* bp = [[Breakpoint alloc] initWithLine:line inFile:file];
+ [manager addBreakpoint:bp];
+ [bp release];
+ }
+
+ [[sourceView numberView] setMarkers:[NSSet setWithArray:[manager breakpointsForFile:file]]];
+ [[sourceView numberView] setNeedsDisplay:YES];
}
@end
@interface BreakpointManager : NSObject
{
- NSMutableArray* breakpoints;
- NSMutableArray* savedBreakpoints;
-
- DebuggerProcessor* connection;
+ NSMutableArray* breakpoints;
+ NSMutableArray* savedBreakpoints;
+
+ DebuggerProcessor* connection;
}
@property(readwrite, assign) DebuggerProcessor* connection;
*/
- (id)init
{
- if (self = [super init])
- {
- if (!breakpoints)
- {
- breakpoints = [[NSMutableArray alloc] init];
- }
-
- savedBreakpoints = [[[NSUserDefaults standardUserDefaults] mutableArrayValueForKey:@"Breakpoints"] retain];
- if (savedBreakpoints)
- {
- for (NSDictionary* d in savedBreakpoints)
- {
- [breakpoints addObject:[[[Breakpoint alloc] initWithDictionary:d] autorelease]];
- }
- }
- }
- return self;
+ if (self = [super init])
+ {
+ if (!breakpoints)
+ {
+ breakpoints = [[NSMutableArray alloc] init];
+ }
+
+ savedBreakpoints = [[[NSUserDefaults standardUserDefaults] mutableArrayValueForKey:@"Breakpoints"] retain];
+ if (savedBreakpoints)
+ {
+ for (NSDictionary* d in savedBreakpoints)
+ {
+ [breakpoints addObject:[[[Breakpoint alloc] initWithDictionary:d] autorelease]];
+ }
+ }
+ }
+ return self;
}
/**
*/
+ (BreakpointManager*)sharedManager
{
- static BreakpointManager* manager;
- if (!manager)
- {
- manager = [[BreakpointManager alloc] init];
- }
- return manager;
+ static BreakpointManager* manager;
+ if (!manager)
+ {
+ manager = [[BreakpointManager alloc] init];
+ }
+ return manager;
}
/**
*/
- (void)addBreakpoint:(Breakpoint*)bp;
{
- if (![breakpoints containsObject:bp])
- {
- [breakpoints addObject:bp];
- [connection addBreakpoint:bp];
-
- [savedBreakpoints addObject:[bp dictionary]];
- [[NSUserDefaults standardUserDefaults] setValue:savedBreakpoints forKey:@"Breakpoints"];
-
- [self updateDisplaysForFile:[bp file]];
- }
+ if (![breakpoints containsObject:bp])
+ {
+ [breakpoints addObject:bp];
+ [connection addBreakpoint:bp];
+
+ [savedBreakpoints addObject:[bp dictionary]];
+ [[NSUserDefaults standardUserDefaults] setValue:savedBreakpoints forKey:@"Breakpoints"];
+
+ [self updateDisplaysForFile:[bp file]];
+ }
}
/**
*/
- (Breakpoint*)removeBreakpointAt:(int)line inFile:(NSString*)file
{
- for (Breakpoint* b in breakpoints)
- {
- if ([b line] == line && [[b file] isEqualToString:file])
- {
- [breakpoints removeObject:b];
- [connection removeBreakpoint:b];
-
- [savedBreakpoints removeObject:[b dictionary]];
- [[NSUserDefaults standardUserDefaults] setValue:savedBreakpoints forKey:@"Breakpoints"];
-
- [self updateDisplaysForFile:file];
- return b;
- }
- }
- return nil;
+ for (Breakpoint* b in breakpoints)
+ {
+ if ([b line] == line && [[b file] isEqualToString:file])
+ {
+ [breakpoints removeObject:b];
+ [connection removeBreakpoint:b];
+
+ [savedBreakpoints removeObject:[b dictionary]];
+ [[NSUserDefaults standardUserDefaults] setValue:savedBreakpoints forKey:@"Breakpoints"];
+
+ [self updateDisplaysForFile:file];
+ return b;
+ }
+ }
+ return nil;
}
/**
*/
- (NSArray*)breakpointsForFile:(NSString*)file
{
- NSMutableArray* matches = [NSMutableArray array];
- for (Breakpoint* b in breakpoints)
- {
- if ([[b file] isEqualToString:file])
- {
- [matches addObject:b];
- }
- }
-
- return matches;
+ NSMutableArray* matches = [NSMutableArray array];
+ for (Breakpoint* b in breakpoints)
+ {
+ if ([[b file] isEqualToString:file])
+ {
+ [matches addObject:b];
+ }
+ }
+
+ return matches;
}
/**
*/
- (BOOL)hasBreakpointAt:(int)line inFile:(NSString*)file
{
- return [breakpoints containsObject:[[[Breakpoint alloc] initWithLine:line inFile:file] autorelease]];
+ return [breakpoints containsObject:[[[Breakpoint alloc] initWithLine:line inFile:file] autorelease]];
}
#pragma mark Private
*/
- (void)updateDisplaysForFile:(NSString*)file
{
- AppDelegate* appDel = [NSApp delegate];
- [[[appDel breakpoint] arrayController] rearrangeObjects];
- [[[appDel breakpoint] sourceView] setNeedsDisplay:YES];
- [[[[appDel breakpoint] sourceView] numberView] setMarkers:[NSSet setWithArray:[self breakpointsForFile:file]]];
- [[[appDel debugger] sourceViewer] setNeedsDisplay:YES];
- [[[[appDel debugger] sourceViewer] numberView] setMarkers:[NSSet setWithArray:[self breakpointsForFile:file]]];
+ AppDelegate* appDel = [NSApp delegate];
+ [[[appDel breakpoint] arrayController] rearrangeObjects];
+ [[[appDel breakpoint] sourceView] setNeedsDisplay:YES];
+ [[[[appDel breakpoint] sourceView] numberView] setMarkers:[NSSet setWithArray:[self breakpointsForFile:file]]];
+ [[[appDel debugger] sourceViewer] setNeedsDisplay:YES];
+ [[[[appDel debugger] sourceViewer] numberView] setMarkers:[NSSet setWithArray:[self breakpointsForFile:file]]];
}
@end
// asked to connect and shutdown when asked to close.
@interface DebuggerConnection : NSObject
{
- // The port to connect on.
- NSUInteger port_;
-
- // If the connection to the debugger engine is currently active.
- BOOL connected_;
+ // The port to connect on.
+ NSUInteger port_;
+
+ // If the connection to the debugger engine is currently active.
+ BOOL connected_;
// The thread on which network operations are performed. Weak.
NSThread* thread_;
- // Reference to the message loop that the socket runs on. Weak.
- NSRunLoop* runLoop_;
-
- // The raw CFSocket on which the two streams are based. Strong.
- CFSocketRef socket_;
-
- // The read stream that is scheduled on the main run loop. Weak.
- CFReadStreamRef readStream_;
-
- // The write stream. Weak.
- CFWriteStreamRef writeStream_;
-
- // An ever-increasing integer that gives each transaction a unique ID for the
- // debugging engine.
- NSUInteger transactionID;
-
- // The most recently received transaction ID.
- NSUInteger lastReadTransaction_;
-
- // The last transactionID written to the stream.
- NSUInteger lastWrittenTransaction_;
-
- // To prevent blocked writing, we enqueue all writes and then wait for the
- // write stream to tell us it's ready. We store the pending commands in this
- // array. We use this as a queue (FIFO), with index 0 being first.
- NSMutableArray* queuedWrites_;
-
- // We send queued writes in multiple places, sometimes off a run loop event.
- // Because of this, we need to ensure that only one client is dequeing and
- // sending at a time.
- NSRecursiveLock* writeQueueLock_;
-
- // Information about the current read loop. We append to |currentPacket_|
- // until |currentPacketSize_| has reached |packetSize_|.
- NSMutableString* currentPacket_;
- int packetSize_;
- int currentPacketIndex_;
-
- // The delegate. All methods are executed on the main thread.
- NSObject<DebuggerConnectionDelegate>* delegate_;
+ // Reference to the message loop that the socket runs on. Weak.
+ NSRunLoop* runLoop_;
+
+ // The raw CFSocket on which the two streams are based. Strong.
+ CFSocketRef socket_;
+
+ // The read stream that is scheduled on the main run loop. Weak.
+ CFReadStreamRef readStream_;
+
+ // The write stream. Weak.
+ CFWriteStreamRef writeStream_;
+
+ // An ever-increasing integer that gives each transaction a unique ID for the
+ // debugging engine.
+ NSUInteger transactionID;
+
+ // The most recently received transaction ID.
+ NSUInteger lastReadTransaction_;
+
+ // The last transactionID written to the stream.
+ NSUInteger lastWrittenTransaction_;
+
+ // To prevent blocked writing, we enqueue all writes and then wait for the
+ // write stream to tell us it's ready. We store the pending commands in this
+ // array. We use this as a queue (FIFO), with index 0 being first.
+ NSMutableArray* queuedWrites_;
+
+ // We send queued writes in multiple places, sometimes off a run loop event.
+ // Because of this, we need to ensure that only one client is dequeing and
+ // sending at a time.
+ NSRecursiveLock* writeQueueLock_;
+
+ // Information about the current read loop. We append to |currentPacket_|
+ // until |currentPacketSize_| has reached |packetSize_|.
+ NSMutableString* currentPacket_;
+ int packetSize_;
+ int currentPacketIndex_;
+
+ // The delegate. All methods are executed on the main thread.
+ NSObject<DebuggerConnectionDelegate>* delegate_;
}
@property (readonly) NSUInteger port;
void ReadStreamCallback(CFReadStreamRef stream, CFStreamEventType eventType, void* connectionRaw)
{
- DebuggerConnection* connection = (DebuggerConnection*)connectionRaw;
- switch (eventType)
- {
- case kCFStreamEventHasBytesAvailable:
- [connection readStreamHasData];
- break;
-
- case kCFStreamEventErrorOccurred:
- {
- CFErrorRef error = CFReadStreamCopyError(stream);
- CFReadStreamUnscheduleFromRunLoop(stream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
- CFReadStreamClose(stream);
- CFRelease(stream);
- [connection errorEncountered:[[(NSError*)error autorelease] description]];
- break;
- }
-
- case kCFStreamEventEndEncountered:
- CFReadStreamUnscheduleFromRunLoop(stream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
- CFReadStreamClose(stream);
- CFRelease(stream);
- [connection socketDisconnected];
- break;
- };
+ DebuggerConnection* connection = (DebuggerConnection*)connectionRaw;
+ switch (eventType)
+ {
+ case kCFStreamEventHasBytesAvailable:
+ [connection readStreamHasData];
+ break;
+
+ case kCFStreamEventErrorOccurred:
+ {
+ CFErrorRef error = CFReadStreamCopyError(stream);
+ CFReadStreamUnscheduleFromRunLoop(stream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
+ CFReadStreamClose(stream);
+ CFRelease(stream);
+ [connection errorEncountered:[[(NSError*)error autorelease] description]];
+ break;
+ }
+
+ case kCFStreamEventEndEncountered:
+ CFReadStreamUnscheduleFromRunLoop(stream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
+ CFReadStreamClose(stream);
+ CFRelease(stream);
+ [connection socketDisconnected];
+ break;
+ };
}
void WriteStreamCallback(CFWriteStreamRef stream, CFStreamEventType eventType, void* connectionRaw)
{
- DebuggerConnection* connection = (DebuggerConnection*)connectionRaw;
- switch (eventType)
- {
- case kCFStreamEventCanAcceptBytes:
- [connection sendQueuedWrites];
- break;
-
- case kCFStreamEventErrorOccurred:
- {
- CFErrorRef error = CFWriteStreamCopyError(stream);
- CFWriteStreamUnscheduleFromRunLoop(stream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
- CFWriteStreamClose(stream);
- CFRelease(stream);
- [connection errorEncountered:[[(NSError*)error autorelease] description]];
- break;
- }
-
- case kCFStreamEventEndEncountered:
- CFWriteStreamUnscheduleFromRunLoop(stream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
- CFWriteStreamClose(stream);
- CFRelease(stream);
- [connection socketDisconnected];
- break;
- }
+ DebuggerConnection* connection = (DebuggerConnection*)connectionRaw;
+ switch (eventType)
+ {
+ case kCFStreamEventCanAcceptBytes:
+ [connection sendQueuedWrites];
+ break;
+
+ case kCFStreamEventErrorOccurred:
+ {
+ CFErrorRef error = CFWriteStreamCopyError(stream);
+ CFWriteStreamUnscheduleFromRunLoop(stream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
+ CFWriteStreamClose(stream);
+ CFRelease(stream);
+ [connection errorEncountered:[[(NSError*)error autorelease] description]];
+ break;
+ }
+
+ case kCFStreamEventEndEncountered:
+ CFWriteStreamUnscheduleFromRunLoop(stream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
+ CFWriteStreamClose(stream);
+ CFRelease(stream);
+ [connection socketDisconnected];
+ break;
+ }
}
void SocketAcceptCallback(CFSocketRef socket,
- CFSocketCallBackType callbackType,
- CFDataRef address,
- const void* data,
- void* connectionRaw)
+ CFSocketCallBackType callbackType,
+ CFDataRef address,
+ const void* data,
+ void* connectionRaw)
{
- assert(callbackType == kCFSocketAcceptCallBack);
- NSLog(@"SocketAcceptCallback()");
-
- DebuggerConnection* connection = (DebuggerConnection*)connectionRaw;
-
- CFReadStreamRef readStream;
- CFWriteStreamRef writeStream;
-
- // Create the streams on the socket.
- CFStreamCreatePairWithSocket(kCFAllocatorDefault,
- *(CFSocketNativeHandle*)data, // Socket handle.
- &readStream, // Read stream in-pointer.
- &writeStream); // Write stream in-pointer.
-
- // Create struct to register callbacks for the stream.
- CFStreamClientContext context;
- context.version = 0;
- context.info = connection;
- context.retain = NULL;
- context.release = NULL;
- context.copyDescription = NULL;
-
- // Set the client of the read stream.
- CFOptionFlags readFlags =
- kCFStreamEventOpenCompleted |
- kCFStreamEventHasBytesAvailable |
- kCFStreamEventErrorOccurred |
- kCFStreamEventEndEncountered;
- if (CFReadStreamSetClient(readStream, readFlags, ReadStreamCallback, &context))
- // Schedule in run loop to do asynchronous communication with the engine.
- CFReadStreamScheduleWithRunLoop(readStream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
- else
- return;
-
- // Open the stream now that it's scheduled on the run loop.
- if (!CFReadStreamOpen(readStream))
- {
- CFStreamError error = CFReadStreamGetError(readStream);
- NSLog(@"error! %@", error);
- return;
- }
-
- // Set the client of the write stream.
- CFOptionFlags writeFlags =
- kCFStreamEventOpenCompleted |
- kCFStreamEventCanAcceptBytes |
- kCFStreamEventErrorOccurred |
- kCFStreamEventEndEncountered;
- if (CFWriteStreamSetClient(writeStream, writeFlags, WriteStreamCallback, &context))
- // Schedule it in the run loop to receive error information.
- CFWriteStreamScheduleWithRunLoop(writeStream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
- else
- return;
-
- // Open the write stream.
- if (!CFWriteStreamOpen(writeStream))
- {
- CFStreamError error = CFWriteStreamGetError(writeStream);
- NSLog(@"error! %@", error);
- return;
- }
-
- connection.readStream = readStream;
- connection.writeStream = writeStream;
- [connection socketDidAccept];
+ assert(callbackType == kCFSocketAcceptCallBack);
+ NSLog(@"SocketAcceptCallback()");
+
+ DebuggerConnection* connection = (DebuggerConnection*)connectionRaw;
+
+ CFReadStreamRef readStream;
+ CFWriteStreamRef writeStream;
+
+ // Create the streams on the socket.
+ CFStreamCreatePairWithSocket(kCFAllocatorDefault,
+ *(CFSocketNativeHandle*)data, // Socket handle.
+ &readStream, // Read stream in-pointer.
+ &writeStream); // Write stream in-pointer.
+
+ // Create struct to register callbacks for the stream.
+ CFStreamClientContext context;
+ context.version = 0;
+ context.info = connection;
+ context.retain = NULL;
+ context.release = NULL;
+ context.copyDescription = NULL;
+
+ // Set the client of the read stream.
+ CFOptionFlags readFlags =
+ kCFStreamEventOpenCompleted |
+ kCFStreamEventHasBytesAvailable |
+ kCFStreamEventErrorOccurred |
+ kCFStreamEventEndEncountered;
+ if (CFReadStreamSetClient(readStream, readFlags, ReadStreamCallback, &context))
+ // Schedule in run loop to do asynchronous communication with the engine.
+ CFReadStreamScheduleWithRunLoop(readStream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
+ else
+ return;
+
+ // Open the stream now that it's scheduled on the run loop.
+ if (!CFReadStreamOpen(readStream))
+ {
+ CFStreamError error = CFReadStreamGetError(readStream);
+ NSLog(@"error! %@", error);
+ return;
+ }
+
+ // Set the client of the write stream.
+ CFOptionFlags writeFlags =
+ kCFStreamEventOpenCompleted |
+ kCFStreamEventCanAcceptBytes |
+ kCFStreamEventErrorOccurred |
+ kCFStreamEventEndEncountered;
+ if (CFWriteStreamSetClient(writeStream, writeFlags, WriteStreamCallback, &context))
+ // Schedule it in the run loop to receive error information.
+ CFWriteStreamScheduleWithRunLoop(writeStream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
+ else
+ return;
+
+ // Open the write stream.
+ if (!CFWriteStreamOpen(writeStream))
+ {
+ CFStreamError error = CFWriteStreamGetError(writeStream);
+ NSLog(@"error! %@", error);
+ return;
+ }
+
+ connection.readStream = readStream;
+ connection.writeStream = writeStream;
+ [connection socketDidAccept];
}
////////////////////////////////////////////////////////////////////////////////
- (id)initWithPort:(NSUInteger)aPort
{
- if (self = [super init])
- {
- port_ = aPort;
- }
- return self;
+ if (self = [super init])
+ {
+ port_ = aPort;
+ }
+ return self;
}
- (void)dealloc
{
- self.currentPacket = nil;
- [super dealloc];
+ self.currentPacket = nil;
+ [super dealloc];
}
/**
*/
- (void)connect
{
- [NSThread detachNewThreadSelector:@selector(connectInternal) toTarget:self withObject:nil];
+ [NSThread detachNewThreadSelector:@selector(connectInternal) toTarget:self withObject:nil];
}
/**
*/
- (void)connectInternal
{
- NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+ NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
thread_ = [NSThread currentThread];
- runLoop_ = [NSRunLoop currentRunLoop];
-
- // Pass ourselves to the callback so we don't have to use ugly globals.
- CFSocketContext context;
- context.version = 0;
- context.info = self;
- context.retain = NULL;
- context.release = NULL;
- context.copyDescription = NULL;
-
- // Create the address structure.
- struct sockaddr_in address;
- memset(&address, 0, sizeof(address));
- address.sin_len = sizeof(address);
- address.sin_family = AF_INET;
- address.sin_port = htons(port_);
- address.sin_addr.s_addr = htonl(INADDR_ANY);
-
- // Create the socket signature.
- CFSocketSignature signature;
- signature.protocolFamily = PF_INET;
- signature.socketType = SOCK_STREAM;
- signature.protocol = IPPROTO_TCP;
- signature.address = (CFDataRef)[NSData dataWithBytes:&address length:sizeof(address)];
-
- socket_ = CFSocketCreateWithSocketSignature(kCFAllocatorDefault,
- &signature, // Socket signature.
- kCFSocketAcceptCallBack, // Callback types.
- SocketAcceptCallback, // Callout function pointer.
- &context); // Context to pass to callout.
- if (!socket_)
- {
- [self errorEncountered:@"Could not open socket."];
- return;
- }
-
- // Allow old, yet-to-be recycled sockets to be reused.
- BOOL yes = YES;
- setsockopt(CFSocketGetNative(socket_), SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(BOOL));
-
- // Schedule the socket on the run loop.
- CFRunLoopSourceRef source = CFSocketCreateRunLoopSource(kCFAllocatorDefault, socket_, 0);
- CFRunLoopAddSource([runLoop_ getCFRunLoop], source, kCFRunLoopCommonModes);
- CFRelease(source);
-
- [runLoop_ run];
+ runLoop_ = [NSRunLoop currentRunLoop];
+
+ // Pass ourselves to the callback so we don't have to use ugly globals.
+ CFSocketContext context;
+ context.version = 0;
+ context.info = self;
+ context.retain = NULL;
+ context.release = NULL;
+ context.copyDescription = NULL;
+
+ // Create the address structure.
+ struct sockaddr_in address;
+ memset(&address, 0, sizeof(address));
+ address.sin_len = sizeof(address);
+ address.sin_family = AF_INET;
+ address.sin_port = htons(port_);
+ address.sin_addr.s_addr = htonl(INADDR_ANY);
+
+ // Create the socket signature.
+ CFSocketSignature signature;
+ signature.protocolFamily = PF_INET;
+ signature.socketType = SOCK_STREAM;
+ signature.protocol = IPPROTO_TCP;
+ signature.address = (CFDataRef)[NSData dataWithBytes:&address length:sizeof(address)];
+
+ socket_ = CFSocketCreateWithSocketSignature(kCFAllocatorDefault,
+ &signature, // Socket signature.
+ kCFSocketAcceptCallBack, // Callback types.
+ SocketAcceptCallback, // Callout function pointer.
+ &context); // Context to pass to callout.
+ if (!socket_)
+ {
+ [self errorEncountered:@"Could not open socket."];
+ return;
+ }
+
+ // Allow old, yet-to-be recycled sockets to be reused.
+ BOOL yes = YES;
+ setsockopt(CFSocketGetNative(socket_), SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(BOOL));
+
+ // Schedule the socket on the run loop.
+ CFRunLoopSourceRef source = CFSocketCreateRunLoopSource(kCFAllocatorDefault, socket_, 0);
+ CFRunLoopAddSource([runLoop_ getCFRunLoop], source, kCFRunLoopCommonModes);
+ CFRelease(source);
+
+ [runLoop_ run];
thread_ = nil;
runLoop_ = nil;
- [pool release];
+ [pool release];
}
/**
*/
- (void)socketDidAccept
{
- connected_ = YES;
- transactionID = 1;
- self.queuedWrites = [NSMutableArray array];
- writeQueueLock_ = [NSRecursiveLock new];
+ connected_ = YES;
+ transactionID = 1;
+ self.queuedWrites = [NSMutableArray array];
+ writeQueueLock_ = [NSRecursiveLock new];
}
/**
*/
- (void)close
{
- if (runLoop_) {
- CFRunLoopStop([runLoop_ getCFRunLoop]);
- }
-
- // The socket goes down, so do the streams, which clean themselves up.
- if (socket_) {
- CFSocketInvalidate(socket_);
- CFRelease(socket_);
- }
- self.queuedWrites = nil;
- [writeQueueLock_ release];
+ if (runLoop_) {
+ CFRunLoopStop([runLoop_ getCFRunLoop]);
+ }
+
+ // The socket goes down, so do the streams, which clean themselves up.
+ if (socket_) {
+ CFSocketInvalidate(socket_);
+ CFRelease(socket_);
+ }
+ self.queuedWrites = nil;
+ [writeQueueLock_ release];
}
/**
*/
- (void)socketDisconnected
{
- [self close];
- [delegate_ connectionDidClose:self];
+ [self close];
+ [delegate_ connectionDidClose:self];
}
/**
*/
- (void)send:(NSString*)command
{
- if (lastReadTransaction_ >= lastWrittenTransaction_ && CFWriteStreamCanAcceptBytes(writeStream_)) {
- [self performSend:command];
- } else {
- [writeQueueLock_ lock];
- [queuedWrites_ addObject:command];
- [writeQueueLock_ unlock];
- }
- [self sendQueuedWrites];
+ if (lastReadTransaction_ >= lastWrittenTransaction_ && CFWriteStreamCanAcceptBytes(writeStream_)) {
+ [self performSend:command];
+ } else {
+ [writeQueueLock_ lock];
+ [queuedWrites_ addObject:command];
+ [writeQueueLock_ unlock];
+ }
+ [self sendQueuedWrites];
}
/**
*/
- (NSNumber*)sendCommandWithFormat:(NSString*)format, ...
{
- // Collect varargs and format command.
- va_list args;
- va_start(args, format);
- NSString* command = [[NSString alloc] initWithFormat:format arguments:args];
- va_end(args);
-
- NSNumber* callbackKey = [NSNumber numberWithInt:transactionID++];
+ // Collect varargs and format command.
+ va_list args;
+ va_start(args, format);
+ NSString* command = [[NSString alloc] initWithFormat:format arguments:args];
+ va_end(args);
+
+ NSNumber* callbackKey = [NSNumber numberWithInt:transactionID++];
NSString* taggedCommand = [NSString stringWithFormat:@"%@ -i %@", [command autorelease], callbackKey];
[self performSelector:@selector(send:)
onThread:thread_
withObject:taggedCommand
waitUntilDone:YES];
-
- return callbackKey;
+
+ return callbackKey;
}
/**
*/
- (NSString*)escapedURIPath:(NSString*)path
{
- // Custon GDBp paths are fine.
- if ([[path substringToIndex:4] isEqualToString:@"gdbp"])
- return path;
-
- // Create a temporary URL that will escape all the nasty characters.
- NSURL* url = [NSURL fileURLWithPath:path];
- NSString* urlString = [url absoluteString];
-
- // Remove the host because this is a file:// URL;
- urlString = [urlString stringByReplacingOccurrencesOfString:[url host] withString:@""];
-
- // Escape % for use in printf-style NSString formatters.
- urlString = [urlString stringByReplacingOccurrencesOfString:@"%" withString:@"%%"];
- return urlString;
+ // Custon GDBp paths are fine.
+ if ([[path substringToIndex:4] isEqualToString:@"gdbp"])
+ return path;
+
+ // Create a temporary URL that will escape all the nasty characters.
+ NSURL* url = [NSURL fileURLWithPath:path];
+ NSString* urlString = [url absoluteString];
+
+ // Remove the host because this is a file:// URL;
+ urlString = [urlString stringByReplacingOccurrencesOfString:[url host] withString:@""];
+
+ // Escape % for use in printf-style NSString formatters.
+ urlString = [urlString stringByReplacingOccurrencesOfString:@"%" withString:@"%%"];
+ return urlString;
}
/**
*/
- (NSInteger)transactionIDFromResponse:(NSXMLDocument*)response
{
- return [[[[response rootElement] attributeForName:@"transaction_id"] stringValue] intValue];
+ return [[[[response rootElement] attributeForName:@"transaction_id"] stringValue] intValue];
}
/**
*/
- (NSInteger)transactionIDFromCommand:(NSString*)command
{
- NSRange occurrence = [command rangeOfString:@"-i "];
- if (occurrence.location == NSNotFound)
- return NSNotFound;
- NSString* transaction = [command substringFromIndex:occurrence.location + occurrence.length];
- return [transaction intValue];
+ NSRange occurrence = [command rangeOfString:@"-i "];
+ if (occurrence.location == NSNotFound)
+ return NSNotFound;
+ NSString* transaction = [command substringFromIndex:occurrence.location + occurrence.length];
+ return [transaction intValue];
}
// Private /////////////////////////////////////////////////////////////////////
*/
- (void)errorEncountered:(NSString*)error
{
- [delegate_ performSelectorOnMainThread:@selector(errorEncountered:)
+ [delegate_ performSelectorOnMainThread:@selector(errorEncountered:)
withObject:error
waitUntilDone:NO];
}
- (LogEntry*)recordReceive:(NSString*)command
{
- LoggingController* logger = [(AppDelegate*)[NSApp delegate] loggingController];
- [logger performSelectorOnMainThread:@selector(recordReceive:)
+ LoggingController* logger = [(AppDelegate*)[NSApp delegate] loggingController];
+ [logger performSelectorOnMainThread:@selector(recordReceive:)
withObject:command
waitUntilDone:NO];
return [logger.logEntries lastObject];
*/
- (void)readStreamHasData
{
- const NSUInteger kBufferSize = 1024;
- UInt8 buffer[kBufferSize];
- CFIndex bufferOffset = 0; // Starting point in |buffer| to work with.
- CFIndex bytesRead = CFReadStreamRead(readStream_, buffer, kBufferSize);
- const char* charBuffer = (const char*)buffer;
-
- // The read loop works by going through the buffer until all the bytes have
- // been processed.
- while (bufferOffset < bytesRead)
- {
- // Find the NULL separator, or the end of the string.
- NSUInteger partLength = 0;
- for (NSUInteger i = bufferOffset; i < bytesRead && charBuffer[i] != '\0'; ++i, ++partLength) ;
-
- // If there is not a current packet, set some state.
- if (!self.currentPacket)
- {
- // Read the message header: the size. This will be |partLength| bytes.
- packetSize_ = atoi(charBuffer + bufferOffset);
- currentPacketIndex_ = 0;
- self.currentPacket = [NSMutableString stringWithCapacity:packetSize_];
- bufferOffset += partLength + 1; // Pass over the NULL byte.
- continue; // Spin the loop to begin reading actual data.
- }
-
- // Substring the byte stream and append it to the packet string.
- CFStringRef bufferString = CFStringCreateWithBytes(kCFAllocatorDefault,
- buffer + bufferOffset, // Byte pointer, offset by start index.
- partLength, // Length.
- kCFStringEncodingUTF8,
- true);
- [self.currentPacket appendString:(NSString*)bufferString];
- CFRelease(bufferString);
-
- // Advance counters.
- currentPacketIndex_ += partLength;
- bufferOffset += partLength + 1;
-
- // If this read finished the packet, handle it and reset.
- NSLog(@"cpi %d ps %d br %d ds %d", currentPacketIndex_, packetSize_, bytesRead, partLength);
- if (currentPacketIndex_ >= packetSize_)
- {
- [self handlePacket:[[currentPacket_ retain] autorelease]];
- self.currentPacket = nil;
- packetSize_ = 0;
- currentPacketIndex_ = 0;
- }
- }
+ const NSUInteger kBufferSize = 1024;
+ UInt8 buffer[kBufferSize];
+ CFIndex bufferOffset = 0; // Starting point in |buffer| to work with.
+ CFIndex bytesRead = CFReadStreamRead(readStream_, buffer, kBufferSize);
+ const char* charBuffer = (const char*)buffer;
+
+ // The read loop works by going through the buffer until all the bytes have
+ // been processed.
+ while (bufferOffset < bytesRead)
+ {
+ // Find the NULL separator, or the end of the string.
+ NSUInteger partLength = 0;
+ for (NSUInteger i = bufferOffset; i < bytesRead && charBuffer[i] != '\0'; ++i, ++partLength) ;
+
+ // If there is not a current packet, set some state.
+ if (!self.currentPacket)
+ {
+ // Read the message header: the size. This will be |partLength| bytes.
+ packetSize_ = atoi(charBuffer + bufferOffset);
+ currentPacketIndex_ = 0;
+ self.currentPacket = [NSMutableString stringWithCapacity:packetSize_];
+ bufferOffset += partLength + 1; // Pass over the NULL byte.
+ continue; // Spin the loop to begin reading actual data.
+ }
+
+ // Substring the byte stream and append it to the packet string.
+ CFStringRef bufferString = CFStringCreateWithBytes(kCFAllocatorDefault,
+ buffer + bufferOffset, // Byte pointer, offset by start index.
+ partLength, // Length.
+ kCFStringEncodingUTF8,
+ true);
+ [self.currentPacket appendString:(NSString*)bufferString];
+ CFRelease(bufferString);
+
+ // Advance counters.
+ currentPacketIndex_ += partLength;
+ bufferOffset += partLength + 1;
+
+ // If this read finished the packet, handle it and reset.
+ NSLog(@"cpi %d ps %d br %d ds %d", currentPacketIndex_, packetSize_, bytesRead, partLength);
+ if (currentPacketIndex_ >= packetSize_)
+ {
+ [self handlePacket:[[currentPacket_ retain] autorelease]];
+ self.currentPacket = nil;
+ packetSize_ = 0;
+ currentPacketIndex_ = 0;
+ }
+ }
}
/**
*/
- (void)handlePacket:(NSString*)packet
{
- // Test if we can convert it into an NSXMLDocument.
- NSError* error = nil;
- NSXMLDocument* xmlTest = [[NSXMLDocument alloc] initWithXMLString:currentPacket_ options:NSXMLDocumentTidyXML error:&error];
-
- // Try to recover if we encountered an error.
- if (!xmlTest)
- {
- // We do not want to starve the write queue, so manually parse out the
- // transaction ID.
- NSRange location = [currentPacket_ rangeOfString:@"transaction_id"];
- if (location.location != NSNotFound)
- {
- NSUInteger start = location.location + location.length;
- NSUInteger end = start;
-
- NSCharacterSet* numericSet = [NSCharacterSet decimalDigitCharacterSet];
-
- // Loop over the characters after the attribute name to extract the ID.
- while (end < [currentPacket_ length])
- {
- unichar c = [currentPacket_ characterAtIndex:end];
- if ([numericSet characterIsMember:c])
- {
- // If this character is numeric, extend the range to substring.
- ++end;
- }
- else
- {
- if (start == end)
- {
- // If this character is nonnumeric and we have nothing in the
- // range, skip this character.
- ++start;
- ++end;
- }
- else
- {
- // We've moved past the numeric ID so we should stop searching.
- break;
- }
- }
- }
-
- // If we were able to extract the transaction ID, update the last read.
- NSRange substringRange = NSMakeRange(start, end - start);
- NSString* transactionStr = [currentPacket_ substringWithRange:substringRange];
- if ([transactionStr length])
- lastReadTransaction_ = [transactionStr intValue];
- }
-
- // Otherwise, assume +1 and hope it works.
- ++lastReadTransaction_;
- }
- else
- {
- // See if the transaction can be parsed out.
- NSInteger transaction = [self transactionIDFromResponse:xmlTest];
- if (transaction < lastReadTransaction_)
- {
- NSLog(@"tx = %d vs %d", transaction, lastReadTransaction_);
- NSLog(@"out of date transaction %@", packet);
- return;
- }
-
- if (transaction != lastWrittenTransaction_)
- NSLog(@"txn %d <> %d last written, %d last read", transaction, lastWrittenTransaction_, lastReadTransaction_);
-
- lastReadTransaction_ = transaction;
- }
-
- // Log this receive event.
- LogEntry* log = [self recordReceive:currentPacket_];
- log.error = error;
- log.lastWrittenTransactionID = lastWrittenTransaction_;
- log.lastReadTransactionID = lastReadTransaction_;
-
- // Finally, dispatch the handler for this response.
- [self handleResponse:[xmlTest autorelease]];
+ // Test if we can convert it into an NSXMLDocument.
+ NSError* error = nil;
+ NSXMLDocument* xmlTest = [[NSXMLDocument alloc] initWithXMLString:currentPacket_ options:NSXMLDocumentTidyXML error:&error];
+
+ // Try to recover if we encountered an error.
+ if (!xmlTest)
+ {
+ // We do not want to starve the write queue, so manually parse out the
+ // transaction ID.
+ NSRange location = [currentPacket_ rangeOfString:@"transaction_id"];
+ if (location.location != NSNotFound)
+ {
+ NSUInteger start = location.location + location.length;
+ NSUInteger end = start;
+
+ NSCharacterSet* numericSet = [NSCharacterSet decimalDigitCharacterSet];
+
+ // Loop over the characters after the attribute name to extract the ID.
+ while (end < [currentPacket_ length])
+ {
+ unichar c = [currentPacket_ characterAtIndex:end];
+ if ([numericSet characterIsMember:c])
+ {
+ // If this character is numeric, extend the range to substring.
+ ++end;
+ }
+ else
+ {
+ if (start == end)
+ {
+ // If this character is nonnumeric and we have nothing in the
+ // range, skip this character.
+ ++start;
+ ++end;
+ }
+ else
+ {
+ // We've moved past the numeric ID so we should stop searching.
+ break;
+ }
+ }
+ }
+
+ // If we were able to extract the transaction ID, update the last read.
+ NSRange substringRange = NSMakeRange(start, end - start);
+ NSString* transactionStr = [currentPacket_ substringWithRange:substringRange];
+ if ([transactionStr length])
+ lastReadTransaction_ = [transactionStr intValue];
+ }
+
+ // Otherwise, assume +1 and hope it works.
+ ++lastReadTransaction_;
+ }
+ else
+ {
+ // See if the transaction can be parsed out.
+ NSInteger transaction = [self transactionIDFromResponse:xmlTest];
+ if (transaction < lastReadTransaction_)
+ {
+ NSLog(@"tx = %d vs %d", transaction, lastReadTransaction_);
+ NSLog(@"out of date transaction %@", packet);
+ return;
+ }
+
+ if (transaction != lastWrittenTransaction_)
+ NSLog(@"txn %d <> %d last written, %d last read", transaction, lastWrittenTransaction_, lastReadTransaction_);
+
+ lastReadTransaction_ = transaction;
+ }
+
+ // Log this receive event.
+ LogEntry* log = [self recordReceive:currentPacket_];
+ log.error = error;
+ log.lastWrittenTransactionID = lastWrittenTransaction_;
+ log.lastReadTransactionID = lastReadTransaction_;
+
+ // Finally, dispatch the handler for this response.
+ [self handleResponse:[xmlTest autorelease]];
}
- (void)handleResponse:(NSXMLDocument*)response
{
- // Check and see if there's an error.
- NSArray* error = [[response rootElement] elementsForName:@"error"];
- if ([error count] > 0)
- {
- NSLog(@"Xdebug error: %@", error);
+ // Check and see if there's an error.
+ NSArray* error = [[response rootElement] elementsForName:@"error"];
+ if ([error count] > 0)
+ {
+ NSLog(@"Xdebug error: %@", error);
NSString* errorMessage = [[[[error objectAtIndex:0] children] objectAtIndex:0] stringValue];
[self errorEncountered:errorMessage];
- }
-
- if ([[[response rootElement] name] isEqualToString:@"init"])
- {
+ }
+
+ if ([[[response rootElement] name] isEqualToString:@"init"])
+ {
[delegate_ performSelectorOnMainThread:@selector(handleInitialResponse:)
withObject:response
waitUntilDone:NO];
- return;
- }
-
- if ([delegate_ respondsToSelector:@selector(handleResponse:)])
- [delegate_ performSelectorOnMainThread:@selector(handleResponse:)
+ return;
+ }
+
+ if ([delegate_ respondsToSelector:@selector(handleResponse:)])
+ [delegate_ performSelectorOnMainThread:@selector(handleResponse:)
withObject:response
waitUntilDone:NO];
-
- [self sendQueuedWrites];
+
+ [self sendQueuedWrites];
}
/**
*/
- (void)performSend:(NSString*)command
{
- // If this is an out-of-date transaction, do not bother sending it.
- NSInteger transaction = [self transactionIDFromCommand:command];
- if (transaction != NSNotFound && transaction < lastWrittenTransaction_)
- return;
-
- BOOL done = NO;
-
- char* string = (char*)[command UTF8String];
- int stringLength = strlen(string);
-
- // Busy wait while writing. BAADD. Should background this operation.
- while (!done)
- {
- if (CFWriteStreamCanAcceptBytes(writeStream_))
- {
- // Include the NULL byte in the string when we write.
- int bytesWritten = CFWriteStreamWrite(writeStream_, (UInt8*)string, stringLength + 1);
- if (bytesWritten < 0)
- {
- NSLog(@"write error");
- }
- // Incomplete write.
- else if (bytesWritten < strlen(string))
- {
- // Adjust the buffer and wait for another chance to write.
- stringLength -= bytesWritten;
- memmove(string, string + bytesWritten, stringLength);
- }
- else
- {
- done = YES;
-
- // We need to scan the string to find the transactionID.
- if (transaction == NSNotFound)
- {
- NSLog(@"sent %@ without a transaction ID", command);
- continue;
- }
- lastWrittenTransaction_ = transaction;
- }
- }
- }
-
- // Log this trancation.
- LogEntry* log = [self recordSend:command];
- log.lastWrittenTransactionID = lastWrittenTransaction_;
- log.lastReadTransactionID = lastReadTransaction_;
+ // If this is an out-of-date transaction, do not bother sending it.
+ NSInteger transaction = [self transactionIDFromCommand:command];
+ if (transaction != NSNotFound && transaction < lastWrittenTransaction_)
+ return;
+
+ BOOL done = NO;
+
+ char* string = (char*)[command UTF8String];
+ int stringLength = strlen(string);
+
+ // Busy wait while writing. BAADD. Should background this operation.
+ while (!done)
+ {
+ if (CFWriteStreamCanAcceptBytes(writeStream_))
+ {
+ // Include the NULL byte in the string when we write.
+ int bytesWritten = CFWriteStreamWrite(writeStream_, (UInt8*)string, stringLength + 1);
+ if (bytesWritten < 0)
+ {
+ NSLog(@"write error");
+ }
+ // Incomplete write.
+ else if (bytesWritten < strlen(string))
+ {
+ // Adjust the buffer and wait for another chance to write.
+ stringLength -= bytesWritten;
+ memmove(string, string + bytesWritten, stringLength);
+ }
+ else
+ {
+ done = YES;
+
+ // We need to scan the string to find the transactionID.
+ if (transaction == NSNotFound)
+ {
+ NSLog(@"sent %@ without a transaction ID", command);
+ continue;
+ }
+ lastWrittenTransaction_ = transaction;
+ }
+ }
+ }
+
+ // Log this trancation.
+ LogEntry* log = [self recordSend:command];
+ log.lastWrittenTransactionID = lastWrittenTransaction_;
+ log.lastReadTransactionID = lastReadTransaction_;
}
/**
*/
- (void)sendQueuedWrites
{
- if (!connected_)
- return;
-
- [writeQueueLock_ lock];
- if (lastReadTransaction_ >= lastWrittenTransaction_ && [queuedWrites_ count] > 0)
- {
- NSString* command = [queuedWrites_ objectAtIndex:0];
-
- // We don't want to block because this is called from the main thread.
- // |-performSend:| busy waits when the stream is not ready. Bail out
- // before we do that becuase busy waiting is BAD.
- if (CFWriteStreamCanAcceptBytes(writeStream_))
- {
- [self performSend:command];
- [queuedWrites_ removeObjectAtIndex:0];
- }
- }
- [writeQueueLock_ unlock];
+ if (!connected_)
+ return;
+
+ [writeQueueLock_ lock];
+ if (lastReadTransaction_ >= lastWrittenTransaction_ && [queuedWrites_ count] > 0)
+ {
+ NSString* command = [queuedWrites_ objectAtIndex:0];
+
+ // We don't want to block because this is called from the main thread.
+ // |-performSend:| busy waits when the stream is not ready. Bail out
+ // before we do that becuase busy waiting is BAD.
+ if (CFWriteStreamCanAcceptBytes(writeStream_))
+ {
+ [self performSend:command];
+ [queuedWrites_ removeObjectAtIndex:0];
+ }
+ }
+ [writeQueueLock_ unlock];
}
@end
@interface DebuggerController : NSWindowController <DebuggerProcessorDelegate>
{
- DebuggerProcessor* connection;
-
- // This is true when the |connection| has told us to clobber. We will do
- // so upon receipt of the first new stack frame.
- BOOL aboutToClobber_;
-
- StackController* stackController;
- IBOutlet NSArrayController* stackArrayController;
-
- IBOutlet NSTreeController* variablesTreeController;
- IBOutlet NSOutlineView* variablesOutlineView;
- NSMutableSet* expandedVariables;
- NSXMLElement* selectedVariable;
-
- IBOutlet NSWindow* inspector;
-
- IBOutlet NSTextField* statusmsg;
- IBOutlet NSTextField* errormsg;
-
- IBOutlet BSSourceView* sourceViewer;
+ DebuggerProcessor* connection;
+
+ // This is true when the |connection| has told us to clobber. We will do
+ // so upon receipt of the first new stack frame.
+ BOOL aboutToClobber_;
+
+ StackController* stackController;
+ IBOutlet NSArrayController* stackArrayController;
+
+ IBOutlet NSTreeController* variablesTreeController;
+ IBOutlet NSOutlineView* variablesOutlineView;
+ NSMutableSet* expandedVariables;
+ NSXMLElement* selectedVariable;
+
+ IBOutlet NSWindow* inspector;
+
+ IBOutlet NSTextField* statusmsg;
+ IBOutlet NSTextField* errormsg;
+
+ IBOutlet BSSourceView* sourceViewer;
}
@property(readonly) DebuggerProcessor* connection;
*/
- (id)init
{
- if (self = [super initWithWindowNibName:@"Debugger"])
- {
- stackController = [[StackController alloc] init];
-
- NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
-
- connection = [[DebuggerProcessor alloc] initWithPort:[defaults integerForKey:@"Port"]];
- connection.delegate = self;
- expandedVariables = [[NSMutableSet alloc] init];
- [[self window] makeKeyAndOrderFront:nil];
- [[self window] setDelegate:self];
-
- if ([[NSUserDefaults standardUserDefaults] boolForKey:@"InspectorWindowVisible"])
- [inspector orderFront:self];
- }
- return self;
+ if (self = [super initWithWindowNibName:@"Debugger"])
+ {
+ stackController = [[StackController alloc] init];
+
+ NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
+
+ connection = [[DebuggerProcessor alloc] initWithPort:[defaults integerForKey:@"Port"]];
+ connection.delegate = self;
+ expandedVariables = [[NSMutableSet alloc] init];
+ [[self window] makeKeyAndOrderFront:nil];
+ [[self window] setDelegate:self];
+
+ if ([[NSUserDefaults standardUserDefaults] boolForKey:@"InspectorWindowVisible"])
+ [inspector orderFront:self];
+ }
+ return self;
}
/**
*/
- (void)dealloc
{
- [connection release];
- [expandedVariables release];
- [stackController release];
- [super dealloc];
+ [connection release];
+ [expandedVariables release];
+ [stackController release];
+ [super dealloc];
}
/**
*/
- (void)awakeFromNib
{
- [[self window] setExcludedFromWindowsMenu:YES];
- [[self window] setTitle:[NSString stringWithFormat:@"GDBp @ %@:%d", [connection remoteHost], [connection port]]];
- [sourceViewer setDelegate:self];
- [stackArrayController setSortDescriptors:[NSArray arrayWithObject:[[[NSSortDescriptor alloc] initWithKey:@"index" ascending:YES] autorelease]]];
+ [[self window] setExcludedFromWindowsMenu:YES];
+ [[self window] setTitle:[NSString stringWithFormat:@"GDBp @ %@:%d", [connection remoteHost], [connection port]]];
+ [sourceViewer setDelegate:self];
+ [stackArrayController setSortDescriptors:[NSArray arrayWithObject:[[[NSSortDescriptor alloc] initWithKey:@"index" ascending:YES] autorelease]]];
}
/**
*/
- (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)anItem
{
- SEL action = [anItem action];
-
- if (action == @selector(stepOut:))
- return ([connection isConnected] && [stackController.stack count] > 1);
- else if (action == @selector(stepIn:) || action == @selector(stepOver:) || action == @selector(run:))
- return [connection isConnected];
- else if (action == @selector(reconnect:))
- return ![connection isConnected];
-
- return [[self window] validateUserInterfaceItem:anItem];
+ SEL action = [anItem action];
+
+ if (action == @selector(stepOut:))
+ return ([connection isConnected] && [stackController.stack count] > 1);
+ else if (action == @selector(stepIn:) || action == @selector(stepOver:) || action == @selector(run:))
+ return [connection isConnected];
+ else if (action == @selector(reconnect:))
+ return ![connection isConnected];
+
+ return [[self window] validateUserInterfaceItem:anItem];
}
/**
*/
- (IBAction)showInspectorWindow:(id)sender
{
- if (![inspector isVisible])
- [inspector makeKeyAndOrderFront:sender];
- else
- [inspector orderOut:sender];
+ if (![inspector isVisible])
+ [inspector makeKeyAndOrderFront:sender];
+ else
+ [inspector orderOut:sender];
}
/**
*/
- (void)resetDisplays
{
- [variablesTreeController setContent:nil];
- [stackController.stack removeAllObjects];
- [stackArrayController rearrangeObjects];
- [[sourceViewer textView] setString:@""];
- sourceViewer.file = nil;
+ [variablesTreeController setContent:nil];
+ [stackController.stack removeAllObjects];
+ [stackArrayController rearrangeObjects];
+ [[sourceViewer textView] setString:@""];
+ sourceViewer.file = nil;
}
/**
*/
- (void)setError:(NSString*)anError
{
- [errormsg setStringValue:anError];
- [errormsg setHidden:NO];
+ [errormsg setStringValue:anError];
+ [errormsg setHidden:NO];
}
/**
*/
- (void)errorEncountered:(NSString*)error
{
- [self setError:error];
+ [self setError:error];
}
/**
*/
- (void)debuggerConnected
{
- [self startDebugger];
+ [self startDebugger];
}
/**
*/
- (void)startDebugger
{
- if ([[NSUserDefaults standardUserDefaults] boolForKey:@"BreakOnFirstLine"])
- [self stepIn:self];
+ if ([[NSUserDefaults standardUserDefaults] boolForKey:@"BreakOnFirstLine"])
+ [self stepIn:self];
}
/**
*/
- (void)debuggerDisconnected
{
- if ([[NSUserDefaults standardUserDefaults] boolForKey:@"AutoReconnect"])
- [self reconnect:self];
-
- // Invalidate the marked line so we don't look like we're still running.
- sourceViewer.markedLine = -1;
- [sourceViewer setNeedsDisplay:YES];
+ if ([[NSUserDefaults standardUserDefaults] boolForKey:@"AutoReconnect"])
+ [self reconnect:self];
+
+ // Invalidate the marked line so we don't look like we're still running.
+ sourceViewer.markedLine = -1;
+ [sourceViewer setNeedsDisplay:YES];
}
/**
*/
- (IBAction)run:(id)sender
{
- [connection run];
+ [connection run];
}
/**
*/
- (IBAction)reconnect:(id)sender
{
- [connection reconnect];
- [self resetDisplays];
+ [connection reconnect];
+ [self resetDisplays];
}
/**
*/
- (IBAction)stepIn:(id)sender
{
- if ([[variablesTreeController selectedObjects] count] > 0)
- selectedVariable = [[variablesTreeController selectedObjects] objectAtIndex:0];
-
- [connection stepIn];
+ if ([[variablesTreeController selectedObjects] count] > 0)
+ selectedVariable = [[variablesTreeController selectedObjects] objectAtIndex:0];
+
+ [connection stepIn];
}
/**
*/
- (IBAction)stepOut:(id)sender
{
- if ([[variablesTreeController selectedObjects] count] > 0)
- selectedVariable = [[variablesTreeController selectedObjects] objectAtIndex:0];
-
- [connection stepOut];
+ if ([[variablesTreeController selectedObjects] count] > 0)
+ selectedVariable = [[variablesTreeController selectedObjects] objectAtIndex:0];
+
+ [connection stepOut];
}
/**
*/
- (IBAction)stepOver:(id)sender
{
- if ([[variablesTreeController selectedObjects] count] > 0)
- selectedVariable = [[variablesTreeController selectedObjects] objectAtIndex:0];
-
- [connection stepOver];
+ if ([[variablesTreeController selectedObjects] count] > 0)
+ selectedVariable = [[variablesTreeController selectedObjects] objectAtIndex:0];
+
+ [connection stepOver];
}
/**
*/
- (void)tableViewSelectionDidChange:(NSNotification*)notif
{
- [self updateSourceViewer];
- [self expandVariables];
+ [self updateSourceViewer];
+ [self expandVariables];
}
/**
*/
- (void)outlineViewItemDidExpand:(NSNotification*)notif
{
- NSTreeNode* node = [[notif userInfo] objectForKey:@"NSObject"];
- [expandedVariables addObject:[[node representedObject] fullname]];
+ NSTreeNode* node = [[notif userInfo] objectForKey:@"NSObject"];
+ [expandedVariables addObject:[[node representedObject] fullname]];
}
/**
*/
- (void)outlineViewItemDidCollapse:(NSNotification*)notif
{
- [expandedVariables removeObject:[[[[notif userInfo] objectForKey:@"NSObject"] representedObject] fullname]];
+ [expandedVariables removeObject:[[[[notif userInfo] objectForKey:@"NSObject"] representedObject] fullname]];
}
#pragma mark Private
*/
- (void)updateSourceViewer
{
- NSArray* selection = [stackArrayController selectedObjects];
- if (!selection || [selection count] < 1)
- return;
- if ([selection count] > 1)
- NSLog(@"INVALID SELECTION");
- StackFrame* frame = [selection objectAtIndex:0];
-
- if (!frame.loaded) {
- [connection loadStackFrame:frame];
- return;
- }
-
- // Get the filename.
- NSString* filename = [[NSURL URLWithString:frame.filename] path];
- if ([filename isEqualToString:@""])
- return;
-
- // Replace the source if necessary.
- if (frame.source && ![sourceViewer.file isEqualToString:filename])
- {
- [sourceViewer setString:frame.source asFile:filename];
-
- NSSet* breakpoints = [NSSet setWithArray:[[BreakpointManager sharedManager] breakpointsForFile:filename]];
- [[sourceViewer numberView] setMarkers:breakpoints];
- }
-
- [sourceViewer setMarkedLine:frame.lineNumber];
- [sourceViewer scrollToLine:frame.lineNumber];
-
- [[sourceViewer textView] display];
+ NSArray* selection = [stackArrayController selectedObjects];
+ if (!selection || [selection count] < 1)
+ return;
+ if ([selection count] > 1)
+ NSLog(@"INVALID SELECTION");
+ StackFrame* frame = [selection objectAtIndex:0];
+
+ if (!frame.loaded) {
+ [connection loadStackFrame:frame];
+ return;
+ }
+
+ // Get the filename.
+ NSString* filename = [[NSURL URLWithString:frame.filename] path];
+ if ([filename isEqualToString:@""])
+ return;
+
+ // Replace the source if necessary.
+ if (frame.source && ![sourceViewer.file isEqualToString:filename])
+ {
+ [sourceViewer setString:frame.source asFile:filename];
+
+ NSSet* breakpoints = [NSSet setWithArray:[[BreakpointManager sharedManager] breakpointsForFile:filename]];
+ [[sourceViewer numberView] setMarkers:breakpoints];
+ }
+
+ [sourceViewer setMarkedLine:frame.lineNumber];
+ [sourceViewer scrollToLine:frame.lineNumber];
+
+ [[sourceViewer textView] display];
}
/**
*/
- (void)updateStackViewer
{
- [stackArrayController rearrangeObjects];
- [stackArrayController setSelectionIndex:0];
- [self expandVariables];
+ [stackArrayController rearrangeObjects];
+ [stackArrayController setSelectionIndex:0];
+ [self expandVariables];
}
/**
*/
- (void)expandVariables
{
- NSString* selection = [selectedVariable fullname];
-
- for (int i = 0; i < [variablesOutlineView numberOfRows]; i++)
- {
- NSTreeNode* node = [variablesOutlineView itemAtRow:i];
- NSString* fullname = [[node representedObject] fullname];
-
- // see if it needs expanding
- if ([expandedVariables containsObject:fullname])
- [variablesOutlineView expandItem:node];
-
- // select it if we had it selected before
- if ([fullname isEqualToString:selection])
- [variablesTreeController setSelectionIndexPath:[node indexPath]];
- }
+ NSString* selection = [selectedVariable fullname];
+
+ for (int i = 0; i < [variablesOutlineView numberOfRows]; i++)
+ {
+ NSTreeNode* node = [variablesOutlineView itemAtRow:i];
+ NSString* fullname = [[node representedObject] fullname];
+
+ // see if it needs expanding
+ if ([expandedVariables containsObject:fullname])
+ [variablesOutlineView expandItem:node];
+
+ // select it if we had it selected before
+ if ([fullname isEqualToString:selection])
+ [variablesTreeController setSelectionIndexPath:[node indexPath]];
+ }
}
#pragma mark BSSourceView Delegate
*/
- (void)gutterClickedAtLine:(int)line forFile:(NSString*)file
{
- BreakpointManager* mngr = [BreakpointManager sharedManager];
-
- if ([mngr hasBreakpointAt:line inFile:file])
- {
- [mngr removeBreakpointAt:line inFile:file];
- }
- else
- {
- Breakpoint* bp = [[Breakpoint alloc] initWithLine:line inFile:file];
- [mngr addBreakpoint:bp];
- [bp release];
- }
-
- [[sourceViewer numberView] setMarkers:[NSSet setWithArray:[mngr breakpointsForFile:file]]];
- [[sourceViewer numberView] setNeedsDisplay:YES];
+ BreakpointManager* mngr = [BreakpointManager sharedManager];
+
+ if ([mngr hasBreakpointAt:line inFile:file])
+ {
+ [mngr removeBreakpointAt:line inFile:file];
+ }
+ else
+ {
+ Breakpoint* bp = [[Breakpoint alloc] initWithLine:line inFile:file];
+ [mngr addBreakpoint:bp];
+ [bp release];
+ }
+
+ [[sourceViewer numberView] setMarkers:[NSSet setWithArray:[mngr breakpointsForFile:file]]];
+ [[sourceViewer numberView] setNeedsDisplay:YES];
}
#pragma mark GDBpConnectionDelegate
- (void)clobberStack
{
- aboutToClobber_ = YES;
+ aboutToClobber_ = YES;
}
- (void)newStackFrame:(StackFrame*)frame
{
- if (aboutToClobber_)
- {
- [stackController.stack removeAllObjects];
- aboutToClobber_ = NO;
- }
- [stackController push:frame];
- [self updateStackViewer];
- [self updateSourceViewer];
+ if (aboutToClobber_)
+ {
+ [stackController.stack removeAllObjects];
+ aboutToClobber_ = NO;
+ }
+ [stackController push:frame];
+ [self updateStackViewer];
+ [self updateSourceViewer];
}
- (void)sourceUpdated:(StackFrame*)frame
{
- [self updateSourceViewer];
+ [self updateSourceViewer];
}
@end
// a new frame is created or the stack should be destroyed.
@interface DebuggerProcessor : NSObject <DebuggerConnectionDelegate>
{
- // The connection to the debugger engine.
- DebuggerConnection* connection_;
-
- // Human-readable status of the connection.
- NSString* status;
-
- // The connection's delegate.
- id <DebuggerProcessorDelegate> delegate;
-
- // A dictionary that maps routingIDs to StackFrame objects.
- NSMutableDictionary* stackFrames_;
- // The stack depth for the current build of |stackFrames_|.
- NSInteger stackDepth_;
- // The earliest transaction ID for the current build of |stackFrames_|.
- NSInteger stackFirstTransactionID_;
-
- // Callback table. This maps transaction IDs to selectors. When the engine
- // returns a response to the debugger, we will dispatch the response XML to
- // the selector, based on transaction_id.
- NSMutableDictionary* callTable_;
-
- // This stores additional context information for the callback selector.
- // This dictionary is keyed by the same transaction IDs in |callTable_|, but
- // also stores some other object that can be accessed in the callback.
- NSMutableDictionary* callbackContext_;
+ // The connection to the debugger engine.
+ DebuggerConnection* connection_;
+
+ // Human-readable status of the connection.
+ NSString* status;
+
+ // The connection's delegate.
+ id <DebuggerProcessorDelegate> delegate;
+
+ // A dictionary that maps routingIDs to StackFrame objects.
+ NSMutableDictionary* stackFrames_;
+ // The stack depth for the current build of |stackFrames_|.
+ NSInteger stackDepth_;
+ // The earliest transaction ID for the current build of |stackFrames_|.
+ NSInteger stackFirstTransactionID_;
+
+ // Callback table. This maps transaction IDs to selectors. When the engine
+ // returns a response to the debugger, we will dispatch the response XML to
+ // the selector, based on transaction_id.
+ NSMutableDictionary* callTable_;
+
+ // This stores additional context information for the callback selector.
+ // This dictionary is keyed by the same transaction IDs in |callTable_|, but
+ // also stores some other object that can be accessed in the callback.
+ NSMutableDictionary* callbackContext_;
}
@property (readonly, copy) NSString* status;
*/
- (id)initWithPort:(NSUInteger)aPort
{
- if (self = [super init])
- {
- stackFrames_ = [[NSMutableDictionary alloc] init];
- callbackContext_ = [NSMutableDictionary new];
- callTable_ = [NSMutableDictionary new];
-
- [[BreakpointManager sharedManager] setConnection:self];
- connection_ = [[DebuggerConnection alloc] initWithPort:aPort];
- connection_.delegate = self;
- [connection_ connect];
- }
- return self;
+ if (self = [super init])
+ {
+ stackFrames_ = [[NSMutableDictionary alloc] init];
+ callbackContext_ = [NSMutableDictionary new];
+ callTable_ = [NSMutableDictionary new];
+
+ [[BreakpointManager sharedManager] setConnection:self];
+ connection_ = [[DebuggerConnection alloc] initWithPort:aPort];
+ connection_.delegate = self;
+ [connection_ connect];
+ }
+ return self;
}
/**
*/
- (void)dealloc
{
- [connection_ close];
- [stackFrames_ release];
- [callTable_ release];
- [callbackContext_ release];
- [super dealloc];
+ [connection_ close];
+ [stackFrames_ release];
+ [callTable_ release];
+ [callbackContext_ release];
+ [super dealloc];
}
*/
- (NSUInteger)port
{
- return [connection_ port];
+ return [connection_ port];
}
/**
*/
- (NSString*)remoteHost
{
- if (![connection_ connected])
- return @"(DISCONNECTED)";
+ if (![connection_ connected])
+ return @"(DISCONNECTED)";
- // TODO: Either impl or remove.
- return @"";
+ // TODO: Either impl or remove.
+ return @"";
}
/**
*/
- (BOOL)isConnected
{
- return [connection_ connected];
+ return [connection_ connected];
}
// Commands ////////////////////////////////////////////////////////////////////
*/
- (void)reconnect
{
- [connection_ close];
- self.status = @"Connecting";
- [connection_ connect];
+ [connection_ close];
+ self.status = @"Connecting";
+ [connection_ connect];
}
/**
*/
- (void)run
{
- NSNumber* tx = [connection_ sendCommandWithFormat:@"run"];
- [self recordCallback:@selector(debuggerStep:) forTransaction:tx];
+ NSNumber* tx = [connection_ sendCommandWithFormat:@"run"];
+ [self recordCallback:@selector(debuggerStep:) forTransaction:tx];
}
/**
*/
- (void)stepIn
{
- NSNumber* tx = [connection_ sendCommandWithFormat:@"step_into"];
- [self recordCallback:@selector(debuggerStep:) forTransaction:tx];
+ NSNumber* tx = [connection_ sendCommandWithFormat:@"step_into"];
+ [self recordCallback:@selector(debuggerStep:) forTransaction:tx];
}
/**
*/
- (void)stepOut
{
- NSNumber* tx = [connection_ sendCommandWithFormat:@"step_out"];
- [self recordCallback:@selector(debuggerStep:) forTransaction:tx];
+ NSNumber* tx = [connection_ sendCommandWithFormat:@"step_out"];
+ [self recordCallback:@selector(debuggerStep:) forTransaction:tx];
}
/**
*/
- (void)stepOver
{
- NSNumber* tx = [connection_ sendCommandWithFormat:@"step_over"];
- [self recordCallback:@selector(debuggerStep:) forTransaction:tx];
+ NSNumber* tx = [connection_ sendCommandWithFormat:@"step_over"];
+ [self recordCallback:@selector(debuggerStep:) forTransaction:tx];
}
/**
*/
- (NSInteger)getProperty:(NSString*)property
{
- NSNumber* tx = [connection_ sendCommandWithFormat:@"property_get -n \"%@\"", property];
- [self recordCallback:@selector(propertiesReceived:) forTransaction:tx];
+ NSNumber* tx = [connection_ sendCommandWithFormat:@"property_get -n \"%@\"", property];
+ [self recordCallback:@selector(propertiesReceived:) forTransaction:tx];
}
- (void)loadStackFrame:(StackFrame*)frame
{
- if (frame.loaded)
- return;
-
- NSNumber* routingNumber = [NSNumber numberWithInt:frame.routingID];
-
- // Get the source code of the file. Escape % in URL chars.
- NSString* escapedFilename = [frame.filename stringByReplacingOccurrencesOfString:@"%" withString:@"%%"];
- NSNumber* transaction = [connection_ sendCommandWithFormat:@"source -f %@", escapedFilename];
- [self recordCallback:@selector(setSource:) forTransaction:transaction];
- [callbackContext_ setObject:routingNumber forKey:transaction];
-
- // Get the names of all the contexts.
- transaction = [connection_ sendCommandWithFormat:@"context_names -d %d", frame.index];
- [self recordCallback:@selector(contextsReceived:) forTransaction:transaction];
- [callbackContext_ setObject:routingNumber forKey:transaction];
-
- // This frame will be fully loaded.
- frame.loaded = YES;
+ if (frame.loaded)
+ return;
+
+ NSNumber* routingNumber = [NSNumber numberWithInt:frame.routingID];
+
+ // Get the source code of the file. Escape % in URL chars.
+ NSString* escapedFilename = [frame.filename stringByReplacingOccurrencesOfString:@"%" withString:@"%%"];
+ NSNumber* transaction = [connection_ sendCommandWithFormat:@"source -f %@", escapedFilename];
+ [self recordCallback:@selector(setSource:) forTransaction:transaction];
+ [callbackContext_ setObject:routingNumber forKey:transaction];
+
+ // Get the names of all the contexts.
+ transaction = [connection_ sendCommandWithFormat:@"context_names -d %d", frame.index];
+ [self recordCallback:@selector(contextsReceived:) forTransaction:transaction];
+ [callbackContext_ setObject:routingNumber forKey:transaction];
+
+ // This frame will be fully loaded.
+ frame.loaded = YES;
}
// Breakpoint Management ///////////////////////////////////////////////////////
*/
- (void)addBreakpoint:(Breakpoint*)bp
{
- if (![connection_ connected])
- return;
-
- NSString* file = [connection_ escapedURIPath:[bp transformedPath]];
- NSNumber* tx = [connection_ sendCommandWithFormat:@"breakpoint_set -t line -f %@ -n %i", file, [bp line]];
- [self recordCallback:@selector(breakpointReceived:) forTransaction:tx];
- [callbackContext_ setObject:bp forKey:tx];
+ if (![connection_ connected])
+ return;
+
+ NSString* file = [connection_ escapedURIPath:[bp transformedPath]];
+ NSNumber* tx = [connection_ sendCommandWithFormat:@"breakpoint_set -t line -f %@ -n %i", file, [bp line]];
+ [self recordCallback:@selector(breakpointReceived:) forTransaction:tx];
+ [callbackContext_ setObject:bp forKey:tx];
}
/**
*/
- (void)removeBreakpoint:(Breakpoint*)bp
{
- if (![connection_ connected])
- return;
-
- [connection_ sendCommandWithFormat:@"breakpoint_remove -d %i", [bp debuggerId]];
+ if (![connection_ connected])
+ return;
+
+ [connection_ sendCommandWithFormat:@"breakpoint_remove -d %i", [bp debuggerId]];
}
// Specific Response Handlers //////////////////////////////////////////////////
*/
- (void)handleInitialResponse:(NSXMLDocument*)response
{
- // Register any breakpoints that exist offline.
- for (Breakpoint* bp in [[BreakpointManager sharedManager] breakpoints])
- [self addBreakpoint:bp];
-
- // Load the debugger to make it look active.
- [delegate debuggerConnected];
-
- // TODO: update the status.
+ // Register any breakpoints that exist offline.
+ for (Breakpoint* bp in [[BreakpointManager sharedManager] breakpoints])
+ [self addBreakpoint:bp];
+
+ // Load the debugger to make it look active.
+ [delegate debuggerConnected];
+
+ // TODO: update the status.
}
- (void)handleResponse:(NSXMLDocument*)response
{
- NSInteger transactionID = [connection_ transactionIDFromResponse:response];
- NSNumber* key = [NSNumber numberWithInt:transactionID];
- NSString* callbackStr = [callTable_ objectForKey:key];
- if (callbackStr)
- {
- SEL callback = NSSelectorFromString(callbackStr);
- [self performSelector:callback withObject:response];
- }
- [callTable_ removeObjectForKey:key];
-}
+ NSInteger transactionID = [connection_ transactionIDFromResponse:response];
+ NSNumber* key = [NSNumber numberWithInt:transactionID];
+ NSString* callbackStr = [callTable_ objectForKey:key];
+ if (callbackStr)
+ {
+ SEL callback = NSSelectorFromString(callbackStr);
+ [self performSelector:callback withObject:response];
+ }
+ [callTable_ removeObjectForKey:key];
+}
/**
* Receiver for status updates. This just freshens up the UI.
*/
- (void)updateStatus:(NSXMLDocument*)response
{
- self.status = [[[[response rootElement] attributeForName:@"status"] stringValue] capitalizedString];
- if (status == nil || [status isEqualToString:@"Stopped"] || [status isEqualToString:@"Stopping"])
- {
- [connection_ close];
- [delegate debuggerDisconnected];
-
- self.status = @"Stopped";
- }
+ self.status = [[[[response rootElement] attributeForName:@"status"] stringValue] capitalizedString];
+ if (status == nil || [status isEqualToString:@"Stopped"] || [status isEqualToString:@"Stopping"])
+ {
+ [connection_ close];
+ [delegate debuggerDisconnected];
+
+ self.status = @"Stopped";
+ }
}
/**
*/
- (void)debuggerStep:(NSXMLDocument*)response
{
- [self updateStatus:response];
- if (![connection_ connected])
- return;
-
- // If this is the run command, tell the delegate that a bunch of updates
- // are coming. Also remove all existing stack routes and request a new stack.
- // TODO: figure out if we can not clobber the stack every time.
- NSString* command = [[[response rootElement] attributeForName:@"command"] stringValue];
- if (YES || [command isEqualToString:@"run"])
- {
- if ([delegate respondsToSelector:@selector(clobberStack)])
- [delegate clobberStack];
- [stackFrames_ removeAllObjects];
- NSNumber* tx = [connection_ sendCommandWithFormat:@"stack_depth"];
- [self recordCallback:@selector(rebuildStack:) forTransaction:tx];
- stackFirstTransactionID_ = [tx intValue];
- }
+ [self updateStatus:response];
+ if (![connection_ connected])
+ return;
+
+ // If this is the run command, tell the delegate that a bunch of updates
+ // are coming. Also remove all existing stack routes and request a new stack.
+ // TODO: figure out if we can not clobber the stack every time.
+ NSString* command = [[[response rootElement] attributeForName:@"command"] stringValue];
+ if (YES || [command isEqualToString:@"run"])
+ {
+ if ([delegate respondsToSelector:@selector(clobberStack)])
+ [delegate clobberStack];
+ [stackFrames_ removeAllObjects];
+ NSNumber* tx = [connection_ sendCommandWithFormat:@"stack_depth"];
+ [self recordCallback:@selector(rebuildStack:) forTransaction:tx];
+ stackFirstTransactionID_ = [tx intValue];
+ }
}
/**
*/
- (void)rebuildStack:(NSXMLDocument*)response
{
- NSInteger depth = [[[[response rootElement] attributeForName:@"depth"] stringValue] intValue];
-
- if (stackFirstTransactionID_ == [connection_ transactionIDFromResponse:response])
- stackDepth_ = depth;
-
- // We now need to alloc a bunch of stack frames and get the basic information
- // for them.
- for (NSInteger i = 0; i < depth; i++)
- {
- // Use the transaction ID to create a routing path.
- NSNumber* routingID = [connection_ sendCommandWithFormat:@"stack_get -d %d", i];
- [self recordCallback:@selector(getStackFrame:) forTransaction:routingID];
- [stackFrames_ setObject:[[StackFrame new] autorelease] forKey:routingID];
- }
+ NSInteger depth = [[[[response rootElement] attributeForName:@"depth"] stringValue] intValue];
+
+ if (stackFirstTransactionID_ == [connection_ transactionIDFromResponse:response])
+ stackDepth_ = depth;
+
+ // We now need to alloc a bunch of stack frames and get the basic information
+ // for them.
+ for (NSInteger i = 0; i < depth; i++)
+ {
+ // Use the transaction ID to create a routing path.
+ NSNumber* routingID = [connection_ sendCommandWithFormat:@"stack_get -d %d", i];
+ [self recordCallback:@selector(getStackFrame:) forTransaction:routingID];
+ [stackFrames_ setObject:[[StackFrame new] autorelease] forKey:routingID];
+ }
}
/**
*/
- (void)getStackFrame:(NSXMLDocument*)response
{
- // Get the routing information.
- NSInteger routingID = [connection_ transactionIDFromResponse:response];
- if (routingID < stackFirstTransactionID_)
- return;
- NSNumber* routingNumber = [NSNumber numberWithInt:routingID];
-
- // Make sure we initialized this frame in our last |-rebuildStack:|.
- StackFrame* frame = [stackFrames_ objectForKey:routingNumber];
- if (!frame)
- return;
-
- NSXMLElement* xmlframe = [[[response rootElement] children] objectAtIndex:0];
-
- // Initialize the stack frame.
- frame.index = [[[xmlframe attributeForName:@"level"] stringValue] intValue];
- frame.filename = [[xmlframe attributeForName:@"filename"] stringValue];
- frame.lineNumber = [[[xmlframe attributeForName:@"lineno"] stringValue] intValue];
- frame.function = [[xmlframe attributeForName:@"where"] stringValue];
- frame.routingID = routingID;
-
- // Only get the complete frame for the first level. The other frames will get
- // information loaded lazily when the user clicks on one.
- if (frame.index == 0) {
- [self loadStackFrame:frame];
- }
-
- if ([delegate respondsToSelector:@selector(newStackFrame:)])
- [delegate newStackFrame:frame];
+ // Get the routing information.
+ NSInteger routingID = [connection_ transactionIDFromResponse:response];
+ if (routingID < stackFirstTransactionID_)
+ return;
+ NSNumber* routingNumber = [NSNumber numberWithInt:routingID];
+
+ // Make sure we initialized this frame in our last |-rebuildStack:|.
+ StackFrame* frame = [stackFrames_ objectForKey:routingNumber];
+ if (!frame)
+ return;
+
+ NSXMLElement* xmlframe = [[[response rootElement] children] objectAtIndex:0];
+
+ // Initialize the stack frame.
+ frame.index = [[[xmlframe attributeForName:@"level"] stringValue] intValue];
+ frame.filename = [[xmlframe attributeForName:@"filename"] stringValue];
+ frame.lineNumber = [[[xmlframe attributeForName:@"lineno"] stringValue] intValue];
+ frame.function = [[xmlframe attributeForName:@"where"] stringValue];
+ frame.routingID = routingID;
+
+ // Only get the complete frame for the first level. The other frames will get
+ // information loaded lazily when the user clicks on one.
+ if (frame.index == 0) {
+ [self loadStackFrame:frame];
+ }
+
+ if ([delegate respondsToSelector:@selector(newStackFrame:)])
+ [delegate newStackFrame:frame];
}
/**
*/
- (void)setSource:(NSXMLDocument*)response
{
- NSNumber* transaction = [NSNumber numberWithInt:[connection_ transactionIDFromResponse:response]];
- if ([transaction intValue] < stackFirstTransactionID_)
- return;
- NSNumber* routingNumber = [callbackContext_ objectForKey:transaction];
- if (!routingNumber)
- return;
-
- [callbackContext_ removeObjectForKey:transaction];
- StackFrame* frame = [stackFrames_ objectForKey:routingNumber];
- if (!frame)
- return;
-
- frame.source = [[response rootElement] value];
-
- if ([delegate respondsToSelector:@selector(sourceUpdated:)])
- [delegate sourceUpdated:frame];
+ NSNumber* transaction = [NSNumber numberWithInt:[connection_ transactionIDFromResponse:response]];
+ if ([transaction intValue] < stackFirstTransactionID_)
+ return;
+ NSNumber* routingNumber = [callbackContext_ objectForKey:transaction];
+ if (!routingNumber)
+ return;
+
+ [callbackContext_ removeObjectForKey:transaction];
+ StackFrame* frame = [stackFrames_ objectForKey:routingNumber];
+ if (!frame)
+ return;
+
+ frame.source = [[response rootElement] value];
+
+ if ([delegate respondsToSelector:@selector(sourceUpdated:)])
+ [delegate sourceUpdated:frame];
}
/**
*/
- (void)contextsReceived:(NSXMLDocument*)response
{
- // Get the stack frame's routing ID and use it again.
- NSNumber* receivedTransaction = [NSNumber numberWithInt:[connection_ transactionIDFromResponse:response]];
- if ([receivedTransaction intValue] < stackFirstTransactionID_)
- return;
- NSNumber* routingID = [callbackContext_ objectForKey:receivedTransaction];
- if (!routingID)
- return;
-
- // Get the stack frame by the |routingID|.
- StackFrame* frame = [stackFrames_ objectForKey:routingID];
-
- NSXMLElement* contextNames = [response rootElement];
- for (NSXMLElement* context in [contextNames children])
- {
- NSInteger cid = [[[context attributeForName:@"id"] stringValue] intValue];
-
- // Fetch each context's variables.
- NSNumber* tx = [connection_ sendCommandWithFormat:@"context_get -d %d -c %d", frame.index, cid];
- [self recordCallback:@selector(variablesReceived:) forTransaction:tx];
- [callbackContext_ setObject:routingID forKey:tx];
- }
+ // Get the stack frame's routing ID and use it again.
+ NSNumber* receivedTransaction = [NSNumber numberWithInt:[connection_ transactionIDFromResponse:response]];
+ if ([receivedTransaction intValue] < stackFirstTransactionID_)
+ return;
+ NSNumber* routingID = [callbackContext_ objectForKey:receivedTransaction];
+ if (!routingID)
+ return;
+
+ // Get the stack frame by the |routingID|.
+ StackFrame* frame = [stackFrames_ objectForKey:routingID];
+
+ NSXMLElement* contextNames = [response rootElement];
+ for (NSXMLElement* context in [contextNames children])
+ {
+ NSInteger cid = [[[context attributeForName:@"id"] stringValue] intValue];
+
+ // Fetch each context's variables.
+ NSNumber* tx = [connection_ sendCommandWithFormat:@"context_get -d %d -c %d", frame.index, cid];
+ [self recordCallback:@selector(variablesReceived:) forTransaction:tx];
+ [callbackContext_ setObject:routingID forKey:tx];
+ }
}
/**
*/
- (void)variablesReceived:(NSXMLDocument*)response
{
- // Get the stack frame's routing ID and use it again.
- NSInteger transaction = [connection_ transactionIDFromResponse:response];
- if (transaction < stackFirstTransactionID_)
- return;
- NSNumber* receivedTransaction = [NSNumber numberWithInt:transaction];
- NSNumber* routingID = [callbackContext_ objectForKey:receivedTransaction];
- if (!routingID)
- return;
-
- // Get the stack frame by the |routingID|.
- StackFrame* frame = [stackFrames_ objectForKey:routingID];
-
- NSMutableArray* variables = [NSMutableArray array];
-
- // Merge the frame's existing variables.
- if (frame.variables)
- [variables addObjectsFromArray:frame.variables];
-
- // Add these new variables.
- NSArray* addVariables = [[response rootElement] children];
- if (addVariables)
- [variables addObjectsFromArray:addVariables];
-
- frame.variables = variables;
+ // Get the stack frame's routing ID and use it again.
+ NSInteger transaction = [connection_ transactionIDFromResponse:response];
+ if (transaction < stackFirstTransactionID_)
+ return;
+ NSNumber* receivedTransaction = [NSNumber numberWithInt:transaction];
+ NSNumber* routingID = [callbackContext_ objectForKey:receivedTransaction];
+ if (!routingID)
+ return;
+
+ // Get the stack frame by the |routingID|.
+ StackFrame* frame = [stackFrames_ objectForKey:routingID];
+
+ NSMutableArray* variables = [NSMutableArray array];
+
+ // Merge the frame's existing variables.
+ if (frame.variables)
+ [variables addObjectsFromArray:frame.variables];
+
+ // Add these new variables.
+ NSArray* addVariables = [[response rootElement] children];
+ if (addVariables)
+ [variables addObjectsFromArray:addVariables];
+
+ frame.variables = variables;
}
/**
*/
- (void)propertiesReceived:(NSXMLDocument*)response
{
- NSInteger transaction = [connection_ transactionIDFromResponse:response];
-
- /*
- <response>
- <property> <!-- this is the one we requested -->
- <property ... /> <!-- these are what we want -->
- </property>
- </repsonse>
- */
-
- // Detach all the children so we can insert them into another document.
- NSXMLElement* parent = (NSXMLElement*)[[response rootElement] childAtIndex:0];
- NSArray* children = [parent children];
- [parent setChildren:nil];
-
- [delegate receivedProperties:children forTransaction:transaction];
+ NSInteger transaction = [connection_ transactionIDFromResponse:response];
+
+ /*
+ <response>
+ <property> <!-- this is the one we requested -->
+ <property ... /> <!-- these are what we want -->
+ </property>
+ </repsonse>
+ */
+
+ // Detach all the children so we can insert them into another document.
+ NSXMLElement* parent = (NSXMLElement*)[[response rootElement] childAtIndex:0];
+ NSArray* children = [parent children];
+ [parent setChildren:nil];
+
+ [delegate receivedProperties:children forTransaction:transaction];
}
/**
*/
- (void)breakpointReceived:(NSXMLDocument*)response
{
- NSNumber* transaction = [NSNumber numberWithInt:[connection_ transactionIDFromResponse:response]];
- Breakpoint* bp = [callbackContext_ objectForKey:transaction];
- if (!bp)
- return;
-
- [callbackContext_ removeObjectForKey:callbackContext_];
- [bp setDebuggerId:[[[[response rootElement] attributeForName:@"id"] stringValue] intValue]];
+ NSNumber* transaction = [NSNumber numberWithInt:[connection_ transactionIDFromResponse:response]];
+ Breakpoint* bp = [callbackContext_ objectForKey:transaction];
+ if (!bp)
+ return;
+
+ [callbackContext_ removeObjectForKey:callbackContext_];
+ [bp setDebuggerId:[[[[response rootElement] attributeForName:@"id"] stringValue] intValue]];
}
// Private /////////////////////////////////////////////////////////////////////
- (void)recordCallback:(SEL)callback forTransaction:(NSNumber*)txn
{
- [callTable_ setObject:NSStringFromSelector(callback) forKey:txn];
+ [callTable_ setObject:NSStringFromSelector(callback) forKey:txn];
}
@end
// this class to record the relevant information.
@interface LoggingController : NSWindowController
{
- // An array of log entries, with object at index 0 being the oldest entry.
- NSMutableArray* logEntries_;
+ // An array of log entries, with object at index 0 being the oldest entry.
+ NSMutableArray* logEntries_;
- // The array controller.
- IBOutlet NSArrayController* logEntriesController_;
+ // The array controller.
+ IBOutlet NSArrayController* logEntriesController_;
}
@property (readonly) NSArray* logEntries;
// Log Entry ///////////////////////////////////////////////////////////////////
typedef enum _LogEntryDirection {
- kLogEntrySending = 0,
- kLogEntryReceiving
+ kLogEntrySending = 0,
+ kLogEntryReceiving
} LogEntryDirection;
// A simple class that stores information for a single log entry.
@interface LogEntry : NSObject
{
- // The direction this communication went.
- LogEntryDirection direction_;
-
- // The command that was sent or the response.
- NSString* contents_;
+ // The direction this communication went.
+ LogEntryDirection direction_;
+
+ // The command that was sent or the response.
+ NSString* contents_;
- // Any error information.
- NSError* error_;
+ // Any error information.
+ NSError* error_;
- // The values of the last read and written transaction IDs.
- NSUInteger lastWrittenTransactionID_;
- NSUInteger lastReadTransactionID_;
+ // The values of the last read and written transaction IDs.
+ NSUInteger lastWrittenTransactionID_;
+ NSUInteger lastReadTransactionID_;
}
@property (assign) LogEntryDirection direction;
@property (copy) NSString* contents;
- (id)init
{
- if (self = [self initWithWindowNibName:@"Log"])
- {
- logEntries_ = [NSMutableArray new];
- }
- return self;
+ if (self = [self initWithWindowNibName:@"Log"])
+ {
+ logEntries_ = [NSMutableArray new];
+ }
+ return self;
}
- (void)dealloc
{
- [logEntries_ release];
- [super dealloc];
+ [logEntries_ release];
+ [super dealloc];
}
- (LogEntry*)recordSend:(NSString*)command
{
- LogEntry* entry = [LogEntry new];
- entry.direction = kLogEntrySending;
- entry.contents = command;
- [logEntries_ addObject:entry];
- [logEntriesController_ rearrangeObjects];
- return [entry autorelease];
+ LogEntry* entry = [LogEntry new];
+ entry.direction = kLogEntrySending;
+ entry.contents = command;
+ [logEntries_ addObject:entry];
+ [logEntriesController_ rearrangeObjects];
+ return [entry autorelease];
}
- (LogEntry*)recordReceive:(NSString*)response
{
- LogEntry* entry = [LogEntry new];
- entry.direction = kLogEntryReceiving;
- entry.contents = response;
- [logEntries_ addObject:entry];
- [logEntriesController_ rearrangeObjects];
- return [entry autorelease];
+ LogEntry* entry = [LogEntry new];
+ entry.direction = kLogEntryReceiving;
+ entry.contents = response;
+ [logEntries_ addObject:entry];
+ [logEntriesController_ rearrangeObjects];
+ return [entry autorelease];
}
@end
- (void)dealloc
{
- self.contents = nil;
- self.error = nil;
- self.lastWrittenTransactionID = 0;
- self.lastReadTransactionID = 0;
+ self.contents = nil;
+ self.error = nil;
+ self.lastWrittenTransactionID = 0;
+ self.lastReadTransactionID = 0;
}
- (NSString*)directionName
{
- return (direction_ == kLogEntryReceiving ? @"Recv" : @"Send");
+ return (direction_ == kLogEntryReceiving ? @"Recv" : @"Send");
}
@end
*/
- (NSString*)fullname
{
- return [[self attributeForName:@"fullname"] stringValue];
+ return [[self attributeForName:@"fullname"] stringValue];
}
/**
*/
- (NSString*)variable
{
- return [[self attributeForName:@"name"] stringValue];
+ return [[self attributeForName:@"name"] stringValue];
}
/**
*/
- (BOOL)isLeaf
{
- return ([[[self attributeForName:@"children"] stringValue] intValue] == 0);
+ return ([[[self attributeForName:@"children"] stringValue] intValue] == 0);
}
/**
*/
- (NSArray*)subnodes
{
- NSArray* children = [self children];
- if (![self isLeaf] && [children count] < 1)
- {
- return [[[(AppDelegate*)[NSApp delegate] debugger] connection] getProperty:[self fullname]];
- }
- return children;
+ NSArray* children = [self children];
+ if (![self isLeaf] && [children count] < 1)
+ {
+ return [[[(AppDelegate*)[NSApp delegate] debugger] connection] getProperty:[self fullname]];
+ }
+ return children;
}
/**
*/
- (NSString*)value
{
- // not a leaf, so don't display any value
- if (![self isLeaf])
- {
- return @"...";
- }
-
- // base64 encoded data
- if ([[[self attributeForName:@"encoding"] stringValue] isEqualToString:@"base64"])
- {
- const char* str = [[self stringValue] UTF8String];
- int strlen = [[self stringValue] length];
-
- char* data;
- size_t datalen;
-
- if (!base64_decode_alloc(str, strlen, &data, &datalen))
- NSLog(@"error in converting %@ from base64", self);
-
- NSString* ret = nil;
- if (data)
- {
- ret = [NSString stringWithUTF8String:data];
- free(data);
- }
-
- return ret;
- }
-
- // just a normal string
- return [self stringValue];
+ // not a leaf, so don't display any value
+ if (![self isLeaf])
+ {
+ return @"...";
+ }
+
+ // base64 encoded data
+ if ([[[self attributeForName:@"encoding"] stringValue] isEqualToString:@"base64"])
+ {
+ const char* str = [[self stringValue] UTF8String];
+ int strlen = [[self stringValue] length];
+
+ char* data;
+ size_t datalen;
+
+ if (!base64_decode_alloc(str, strlen, &data, &datalen))
+ NSLog(@"error in converting %@ from base64", self);
+
+ NSString* ret = nil;
+ if (data)
+ {
+ ret = [NSString stringWithUTF8String:data];
+ free(data);
+ }
+
+ return ret;
+ }
+
+ // just a normal string
+ return [self stringValue];
}
/**
*/
- (NSString*)type
{
- NSXMLNode* className = [self attributeForName:@"classname"];
- NSString* type = [[self attributeForName:@"type"] stringValue];
- if (className != nil)
- {
- return [NSString stringWithFormat:@"%@ (%@)", [className stringValue], type];
- }
- return type;
+ NSXMLNode* className = [self attributeForName:@"classname"];
+ NSString* type = [[self attributeForName:@"type"] stringValue];
+ if (className != nil)
+ {
+ return [NSString stringWithFormat:@"%@ (%@)", [className stringValue], type];
+ }
+ return type;
}
@end
@interface PreferencesController : NSWindowController
{
- IBOutlet NSToolbar* toolbar;
-
- NSView* blankView;
-
- IBOutlet NSView* generalPreferencesView;
- IBOutlet NSToolbarItem* generalPreferencesItem;
-
- IBOutlet NSView* pathsPreferencesView;
- IBOutlet NSToolbarItem* pathsPreferencesItem;
+ IBOutlet NSToolbar* toolbar;
+
+ NSView* blankView;
+
+ IBOutlet NSView* generalPreferencesView;
+ IBOutlet NSToolbarItem* generalPreferencesItem;
+
+ IBOutlet NSView* pathsPreferencesView;
+ IBOutlet NSToolbarItem* pathsPreferencesItem;
}
- (void)showPreferencesWindow;
*/
- (id)init
{
- if (self = [super initWithWindowNibName:@"Preferences"])
- {
- blankView = [[NSView alloc] init];
- }
- return self;
+ if (self = [super initWithWindowNibName:@"Preferences"])
+ {
+ blankView = [[NSView alloc] init];
+ }
+ return self;
}
/**
*/
- (void)dealloc
{
- [blankView release];
- [super dealloc];
+ [blankView release];
+ [super dealloc];
}
/**
*/
- (void)awakeFromNib
{
- generalSize = [generalPreferencesView frame].size;
- pathsSize = [pathsPreferencesView frame].size;
+ generalSize = [generalPreferencesView frame].size;
+ pathsSize = [pathsPreferencesView frame].size;
}
/**
*/
- (void)showPreferencesWindow
{
- [self showGeneral:self];
- [[self window] center];
- [[self window] makeKeyAndOrderFront:self];
+ [self showGeneral:self];
+ [[self window] center];
+ [[self window] makeKeyAndOrderFront:self];
}
#pragma mark Panel Switching
*/
- (IBAction)showGeneral:(id)sender
{
- if ([[self window] contentView] == generalPreferencesView)
- return;
-
- [self resizeWindowToSize:generalSize];
-
- [[self window] setContentView:generalPreferencesView];
- [toolbar setSelectedItemIdentifier:[generalPreferencesItem itemIdentifier]];
+ if ([[self window] contentView] == generalPreferencesView)
+ return;
+
+ [self resizeWindowToSize:generalSize];
+
+ [[self window] setContentView:generalPreferencesView];
+ [toolbar setSelectedItemIdentifier:[generalPreferencesItem itemIdentifier]];
}
/**
*/
- (IBAction)showPaths:(id)sender
{
- if ([[self window] contentView] == pathsPreferencesView)
- return;
-
- [self resizeWindowToSize:pathsSize];
-
- [[self window] setContentView:pathsPreferencesView];
- [toolbar setSelectedItemIdentifier:[pathsPreferencesItem itemIdentifier]];
+ if ([[self window] contentView] == pathsPreferencesView)
+ return;
+
+ [self resizeWindowToSize:pathsSize];
+
+ [[self window] setContentView:pathsPreferencesView];
+ [toolbar setSelectedItemIdentifier:[pathsPreferencesItem itemIdentifier]];
}
#pragma mark NSToolbar Delegate
*/
- (NSArray*)toolbarSelectableItemIdentifiers:(NSToolbar*)toolbar
{
- return [NSArray arrayWithObjects:
- [generalPreferencesItem itemIdentifier],
- [pathsPreferencesItem itemIdentifier],
- nil
- ];
+ return [NSArray arrayWithObjects:
+ [generalPreferencesItem itemIdentifier],
+ [pathsPreferencesItem itemIdentifier],
+ nil
+ ];
}
#pragma mark Private
*/
- (void)resizeWindowToSize:(NSSize)size
{
- [[self window] setContentView:blankView]; // don't want weird redraw artifacts
-
- NSRect newFrame;
-
- newFrame = [NSWindow contentRectForFrameRect:[[self window] frame] styleMask:[[self window] styleMask]];
-
- float height = size.height + 55;
-
- newFrame.origin.y += newFrame.size.height;
- newFrame.origin.y -= height;
- newFrame.size.height = height;
- newFrame.size.width = size.width;
-
- newFrame = [NSWindow frameRectForContentRect:newFrame styleMask:[[self window] styleMask]];
-
- [[self window] setFrame:newFrame display:YES animate:YES];
+ [[self window] setContentView:blankView]; // don't want weird redraw artifacts
+
+ NSRect newFrame;
+
+ newFrame = [NSWindow contentRectForFrameRect:[[self window] frame] styleMask:[[self window] styleMask]];
+
+ float height = size.height + 55;
+
+ newFrame.origin.y += newFrame.size.height;
+ newFrame.origin.y -= height;
+ newFrame.size.height = height;
+ newFrame.size.width = size.width;
+
+ newFrame = [NSWindow frameRectForContentRect:newFrame styleMask:[[self window] styleMask]];
+
+ [[self window] setFrame:newFrame display:YES animate:YES];
}
@end
*/
- (id)newObject
{
- NSMutableDictionary* obj = (NSMutableDictionary*)[super newObject];
- [obj setValue:@"Remote Path" forKey:@"remote"];
- [obj setValue:@"Local Path" forKey:@"local"];
- return obj;
+ NSMutableDictionary* obj = (NSMutableDictionary*)[super newObject];
+ [obj setValue:@"Remote Path" forKey:@"remote"];
+ [obj setValue:@"Local Path" forKey:@"local"];
+ return obj;
}
@end
@interface StackController : NSObject
{
- /**
- * Array of StackFrame's (LIFO stack)
- */
- NSMutableArray* stack;
+ /**
+ * Array of StackFrame's (LIFO stack)
+ */
+ NSMutableArray* stack;
}
@property(readonly) NSMutableArray* stack;
*/
- (id)init
{
- if (self = [super init])
- {
- stack = [[NSMutableArray alloc] init];
- }
- return self;
+ if (self = [super init])
+ {
+ stack = [[NSMutableArray alloc] init];
+ }
+ return self;
}
/**
*/
- (void)dealloc
{
- [stack release];
- [super dealloc];
+ [stack release];
+ [super dealloc];
}
/**
*/
- (StackFrame*)peek
{
- return [stack lastObject];
+ return [stack lastObject];
}
/**
*/
- (StackFrame*)pop
{
- StackFrame* frame = [stack lastObject];
-
- if (frame != nil)
- [stack removeLastObject];
+ StackFrame* frame = [stack lastObject];
+
+ if (frame != nil)
+ [stack removeLastObject];
- return frame;
+ return frame;
}
/**
*/
- (void)push:(StackFrame*)frame
{
- [stack insertObject:frame atIndex:[stack count]];
+ [stack insertObject:frame atIndex:[stack count]];
}
@end
@interface StackFrame : NSObject
{
- /**
- * Whether or not the stack frame has been fully loaded.
- */
- BOOL loaded_;
+ /**
+ * Whether or not the stack frame has been fully loaded.
+ */
+ BOOL loaded_;
- /**
- * The routing ID used to receive response information from the engine.
- */
- NSUInteger routingID_;
-
- /**
- * The position in the stack
- */
- NSUInteger index_;
-
- /**
- * File the current frame is in
- */
- NSString* filename_;
-
- /**
- * Cached, highlighted version of the source
- */
- NSString* source_;
-
- /**
- * Line number of the source the frame points to
- */
- NSUInteger lineNumber_;
-
- /**
- * Current-executing function
- */
- NSString* function_;
-
- /**
- * Variable list
- */
- NSArray* variables_;
+ /**
+ * The routing ID used to receive response information from the engine.
+ */
+ NSUInteger routingID_;
+
+ /**
+ * The position in the stack
+ */
+ NSUInteger index_;
+
+ /**
+ * File the current frame is in
+ */
+ NSString* filename_;
+
+ /**
+ * Cached, highlighted version of the source
+ */
+ NSString* source_;
+
+ /**
+ * Line number of the source the frame points to
+ */
+ NSUInteger lineNumber_;
+
+ /**
+ * Current-executing function
+ */
+ NSString* function_;
+
+ /**
+ * Variable list
+ */
+ NSArray* variables_;
}
@property BOOL loaded;
*/
- (BOOL)isShiftedFrame:(StackFrame*)frame
{
- return ([self.filename isEqualToString:frame.filename] && [self.function isEqualToString:frame.function]);
+ return ([self.filename isEqualToString:frame.filename] && [self.function isEqualToString:frame.function]);
}
/**
*/
- (NSString*)description
{
- return [NSString stringWithFormat:@"#%d %@ [%@:%d]", self.index, self.function, self.filename, self.lineNumber];
+ return [NSString stringWithFormat:@"#%d %@ [%@:%d]", self.index, self.function, self.filename, self.lineNumber];
}
@end