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 ; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.