This is Eval-ObjC.m in view mode; [Download] [Up]
/**
** Eval(ObjC)
**
** Methods for evaluating and loading
** objective C code, object modules,
** and libraries.
**/
#import "Eval.h"
@implementation Eval(ObjC)
- evalObjC:(id) pboard userData: (const char *) uBuf error: (char **) msg ;
{ // evaluate the pasteboard selection
char *text ;
const char *const *types ;
int i, textLen ;
BOOL found = NO ;
// fetch the data from pasteboard
types = [pboard types] ;
for(i = 0 ; types[i]; i++)
{ if(!strcmp(types[i], NXAsciiPboardType))
{ found = YES ;
break ;
}
}
if(!found) // no ascii found...
return self ;
[pboard readType:NXAsciiPboardType data:&text length:&textLen];
if(!text || !textLen) // nothing there...
return self ;
else
{ [self evalObjC: text length: textLen] ;
[pboard deallocatePasteboardData:text length:textLen];
}
return self ;
}
- evalObjC: (char *) text length: (int) len ;
{ // evaluate objc in text (not necessarily null-terminated)...of length len
char *lastTextChar, aStr[128], *header, *body, tmpFile[18] = "EvalXXXXXXXX" ;
FILE *fp ;
int firstHeaderLine = 1, headerLineKnt = 1 ;
NXHandler exception;
Module *mod ;
[self message: "Creating program text..."] ;
// get pointer to end of text
lastTextChar = &text[len - 1] ;
// find out if we have any header
header = body = text ;
// move header pointer to start of header
while((header <= lastTextChar) && isspace(*header))
{ // scan past any initial whiteSpace, counting lines as we go
if(*header == '\n')
firstHeaderLine++ ;
header++ ;
}
if(*header == '#') // then we have a header
{ // move body pointer to start of body
body = header ;
while(strncmp(body++,"\n\n", 2)) // "empty" line is end of header
{ if(body == lastTextChar) // then header ends without a body
{ NXRunAlertPanel("Eval", "No body to evaluate.\n", NULL,NULL,NULL) ;
[self message: ""] ;
return self ;
}
if(*body == '\n')
headerLineKnt++ ;
}
body++ ; // make body point 1 char beyond end of header,
}
else
{ header = "" ; // no header at all
firstHeaderLine = 1 ;
headerLineKnt = 0 ;
}
// The string tmpFile is both the name of the class we will create
// and the base name of the file, within /tmp, it will live in...
mkTempFile("/tmp",tmpFile) ;
sprintf(aStr,"/tmp/%s.m",tmpFile) ;
fp = fopen(aStr,"w+") ;
fprintf(fp,
"%.*s\n"
"#import <objc/Object.h>\n"
"@interface ODict: Object\n"
"+ insertKey: (char *) aKey value: (void *) data ;\n"
"+ removeKey: (char *) aKey ;"
"+ (void *) valueForKey: (char *) aKey ;\n"
"@end\n"
"@interface Eval: Object\n"
"+ clearGraphics ;\n"
"+ clearText ;\n"
"+ printf: (char *) format, ... ;\n"
"+ ps: (char *) format, ... ;\n"
"+ startPS ;\n"
"+ stopPS ;\n"
"@end\n"
"@interface EvalDoit: Object\n"
"+(void) doit ;\n"
"@end\n\n"
"@implementation EvalDoit\n"
"+ (void) doit\n"
"{\n"
"#line %d\n"
"%.*s\n"
"}\n"
"@end\n",
(int) ((unsigned) body - (unsigned) text), header,
headerLineKnt + firstHeaderLine,
(int) ((unsigned) lastTextChar - (unsigned) body) + 1,body) ;
fflush(fp) ;
fclose(fp) ;
if(mod = [[Module alloc] initPath: aStr])
{ if([self loadModule: mod])
{ [self message: "Executing..."] ;
exception.code = 0 ;
NX_DURING
// send the message...
objc_msgSend(objc_getClass("EvalDoit"), sel_getUid("doit")) ;
NX_HANDLER
exception = NXLocalHandler ;
NX_ENDHANDLER
// now remove the module
[self unloadModule: mod] ;
}
}
// free file we created
sprintf(aStr,"/tmp/%s.m",tmpFile) ;
unlink(aStr) ;
// free the module
[mod free] ;
[self message: ""] ;
return self ;
}
- evalObjCHelpPanel: sender ;
{ // evaluate selection in help panel
NXSelPt start, end ;
int textLen ;
char *textBuf ;
if(!helpText)
[self helpText: sender] ;
[helpText getSel:&start :&end] ;
textLen = end.cp - start.cp ;
textBuf = malloc(textLen + 1) ;
if(textBuf)
{ [helpText getSubstring:textBuf start:start.cp length:textLen] ;
[self evalObjC: textBuf length: textLen] ;
}
return self ;
}
- loadFromFile: sender ;
{ // Load a .m,.o, or .a file from disk.
static const char *loadFileTypes[] = {"m","o","a",NULL } ;
char buf[1024] ;
Module *mod ;
id openPanel = [OpenPanel new] ;
if(![openPanel runModalForTypes: loadFileTypes])
return nil ;
else
sprintf(buf,"%s/%s",[openPanel directory],*[openPanel filenames]) ;
if(mod = [[Module alloc] initPath: buf])
[self loadModule: mod] ;
[moduleBrowser loadColumnZero] ;
return self ;
}
- loadModule: (Module *) aMod ;
{ // Load module mod. If a module which equals: mod is already
// loaded, it and everything loaded after it must be unloaded,
// then mod is loaded, and finally everything loaded after
// must be reloaded.
int i,j,knt = [modList count] ;
for(i = knt ; i > 0 ; i--)
{ id currentMod = [modList objectAt: i - 1] ;
if([aMod equals: currentMod])
{ // unload mudules loaded after currentMod, then unload currentMod
// remove it from the moduelList and free it
for(j = 0 ; j < i ; j++)
[[modList objectAt: j] unload] ;
[[modList removeObjectAt: i - 1] free] ;
i-- ;
break ;
}
}
[modList insertObject: aMod at: i] ;
for( ; i >= 0 ; i--)
[[modList objectAt: i] load] ;
return self ;
}
- loadObjC:(id) pboard userData: (const char *) uBuf error: (char **) msg ;
{ // compile and load the pasteboard selection
char *text ;
const char *const *types ;
int i, textLen ;
BOOL found = NO ;
// fetch the data from pasteboard
types = [pboard types] ;
for(i = 0 ; types[i]; i++)
{ if(!strcmp(types[i], NXAsciiPboardType))
{ found = YES ;
break ;
}
}
if(!found) // no ascii found...
return self ;
[pboard readType:NXAsciiPboardType data:&text length:&textLen];
if(!text || !textLen) // nothing there...
return self ;
else
{ [self loadObjC: text length: textLen] ;
[pboard deallocatePasteboardData:text length:textLen];
}
[moduleBrowser loadColumnZero] ;
return self ;
}
- loadObjC: (char *) textBuf length: (int) textLen
{ // Load ObjC class(es) from textbuf.
// First, create a file...
int tmpFileLen ;
char tmpFile[20] = "/tmp/EvalXXXXXXXX" ;
int fd ;
// write text into a file in /tmp
mkTempFile(NULL,tmpFile) ;
tmpFileLen = strlen(tmpFile) ;
tmpFile[tmpFileLen] = '.' ; // add .m extension
tmpFile[tmpFileLen+1] = 'm' ;
tmpFile[tmpFileLen+2] = '\0' ;
fd = open(tmpFile,O_WRONLY | O_CREAT | O_TRUNC, 0666) ;
if((fd == -1) || (write(fd,textBuf,textLen) == -1))
{ // run an alert panel...
NXRunAlertPanel("Eval","Can't create temporary file: %s",NULL,NULL,NULL,tmpFile) ;
if(fd != -1) // if file was opened,
close(fd) ; // close it
return self ;
}
[self loadModule: [[Module alloc] initPath: tmpFile]] ;
unlink(tmpFile) ;
return self ;
}
- unloadModule: (Module *) aMod ;
{ // Unload module mod. If aMod is not on the top of
// the loadList, then everything loaded after it must
// first be unloaded before aMod may be unloaded, and
// finally these modules must be reloaded. Returns aMod.
int i,j,knt = [modList count] ;
for(i = knt ; i > 0 ; i--)
{ id currentMod = [modList objectAt: i - 1] ;
if([aMod equals: currentMod])
{ // unload mudules loaded after currentMod, then unload currentMod
// and remove it from the moduleList
for(j = 0 ; j < i ; j++)
[[modList objectAt: j] unload] ;
[modList removeObjectAt: i - 1] ;
i-- ;
break ;
}
}
i-- ;
for( ; i >= 0 ; i--)
[[modList objectAt: i] load] ;
return aMod ;
}
@endThese are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.