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 "NSException+misc.h" 25#include "common.h" 26 27@implementation NSObject(StringBindings) 28 29- (NSString *)valueForStringBinding:(NSString *)_key { 30 if (_key == nil) return nil; 31 return [[self valueForKeyPath:_key] stringValue]; 32} 33 34@end /* NSObject(StringBindings) */ 35 36@implementation NSString(misc) 37 38- (NSSet *)bindingVariables 39{ 40 unsigned len, pos = 0; 41 unichar *wbuf = NULL; 42 NSMutableSet *result = nil; 43 44 result = [NSMutableSet setWithCapacity:16]; 45 len = [self length]; 46 wbuf = malloc(sizeof(unichar) * (len + 4)); 47 [self getCharacters:wbuf]; 48 49 while (pos < len) { 50 unsigned startPos; 51 52 if (pos + 1 == len) { /* last entry */ 53 if (wbuf[pos] == '$') { /* found $ without end-char */ 54 [[NSException exceptionWithName: @"NSStringVariableBindingException" 55 reason:[NSString stringWithFormat: 56 @"did not find end of variable for string %@", self] 57 userInfo:nil] raise]; 58 } 59 break; 60 } 61 if (wbuf[pos] != '$') { 62 pos++; 63 continue; 64 } 65 66 if (wbuf[pos + 1] == '$') { /* found $$ --> ignore*/ 67 pos += 2; 68 continue; 69 } 70 71 /* process binding */ 72 73 startPos = pos; 74 75 pos += 2; /* wbuf[pos + 1] != '$' */ 76 while (pos < len) { 77 if (wbuf[pos] != '$') 78 pos++; 79 else 80 break; 81 } 82 if (pos == len) { /* end of string was reached */ 83 [[NSException exceptionWithName: @"NSStringVariableBindingException" 84 reason:[NSString stringWithFormat: 85 @"did not find end of variable for string %@", self] 86 userInfo:nil] raise]; 87 } 88 else { 89 NSString *key = nil; 90 91 key = [[NSString alloc] 92 initWithCharacters:(unichar *)wbuf + startPos + 1 93 length:(pos - startPos - 1)]; 94 [result addObject:key]; 95 [key release]; 96 } 97 pos++; 98 } 99 if (wbuf != NULL) { free(wbuf); wbuf = NULL; } 100 101 return [[result copy] autorelease]; 102} 103 104- (NSString *)stringByReplacingVariablesWithBindings:(id)_bindings 105 stringForUnknownBindings:(NSString *)_unknown 106{ 107 unsigned len, pos = 0; 108 unichar *wbuf = NULL; 109 NSMutableString *str = nil; 110 111 str = [self mutableCopy]; 112 len = [str length]; 113 wbuf = malloc(sizeof(unichar) * (len + 4)); 114 [self getCharacters:wbuf]; 115 116 while (pos < len) { 117 if (pos + 1 == len) { /* last entry */ 118 if (wbuf[pos] == '$') { /* found $ without end-char */ 119 [[NSException exceptionWithName: @"NSStringVariableBindingException" 120 reason:[NSString stringWithFormat: 121 @"did not find end of variable for string %@", self] 122 userInfo:nil] raise]; 123 } 124 break; 125 } 126 if (wbuf[pos] == '$') { 127 if (wbuf[pos + 1] == '$') { /* found $$ --> $ */ 128 [str deleteCharactersInRange:NSMakeRange(pos, 1)]; 129 130 if (wbuf != NULL) { free(wbuf); wbuf = NULL; } 131 len = [str length]; 132 wbuf = malloc(sizeof(unichar) * (len + 4)); 133 [str getCharacters:wbuf]; 134 } 135 else { 136 unsigned startPos = pos; 137 138 pos += 2; /* wbuf[pos + 1] != '$' */ 139 while (pos < len) { 140 if (wbuf[pos] != '$') 141 pos++; 142 else 143 break; 144 } 145 if (pos == len) { /* end of string was reached */ 146 [[NSException exceptionWithName: @"NSStringVariableBindingException" 147 reason:[NSString stringWithFormat: 148 @"did not find end of variable for string %@", self] 149 userInfo:nil] raise]; 150 } 151 else { 152 NSString *key; 153 NSString *value; 154 155 key = [[NSString alloc] 156 initWithCharacters:(wbuf + startPos + 1) 157 length:(pos - startPos - 1)]; 158 159 if ((value = [_bindings valueForStringBinding:key]) == nil) { 160 if (_unknown == nil) { 161 [[NSException exceptionWithName: 162 @"NSStringVariableBindingException" 163 reason:[NSString stringWithFormat: 164 @"did not find binding for " 165 @"name %@ in binding-dictionary %@", 166 [key autorelease], _bindings] 167 userInfo:nil] raise]; 168 } 169 else 170 value = _unknown; 171 } 172 [key release]; key = nil; 173 174 [str replaceCharactersInRange: 175 NSMakeRange(startPos, pos - startPos + 1) 176 withString:value]; 177 178 if (wbuf != NULL) { free(wbuf); wbuf = NULL; } 179 len = [str length]; 180 wbuf = malloc(sizeof(unichar) * (len + 4)); 181 [str getCharacters:wbuf]; 182 183 pos = startPos - 1 + [value length]; 184 } 185 } 186 } 187 pos++; 188 } 189 if (wbuf != NULL) { free(wbuf); wbuf = NULL; } 190 { 191 id tmp = str; 192 str = [str copy]; 193 [tmp release]; tmp = nil; 194 } 195 return [str autorelease]; 196} 197 198- (NSString *)stringByReplacingVariablesWithBindings:(id)_bindings { 199 return [self stringByReplacingVariablesWithBindings:_bindings 200 stringForUnknownBindings:nil]; 201} 202 203@end /* NSString(misc) */ 204 205 206@implementation NSString(FilePathVersioningMethods) 207 208/* 209 "/path/file.txt;1" 210*/ 211- (NSString *)pathVersion { 212 NSRange r; 213 214 r = [self rangeOfString:@";"]; 215 if (r.length > 0) { 216 return ([self length] > r.location) 217 ? [self substringFromIndex:(r.location + r.length)] 218 : (NSString *)@""; 219 } 220 return nil; 221} 222 223- (NSString *)stringByDeletingPathVersion { 224 NSRange r; 225 226 r = [self rangeOfString:@";"]; 227 return (r.length > 0) 228 ? [self substringToIndex:r.location] 229 : self; 230} 231 232- (NSString *)stringByAppendingPathVersion:(NSString *)_version { 233 return [[self stringByAppendingString:@";"] 234 stringByAppendingString:_version]; 235} 236 237@end /* NSString(FilePathMethodsVersioning) */ 238 239@implementation NSString(NGScanning) 240 241- (NSRange)rangeOfString:(NSString *)_s 242 skipQuotes:(NSString *)_quotes 243 escapedByChar:(unichar)_escape 244{ 245 // TODO: speed ... 246 // TODO: check correctness with invalid input ! 247 static NSRange notFound = { 0, 0 }; 248 NSCharacterSet *quotes; 249 unsigned i, len, slen; 250 unichar sc; 251 252 if ((slen = [_s length]) == 0) 253 return notFound; 254 if ((len = [self length]) < slen) /* to short */ 255 return notFound; 256 257 if ([_quotes length] == 0) 258 _quotes = @"'\""; 259 quotes = [NSCharacterSet characterSetWithCharactersInString:_quotes]; 260 261 sc = [_s characterAtIndex:0]; 262 263 for (i = 0; i < len; i++) { 264 unichar c; 265 266 c = [self characterAtIndex:i]; 267 268 if (c == sc) { 269 /* start search section */ 270 if (slen == 1) 271 return NSMakeRange(i, 1); 272 273 if ([[self substringFromIndex:i] hasPrefix:_s]) 274 return NSMakeRange(i, slen); 275 } 276 else if ([quotes characterIsMember:c]) { 277 /* skip quotes */ 278 i++; 279 c = [self characterAtIndex:i]; 280 for (; i < len && ![quotes characterIsMember:c]; i++) { 281 c = [self characterAtIndex:i]; 282 if (c == _escape) { 283 i++; /* skip next char (eg \') */ 284 continue; 285 } 286 } 287 } 288 } 289 290 return notFound; 291} 292 293- (NSRange)rangeOfString:(NSString *)_s skipQuotes:(NSString *)_quotes { 294 return [self rangeOfString:_s skipQuotes:_quotes escapedByChar:'\\']; 295} 296 297@end /* NSString(NGScanning) */ 298 299 300@implementation NSString(MailQuoting) 301 302- (NSString *)stringByApplyingMailQuoting { 303 NSString *s; 304 unsigned i, len, nl; 305 unichar *sourceBuf, *targetBuf; 306 307 if ((len = [self length]) == 0) 308 return @""; 309 310 sourceBuf = malloc((len + 4) * sizeof(unichar)); 311 [self getCharacters:sourceBuf]; 312 313 for (nl = 0, i = 0; i < len; i++) { 314 if (sourceBuf[i] == '\n') 315 nl++; 316 } 317 318 if (nl == 0) { 319 if (sourceBuf) free(sourceBuf); 320 return [@"> " stringByAppendingString:self]; 321 } 322 323 targetBuf = malloc((len + 8 + (nl * 3)) * sizeof(unichar)); 324 targetBuf[0] = '>'; 325 targetBuf[1] = ' '; 326 nl = 2; 327 328 for (i = 0; i < len; i++) { 329 targetBuf[nl] = sourceBuf[i]; 330 nl++; 331 332 if (sourceBuf[i] == '\n' && (i + 1 != len)) { 333 targetBuf[nl] = '>'; nl++; 334 targetBuf[nl] = ' '; nl++; 335 } 336 } 337 338 s = [[NSString alloc] initWithCharacters:targetBuf length:nl]; 339 if (targetBuf) free(targetBuf); 340 if (sourceBuf) free(sourceBuf); 341 return [s autorelease]; 342} 343 344@end /* NSString(MailQuoting) */ 345 346@implementation NSString(HeaderCapitalization) 347 348- (NSString *) asCapitalizedHeader 349{ 350 NSString *result; 351 NSUInteger count, max; 352 unichar *chars; 353 BOOL capitalize = YES; 354 355 max = [self length]; 356 if (max == 3 && [[self lowercaseString] isEqualToString: @"dav"]) 357 result = @"DAV"; 358 else 359 { 360 chars = malloc (max * sizeof (unichar)); 361 [self getCharacters: chars]; 362 for (count = 0; count < max; count++) 363 { 364 if (capitalize) 365 { 366 if (chars[count] >= 97 && chars[count] <= 122) 367 chars[count] -= 32; 368 capitalize = NO; 369 } 370 else if (chars[count] == '-') 371 capitalize = YES; 372 } 373 result = [NSString stringWithCharacters: chars length: max]; 374 free (chars); 375 } 376 377 return result; 378} 379 380@end 381 382// linking 383 384void __link_NSString_misc(void) { 385 __link_NSString_misc(); 386} 387