2002-05-29 21:59:25 +00:00
|
|
|
/**
|
|
|
|
STShell
|
|
|
|
StepTalk Shell
|
|
|
|
|
|
|
|
Copyright (c) 2002 Free Software Foundation
|
|
|
|
|
|
|
|
Written by: Stefan Urbanek <urbanek@host.sk>
|
|
|
|
Date: 2002 May 29
|
|
|
|
|
|
|
|
This file is part of the StepTalk project.
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02111, USA.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
#import "STShell.h"
|
|
|
|
|
|
|
|
#import <StepTalk/StepTalk.h>
|
|
|
|
|
|
|
|
#import <Foundation/NSArray.h>
|
2002-06-04 17:59:06 +00:00
|
|
|
#import <Foundation/NSBundle.h>
|
2002-05-29 21:59:25 +00:00
|
|
|
#import <Foundation/NSDebug.h>
|
2002-06-04 17:59:06 +00:00
|
|
|
#import <Foundation/NSNotification.h>
|
2002-05-29 21:59:25 +00:00
|
|
|
#import <Foundation/NSException.h>
|
2003-09-21 16:12:46 +00:00
|
|
|
#import <Foundation/NSFileManager.h>
|
2002-05-29 21:59:25 +00:00
|
|
|
#import <Foundation/NSSet.h>
|
|
|
|
#import <Foundation/NSString.h>
|
|
|
|
#import <Foundation/NSValue.h>
|
|
|
|
|
|
|
|
#include <readline/readline.h>
|
|
|
|
|
|
|
|
static Class NSString_class;
|
|
|
|
static Class NSNumber_class;
|
|
|
|
|
|
|
|
NSArray *objcSelectors = nil;
|
|
|
|
|
2002-09-17 12:40:41 +00:00
|
|
|
static STShell *sharedShell = nil;
|
2002-05-29 21:59:25 +00:00
|
|
|
|
2003-04-04 10:57:04 +00:00
|
|
|
@interface STShell(STPrivateMethods)
|
2002-09-17 12:40:41 +00:00
|
|
|
- (int) completion;
|
2002-09-15 10:22:15 +00:00
|
|
|
- (NSString *)readLine;
|
|
|
|
- (void)initReadline;
|
|
|
|
@end
|
|
|
|
|
2002-05-29 21:59:25 +00:00
|
|
|
int complete_handler(void)
|
|
|
|
{
|
2002-09-17 12:40:41 +00:00
|
|
|
return [sharedShell completion];
|
2002-05-29 21:59:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@implementation STShell
|
2002-09-17 12:40:41 +00:00
|
|
|
|
2002-05-29 21:59:25 +00:00
|
|
|
+ (void)initialize
|
|
|
|
{
|
|
|
|
NSString_class = [NSString class];
|
|
|
|
NSNumber_class = [NSNumber class];
|
|
|
|
}
|
2002-09-17 12:40:41 +00:00
|
|
|
|
2002-05-29 21:59:25 +00:00
|
|
|
+ sharedShell
|
|
|
|
{
|
|
|
|
return sharedShell;
|
|
|
|
}
|
2002-09-17 12:40:41 +00:00
|
|
|
|
2003-11-08 01:02:35 +00:00
|
|
|
- initWithEnvironment:(STEnvironment *)env
|
2002-05-29 21:59:25 +00:00
|
|
|
{
|
|
|
|
self = [super init];
|
|
|
|
|
|
|
|
[self initReadline];
|
|
|
|
|
|
|
|
objectStack = [[NSMutableArray alloc] init];
|
|
|
|
|
2002-06-04 17:59:06 +00:00
|
|
|
[[NSNotificationCenter defaultCenter]
|
|
|
|
addObserver:self
|
|
|
|
selector:@selector(bundleLoaded:)
|
|
|
|
name:NSBundleDidLoadNotification
|
|
|
|
object:nil];
|
2003-09-21 16:23:09 +00:00
|
|
|
|
2002-06-21 22:40:59 +00:00
|
|
|
scriptsManager = RETAIN([STScriptsManager defaultManager]);
|
2003-09-21 16:23:09 +00:00
|
|
|
prompt = @"StepTalk > ";
|
2002-05-29 21:59:25 +00:00
|
|
|
|
2003-11-08 01:02:35 +00:00
|
|
|
conversation = [[STConversation alloc] initWithEnvironment:env language:nil];
|
|
|
|
/* FIXME: make this more clever for completion handler */
|
|
|
|
if(!sharedShell)
|
|
|
|
{
|
|
|
|
sharedShell = self;
|
|
|
|
}
|
|
|
|
|
2002-05-29 21:59:25 +00:00
|
|
|
return self;
|
|
|
|
}
|
2002-06-06 17:14:05 +00:00
|
|
|
|
2002-09-17 12:40:41 +00:00
|
|
|
- (void)updateCompletionList
|
2002-06-06 17:14:05 +00:00
|
|
|
{
|
2002-09-17 12:40:41 +00:00
|
|
|
NSMutableArray *array = [[NSMutableArray alloc] init];
|
|
|
|
RELEASE(completionList);
|
2002-06-06 17:14:05 +00:00
|
|
|
|
2002-09-15 10:22:15 +00:00
|
|
|
[array addObjectsFromArray:STAllObjectiveCSelectors()];
|
|
|
|
|
2002-09-17 12:40:41 +00:00
|
|
|
completionList = [[NSArray alloc] initWithArray:array];
|
2002-09-15 10:22:15 +00:00
|
|
|
|
2002-09-17 12:40:41 +00:00
|
|
|
updateCompletionList = NO;
|
2002-06-06 17:14:05 +00:00
|
|
|
}
|
|
|
|
|
2002-06-04 17:59:06 +00:00
|
|
|
- (void)dealloc
|
|
|
|
{
|
|
|
|
RELEASE(objectStack);
|
2002-09-17 12:40:41 +00:00
|
|
|
RELEASE(completionList);
|
2002-06-21 22:40:59 +00:00
|
|
|
RELEASE(scriptsManager);
|
2003-11-08 01:02:35 +00:00
|
|
|
RELEASE(conversation);
|
2002-06-06 17:14:05 +00:00
|
|
|
|
2002-06-04 17:59:06 +00:00
|
|
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
|
|
|
|
|
|
|
[super dealloc];
|
|
|
|
}
|
|
|
|
-(void)bundleLoaded:(NSNotification *)notif
|
|
|
|
{
|
2002-09-17 12:40:41 +00:00
|
|
|
updateCompletionList = YES;
|
2002-06-04 17:59:06 +00:00
|
|
|
}
|
2002-05-29 21:59:25 +00:00
|
|
|
|
|
|
|
- (void)initReadline
|
|
|
|
{
|
|
|
|
rl_initialize();
|
|
|
|
rl_bind_key('\t', complete_handler);
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)setLanguage:(NSString *)langName
|
|
|
|
{
|
|
|
|
NSDebugLog(@"Setting language to %@", langName);
|
|
|
|
|
2003-11-08 01:02:35 +00:00
|
|
|
[conversation setLanguage:langName];
|
2002-05-29 21:59:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)setEnvironment:(STEnvironment *)newEnv
|
|
|
|
{
|
2003-11-24 09:43:42 +00:00
|
|
|
[conversation setEnvironment:newEnv];
|
2002-05-29 21:59:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (STEnvironment *)environment
|
|
|
|
{
|
2003-11-24 09:43:42 +00:00
|
|
|
return [conversation environment];
|
2002-05-29 21:59:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)run
|
|
|
|
{
|
2003-11-24 09:43:42 +00:00
|
|
|
STEnvironment *env = [conversation environment];
|
|
|
|
NSString *line;
|
|
|
|
id result;
|
2002-05-29 21:59:25 +00:00
|
|
|
|
|
|
|
[env setCreatesUnknownObjects:YES];
|
2002-06-04 17:59:06 +00:00
|
|
|
|
2003-09-21 16:12:46 +00:00
|
|
|
/* Add standard objects */
|
2002-05-29 21:59:25 +00:00
|
|
|
[env setObject:self forName:@"Shell"];
|
|
|
|
[env setObject:self forName:@"Transcript"];
|
|
|
|
[env setObject:objectStack forName:@"Objects"];
|
|
|
|
|
2003-09-21 16:12:46 +00:00
|
|
|
[env setObject:[NSFileManager defaultManager] forName:@"FileManager"];
|
|
|
|
|
2002-06-04 17:59:06 +00:00
|
|
|
/* FIXME: This is unsafe !*/
|
|
|
|
[env setObject:env forName:@"Environment"];
|
|
|
|
|
2002-05-29 21:59:25 +00:00
|
|
|
[self showLine:@"Welcome to the StepTalk shell."];
|
|
|
|
|
2003-11-24 09:43:42 +00:00
|
|
|
NSLog(@"Environment %@", env);
|
|
|
|
|
2002-05-29 21:59:25 +00:00
|
|
|
while(1)
|
|
|
|
{
|
|
|
|
line = [self readLine];
|
2002-05-29 22:32:24 +00:00
|
|
|
|
|
|
|
if(exitRequest)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if(!line)
|
|
|
|
continue;
|
|
|
|
|
2002-05-29 21:59:25 +00:00
|
|
|
result = [self executeLine:line];
|
|
|
|
|
|
|
|
if(result)
|
|
|
|
{
|
2002-06-07 22:11:01 +00:00
|
|
|
if(result != objectStack)
|
|
|
|
{
|
|
|
|
[objectStack addObject:result];
|
|
|
|
}
|
2002-05-29 21:59:25 +00:00
|
|
|
[self showResult:result];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
[self showResult:result];
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2002-05-29 22:32:24 +00:00
|
|
|
printf("\n");
|
2002-05-29 21:59:25 +00:00
|
|
|
}
|
|
|
|
- (id)executeLine:(NSString *)line
|
|
|
|
{
|
2003-11-24 09:43:42 +00:00
|
|
|
STEnvironment *env = [conversation environment];
|
|
|
|
NSString *cmd;
|
|
|
|
id result = nil;
|
2002-05-29 21:59:25 +00:00
|
|
|
|
|
|
|
/* FIXME: why? */
|
2003-09-21 16:12:46 +00:00
|
|
|
|
|
|
|
cmd = [line stringByAppendingString:@" "];
|
2002-05-29 21:59:25 +00:00
|
|
|
NS_DURING
|
2003-11-08 01:02:35 +00:00
|
|
|
result = [conversation runScriptFromString:cmd];
|
2002-05-29 21:59:25 +00:00
|
|
|
NS_HANDLER
|
|
|
|
[self showException:localException];
|
|
|
|
NS_ENDHANDLER
|
|
|
|
|
2003-09-21 16:12:46 +00:00
|
|
|
[env setObject:line forName:@"LastCommand"];
|
|
|
|
[env setObject:result forName:@"LastObject"];
|
|
|
|
|
2002-05-29 21:59:25 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString *)readLine
|
|
|
|
{
|
|
|
|
const char *str;
|
|
|
|
NSString *actualPrompt = prompt;
|
|
|
|
NSString *line = @"";
|
|
|
|
BOOL done = NO;
|
2002-05-29 22:32:24 +00:00
|
|
|
int len;
|
|
|
|
|
2002-05-29 21:59:25 +00:00
|
|
|
while(!done)
|
|
|
|
{
|
|
|
|
str = readline([actualPrompt cString]);
|
|
|
|
done = YES;
|
2002-05-29 22:32:24 +00:00
|
|
|
|
|
|
|
if(!str)
|
|
|
|
{
|
|
|
|
exitRequest = YES;
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
len = strlen(str);
|
|
|
|
if(!len)
|
|
|
|
return nil;
|
2002-05-29 21:59:25 +00:00
|
|
|
|
2002-05-29 22:32:24 +00:00
|
|
|
if(str[len-1] == '\\')
|
2002-05-29 21:59:25 +00:00
|
|
|
{
|
|
|
|
actualPrompt = @"... ? ";
|
|
|
|
str[strlen(str) - 1] = '\0';
|
|
|
|
done = NO;
|
|
|
|
}
|
|
|
|
|
|
|
|
line = [line stringByAppendingString:[NSString stringWithCString:str]];
|
|
|
|
}
|
|
|
|
|
|
|
|
add_history([line cString]);
|
|
|
|
|
|
|
|
return line;
|
|
|
|
}
|
|
|
|
|
2002-09-17 12:40:41 +00:00
|
|
|
- (int)completion
|
2002-05-29 21:59:25 +00:00
|
|
|
{
|
2003-11-24 09:43:42 +00:00
|
|
|
STEnvironment *env = [conversation environment];
|
|
|
|
NSEnumerator *enumerator;
|
|
|
|
NSMutableSet *set;
|
|
|
|
NSString *match;
|
|
|
|
NSString *tail;
|
|
|
|
NSString *str;
|
|
|
|
NSArray *array;
|
2002-05-29 21:59:25 +00:00
|
|
|
int pos = 0;
|
|
|
|
int c;
|
|
|
|
|
|
|
|
if(rl_point <= 0)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
pos = rl_point - 1;
|
|
|
|
c = rl_line_buffer[pos];
|
|
|
|
|
|
|
|
while((isalnum(c) || c == '_') && pos >= 0)
|
|
|
|
{
|
|
|
|
pos--;
|
|
|
|
c = rl_line_buffer[pos];
|
|
|
|
}
|
|
|
|
pos++;
|
|
|
|
|
|
|
|
match = [NSString stringWithCString:rl_line_buffer + pos
|
|
|
|
length:rl_point - pos];
|
|
|
|
|
|
|
|
set = [NSMutableSet set];
|
|
|
|
|
2002-09-17 12:40:41 +00:00
|
|
|
if(!completionList || updateCompletionList)
|
2002-05-29 21:59:25 +00:00
|
|
|
{
|
2002-09-17 12:40:41 +00:00
|
|
|
[self updateCompletionList];
|
2002-05-29 21:59:25 +00:00
|
|
|
}
|
|
|
|
|
2002-09-17 12:40:41 +00:00
|
|
|
enumerator = [completionList objectEnumerator];
|
2002-05-29 21:59:25 +00:00
|
|
|
while( (str = [enumerator nextObject]) )
|
|
|
|
{
|
|
|
|
if( [str hasPrefix:match] )
|
|
|
|
{
|
|
|
|
[set addObject:str];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-06-14 08:42:00 +00:00
|
|
|
enumerator = [[env knownObjectNames] objectEnumerator];
|
|
|
|
while( (str = [enumerator nextObject]) )
|
|
|
|
{
|
|
|
|
if( [str hasPrefix:match] )
|
|
|
|
{
|
|
|
|
[set addObject:str];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-05-29 21:59:25 +00:00
|
|
|
array = [set allObjects];
|
|
|
|
|
|
|
|
if( [array count] == 0 )
|
|
|
|
{
|
2002-09-17 12:40:41 +00:00
|
|
|
printf("\nNo match for completion.\n");
|
2002-05-29 21:59:25 +00:00
|
|
|
rl_forced_update_display();
|
|
|
|
}
|
|
|
|
else if ( [array count] == 1 )
|
|
|
|
{
|
|
|
|
str = [array objectAtIndex:0];
|
|
|
|
str = [str substringFromIndex:rl_point - pos];
|
|
|
|
rl_insert_text([str cString]);
|
|
|
|
rl_insert_text(" ");
|
|
|
|
|
|
|
|
rl_redisplay();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
enumerator = [array objectEnumerator];
|
|
|
|
|
|
|
|
tail = [enumerator nextObject];
|
|
|
|
|
|
|
|
while( (str = [enumerator nextObject]) )
|
|
|
|
{
|
|
|
|
tail = [str commonPrefixWithString:tail options:NSLiteralSearch];
|
|
|
|
}
|
|
|
|
|
|
|
|
tail = [tail substringFromIndex:[match length]];
|
|
|
|
|
|
|
|
if( tail && ![tail isEqualToString:@""] )
|
|
|
|
{
|
|
|
|
rl_insert_text([tail cString]);
|
|
|
|
rl_redisplay();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
printf("\n");
|
|
|
|
enumerator = [array objectEnumerator];
|
|
|
|
while( (str = [enumerator nextObject]) )
|
|
|
|
{
|
|
|
|
printf("%s\n", [str cString]);
|
|
|
|
}
|
|
|
|
rl_forced_update_display();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)exit
|
|
|
|
{
|
|
|
|
/* FIXME: this is not nice */
|
|
|
|
exit(0);
|
|
|
|
}
|
2002-06-21 22:40:59 +00:00
|
|
|
|
|
|
|
- (id)executeScriptNamed:(NSString *)scriptName
|
|
|
|
{
|
|
|
|
STScript *script = [scriptsManager scriptWithName:scriptName];
|
|
|
|
id result = nil;
|
|
|
|
|
|
|
|
if(!script)
|
|
|
|
{
|
|
|
|
[self showError:[NSString stringWithFormat:
|
|
|
|
@"Unable to find script with name '%@'",
|
|
|
|
scriptName]];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
NS_DURING
|
2003-11-08 01:02:35 +00:00
|
|
|
result = [conversation runScriptFromString:[script source]];
|
2002-06-21 22:40:59 +00:00
|
|
|
NS_HANDLER
|
|
|
|
[self showException:localException];
|
|
|
|
NS_ENDHANDLER
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
2003-09-21 16:23:09 +00:00
|
|
|
- (void)setPrompt:(NSString *)aString
|
|
|
|
{
|
|
|
|
ASSIGN(prompt, aString);
|
|
|
|
}
|
|
|
|
- (NSString *)prompt
|
|
|
|
{
|
|
|
|
return prompt;
|
|
|
|
}
|
2002-05-29 21:59:25 +00:00
|
|
|
@end
|