ftp.nice.ch/pub/next/science/chemistry/BeakerBoy.0.31.s.tar.gz#/BeakerBoy.0.31.s/FileManager.subproj/BBPdbFilter.m

This is BBPdbFilter.m in view mode; [Download] [Up]

/* BBPdbFilter.m				 
 *
 * This format filter does handle read/write of molecules in the
 * Protein Data Bank (.pdb or .PDB) fileformat.
 *
 * For interface-info see the header file. The comments in this file mostly
 * cover only the real implementation details.
 *
 * Written by: 		Thomas Engel
 * Created:    		01.11.1994 (Copyleft)
 * Last modified: 	01.11.1994
 */

#import "BBPdbFilter.h"
#import "BBFileFilterManager.h"
#import "../BBAppManager.h"
#import "../AtomLibrary.subproj/BBAtomLibraryManager.h"

#import "../BBBeaker.h"
#import "../BBMolecule.h"
#import "../BBAtom.h"
#import "../BBBond.h"

#import <misckit/MiscString.h>

#define MYBUFFERSIZE	500

#define SINGLEBONDTOKEN				"E"
#define SINGLEFIXEDBONDTOKEN		"Ef"
#define DOUBLEBONDTOKEN				"D"
#define TRIPLEBONDTOKEN				"T"
#define DOUBLEDELOCATEDBONDTOKEN	"Dd"

// I hate statics but here they might be useful.
// The other variables have been added to the intercase to allow debugging.

static char lineBuffer[MYBUFFERSIZE];
static FILE	*inStream;

@implementation BBPdbFilter

- (float)canReadFile:(const char*)filename
{
	// Let's see if we can handle the file. Well this is a stupid check.
	// Right now we only check the file extention. If its "pdb" or "PDB" we
	// will do it.
	// Normally we should return (0, 0.5, 1) according to the percentage of
	// data we understand.
	
	id		pathString;
	id		aString;
	float	answer;
	
	pathString = [MiscString new];
	[pathString setPath:filename];
	aString = [pathString fileExtension];
	
	if( [aString casecmp:"pdb"] == 0 )
			answer = (float)YES;
	else	answer = (float)NO;
	
	[pathString free];
	[aString free];
	
	return answer;
}

- readBeaker:aBeaker fromFile:(const char*)filename
{	
	// A simple parser for Protein Data Bank Molecules.
	// The tokenList is only defined as long as its data is not allready
	// parsed or it contains the parts that have to be parsed. Freeing
	// the list is not enough! We have to reset the id to nil to make the
	// check work properly. 

	BOOL goAhead = YES;
	
	inStream = fopen( filename, "r" );
	if( inStream == NULL ) return self;
		
	// So lets parse the data get one line and do it. We will
	// not take care of all the settings! We'll say that the current line
	// is already parsed because we wan another one to get read.
	
	mol = [BBMolecule new];
	
	theLine = [MiscString new];
	tokenList = nil;
	
	do
	{
		// Read a new line if no already done. Let the MiscString create the
		// tokenList. We will only free it.
		
		if( !tokenList )
		{
			if( !fgets( lineBuffer, MYBUFFERSIZE, inStream )) break;
			[theLine setStringValue:lineBuffer];
			tokenList = [theLine tokenize:" \t\n\r" into:nil];
		}
		// Now lets read till we have to stop. 
		
		goAhead = [self readNewLine];
	}
	while( goAhead );
	
	[aBeaker addMolecule:mol];
	[theLine free];
	fclose( inStream );

	return self;
}

- (BOOL)readNewLine
{
	// Lets check the tokens..skip empty lines and comments
	// theLine and tokenList are already set acording to our lineBuffer
	// If there is nothing to parse we want to see the next line..

	BOOL	goAhead = YES;
	id		token;
	id		aString;
		
	token = [tokenList objectAt:0];
	
	if( [tokenList count] == 0 )
	{
		[[tokenList freeObjects] free];
		tokenList = nil;
	}
	else if( [token compareStr:"COMPND"] == 0 )
	{
		aString = [theLine substringFrom:11 to:70];
		[aString trimTailWhiteSpaces];
		[(BBMolecule *)mol setName:[aString stringValue]];
		[aString free];
		[[tokenList freeObjects] free];
		tokenList = nil;
	}
	else if( [token compareStr:"ATOM"] == 0 )
	{
		[[tokenList freeObjects] free];		
		tokenList = nil;
		goAhead = [self readAtomData];
	}
	else if( [token compareStr:"HETATM"] == 0 )
	{
		[[tokenList freeObjects] free];		
		tokenList = nil;
		goAhead = [self readAtomData];
	}
	else if( [token compareStr:"CONECT"] == 0 ) 
	{
		[[tokenList freeObjects] free];		
		tokenList = nil;
		// goAhead = [self readBondData];
	}
	
	// Currently we do not evaluate every possible token.
	// We will simple ingore everything else and just free the tokenList
	// if this has not already happened.
	
	else
	{
		[[tokenList freeObjects] free];
		tokenList = nil;
	}
	return goAhead;
}

- (BOOL)readAtomData
{
	// Reading the atom data
	// Right here we will continue to read lines until a new token comes.
	// As a token we will take everything that does not match a atom definition
		
	id		anAtom;
	id		basicAtom;
	id		atomLibrary;		
	id		string;
	id		symbol;
	
	atomLibrary = [[NXApp delegate] atomLibrary];

	// Well now let's check the single details of the current theLine...
	// the ATOM entries..
	
	symbol = [theLine substringFrom:13 to:16];
	[symbol trimTailWhiteSpaces];
	string = [MiscString new];
	[self checkSymbol:symbol andUpdate:string];
	
	// We have to find the basicAtom too.
		
	anAtom = [BBAtom new];
	basicAtom = [atomLibrary findBasicAtomWithSymbol:[symbol stringValue]];
	[anAtom setMotherAtom:basicAtom];
	
	[anAtom setSymbolExtention:[string stringValue]];
	[string free];
	[symbol free];
	
	string = [theLine substringFrom:31 to:38];
	[string trimTailWhiteSpaces];
	[anAtom setXPos:[string doubleValue]];
	[string free];
	
	string = [theLine substringFrom:39 to:46];
	[string trimTailWhiteSpaces];
	[anAtom setYPos:[string doubleValue]];
	[string free];

	string = [theLine substringFrom:47 to:54];
	[string trimTailWhiteSpaces];
	[anAtom setZPos:[string doubleValue]];
	[string free];
			
	[mol addAtom:anAtom];
		
	return YES;
}

- (BOOL)readBondData
{
	// Reading the bond data.
	// Right here we will continue to read lines until a new token comes.
	// As a token we will take everything that does not match a bond definition
		
	BOOL 	goAhead = YES;
	BBBond * aBond;
	id		atomList;
	id		fromAtom;
	id		toAtom;
	id		token;
	char	type;
	
	atomList = [mol atomList];

		// Check for comments, blank lines and new tokens.
		// If there are not enough elements it has to be a token.
		// Well kind of stupid but it should work for every LOOK mol


		// otherwise lets init a new bond from this line:
		// We will set the name to some usefull value.
		
		aBond = [BBBond new];
		
		if( [token compareStr:SINGLEBONDTOKEN] == 0 )
			type = BOND_SINGLE;
		else if( [token compareStr:SINGLEFIXEDBONDTOKEN] == 0 )
			type = BOND_SINGLE;
		else if( [token compareStr:DOUBLEBONDTOKEN] == 0 )
			type = BOND_DOUBLE;
		else if( [token compareStr:TRIPLEBONDTOKEN] == 0 )
			type = BOND_TRIPLE;
		else if( [token compareStr:DOUBLEDELOCATEDBONDTOKEN] == 0 )
			type = BOND_DOUBLE_DELOCATED;
		else
			type = BOND_SINGLE;
			
		fromAtom = [atomList objectAt:[[tokenList objectAt:1] intValue]];
		toAtom = [atomList objectAt:[[tokenList objectAt:2] intValue]];
		
		[aBond connect:fromAtom to:toAtom with:type];
	
		// We will use the token string object to compose our Bond name.
		
		[token setStringValue:[fromAtom symbol]];		
		[token catStringValue:"±"];		
		[token catStringValue:[toAtom symbol]];		
		[aBond setName:[token stringValue]];
		
		[mol addBond:aBond];
		
		// Lets free the list and make the line as read. We don't need it
		// anymore

		[[tokenList freeObjects] free];
		tokenList = nil;

	return YES;
}

- checkSymbol:symbol andUpdate:symbolExtention
{
	// PDB symbol contain counts and special symbols at their end.
	// We will move them to the symbolExtentions.
	
	int	i;
	id	aString;
	
	for( i=0; i<[symbol length]; i++ )
		if( [symbol charAt:i] < 'A' ||
			[symbol charAt:i] > 'z' ||
			([symbol charAt:i] < 'a' && i > 0 ))
			break;

	aString = [symbol substringFrom:i to:[symbol length]-1];
	[symbolExtention setStringValue:[aString stringValue]];
	[aString free];
	
	aString = [symbol substringFrom:0 to:i-1];
	[symbol setStringValue:[aString stringValue]];
	[aString free];
	
	return self;
}

- writeBeaker:aBeaker toFile:(const char *)filename
{
	return self;
}

@end

/*
 * History: 01.11.94 Created this object to parse ATOm and BOND info only.
 *
 *
 * Bugs: - many PDB marks not supported
 */

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.