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.