]> err.no Git - sope/blob - sope-core/NGExtensions/FdExt.subproj/NSString+misc.m
Drop apache 1 build-dependency
[sope] / sope-core / NGExtensions / FdExt.subproj / NSString+misc.m
1 /*
2   Copyright (C) 2000-2008 SKYRIX Software AG
3   Copyright (C) 2006-2008 Helge Hess
4
5   This file is part of SOPE.
6
7   SOPE is free software; you can redistribute it and/or modify it under
8   the terms of the GNU Lesser General Public License as published by the
9   Free Software Foundation; either version 2, or (at your option) any
10   later version.
11
12   SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
13   WARRANTY; without even the implied warranty of MERCHANTABILITY or
14   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
15   License for more details.
16
17   You should have received a copy of the GNU Lesser General Public
18   License along with SOPE; see the file COPYING.  If not, write to the
19   Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
20   02111-1307, USA.
21 */
22
23 #include "NSString+misc.h"
24 #include "common.h"
25
26 @interface NSStringVariableBindingException : NSException
27 @end
28
29 @implementation NSStringVariableBindingException
30 @end
31
32 @implementation NSObject(StringBindings)
33
34 - (NSString *)valueForStringBinding:(NSString *)_key {
35   if (_key == nil) return nil;
36   return [[self valueForKeyPath:_key] stringValue];
37 }
38
39 @end /* NSObject(StringBindings) */
40
41 @implementation NSString(misc)
42
43 - (NSSet *)bindingVariables
44 {
45   unsigned        len, pos = 0;
46   unichar         *wbuf    = NULL;
47   NSMutableSet    *result  = nil;
48   
49   result = [NSMutableSet setWithCapacity:16];
50   len    = [self length];  
51   wbuf   = malloc(sizeof(unichar) * (len + 4));
52   [self getCharacters:wbuf];
53   
54   while (pos < len) {
55     unsigned startPos;
56     
57     if (pos + 1 == len) { /* last entry */
58       if (wbuf[pos] == '$') { /* found $ without end-char */
59         [[[NSStringVariableBindingException alloc]
60            initWithFormat:@"did not find end of variable for string %@", self]
61            raise];
62       }
63       break;
64     }
65     if (wbuf[pos] != '$') {
66       pos++;
67       continue;
68     }
69     
70     if (wbuf[pos + 1] == '$') { /* found $$ --> ignore*/
71       pos += 2;
72       continue;
73     }
74
75     /* process binding */
76     
77     startPos = pos;
78     
79     pos += 2; /* wbuf[pos + 1] != '$' */
80     while (pos < len) {
81       if (wbuf[pos] != '$')
82         pos++;
83       else
84         break;
85     }
86     if (pos == len) { /* end of string was reached */
87       [[[NSStringVariableBindingException alloc]
88          initWithFormat:@"did not find end of variable for string %@", self]
89          raise];
90     }
91     else {
92       NSString *key = nil;
93       
94       key = [[NSString alloc]
95                        initWithCharacters:(unichar *)wbuf + startPos + 1
96                        length:(pos - startPos - 1)];
97       [result addObject:key];
98       [key release];
99     }
100     pos++;
101   }
102   if (wbuf != NULL) { free(wbuf); wbuf = NULL; }
103   
104   return [[result copy] autorelease];
105 }
106
107 - (NSString *)stringByReplacingVariablesWithBindings:(id)_bindings
108   stringForUnknownBindings:(NSString *)_unknown
109 {
110   unsigned        len, pos = 0;
111   unichar         *wbuf    = NULL;
112   NSMutableString *str     = nil;
113   
114   str = [self mutableCopy];
115   len = [str length];  
116   wbuf   = malloc(sizeof(unichar) * (len + 4));
117   [self getCharacters:wbuf];
118   
119   while (pos < len) {
120     if (pos + 1 == len) { /* last entry */
121       if (wbuf[pos] == '$') { /* found $ without end-char */
122         [[[NSStringVariableBindingException alloc]
123            initWithFormat:@"did not find end of variable for string %@", self]
124           raise];
125       }
126       break;
127     }
128     if (wbuf[pos] == '$') {
129       if (wbuf[pos + 1] == '$') { /* found $$ --> $ */
130         [str deleteCharactersInRange:NSMakeRange(pos, 1)];
131         
132         if (wbuf != NULL) { free(wbuf); wbuf = NULL; }
133         len  = [str length];
134         wbuf = malloc(sizeof(unichar) * (len + 4));
135         [str getCharacters:wbuf];
136       }
137       else {
138         unsigned startPos = pos;
139
140         pos += 2; /* wbuf[pos + 1] != '$' */
141         while (pos < len) {
142           if (wbuf[pos] != '$')
143             pos++;
144           else
145             break;
146         }
147         if (pos == len) { /* end of string was reached */
148           [[[NSStringVariableBindingException alloc]
149              initWithFormat:@"did not find end of variable for string %@", 
150              self] raise];
151         }
152         else {
153           NSString *key;
154           NSString *value;
155
156           key = [[NSString alloc]
157                   initWithCharacters:(wbuf + startPos + 1)
158                   length:(pos - startPos - 1)];
159           
160           if ((value = [_bindings valueForStringBinding:key]) == nil) {
161             if (_unknown == nil) {
162               [[[NSStringVariableBindingException alloc]
163                           initWithFormat:@"did not find binding for "
164                                          @"name %@ in binding-dictionary %@",
165                                          [key autorelease], _bindings] raise];
166             }
167             else
168               value = _unknown;
169           }
170           [key release]; key = nil;
171           
172           [str replaceCharactersInRange:
173                  NSMakeRange(startPos, pos - startPos + 1)
174                withString:value];
175           
176           if (wbuf != NULL) { free(wbuf); wbuf = NULL; }
177           len  = [str length];
178           wbuf = malloc(sizeof(unichar) * (len + 4));
179           [str getCharacters:wbuf];
180           
181           pos = startPos - 1 + [value length];
182         }
183       }
184     }
185     pos++;
186   }
187   if (wbuf != NULL) { free(wbuf); wbuf = NULL; }
188   {
189     id tmp = str;
190     str = [str copy];
191     [tmp release]; tmp = nil;
192   }
193   return [str autorelease];
194 }
195
196 - (NSString *)stringByReplacingVariablesWithBindings:(id)_bindings {
197   return [self stringByReplacingVariablesWithBindings:_bindings
198                stringForUnknownBindings:nil];
199 }
200
201 @end /* NSString(misc) */
202
203
204 @implementation NSString(FilePathVersioningMethods)
205
206 /*
207   "/path/file.txt;1"
208 */
209 - (NSString *)pathVersion {
210   NSRange r;
211
212   r = [self rangeOfString:@";"];
213   if (r.length > 0) {
214     return ([self length] > r.location)
215       ? [self substringFromIndex:(r.location + r.length)]
216       : (NSString *)@"";
217   }
218   return nil;
219 }
220
221 - (NSString *)stringByDeletingPathVersion {
222   NSRange r;
223
224   r = [self rangeOfString:@";"];
225   return (r.length > 0)
226     ? [self substringToIndex:r.location]
227     : self;
228 }
229
230 - (NSString *)stringByAppendingPathVersion:(NSString *)_version {
231   return [[self stringByAppendingString:@";"] 
232                 stringByAppendingString:_version];
233 }
234
235 @end /* NSString(FilePathMethodsVersioning) */
236
237 @implementation NSString(NGScanning)
238
239 - (NSRange)rangeOfString:(NSString *)_s 
240   skipQuotes:(NSString *)_quotes
241   escapedByChar:(unichar)_escape
242 {
243   // TODO: speed ...
244   // TODO: check correctness with invalid input !
245   static NSRange notFound = { 0, 0 };
246   NSCharacterSet *quotes;
247   unsigned i, len, slen;
248   unichar sc;
249   
250   if ((slen = [_s length]) == 0)
251     return notFound;
252   if ((len = [self length]) < slen) /* to short */
253     return notFound;
254   
255   if ([_quotes length] == 0)
256     _quotes = @"'\"";
257   quotes = [NSCharacterSet characterSetWithCharactersInString:_quotes];
258   
259   sc = [_s characterAtIndex:0];
260   
261   for (i = 0; i < len; i++) {
262     unichar c;
263     
264     c = [self characterAtIndex:i];
265     
266     if (c == sc) {
267       /* start search section */
268       if (slen == 1)
269         return NSMakeRange(i, 1);
270       
271       if ([[self substringFromIndex:i] hasPrefix:_s])
272         return NSMakeRange(i, slen);
273     }
274     else if ([quotes characterIsMember:c]) {
275       /* skip quotes */
276       i++;
277       c = [self characterAtIndex:i];
278       for (; i < len && ![quotes characterIsMember:c]; i++) {
279         c = [self characterAtIndex:i];
280         if (c == _escape) {
281           i++; /* skip next char (eg \') */
282           continue;
283         }
284       }
285     }
286   }
287   
288   return notFound;
289 }
290
291 - (NSRange)rangeOfString:(NSString *)_s skipQuotes:(NSString *)_quotes {
292   return [self rangeOfString:_s skipQuotes:_quotes escapedByChar:'\\'];
293 }
294
295 @end /* NSString(NGScanning) */
296
297
298 @implementation NSString(MailQuoting)
299
300 - (NSString *)stringByApplyingMailQuoting {
301   NSString *s;
302   unsigned i, len, nl;
303   unichar  *sourceBuf, *targetBuf;
304   
305   if ((len = [self length]) == 0)
306     return @"";
307   
308   sourceBuf = malloc((len + 4) * sizeof(unichar));
309   [self getCharacters:sourceBuf];
310   
311   for (nl = 0, i = 0; i < len; i++) {
312     if (sourceBuf[i] == '\n') 
313       nl++;
314   }
315   
316   if (nl == 0) {
317     if (sourceBuf) free(sourceBuf);
318     return [@"> " stringByAppendingString:self];
319   }
320   
321   targetBuf = malloc((len + 8 + (nl * 3)) * sizeof(unichar));
322   targetBuf[0] = '>';
323   targetBuf[1] = ' ';
324   nl = 2;
325   
326   for (i = 0; i < len; i++) {
327     targetBuf[nl] = sourceBuf[i];
328     nl++;
329     
330     if (sourceBuf[i] == '\n' && (i + 1 != len)) {
331       targetBuf[nl] = '>'; nl++;
332       targetBuf[nl] = ' '; nl++;
333     }
334   }
335   
336   s = [[NSString alloc] initWithCharacters:targetBuf length:nl];
337   if (targetBuf) free(targetBuf);
338   if (sourceBuf) free(sourceBuf);
339   return [s autorelease];
340 }
341
342 @end /* NSString(MailQuoting) */
343
344 // linking
345
346 void __link_NSString_misc(void) {
347   __link_NSString_misc();
348 }