This is Eval-DotH.m in view mode; [Download] [Up]
#import "Eval.h" extern int unused ; @implementation Eval(DotH) - buildDotH:(char *) textBuf length:(int)textLen ; { // Build anObjC interface from the (not necessarily // null-terminated) text in textBuf of length textLen. // Normally, this file will have a .h extension, but // this is not checked for. // If there is a #pragma .hfile somePath, save the .h // into somePath, otherwise pop up a save panel to get // the path. // // Every line of the form #pragma .h ``whatever'' has // ``whatever'' copied into the resulting .h. // // Essentially, this method is just a state machine with each // state specified by a combiation of boolean variables // such as "inComment", "inMethodDef", and so on. The // variable inImp (inImplementation) is more complex, as // it is fairly hard to pick out the parts of an @implementation // that belong in the header file. inImp is set to 0 when // we are not scanning an @implementation ...., otherwise it takes // on an integer value specifying one of these states: // (where W = required whitespace (may include comments) // w = optional whitespace (may include comments) // C = required, sequence of nonwhite chars // N = anything other than a ")" // X = anything other that a "(" or a ":" // :,(,) ... exact matches // state: 123 456 // @implementationWCw:wCwC // state: 123 7 // @implementationWCw(N) // state: 123 // @implementationWCWX NXStream *inStream = NXOpenMemory(textBuf, textLen, NX_READONLY) ; NXStream *dotHStream = NXOpenMemory(NULL, 0, NX_READWRITE) ; char buf[1024], *memBuf ; char *dotHFileName = NULL ; int i, len, depthKnt = 0, statementStart = 0 ; BOOL newline ; // do I really care? BOOL inComment = NO, inSlashComment = NO, inString = NO, inStatement = NO, inMethodSig = NO, semiColon = NO, inIvar = NO, eqInStatement = NO, output = YES ; int inImp = 0 ; do { newline = EvalGets(inStream,buf) ; len = strlen(buf) ; if(buf[0] == '#' && !inComment) { // found # in column 1: now look for a pragma i = 1 ; while(buf[i] && isspace(buf[i])) i++ ; // span space if(!strncmp(&buf[i],"pragma ",7)) { // pragma found...now look for .h i += 7 ; while(buf[i] && isspace(buf[i])) i++ ; // span space if(!strncmp(&buf[i],".h ",3)) { // .h found: write #pragma .h to outstream i += 3 ; while(buf[i] && isspace(buf[i])) i++ ; // span space NXWrite(dotHStream,&buf[i],len - i) ; NXPutc(dotHStream,'\n') ; while(newline && buf[len-1] == '\\') { // while there is a continuation line... newline = EvalGets(inStream,buf) ; len = strlen(buf) ; NXWrite(dotHStream,buf,len) ; NXPutc(dotHStream,'\n') ; } } else if(!strncmp(&buf[i],".hfile ",7)) { // .hfile found: grab the dotHFileName which should follow... int j ; i += 7 ; while((i < len) && (buf[i] == '\t' || buf[i] == ' ')) i++ ; // span white space if(buf[i] == '"') i++ ; // if there is a quote, skip over it j = i ; while(buf[j] && !isspace(buf[j]) && buf[j] != '"') j++ ; dotHFileName = alloca(j - i + 1) ; strncpy(dotHFileName,&buf[i],j-i) ; dotHFileName[j-i] = '\0' ; } } } else { inString = NO ; // ansi C forbids newline in string inSlashComment = NO ; for(i = 0 ; i < len ; i++) { switch(buf[i]) { case '"': if(output && !inComment) { if(inString) { if( ((i > 0) && (buf[i-1] != '\\') ) || ((i > 1) && (buf[i-1] == '\\') && (buf[i-2] != '\\') )) inString = NO ; } else if(i == 0) inString = YES ; else if( !( (i > 0) && (len > 2) && (buf[i - 1] == '\'') && (buf[i+1] = '\'') )) // i.e. if not a character constant, '"' inString = YES ; } break ; case '/': if(!inString) { if(!inSlashComment && inComment && (i > 0) && (buf[i - 1] == '*')) inComment = NO ; // end of a slash-star,star-slash comment else if(!inSlashComment && !inComment && (i < (len - 1)) && (buf[i+1] == '*')) inComment = YES ; // start of a slash-star,star-slash comment else if(!inSlashComment && !inComment && (i < (len -1)) && (buf[i + 1] == '/')) inSlashComment = YES ; } break ; case '{': if(output && !inSlashComment && !inComment && !inString) { depthKnt++ ; if(inImp) { inImp = 0 ; inIvar = YES ; } else if(inMethodSig) { inMethodSig = NO ; if(!semiColon) { // we must add a semicolon NXPutc(dotHStream,';') ; NXPutc(dotHStream,'\n') ; NXSeek(dotHStream, 0, NX_FROMEND) ; } } else if(inStatement && (depthKnt == 1) && !eqInStatement) { // This may be a function def. Our algorithm to // recognize a function declarator is any statement that // terminates with an un-embedded '{' , and which // does not begin with struct,union, or typedef, and which // does not contain an = character (other than inside a comment) // This algortithm will not recognize K&R style function declarators. NXStream *tmpStream = NXOpenMemory(NULL, 0, NX_READWRITE) ; int currentPnt = NXTell(inStream) ; int statementLen = currentPnt - 1 - len + i - statementStart ; // copy statement to tmpStream NXSeek(inStream,statementStart,NX_FROMSTART) ; for(i = 0 ; i < statementLen ; i++) NXPutc(tmpStream,NXGetc(inStream)) ; // reset inStream NXSeek(inStream,currentPnt,NX_FROMSTART) ; // we must add a semicolon NXPutc(tmpStream,' ') ; NXPutc(tmpStream,'\0') ; // now see if we have a function def...it might also // be a struct, union, or typedef... NXGetMemoryBuffer(tmpStream,&memBuf,&unused,&unused) ; if(strncmp(memBuf,"struct ",7) && strncmp(memBuf,"union ",6) && strncmp(memBuf,"typedef ",8)) { // we conclude that this is a function def NXWrite(dotHStream,memBuf,strlen(memBuf)) ; NXWrite(dotHStream," ;\n",3) ; } NXCloseMemory(tmpStream,NX_FREEBUFFER) ; inStatement = eqInStatement = NO ; } } break ; case '}': if(output && !inSlashComment && !inComment && !inString) { depthKnt-- ; if(depthKnt < 0) depthKnt = 0 ; if(inIvar && (depthKnt == 0)) { NXWrite(dotHStream,"}\n\n",3) ; inIvar = 0 ; inStatement = NO ; } } break ; case '=': if(output && inStatement && !inComment && !inSlashComment) eqInStatement = YES ; break ; case '@': if(!inSlashComment && !inComment && !inString) { if(output && !strncmp(&buf[i+1],"implementation ",14)) { inImp = 1 ; i += 15 ; // we point to blank after implementation NXWrite(dotHStream,"@interface",10) ; } else if(!strncmp(&buf[i+1],"end",3) && (buf[i+4] == '\0' || isspace(buf[i+4]))) { inImp = 0 ; if(output) NXWrite(dotHStream,"@end",4) ; output = YES ; i += 4 ; } else if((!strncmp(&buf[i+1],"interface ",10)) || (!strncmp(&buf[i+1],"protocol ",9))) { // Skip @protocol or @interface sections that show // up in the implementation files. Setting output to // NO turns off all output (except preprocessor stuff) // until @end is seen. output = NO ; } } break ; case '+': case '-': if(output && (depthKnt == 0) && !inSlashComment && !inComment && !inString && !inStatement) { inMethodSig = YES ; inImp = 0 ; semiColon = NO ; } break ; case ';': if(output && !inSlashComment && !inComment && !inString) { inStatement = eqInStatement = NO ; // end of statement inImp = 0 ; if(inMethodSig) // note that medthod signature has semicolon at end semiColon = YES ; } break ; case ' ': case '\t': /* whitespace !*/ if(output && !inSlashComment && !inComment && !inString) { switch(inImp) // run our state machine for @implementation { case 2: inImp = 3 ; break ; case 5: inImp = 6 ; break ; default: break ; // otherwise no state transitions } } break ; default: if(output && !inSlashComment && !inComment && !inString && !inMethodSig) { switch(inImp) { case 0: if(!inStatement) { inStatement = YES ; statementStart = NXTell(inStream) - len + i - 1 ; } break ; case 1: inImp = 2 ; break ; case 2: case 3: switch(buf[i]) { case ':': inImp = 4 ; break ; case '(': inImp = 7 ; break ; default : if(inImp == 3) { inImp = 0 ; inStatement = YES ; statementStart = NXTell(inStream) - len + i - 1 ; } break ; } break ; case 4: inImp = 5 ; break ; case 6: inImp = 0 ; inStatement = YES ; statementStart = NXTell(inStream) - len + i - 1 ; break ; case 7: if(buf[i] == ')') { NXWrite(dotHStream,")\n",2) ; inImp = 0 ; } break ; } break ; } } if(output && (inMethodSig || inImp || inIvar)) NXPutc(dotHStream,buf[i]) ; } if(output && ((inMethodSig || inImp || inIvar) && newline)) { switch(inImp) // run our state machine for @implementation { case 2: inImp = 3 ; break ; case 5: inImp = 6 ; break ; default: break ; // otherwise no state transitions } NXPutc(dotHStream,'\n') ; } } } while(!NXAtEOS(inStream)) ; NXPutc(dotHStream,'\n') ; NXCloseMemory(inStream,NX_SAVEBUFFER) ; if(!dotHFileName) { id savePanel = [SavePanel new] ; if([savePanel runModalForDirectory: NULL file: NULL]) dotHFileName = (char *) [savePanel filename] ; } if(dotHFileName) { if(NXSaveToFile(dotHStream, dotHFileName) == -1) NXRunAlertPanel("Eval","Couldn't create .h file: %s",NULL,NULL,NULL,dotHFileName) ; } NXCloseMemory(dotHStream,NX_FREEBUFFER) ; return self ; } - buildDotH:(id) pboard userData: (const char *) uBuf error: (char **) msg ; { // build .h file from the 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 buildDotH: text length: textLen] ; [pboard deallocatePasteboardData:text length:textLen]; } return self ; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.