libs-gsweb/GSWeb/GSWElementID.m
Dave Wetzel bd96878757 rename all *.framework top level directories to their basename.
* GSWDatabase/WODisplayGroup.m
remove local NSAutoreleasePool
adjust makefiles



git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gsweb/trunk@30698 72102866-910b-0410-8b05-ffd578937521
2010-06-14 04:19:25 +00:00

909 lines
30 KiB
Objective-C

/** GSWElementID.m - <title>GSWeb: Class GSWElementID</title>
Copyright (C) 2004 Free Software Foundation, Inc.
Written by: Manuel Guesdon <mguesdon@orange-concept.com>
Date: Dec 2004
$Revision$
$Date$
This file is part of the GNUstep Web Library.
<license>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
</license>
**/
#include "config.h"
RCS_ID("$Id$")
#include "GSWeb.h"
/*
ElementID parts are stored in GSWElementIDPart.
We don't care too much about memory as the should be no more than 2 GSWElementIDs
created temporarily per context (the current elementID and the senderElementID
o About GSWElementIDPart:
_string: if elementID part is a string, _string is this string and _number
is the incremented part otherwise
_number: if the elementID is not a string, it's the lementID, otherwise it's the
incremented part of the string
_elementIDString: is a cache of the elementID string from first part to this part.
it is a mutable string to avoid too much string allocation/deallocation
_elementIDString_setStringIMP; is the IMP for _elementIDString -setString:
o About GSWElementID:
_parts: is a dynamic array of GSWElementIDPart. We first alloc
GSWElementID_DefaultElementPartsCount
_allocatedPartsCount: is the number of allocated parts
_partsCount: is the count of used parts
_builtPartsCount: is the number of GSWElementIDPart which have their
elementIDString built
_tmpString: is a working NSMutableString. There's no eed for locking since GSWElementID
is a 'mutable' object used only internally during a request life.
_tmpString_appendStringIMP: is the IMP for _tmpString -appendString:
_tmpString_setStringIMP: is the IMP for _tmpString -setString:
_elementIDString: is the current non mutable elementIDstring (it will save a string
creation when elementIDString is called more than one time without changes;
otherwise, it cost nothing as we have to create it anywat
_isSearchOverLastSenderIDString: is the parameter of last isSearchOver call. We cache isSearchOverLastSenderID
is it will be rused multiple times but we cache if the senderID is non mutable
(wich should always be the case).
_isSearchOverLastSenderID: is the elementID built from isSearchOverLastSenderIDString
_deleteElementsFromIndexIMP: IMP of -_deleteElementsFromIndex
_buildElementIMP: IMP of -_buildElement
Manuel Guesdon
*/
NSString* GSWElementIDPartDescription(GSWElementIDPart* part)
{
return [NSString stringWithFormat:@"<GSWElementIDPart %p: number: %d string: %@ elementID: %@ IMP: %p",
part,
part->_number,
part->_string,
part->_elementIDString,
part->_elementIDString_setStringIMP];
};
//====================================================================
@implementation GSWElementID
// 'Standard' GSWElementID class. Used to get IMPs from standardElementIDIMPs
static Class standardClass=Nil;
// List of standardClass IMPs
static GSWElementIDIMPs standardElementIDIMPs;
// Internal Selectors
static SEL deleteElementsFromIndexSelector = NULL;
static SEL buildElementPartsSelector = NULL;
static SEL appendStringSelector = NULL;
static SEL setStringSelector = NULL;
// Public Selectors
SEL appendZeroElementIDComponentSEL=NULL;
SEL deleteLastElementIDComponentSEL=NULL;
SEL incrementLastElementIDComponentSEL=NULL;
SEL appendElementIDComponentSEL=NULL;
SEL deleteAllElementIDComponentsSEL=NULL;
SEL isParentSearchOverForSenderIDSEL=NULL;
SEL isSearchOverForSenderIDSEL=NULL;
SEL elementIDStringSEL=NULL;
//--------------------------------------------------------------------
// Fill impsPtr structure with IMPs for elementID
void GetGSWElementIDIMPs(GSWElementIDIMPs* impsPtr,GSWElementID* elementID)
{
NSCAssert(elementID,@"No elementID in GetGSWElementIDIMPs()");
if ([elementID class]==standardClass)
{
memcpy(impsPtr,&standardElementIDIMPs,sizeof(GSWElementIDIMPs));
}
else
{
memset(&standardElementIDIMPs,0,sizeof(GSWElementIDIMPs));
impsPtr->_incrementLastElementIDComponentIMP =
[elementID methodForSelector:incrementLastElementIDComponentSEL];
impsPtr->_appendElementIDComponentIMP =
[elementID methodForSelector:appendElementIDComponentSEL];
impsPtr->_appendZeroElementIDComponentIMP =
[elementID methodForSelector:appendZeroElementIDComponentSEL];
impsPtr->_deleteAllElementIDComponentsIMP =
[elementID methodForSelector:deleteAllElementIDComponentsSEL];
impsPtr->_deleteLastElementIDComponentIMP =
[elementID methodForSelector:deleteLastElementIDComponentSEL];
impsPtr->_isParentSearchOverForSenderIDIMP =
(GSWIMP_BOOL)[elementID methodForSelector:isParentSearchOverForSenderIDSEL];
impsPtr->_isSearchOverForSenderIDIMP =
(GSWIMP_BOOL)[elementID methodForSelector:isSearchOverForSenderIDSEL];
impsPtr->_elementIDStringIMP =
[elementID methodForSelector:elementIDStringSEL];
};
};
//--------------------------------------------------------------------
// Initialize GSWElementID selectors
void InitializeGSWElementIDSELs()
{
static BOOL initialized=NO;
if (!initialized)
{
incrementLastElementIDComponentSEL = @selector(incrementLastElementIDComponent);
appendElementIDComponentSEL = @selector(appendElementIDComponent:);
appendZeroElementIDComponentSEL=@selector(appendZeroElementIDComponent);
deleteAllElementIDComponentsSEL = @selector(deleteAllElementIDComponents);
deleteLastElementIDComponentSEL=@selector(deleteLastElementIDComponent);
isParentSearchOverForSenderIDSEL = @selector(isParentSearchOverForSenderID:);
isSearchOverForSenderIDSEL = @selector(isSearchOverForSenderID:);
elementIDStringSEL = @selector(elementIDString);
initialized=YES;
};
};
//--------------------------------------------------------------------
+ (void) initialize
{
if (self == [GSWElementID class])
{
deleteElementsFromIndexSelector=@selector(_deleteElementsFromIndex:);
buildElementPartsSelector=@selector(_buildElementParts);
appendStringSelector=@selector(appendString:);
setStringSelector=@selector(setString:);
InitializeGSWElementIDSELs();
memset(&standardElementIDIMPs,0,sizeof(GSWElementIDIMPs));
[self setStandardClass:[GSWElementID class]];
};
};
//--------------------------------------------------------------------
+(void)setStandardClass:(Class)aStandardClass
{
// TODO MultiThread protection
standardClass=aStandardClass;
memset(&standardElementIDIMPs,0,sizeof(GSWElementIDIMPs));
standardElementIDIMPs._incrementLastElementIDComponentIMP =
[self instanceMethodForSelector:incrementLastElementIDComponentSEL];
standardElementIDIMPs._appendElementIDComponentIMP =
[self instanceMethodForSelector:appendElementIDComponentSEL];
standardElementIDIMPs._appendZeroElementIDComponentIMP =
[self instanceMethodForSelector:appendZeroElementIDComponentSEL];
standardElementIDIMPs._deleteAllElementIDComponentsIMP =
[self instanceMethodForSelector:deleteAllElementIDComponentsSEL];
standardElementIDIMPs._deleteLastElementIDComponentIMP =
[self instanceMethodForSelector:deleteLastElementIDComponentSEL];
standardElementIDIMPs._isParentSearchOverForSenderIDIMP =
(GSWIMP_BOOL)[self instanceMethodForSelector:isParentSearchOverForSenderIDSEL];
standardElementIDIMPs._isSearchOverForSenderIDIMP =
(GSWIMP_BOOL)[self instanceMethodForSelector:isSearchOverForSenderIDSEL];
standardElementIDIMPs._elementIDStringIMP =
[self instanceMethodForSelector:elementIDStringSEL];
};
//--------------------------------------------------------------------
/** Allocate or reallocate allocPartsCount elements. Previous parts are in *partsPtr;
previously allocated parts count is in *allocatedPartsCountPtr.
New parts is stored id *partsPtr and new allocated parts count in *allocatedPartsCountPtr
**/
void GSWElementIDRealloc(GSWElementIDPart** partsPtr,int* allocatedPartsCountPtr,int allocPartsCount)
{
//Really need ?
if (allocPartsCount>*allocatedPartsCountPtr)
{
int allocSize=allocPartsCount*sizeof(GSWElementIDPart);
int allocatedSize=(*allocatedPartsCountPtr)*sizeof(GSWElementIDPart);
GSWElementIDPart* newParts=NULL;
newParts=NSZoneMalloc(NSDefaultMallocZone(),allocSize);
NSCAssert2(newParts,@"Can't alloc %d parts (allocSize bytes)",
allocPartsCount,
allocSize);
if ((*allocatedPartsCountPtr)>0)
{
// Copy previous parts
memcpy(newParts,*partsPtr,allocatedSize);
//Dealloc previous parts
NSZoneFree(NSDefaultMallocZone(),*partsPtr);
};
// Zeroing new parts
memset(newParts+(*allocatedPartsCountPtr),0,
allocSize-allocatedSize);
*allocatedPartsCountPtr=allocPartsCount;
*partsPtr=newParts;
};
};
//--------------------------------------------------------------------
/** Returns a elementID **/
+(GSWElementID*)elementID
{
return [[[self alloc]init]autorelease];
};
//--------------------------------------------------------------------
/** Returns elementID initialized with 'string' **/
+(GSWElementID*)elementIDWithString:(NSString*)string
{
return [[[self alloc]initWithString:string]autorelease];
};
//--------------------------------------------------------------------
-(id)init
{
return [self initWithPartsCountCapacity:
GSWElementID_DefaultElementPartsCount];
};
//--------------------------------------------------------------------
/** Base initializer
partsCount is the number of parts to allocate
**/
-(id)initWithPartsCountCapacity:(int)partsCount
{
if ((self=[super init]))
{
_deleteElementsFromIndexIMP=[self methodForSelector:deleteElementsFromIndexSelector];
_buildElementPartsIMP=[self methodForSelector:buildElementPartsSelector];
if (partsCount>0)
{
GSWElementIDRealloc(&_parts,&_allocatedPartsCount,partsCount);
};
};
return self;
};
//--------------------------------------------------------------------
/** Initialize from 'string' elementID
**/
-(id)initWithString:(NSString*)string
{
int partsCount=0;
unichar* stringChars=NULL;
int length=0;
unichar* ptr=NULL;
unichar* stringEndPtr=NULL;
length=[string length];
if (length>0)
{
stringChars=NSZoneMalloc(NSDefaultMallocZone(),(length+1)*sizeof(unichar));
NSAssert1(stringChars,@"Can't allocate memeory for string of length %d",length);
[string getCharacters:stringChars];
stringChars[length]=(unichar)0;
ptr=stringChars;
stringEndPtr=stringChars+length;
partsCount=1;
while(ptr<stringEndPtr)
{
if (*ptr=='.')
partsCount++;
ptr++;
};
partsCount+=16; // keeps space for extensions
}
else
partsCount=GSWElementID_DefaultElementPartsCount;
if ((self=[self initWithPartsCountCapacity:partsCount]))
{
if (stringChars)
{
GSWElementIDPart* part=_parts;
unichar* startPartPtr=NULL;
unichar* endPartPtr=NULL;
startPartPtr=stringChars;
// For each part, we'll find start and end of part, if it is all numeric
// or a string (+numeric part).
while(startPartPtr<stringEndPtr)
{
int number=0; // result numeric part
BOOL isAllNumeric=YES; // is entirely numeric ?
unichar* numericIndexPtr=NULL; // end numeric part pointer
ptr=startPartPtr;
endPartPtr=NULL; // end part pointer
while(ptr<stringEndPtr)
{
// End of part ?
if (*ptr=='.')
{
endPartPtr=ptr-1;
break;
}
else if (isdigit(*ptr)) // Is digit ?
{
// (re-)start calculating numeric part
if (!isAllNumeric && !numericIndexPtr)
numericIndexPtr=ptr;
number=number*10+(*ptr-'0');
}
else // Not a digit ?
{
//Stop numeric calculation
isAllNumeric=NO;
numericIndexPtr=NULL;
};
ptr++;
};
// no '.' found ==> last part
if (!endPartPtr)
endPartPtr=stringEndPtr-1;
// Entirely numeric ?
if (isAllNumeric)
{
// number is calculated
part->_number=number;
}
else
{
// Numeric part (if any) is calculated
if (numericIndexPtr)
part->_number=number;
else
numericIndexPtr=stringEndPtr+1;
ASSIGN(part->_string,([NSString stringWithCharacters:startPartPtr
length:(numericIndexPtr-1)-startPartPtr+1]));
};
//We could also build part elementIDString but I'm not sure it's interesting as
//initializing GSWElementID from string is mainly to be used for 'statics' elementIDs
//Assigning _elementIDString at the end should be sufficient.
_partsCount++;
part++;
startPartPtr=endPartPtr+2;//skip dot
};
};
};
ASSIGN(_elementIDString,string);
return self;
};
//--------------------------------------------------------------------
/** dealloc object **/
-(void)dealloc
{
if (_allocatedPartsCount>0)
{
int i=0;
GSWElementIDPart* part=NULL;
// allocated parts even if not used may keey _elementIDString
for(i=0,part=_parts;i<_allocatedPartsCount;i++,part++)
{
DESTROY(part->_string);
DESTROY(part->_elementIDString);
};
NSZoneFree(NSDefaultMallocZone(),_parts);
};
DESTROY(_tmpString);
DESTROY(_elementIDString);
DESTROY(_isSearchOverLastSenderIDString);
DESTROY(_isSearchOverLastSenderID);
[super dealloc];
};
//--------------------------------------------------------------------
/** Init from coder **/
-(id)initWithCoder:(NSCoder*)decoder
{
NSString* aString=nil;
[decoder decodeValueOfObjCType:@encode(id)
at:&aString];
return [self initWithString:aString];
};
//--------------------------------------------------------------------
/** Encode into coder **/
-(void)encodeWithCoder:(NSCoder*)encoder
{
NSString* aString=[self elementIDString];
[encoder encodeValueOfObjCType:@encode(id)
at:&aString];
};
//--------------------------------------------------------------------
/** Returns a copy **/
-(id)copyWithZone:(NSZone*)zone
{
int i=0;
GSWElementID* clone = [[[self class] alloc]initWithPartsCountCapacity:_partsCount+16];
NSAssert(clone,@"No clone of GSWElementID");
for(i=0;i<_partsCount;i++)
{
GSWElementIDPart* selfPart=_parts+i;
GSWElementIDPart* clonePart=clone->_parts+i;
ASSIGN(clonePart->_string,selfPart->_string);
clonePart->_number=selfPart->_number;
//Should we copy part caches ? I don't think is interesting
};
//_builtPartCount stay to 0;
// Copy pre-built _elementIDString if any
ASSIGN(clone->_elementIDString,_elementIDString);
return clone;
};
//--------------------------------------------------------------------
-(NSString*)description
{
return [self elementIDString];
};
//--------------------------------------------------------------------
/** Returns YES if we should stop search (if self is greater than senderID)
For better performences, senderID should be an immutable string
**/
-(BOOL)isSearchOverForSenderID:(NSString*)senderID
onParent:(BOOL)onParentFlag
{
BOOL over=NO;
if (senderID == nil)
[NSException raise:NSInvalidArgumentException
format:@"compare with nil"];
else
{
int count=0;
int i=0;
GSWElementID* senderElementID=nil;
GSWElementIDPart* selfElementPart=NULL;
GSWElementIDPart* senderElementPart=NULL;
//We can make a == test because we cache only immutable senderIDs
if (senderID==_isSearchOverLastSenderIDString)
senderElementID=_isSearchOverLastSenderID;
else
{
senderElementID=[[self class]elementIDWithString:senderID];
//Cache it if it is not mutable
if ([senderID isKindOfClass:[NSMutableString class]])
{
// NSWarnLog(@"Performances: senderID passed to -isSearchOverForSenderID: is a mutable string");
}
else
{
ASSIGN(_isSearchOverLastSenderIDString,senderID);
ASSIGN(_isSearchOverLastSenderID,senderElementID);
};
};
count=min((onParentFlag ? _partsCount-1 : _partsCount),senderElementID->_partsCount);
for(i=0,selfElementPart=_parts,senderElementPart=senderElementID->_parts;
i<count && !over;
i++,selfElementPart++,senderElementPart++)
{
if (selfElementPart->_string)
{
if (senderElementPart->_string) // string & string
{
NSComparisonResult cResult=[selfElementPart->_string compare:senderElementPart->_string];
if (cResult==NSOrderedDescending)
over=YES;
else if (cResult==NSOrderedSame)
{
if (selfElementPart->_number>senderElementPart->_number)
over=YES;
else if (selfElementPart->_number<senderElementPart->_number) // Not over => break
break;
// else continue
}
else //NSOrderedAscending: not over => break
break;
}
else // string and num
{
//Shouldn't happen logically as the root of 2 elementIDs should be the same
//Anyway, we consider not over and break here
};
}
else
{
if (senderElementPart->_string) // num & string
{
//Shouldn't happen logically as the root of 2 elementIDs should be the same
//Anyway, we consider not over and break here
}
else // num & num
{
if (selfElementPart->_number>senderElementPart->_number)
over=YES;
else if (selfElementPart->_number<senderElementPart->_number)
break; //not over
// else continue
};
};
};
};
return over;
}
//--------------------------------------------------------------------
/** Returns YES if we should stop search (if self is greater than senderID)
For better performences, senderID should be an immutable string
**/
-(BOOL)isSearchOverForSenderID:(NSString*)senderID
{
//NSLog(@"ELEMENTID: [elementID isSearchOverForSenderID:@\"%@\"];",senderID);
return [self isSearchOverForSenderID:senderID
onParent:NO];
};
//--------------------------------------------------------------------
/** Returns YES if we should stop search (if self is greater than senderID)
For better performences, senderID should be an immutable string
**/
-(BOOL)isParentSearchOverForSenderID:(NSString*)senderID
{
//NSLog(@"ELEMENTID: [elementID isParentSearchOverForSenderID:@\"%@\"];",senderID);
return [self isSearchOverForSenderID:senderID
onParent:YES];
};
//--------------------------------------------------------------------
/** Build parts _elementIDString **/
-(void)_buildElementParts
{
static NSString* preBuiltDotPlusNum[] = {
@".0", @".1", @".2", @".3", @".4", @".5", @".6", @".7", @".8", @".9",
@".10", @".11", @".12", @".13", @".14", @".15", @".16", @".17", @".18", @".19",
@".20", @".21", @".22", @".23", @".24", @".25", @".26", @".27", @".28", @".29",
@".30", @".31", @".32", @".33", @".34", @".35", @".36", @".37", @".38", @".39",
@".40", @".41", @".42", @".43", @".44", @".45", @".46", @".47", @".48", @".49",
@".50", @".51", @".52", @".53", @".54", @".55", @".56", @".57", @".58", @".59",
@".60", @".61", @".62", @".63", @".64", @".65", @".66", @".67", @".68", @".69" };
static int preBuiltDotPlusNumCount = sizeof(preBuiltDotPlusNum)/sizeof(NSString*);
NSAssert1(_builtPartCount>=0,@"_builtPartCount=%d",_builtPartCount);
if (_partsCount>0)
{
GSWElementIDPart* part=NULL;
if (_builtPartCount<_partsCount)
{
int i=0;
// No working string created ?
if (!_tmpString)
{
// Create working string and cache -appendString: IMP
_tmpString=(NSMutableString*)[NSMutableString new]; //Retained !
_tmpString_appendStringIMP=[_tmpString methodForSelector:appendStringSelector];
_tmpString_setStringIMP=[_tmpString methodForSelector:setStringSelector];
};
// Start from previous built element if one otherwise, start from empty string
part=_parts+_builtPartCount-1;
(*_tmpString_setStringIMP)(_tmpString,appendStringSelector,
(_builtPartCount>0 ?
(NSString*)(part->_elementIDString) : (NSString*)@""));
for(i=_builtPartCount,part=_parts+_builtPartCount;i<_partsCount;i++,part++)
{
if (part->_string)
{
if (i>0)
{
(*_tmpString_appendStringIMP)(_tmpString,
appendStringSelector,@".");
};
(*_tmpString_appendStringIMP)(_tmpString,
appendStringSelector,part->_string);
if (part->_number>0)
{
(*_tmpString_appendStringIMP)(_tmpString,
appendStringSelector,
GSWIntToNSString(part->_number));
};
}
else
{
if (i>0)
{
if (part->_number<preBuiltDotPlusNumCount)
{
// Save a appendString :-)
(*_tmpString_appendStringIMP)(_tmpString,
appendStringSelector,
preBuiltDotPlusNum[part->_number]);
}
else
{
(*_tmpString_appendStringIMP)(_tmpString,
appendStringSelector,
@".");
(*_tmpString_appendStringIMP)(_tmpString,
appendStringSelector,
GSWIntToNSString(part->_number));
};
}
else
{
(*_tmpString_appendStringIMP)(_tmpString,
appendStringSelector,
GSWIntToNSString(part->_number));
};
};
if (part->_elementIDString)
{
(*part->_elementIDString_setStringIMP)(part->_elementIDString,
setStringSelector,
_tmpString);
}
else
{
part->_elementIDString=[_tmpString mutableCopy]; //Retained !
part->_elementIDString_setStringIMP=[part->_elementIDString
methodForSelector:setStringSelector];
};
};
_builtPartCount=_partsCount;
};
part=_parts+_partsCount-1;
ASSIGN(_elementIDString,([NSString stringWithString:part->_elementIDString]));
};
};
//--------------------------------------------------------------------
/** Returns elementID string representation or empty string if there's not
elements **/
-(NSString*)elementIDString
{
NSString* elementIDString=@"";
if (_partsCount>0)
{
if (!_elementIDString) // Not alreday built ?
(*_buildElementPartsIMP)(self,buildElementPartsSelector);
elementIDString=_elementIDString;
AUTORELEASE(RETAIN(elementIDString));
};
return elementIDString;
}
//--------------------------------------------------------------------
/** Deletes element parts starting at fromIndex. **/
-(void)_deleteElementsFromIndex:(int)fromIndex
{
int i=0;
GSWElementIDPart* part=NULL;
NSAssert1(fromIndex>=0,@"fromIndex (%d) <0",
fromIndex);
NSAssert2(fromIndex<_partsCount,@"fromIndex (%d) >= _partsCount (%d)",
fromIndex,_partsCount);
for(i=fromIndex,part=_parts+fromIndex;i<_partsCount;i++,part++)
{
DESTROY(part->_string);
part->_number=0;
};
// update cache state information
if (_builtPartCount>fromIndex)
_builtPartCount=fromIndex;
DESTROY(_elementIDString);
_partsCount=fromIndex;
}
//--------------------------------------------------------------------
/** empties elementID **/
-(void)deleteAllElementIDComponents
{
if (_partsCount>0)
(*_deleteElementsFromIndexIMP)(self,deleteElementsFromIndexSelector,0);
};
//--------------------------------------------------------------------
/** Deletes last elementID part **/
-(void)deleteLastElementIDComponent
{
if (_partsCount>0)
(*_deleteElementsFromIndexIMP)(self,deleteElementsFromIndexSelector,_partsCount-1);
};
//--------------------------------------------------------------------
/** Increments last elementID part **/
-(void)incrementLastElementIDComponent
{
if (_partsCount == 0) {
return;
}
GSWElementIDPart* part=NULL;
// Update part number
part=_parts+_partsCount-1;
part->_number++;
// update cache state information
if (_builtPartCount>=_partsCount)
_builtPartCount=_partsCount-1;
DESTROY(_elementIDString);
};
//--------------------------------------------------------------------
/** Append zero element ID after last elementID part **/
-(void)appendZeroElementIDComponent
{
GSWElementIDPart* part=NULL;
if (_partsCount>=_allocatedPartsCount)
GSWElementIDRealloc(&_parts,&_allocatedPartsCount,
_allocatedPartsCount+GSWElementID_DefaultElementPartsCount);
// Set to new part
part=_parts+_partsCount;
part->_number=0;
// update cache state information
DESTROY(_elementIDString);
// Increments parts count
_partsCount++;
};
//--------------------------------------------------------------------
/** Append 'element' element ID after last elementID part
You should avoid element ending with digits.
**/
-(void)appendElementIDComponent:(NSString*)element
{
int elementLength=0;
GSWElementIDPart* part=NULL;
elementLength=[element length];
if (elementLength==0)
{
NSWarnLog(@"append empty empty element");
}
else
{
// do we really need this stuff?? davew
// if (isdigit([element characterAtIndex:elementLength-1]))
// {
// NSWarnLog(@"You'll may get problems if you use anElementID which ends with digit(s) like you do: '%@'",
// element);
// };
}
if (_partsCount>=_allocatedPartsCount)
GSWElementIDRealloc(&_parts,&_allocatedPartsCount,
_allocatedPartsCount+GSWElementID_DefaultElementPartsCount);
// Set to new part
part=_parts+_partsCount;
part->_number=0;
ASSIGNCOPY(part->_string,element);
NSDebugMLLog(@"GSWElementID",@"Part #%d: %@",
_partsCount,GSWElementIDPartDescription(part));
// update cache state information
DESTROY(_elementIDString);
// Increments parts count
_partsCount++;
};
//--------------------------------------------------------------------
//NDFN
/** Returns parent element ID **/
-(NSString*)parentElementIDString
{
NSString* elementIDString=@"";
if (_partsCount>1)
{
GSWElementIDPart* part=NULL;
if (_builtPartCount<(_partsCount-1))
(*_buildElementPartsIMP)(self,buildElementPartsSelector);
part=_parts+_partsCount-2;
elementIDString=[NSString stringWithString:part->_elementIDString];
};
return elementIDString;
};
//--------------------------------------------------------------------
//NDFN
/** returns number of element ID parts **/
-(int)elementsCount
{
return _partsCount;
};
@end