4 Copyright (C) 1995, 1996 Ovidiu Predescu and Mircea Oancea.
7 Author: Ovidiu Predescu <ovidiu@bx.logicnet.ro>
9 This file is part of libFoundation.
11 Permission to use, copy, modify, and distribute this software and its
12 documentation for any purpose and without fee is hereby granted, provided
13 that the above copyright notice appear in all copies and that both that
14 copyright notice and this permission notice appear in supporting
17 We disclaim all warranties with regard to this software, including all
18 implied warranties of merchantability and fitness, in no event shall
19 we be liable for any special, indirect or consequential damages or any
20 damages whatsoever resulting from loss of use, data or profits, whether in
21 an action of contract, negligence or other tortious action, arising out of
22 or in connection with the use or performance of this software.
29 #include <Foundation/NSDictionary.h>
30 #include <Foundation/NSString.h>
31 #include <Foundation/NSValue.h>
32 #include <Foundation/NSCharacterSet.h>
34 #include <extensions/support.h>
35 #include <extensions/FormatScanner.h>
37 @implementation FormatScanner
39 enum { SPECIFIER_SIZE = 1000 }; /* This value should be sufficient */
43 specifierSize = SPECIFIER_SIZE;
44 currentSpecifier = MallocAtomic(specifierSize);
55 lfFree(currentSpecifier);
60 - (void)setFormatScannerHandler:(id)anObject
62 ASSIGN(self->handler, anObject);
65 - (id)setAllowOnlySpecifier:(BOOL)flag
70 allowPrecision = !flag;
71 allowModifier = !flag;
75 - (id)setAllowFlags:(BOOL)flag {
83 - (id)setAllowWidth:(BOOL)flag {
91 - (id)setAllowPeriod:(BOOL)flag {
99 - (id)setAllowPrecision:(BOOL)flag {
100 allowPrecision = flag;
103 - (BOOL)allowPrecision {
104 return allowPrecision;
107 - (id)setAllowModifier:(BOOL)flag {
108 allowModifier = flag;
111 - (BOOL)allowModifier {
112 return allowModifier;
115 - (id)formatScannerHandler {
119 - (unsigned int)flags {
126 return self->precision;
129 return self->modifier;
131 - (char)characterSpecifier {
132 return self->characterSpecifier;
134 - (const char *)currentSpecifier {
135 return self->currentSpecifier;
140 /* An unterminated specifier. Break the loop. */ \
141 [self handleOrdinaryString: \
142 [NSString stringWithCString:currentSpecifier]]; \
146 /* Scans the format string looking after specifiers. Doesn't handle '*' as a
147 valid width or precision. */
148 - (BOOL)parseFormatString:(NSString*)format context:(void *)context
150 NSRange searchRange, foundRange;
153 NSCharacterSet *decimals;
156 length = [format length];
157 decimals = [NSCharacterSet decimalDigitCharacterSet];
159 *currentSpecifier = 0;
163 searchRange.location = i;
164 searchRange.length = length - i;
166 foundRange = [format rangeOfString:@"%" options:0 range:searchRange];
167 if (foundRange.length == 0)
168 foundRange.location = length;
169 searchRange.length = foundRange.location - searchRange.location;
171 if (searchRange.length) {
172 if (![self handleOrdinaryString:
173 [format substringWithRange:searchRange]])
177 i = foundRange.location;
181 strcpy(currentSpecifier, "%");
185 flags = width = precision = modifier = characterSpecifier = 0;
187 /* Check for flags. */
188 if (self->allowFlags) {
189 for (; i < length; i++) {
190 ch = [format characterAtIndex:i];
192 case '#': strcat(currentSpecifier, "#");
193 flags |= FS_ALTERNATE_FORM;
195 case '0': strcat(currentSpecifier, "0");
198 case '-': strcat(currentSpecifier, "-");
199 flags |= FS_MINUS_SIGN;
201 case '+': strcat(currentSpecifier, "+");
202 flags |= FS_PLUS_SIGN;
204 case ' ': strcat(currentSpecifier, " ");
209 if (++specifierLen == specifierSize) {
211 Realloc(currentSpecifier,
212 specifierSize += SPECIFIER_SIZE);
219 /* Check for width. */
220 if (self->allowWidth) {
221 for(; i < length; i++) {
222 char str[2] = { 0, 0 };
224 ch = [format characterAtIndex:i];
225 if (![decimals characterIsMember:ch])
229 strcat(currentSpecifier, str);
230 if(++specifierLen == specifierSize) {
232 Realloc(currentSpecifier,
233 specifierSize += SPECIFIER_SIZE);
236 width = 10 * width + (ch - '0');
241 /* Check for period. */
242 if (self->allowPeriod) {
243 ch = [format characterAtIndex:i];
245 char str[2] = { ch, 0 };
247 strcat(currentSpecifier, str);
248 if(++specifierLen == specifierSize) {
250 Realloc(currentSpecifier,
251 specifierSize += SPECIFIER_SIZE);
259 /* Check for precision. */
260 if (self->allowPrecision) {
261 for(; i < length; i++) {
262 char str[2] = { 0, 0 };
264 ch = [format characterAtIndex:i];
265 if (![decimals characterIsMember:ch])
269 strcat(currentSpecifier, str);
270 if(++specifierLen == specifierSize) {
272 Realloc(currentSpecifier,
273 specifierSize += SPECIFIER_SIZE);
275 precision = 10 * precision + (ch - '0');
280 /* Check for data-width modifier. */
282 ch = [format characterAtIndex:i];
283 if (ch == 'h' || ch == 'l') {
284 char str[2] = { ch, 0 };
286 strcat(currentSpecifier, str);
287 if (++specifierLen == specifierSize) {
289 Realloc(currentSpecifier,
290 specifierSize += SPECIFIER_SIZE);
299 /* Finally, the conversion character. */
301 char str[2] = { 0, 0 };
302 ch = [format characterAtIndex:i];
305 strcat(currentSpecifier, str);
306 if(++specifierLen == specifierSize) {
308 Realloc(currentSpecifier,
309 specifierSize += SPECIFIER_SIZE);
312 characterSpecifier = ch;
315 if (![self handleFormatSpecifierWithContext:context])
319 *currentSpecifier = 0;
329 - (BOOL)handleOrdinaryString:(NSString*)string
334 - (BOOL)handleFormatSpecifierWithContext:(void*)context
339 @end /* FormatScanner */