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.