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