This is FormatScanner.m in view mode; [Download] [Up]
/*
Copyright (C) 1996
Ovidiu Predescu <ovidiu@bx.logicnet.ro>
Mircea Oancea <mircea@jupiter.elcom.pub.ro>
Author: Ovidiu Predescu <ovidiu@bx.logicnet.ro>
This file is part of the FoundationExtensions library.
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; see the file COPYING.LIB.
If not, write to the Free Software Foundation,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <ctype.h>
#include "common.h"
#include <Foundation/NSDictionary.h>
#include <Foundation/NSString.h>
#include <Foundation/NSValue.h>
#include <Foundation/NSCharacterSet.h>
#include <extensions/support.h>
#include <extensions/FormatScanner.h>
@implementation FormatScanner
enum { SPECIFIER_SIZE = 1000 }; /* This value should be sufficient */
- init
{
currentSpecifier = Malloc(specifierSize = SPECIFIER_SIZE);
boolFlags.allowFlags = YES;
boolFlags.allowWidth = YES;
boolFlags.allowPeriod = YES;
boolFlags.allowPrecision = YES;
boolFlags.allowModifier = YES;
return self;
}
- (void)dealloc
{
Free(currentSpecifier);
[handler release];
[super dealloc];
}
- (void)setFormatScannerHandler:(id)anObject
{
[anObject retain];
[handler release];
handler = anObject;
}
- setAllowOnlySpecifier:(BOOL)flag
{
boolFlags.allowFlags = !flag;
boolFlags.allowWidth = !flag;
boolFlags.allowPeriod = !flag;
boolFlags.allowPrecision = !flag;
boolFlags.allowModifier = !flag;
return self;
}
- setAllowFlags:(BOOL)flag { boolFlags.allowFlags = flag; return self; }
- setAllowWidth:(BOOL)flag { boolFlags.allowWidth = flag; return self; }
- setAllowPeriod:(BOOL)flag { boolFlags.allowPeriod = flag; return self; }
- setAllowPrecision:(BOOL)flag { boolFlags.allowPrecision = flag; return self;}
- setAllowModifier:(BOOL)flag { boolFlags.allowModifier = flag; return self; }
- (id)formatScannerHandler { return handler; }
- (unsigned int)flags { return flags; }
- (int)width { return width; }
- (int)precision { return precision; }
- (char)modifier { return modifier; }
- (char)characterSpecifier { return characterSpecifier; }
- (const char*)currentSpecifier { return currentSpecifier; }
- (BOOL)allowFlags { return boolFlags.allowFlags; }
- (BOOL)allowWidth { return boolFlags.allowWidth; }
- (BOOL)allowPeriod { return boolFlags.allowPeriod; }
- (BOOL)allowPrecision { return boolFlags.allowPrecision; }
- (BOOL)allowModifier { return boolFlags.allowModifier; }
#define CHECK_END \
if(i >= length) { \
/* An unterminated specifier. Break the loop. */ \
[self handleOrdinaryString: \
[NSString stringWithCString:currentSpecifier]]; \
goto _return; \
}
/* Scans the format string looking after specifiers. Doesn't handle '*' as a
valid width or precision. */
- (BOOL)parseFormatString:(NSString*)format context:(void*)context
{
NSRange searchRange, foundRange;
int i = 0, length = [format length];
unichar ch;
NSCharacterSet* decimals = [NSCharacterSet decimalDigitCharacterSet];
*currentSpecifier = 0;
specifierLen = 0;
while(i < length) {
searchRange.location = i;
searchRange.length = length - i;
foundRange = [format rangeOfString:@"%" options:0 range:searchRange];
if (foundRange.length == 0)
foundRange.location = length;
searchRange.length = foundRange.location - searchRange.location;
if (searchRange.length) {
if (![self handleOrdinaryString:
[format substringWithRange:searchRange]])
return NO;
}
i = foundRange.location;
CHECK_END
i++;
strcpy(currentSpecifier, "%");
specifierLen = 1;
CHECK_END
flags = width = precision = modifier = characterSpecifier = 0;
/* Check for flags. */
if(boolFlags.allowFlags) {
for(; i < length; i++) {
ch = [format characterAtIndex:i];
switch(ch) {
case '#': strcat(currentSpecifier, "#");
flags |= FS_ALTERNATE_FORM;
break;
case '0': strcat(currentSpecifier, "0");
flags |= FS_ZERO;
break;
case '-': strcat(currentSpecifier, "-");
flags |= FS_MINUS_SIGN;
break;
case '+': strcat(currentSpecifier, "+");
flags |= FS_PLUS_SIGN;
break;
case ' ': strcat(currentSpecifier, " ");
flags |= FS_BLANK;
break;
default: goto quit;
}
if(++specifierLen == specifierSize)
currentSpecifier = Realloc(currentSpecifier,
specifierSize += SPECIFIER_SIZE);
}
quit:
CHECK_END
}
/* Check for width. */
if(boolFlags.allowWidth) {
for(; i < length; i++) {
char str[2] = { 0, 0 };
ch = [format characterAtIndex:i];
if (![decimals characterIsMember:ch])
break;
str[0] = ch;
strcat(currentSpecifier, str);
if(++specifierLen == specifierSize)
currentSpecifier = Realloc(currentSpecifier,
specifierSize += SPECIFIER_SIZE);
width = 10 * width + (ch - '0');
}
CHECK_END
}
/* Check for period. */
if(boolFlags.allowPeriod) {
ch = [format characterAtIndex:i];
if(ch == '.') {
char str[2] = { ch, 0 };
strcat(currentSpecifier, str);
if(++specifierLen == specifierSize)
currentSpecifier = Realloc(currentSpecifier,
specifierSize += SPECIFIER_SIZE);
i++;
CHECK_END
}
}
/* Check for precision. */
if(boolFlags.allowPrecision) {
for(; i < length; i++) {
char str[2] = { 0, 0 };
ch = [format characterAtIndex:i];
if (![decimals characterIsMember:ch])
break;
str[0] = ch;
strcat(currentSpecifier, str);
if(++specifierLen == specifierSize)
currentSpecifier = Realloc(currentSpecifier,
specifierSize += SPECIFIER_SIZE);
precision = 10 * precision + (ch - '0');
}
CHECK_END
}
/* Check for data-width modifier. */
if(boolFlags.allowModifier) {
ch = [format characterAtIndex:i];
if(ch == 'h' || ch == 'l') {
char str[2] = { ch, 0 };
strcat(currentSpecifier, str);
if(++specifierLen == specifierSize)
currentSpecifier = Realloc(currentSpecifier,
specifierSize += SPECIFIER_SIZE);
modifier = ch;
i++;
CHECK_END
}
}
/* Finally, the conversion character. */
{
char str[2] = { 0, 0 };
ch = [format characterAtIndex:i];
str[0] = ch;
strcat(currentSpecifier, str);
if(++specifierLen == specifierSize)
currentSpecifier = Realloc(currentSpecifier,
specifierSize += SPECIFIER_SIZE);
characterSpecifier = ch;
}
if (![self handleFormatSpecifierWithContext:context])
return NO;
i++;
*currentSpecifier = 0;
specifierLen = 0;
CHECK_END
}
_return:
return YES;
}
- (BOOL)handleOrdinaryString:(NSString*)string
{
return YES;
}
- (BOOL)handleFormatSpecifierWithContext:(void*)context
{
return YES;
}
@end /* FormatScanner */
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.