The official RSwitch now converted to modern Objective C and can be compiled be 64-bit
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

153 lines
4.2 KiB

5 years ago
#import "SwitchCtrl.h"
NSArray *versions = nil;
NSArray *desc = nil;
BOOL finishedLoading = NO;
@interface SwitchCtrl (Private)
- (void) reloadVersions;
@end
@implementation SwitchCtrl
NSString *where = @"/Library/Frameworks/R.framework/Versions";
- (IBAction)rediscover:(id)sender
{
[self reloadVersions];
}
/* awake */
- (void) awakeFromNib {
[self reloadVersions];
finishedLoading = YES;
}
// fn is now a path to R_HOME. Uses bin/R (for older R) or Rversion.h header
static NSString *getVersionString(NSString *fn) {
char buf[512];
FILE *f = fopen([[fn stringByAppendingString:@"/bin/R"] UTF8String],"r");
if (!f) return @"<incomplete installation>";
buf[511]=0;
while (!feof(f) && fgets(buf,511,f)) {
char *c = strstr(buf,"version=\"");
if (c) {
char *d = c;
while (*d) d++;
d--; while (d > c+10 && (*d=='.' || *d=='\n' || *d=='\r' || *d==' ')) { *d=0; d--; };
fclose(f);
return [NSString stringWithUTF8String:c+9];
}
}
fclose(f);
// bin/R doesn't contain version="" - try headers - it's messy, though
f = fopen([[fn stringByAppendingString:@"/include/i386/Rversion.h"] UTF8String], "r");
if (!f) // possibly not multi-arch -- note that this won't work for multi-arch as it's jsut a stub
f = fopen([[fn stringByAppendingString:@"/include/Rversion.h"] UTF8String], "r");
if (f) {
NSString *ver = @"";
while (!feof(f) && fgets(buf, 511, f)) {
int maj = 1;
char *c = strstr(buf, "R_MAJOR");
if (!c) {
c = strstr(buf, "R_MINOR");
maj = 0;
}
if (c) {
char *anchor;
while (*c && *c != '\"') c++;
if (*c) c++;
anchor = c;
while (*c && *c != '\"') c++;
*c = 0;
ver = [ver stringByAppendingFormat:@"%s%s", maj ? "" : ".", anchor];
}
}
fclose(f);
if ([ver length] > 0)
return ver;
}
return @"<unknown>";
}
- (void) reloadVersions {
NSArray *cont = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:where error:nil];
if (cont) {
NSMutableArray *ma = [[NSMutableArray alloc] initWithCapacity:[cont count]];
if (desc) [desc release];
desc = [[NSMutableArray alloc] initWithCapacity:[cont count]];
NSEnumerator *enumerator = [cont objectEnumerator];
NSString *cur = [[NSFileManager defaultManager] destinationOfSymbolicLinkAtPath:[NSString stringWithFormat:@"%@/Current", where] error: nil];
NSString *ver;
while (ver = (NSString*) [enumerator nextObject]) {
NSString *rsh = [NSString stringWithFormat:@"%@/%@/Resources", where, ver];
if (![ver isEqualToString:@"Current"] && [[NSFileManager defaultManager] fileExistsAtPath:rsh]) {
[ma addObject:ver];
[(NSMutableArray*)desc addObject: getVersionString(rsh)];
}
}
if (versions) [versions release];
versions = ma;
[list reloadData];
if (cur) {
NSUInteger cp = [versions indexOfObject:cur];
if (cp != NSNotFound) [list selectRowIndexes:[NSIndexSet indexSetWithIndex:cp] byExtendingSelection:NO];
}
}
}
/* selection */
- (void) tableViewSelectionDidChange:(NSNotification *)aNotification
{
NSUInteger nr = [list numberOfRows];
NSInteger sel = -1;
if (nr>0) {
sel = [list selectedRow];
if (finishedLoading && sel>=0 && sel<nr) {
NSString *curl = [NSString stringWithFormat:@"%@/Current", where];
NSString *new = [versions objectAtIndex:sel];
[[NSFileManager defaultManager] removeItemAtURL:[NSURL URLWithString:curl] error: nil];
[[NSFileManager defaultManager] createSymbolicLinkAtURL:[NSURL URLWithString:curl] withDestinationURL:[NSURL URLWithString:new] error: nil];
NSLog(@"Requested change of link %@ to %@", curl, new);
}
}
NSLog(@"Did change, nr=%ld, sel=%ld, finished=%d", nr, sel, finishedLoading);
}
/* dataSource callbacks */
- (id)tableView:(NSTableView *)aTableView
objectValueForTableColumn:(NSTableColumn *)aTableColumn
row:(int)rowIndex
{
NSArray *ac = nil;
if ([[aTableColumn identifier] isEqual:@"desc"]) ac = desc;
if ([[aTableColumn identifier] isEqual:@"version"]) ac = versions;
if (!ac) return nil;
NSParameterAssert(rowIndex >= 0 && rowIndex < [ac count]);
return [ac objectAtIndex:rowIndex];
}
- (NSUInteger)numberOfRowsInTableView:(NSTableView *)aTableView
{
return desc?[desc count]:0;
}
/* window callbacks */
- (BOOL)windowShouldClose:(id)sender {
[NSApp terminate:0];
return YES;
}
@end