]> err.no Git - sope/blob - libFoundation/Foundation/FormatScanner.m
fixed some NGMail framework build issue
[sope] / libFoundation / Foundation / FormatScanner.m
1 /* 
2    FormatScanner.m
3
4    Copyright (C) 1995, 1996 Ovidiu Predescu and Mircea Oancea.
5    All rights reserved.
6
7    Author: Ovidiu Predescu <ovidiu@bx.logicnet.ro>
8
9    This file is part of libFoundation.
10
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
15    documentation.
16
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.
23 */
24
25 #include <ctype.h>
26
27 #include "common.h"
28
29 #include <Foundation/NSDictionary.h>
30 #include <Foundation/NSString.h>
31 #include <Foundation/NSValue.h>
32 #include <Foundation/NSCharacterSet.h>
33
34 #include <extensions/support.h>
35 #include <extensions/FormatScanner.h>
36
37 @implementation FormatScanner
38
39 enum { SPECIFIER_SIZE = 1000 }; /* This value should be sufficient */
40
41 - (id)init
42 {
43     specifierSize = SPECIFIER_SIZE;
44     currentSpecifier = MallocAtomic(specifierSize);
45     allowFlags = YES;
46     allowWidth = YES;
47     allowPeriod = YES;
48     allowPrecision = YES;
49     allowModifier = YES;
50     return self;
51 }
52
53 - (void)dealloc
54 {
55     lfFree(currentSpecifier);
56     RELEASE(handler);
57     [super dealloc];
58 }
59
60 - (void)setFormatScannerHandler:(id)anObject
61 {
62     ASSIGN(self->handler, anObject);
63 }
64
65 - (id)setAllowOnlySpecifier:(BOOL)flag
66 {
67     allowFlags     = !flag;
68     allowWidth     = !flag;
69     allowPeriod    = !flag;
70     allowPrecision = !flag;
71     allowModifier  = !flag;
72     return self;
73 }
74
75 - (id)setAllowFlags:(BOOL)flag {
76     allowFlags = flag;
77     return self;
78 }
79 - (BOOL)allowFlags {
80     return allowFlags;
81 }
82
83 - (id)setAllowWidth:(BOOL)flag {
84     allowWidth = flag;
85     return self;
86 }
87 - (BOOL)allowWidth {
88     return allowWidth;
89 }
90
91 - (id)setAllowPeriod:(BOOL)flag {
92     allowPeriod = flag;
93     return self;
94 }
95 - (BOOL)allowPeriod {
96     return allowPeriod;
97 }
98
99 - (id)setAllowPrecision:(BOOL)flag {
100     allowPrecision = flag;
101     return self;
102 }
103 - (BOOL)allowPrecision {
104     return allowPrecision;
105 }
106
107 - (id)setAllowModifier:(BOOL)flag {
108     allowModifier = flag;
109     return self;
110 }
111 - (BOOL)allowModifier {
112     return allowModifier;
113 }
114
115 - (id)formatScannerHandler {
116     return handler;
117 }
118
119 - (unsigned int)flags {
120     return self->flags;
121 }
122 - (int)width {
123     return self->width;
124 }
125 - (int)precision {
126     return self->precision;
127 }
128 - (char)modifier {
129     return self->modifier;
130 }
131 - (char)characterSpecifier {
132     return self->characterSpecifier;
133 }
134 - (const char *)currentSpecifier {
135     return self->currentSpecifier;
136 }
137
138 #define CHECK_END \
139     if(i >= length) { \
140         /* An unterminated specifier. Break the loop. */ \
141         [self handleOrdinaryString: \
142                     [NSString stringWithCString:currentSpecifier]]; \
143         goto _return; \
144     }
145
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
149 {
150     NSRange        searchRange, foundRange;
151     int            i, length;
152     unichar        ch;
153     NSCharacterSet *decimals;
154
155     i        = 0;
156     length   = [format length];
157     decimals = [NSCharacterSet decimalDigitCharacterSet];
158     
159     *currentSpecifier = 0;
160     specifierLen = 0;
161
162     while (i < length) {
163         searchRange.location = i;
164         searchRange.length = length - i;
165
166         foundRange = [format rangeOfString:@"%" options:0 range:searchRange];
167         if (foundRange.length == 0)
168             foundRange.location = length;
169         searchRange.length = foundRange.location - searchRange.location;
170
171         if (searchRange.length) {
172             if (![self handleOrdinaryString:
173                         [format substringWithRange:searchRange]])
174                 return NO;
175         }
176
177         i = foundRange.location;
178         CHECK_END
179
180         i++;
181         strcpy(currentSpecifier, "%");
182         specifierLen = 1;
183         CHECK_END
184
185         flags = width = precision = modifier = characterSpecifier = 0;
186
187         /* Check for flags. */
188         if (self->allowFlags) {
189             for (; i < length; i++) {
190                 ch = [format characterAtIndex:i];
191                 switch(ch) {
192                     case '#':   strcat(currentSpecifier, "#");
193                                 flags |= FS_ALTERNATE_FORM;
194                                 break;
195                     case '0':   strcat(currentSpecifier, "0");
196                                 flags |= FS_ZERO;
197                                 break;
198                     case '-':   strcat(currentSpecifier, "-");
199                                 flags |= FS_MINUS_SIGN;
200                                 break;
201                     case '+':   strcat(currentSpecifier, "+");
202                                 flags |= FS_PLUS_SIGN;
203                                 break;
204                     case ' ':   strcat(currentSpecifier, " ");
205                                 flags |= FS_BLANK;
206                                 break;
207                     default:    goto quit;
208                 }
209                 if (++specifierLen == specifierSize) {
210                     currentSpecifier =
211                         Realloc(currentSpecifier,
212                                 specifierSize += SPECIFIER_SIZE);
213                 }
214             }
215         quit:
216             CHECK_END
217         }
218
219         /* Check for width. */
220         if (self->allowWidth) {
221             for(; i < length; i++) {
222                 char str[2] = { 0, 0 };
223
224                 ch = [format characterAtIndex:i];
225                 if (![decimals characterIsMember:ch])
226                     break;
227                 str[0] = ch;
228
229                 strcat(currentSpecifier, str);
230                 if(++specifierLen == specifierSize) {
231                     currentSpecifier =
232                         Realloc(currentSpecifier,
233                                 specifierSize += SPECIFIER_SIZE);
234                 }
235
236                 width = 10 * width + (ch - '0');
237             }
238             CHECK_END
239         }
240
241         /* Check for period. */
242         if (self->allowPeriod) {
243             ch = [format characterAtIndex:i];
244             if(ch == '.') {
245                 char str[2] = { ch, 0 };
246
247                 strcat(currentSpecifier, str);
248                 if(++specifierLen == specifierSize) {
249                     currentSpecifier =
250                         Realloc(currentSpecifier,
251                                 specifierSize += SPECIFIER_SIZE);
252                 }
253
254                 i++;
255                 CHECK_END
256             }
257         }
258
259         /* Check for precision. */
260         if (self->allowPrecision) {
261             for(; i < length; i++) {
262                 char str[2] = { 0, 0 };
263
264                 ch = [format characterAtIndex:i];
265                 if (![decimals characterIsMember:ch])
266                     break;
267                 str[0] = ch;
268
269                 strcat(currentSpecifier, str);
270                 if(++specifierLen == specifierSize) {
271                     currentSpecifier =
272                         Realloc(currentSpecifier,
273                                 specifierSize += SPECIFIER_SIZE);
274                 }
275                 precision = 10 * precision + (ch - '0');
276             }
277             CHECK_END
278         }
279
280         /* Check for data-width modifier. */
281         if (allowModifier) {
282             ch = [format characterAtIndex:i];
283             if (ch == 'h' || ch == 'l') {
284                 char str[2] = { ch, 0 };
285
286                 strcat(currentSpecifier, str);
287                 if (++specifierLen == specifierSize) {
288                     currentSpecifier =
289                         Realloc(currentSpecifier,
290                                 specifierSize += SPECIFIER_SIZE);
291                 }
292
293                 modifier = ch;
294                 i++;
295                 CHECK_END
296             }
297         }
298
299         /* Finally, the conversion character. */
300         {
301             char str[2] = { 0, 0 };
302             ch = [format characterAtIndex:i];
303             str[0] = ch;
304
305             strcat(currentSpecifier, str);
306             if(++specifierLen == specifierSize) {
307                 currentSpecifier =
308                     Realloc(currentSpecifier,
309                             specifierSize += SPECIFIER_SIZE);
310             }
311
312             characterSpecifier = ch;
313         }
314
315         if (![self handleFormatSpecifierWithContext:context])
316             return NO;
317
318         i++;
319         *currentSpecifier = 0;
320         specifierLen = 0;
321
322         CHECK_END
323     }
324
325 _return:
326     return YES;
327 }
328
329 - (BOOL)handleOrdinaryString:(NSString*)string
330 {
331     return YES;
332 }
333
334 - (BOOL)handleFormatSpecifierWithContext:(void*)context
335 {
336     return YES;
337 }
338
339 @end /* FormatScanner */
340
341 /*
342   Local Variables:
343   c-basic-offset: 4
344   tab-width: 8
345   End:
346 */