#import "Aprica.h"
#include <math.h>
#import <Foundation/NSDebug.h>
// Aprica2
// copyright Pirmin Braun 1997-2007 - pirmin@pirmin.de
// all Rights reserved;
#ifdef GNUSTEP
#include <stdint.h>
#else
typedef unsigned int uint32_t;
@implementation NSTimeZone (PB3)
+ (NSTimeZone *)systemTimeZone;
{// weil auf Windows 2003 Server die system-Timezone nicht richtig ermittelt wird:
return [NSTimeZone timeZoneWithName:@"Europe/Rome"];
}
@end
#endif
/*
in Shell:
export NSZombieEnabled=YES
@interface _NSZombie : NSObject
{}
@end
@implementation _NSZombie
- (id)retain;
{ LOGS([(NSMutableDictionary *)self description]);
PRINTCURRENTSTACK;
[super retain];
return self;
}
@end
*/
@implementation WOContext (PB3)
- (void)setCurrentComponent:(WOComponent *)c;
{ if(_currentComponent == c)return;
[_currentComponent release];
_currentComponent = [c retain];
}
@end
@implementation WOComponent (PB3)
- (NSMutableDictionary *)_subcomponents;
{#ifdef GNUSTEP
return _subComponents;
#else
return _subcomponents;
#endif
}
@end
@implementation NSObject ( PB3 )
- (int)length;
{ //wg. FILLED() macro; NSString ueberschreibt diese Methode
return 1;
}
- (NSString *)classNameNS;
{ return [[self class]description];
}
#ifdef GNUSTEP
- (BOOL)isGreaterThan:(NSObject *)o
{ return ([self compare:o]==NSOrderedDescending);
}
#endif
@end
@implementation NSNumber ( PB3 )
- (BOOL)boolValuePB3 { return [self boolValue]; };@end
@implementation NSArray ( PB3 )
- (NSString *)quotedElements;
{ LMA;
int i,j;
for(i=0,j=[self count];i<j;i++){ [lma addObject:[NSSWF @"'%@'",[[self oai:i]mysqlEscapedString]]];
}
return [lma componentsJoinedByString:@","];
}
- (NSString *)csvString;
{ return [self csvStringSep:@"," escape:@"\"" alwaysEscape:NO];
}
- (NSString *)csvStringOutlook;
{ return [self csvStringSep:@"," escape:@"\"" alwaysEscape:YES];
}
- (NSString *)csvStringSep:(NSString *)sep escape:(NSString *)escape alwaysEscape:(BOOL)alwaysEscape;
{// erzeugt eine Zeile eines csv-Files
// das abgrundtief dumme Outlook versteht sein eigenes csv Format nicht, daher Felder immer escapen
NSMutableString *ms;
int i,j;
NSString *escape2;
if(!FILLED(sep) || !FILLED(escape))return EON;
ms = [NSMutableString stringWithCapacity:100];
[ms setString:EON];
escape2 = [escape stringByAppendingString:escape];
for(i=0,j=[self count];i<j;i++){ NSString *s = [self oai:i];
if((alwaysEscape && FILLED(s)) || [s rangeOfString:sep].length || [s rangeOfString:@"\n"].length ){// sep in s muss escaped werden
if([s rangeOfString:escape].length){// wenn s escaped wird, muss escape in s durch doppeltes escape escaped werden
s = [s replace:escape with:escape2];
}
s = [NSSWF @"%@%@%@",escape,s,escape];
}
if(i)[ms appendString:sep];
[ms appendString:s];
}
return ms;
}
- (NSArray *)sortedArray;
{ return [self sortedArrayUsingSelector:@selector(compare:)];
}
- (NSArray *)sortedArrayNumeric;
{ return [self sortedArrayUsingSelector:@selector(compareNumeric:)];
}
- (NSArray *)sortedArrayCaseInsensitive;
{ return [self sortedArrayUsingSelector:@selector(compareCaseInsensitive:)];
}
+ (NSArray *)soaFrom:(NSString *)s;
{ return [NSArray soaFrom:s selector:EOCompareAscending];
}
+ (NSArray *)soaCaseInsensitiveFrom:(NSString *)s;
{ return [NSArray soaFrom:s selector:@selector(compareCaseInsensitive:)];
}
+ (NSArray *)soaDFrom:(NSString *)s;
{ return [NSArray soaFrom:s selector:EOCompareDescending];
}
+ (NSArray *)soaNFrom:(NSString *)s;
{ return [NSArray soaFrom:s selector:@selector(compareNumeric:)];
}
+ (NSArray *)soaNDFrom:(NSString *)s;
{ return [NSArray soaFrom:s selector:@selector(compareNumericD:)];
}
+ (NSArray *)soaFrom:(NSString *)s selector:(SEL)sel;
{ LMA;
NSArray *a = [s componentsSeparatedByString:@","];
int i,j;
for(i=0,j=[a count];i<j;i++){ [lma addObject:[PBSortOrdering sortOrderingWithKey:[a oai:i] selector:sel]];
}
return lma;
}
+ (NSArray *)soaADFrom:(NSString *)s;
{//an den key angehaengtes :a bzw. :d steuert ascending/descending; :a ist default;
// an = ascending numeric, dn = descending numeric
LMA;
NSArray *a = [s componentsSeparatedByString:@","];
int i,j;
if(!FILLED(s))return lma;
for(i=0,j=[a count];i<j;i++){ NSArray *a1 = [[a oai:i] componentsSeparatedByString:@":"];
SEL sel=EOCompareAscending;
if([a1 count]==2){ NSString *sm = [[a1 oai:1]lowercaseString];
if([sm iE:@"d"]){ sel=EOCompareDescending;
}else if([sm iE:@"a"]){ sel=EOCompareAscending;
}else if([sm iE:@"an"]){ sel=@selector(compareNumeric:);
}else if([sm iE:@"n"]){ sel=@selector(compareNumeric:);
}else if([sm iE:@"dn"]){ sel=@selector(compareNumericD:);
}
}
[lma addObject:[PBSortOrdering sortOrderingWithKey:[a1 oai:0] selector:sel]];
}
return lma;
}
- (void)objectsTakeValue:value forKey:(NSString *)key;
{ int i,j = [self count];
for(i=0;i<j;i++){ [[self oai:i]takeValue:value forKey:key];
}
}
- (NSArray *)valuesForKey:(NSString *)s;
{ int i,j = [self count];
id o,o1;
LMA;
if(!FILLED(s)){ return lma;
}
for(i=0;i<j;i++){ o = [self oai:i];
if((o1 = [o vfk:s])){ //muss ein object sein; int oder so ist schlecht [lma addObject:o1];
}
}
return lma;
}
- firstObject;
{ if(![self count])return nil;
return [self oai:0];
}
- (NSArray *)objectsWithout:(NSArray *)a;
{ int i,j;
LMA;
if(![a count])return self;
for(i=0,j=[self count];i<j;i++){ NSObject *o=[self oai:i];
if([a indexOfObject:o] != NSNotFound)continue;
[lma addObject:o];
}
return lma;
}
- (NSArray *)arrayFromIndex:(int)i;
{ LMA;
int j = [self count];
if(i<0)return nil;
if(i==0)return self;
for(;i<j;i++){ [lma addObject:[self oai:i]];
}
return lma;
}
- (NSArray *)arrayToIndex:(int)j;
{ LMA;
int i;
if(j<=0)return nil;
j = MIN(j,[self count]);
for(i=0;i<j;i++){ [lma addObject:[self oai:i]];
}
return lma;
}
@end
@implementation NSDictionary ( PB3 )
- (BOOL)containsObject:(id)anObject;
{// eigentlich contains Key
if(!anObject)return NO;
return ([self ofk:anObject]>0);
}
- (NSArray *)valuesArrayForKeys:(NSArray *)a;
{ LMA;
int i,j;
for(i=0,j=[a count];i<j;i++){ NSString *s = [self valueForKey:[a oai:i]];
if(!s)s=@"";
[lma addObject:s];
}
return lma;
}
- (NSArray *)objectsForKeys:(NSArray *)keys;
{ return [self objectsForKeys:keys notFoundMarker:@""];
}
- (NSArray *)allObjects;
{ return [self allValues]; //language Correction
}
+ (NSDictionary *)lookupDictForArray:(NSArray *)a; //objekte mit sich selbst als Keys registrieren
{ if(![a count])return nil;
return [NSDictionary dictionaryWithObjects:a forKeys:a];
}
+ (NSDictionary *)lookupDictForArray:(NSArray *)a key:(NSString *)key;
{ NSMutableDictionary *md;
int i,j=[a count];
NSObject *o;
if(!j)return nil;
if(!key){ LOGS(@"lookupDictForArray: kein key");
return nil;
}
md = [NSMutableDictionary dictionaryWithCapacity:j];
for(i=0;i<j;i++){ o = [a oai:i];
[md setSecureObject:o forKey:[o vfk:key]];
}
return (NSDictionary *)md;
}
@end
@implementation NSMutableString ( PB3 )
- valueForKey:(NSString *)key;
{ return self;
}
- (void)takeValue:value forKey:(NSString *)key;
{ if([value isKindOfClass:[NSString class]]){ [self setString:(NSString *)value];
}
}
@end
@implementation NSMutableDictionary ( PB3 )
- (NSMutableDictionary *)values;
{ return self;
}
- (NSArray *)allObjects;
{ return [self allValues]; //language Correction
}
- (void)setSecureObject:o forKey:(NSString *)key;
{ if(!o){// LOGS(([NSSWF @"trying to set nil object forKey:%@",key]));
// PRINTCURRENTSTACK;
if(key)[self removeObjectForKey:key];
return;
}
if(!key){// LOGS(([NSSWF @"trying to set object %@ for nil Key",[o description]]));
// PRINTCURRENTSTACK;
return;
}
[self setObject:o forKey:key];
}
- (void)setObjects:(NSArray *)oa forKeys:(NSArray *)ka;
{ int i,j=MIN([oa count],[ka count]);
for(i=0;i<j;i++){ [self setSecureObject:[oa oai:i] forKey:[ka oai:i]];
}
}
- (void)removeAllEntriesWithPrefix:(NSString *)prefix;
{ NSArray *a;
int i,j;
if(!prefix)return;
a = [self allKeys];
for(i=0,j=[a count];i<j;i++){ NSString *s = [a oai:i];
if([s hasSecurePrefix:prefix]){ [self removeObjectForKey:s];
}
}
}
- (void)removeEmpty;
{ int i,j;
NSArray *a;
NSString *k;
NSString *s;
a = [self allKeys];
for(i=0,j=[a count];i<j;i++){ k = [a oai:i];
s = [self ofk:k];
if(!FILLED(s)){ [self rofk:k];
}
}
}
@end
@implementation NSMutableArray ( PB3 )
- (void)secureRemoveLastObject;
{// Workaround
// original Methode wirft exception, wenn Array leer; das wollen wir nicht.
if([self count]>0){ [self removeLastObject];
}
}
- (void)addObjects:(NSArray *)a afterIndex:(int)i;
{ int j;
if(!a)return;
i++;
if(i >= [self count] || i < 0){ [self addObjectsFromArray:a];
return;
}
j = [a count]-1;
while(j>=0){ [self insertObject:[a oai:j] atIndex:i];
j--;
}
}
- (void)addObjectOverride:anObject;
{ int i = [self indexOfObject:anObject];
if(i==NSNotFound){ [self addObject:anObject];
}else{ [self replaceObjectAtIndex:i withObject:anObject];
}
}
- (void)sort;
{ [self sortUsingSelector:@selector(compare:)];
}
- (void)sortD;
{ [self sortUsingSelector:EOCompareDescending];
}
- (void)addObjectUniq:anObject;
{ if([self indexOfObject:anObject]==NSNotFound){ [self addObject:anObject];
}
}
- (void)addObjectsUniq:(NSArray *)a;
{ int i,j;
for(i=0,j=[a count];i<j;i++){ [self addObjectUniq:[a oai:i]];
}
}
@end
@implementation NSString ( PB3_Date )
// Sammlung scriptfreundlicher normalizedDate Methoden
- (NSString *)normalizedDate; // macht 14 stelliges timestampformat; ausgangsstring darf mysql, dbdate format sein
{ int l = [self length];
if(!l)return EON;
if((l == 8 || l == 14) && [self isNumeric]){ if(l==8)return [self sbas:@"000000"];
return self;
}
if((l == 10 || l== 19) && [self rangeOfString:@"-"].location == 4){ // vermutlich im mysql-format NSString *s = [self onlyDigits];
if([s intValue]==0)return EON;
l = [s length];
if(l==14)return s;
if(l==8)return [s sbas:@"000000"];
}
return EON;
}
- (NSCalendarDate *)nd_NSCD;
{// liefert das NSCalendarDate zum normalizedDate oder nil
if(!FILLED(self))return nil;
return [NSCalendarDate dateWithString:self calendarFormat:ND_FORMAT];
}
- (NSString *)nd_by_adding:(int)amount interval:(NSString *)interval;
{// interval = {y,m,d,w,wd,H,M,S} NSCalendarDate *nscd = [self nd_NSCD];
if(!nscd)return EON;
if(amount==0)return self;
if([interval iE:@"y"])return [[nscd dateByAddingYears:amount months:0 days:0 hours:0 minutes:0 seconds:0]descriptionWithCalendarFormat:ND_FORMAT];
if([interval iE:@"m"])return [[nscd dateByAddingYears:0 months:amount days:0 hours:0 minutes:0 seconds:0]descriptionWithCalendarFormat:ND_FORMAT];
if([interval iE:@"d"])return [[nscd dateByAddingYears:0 months:0 days:amount hours:0 minutes:0 seconds:0]descriptionWithCalendarFormat:ND_FORMAT];
if([interval iE:@"w"])return [[nscd dateByAddingYears:0 months:0 days:amount * 7 hours:0 minutes:0 seconds:0]descriptionWithCalendarFormat:ND_FORMAT]; // sommerzeit bug behoben??
if([interval iE:@"H"])return [[nscd dateByAddingYears:0 months:0 days:0 hours:amount minutes:0 seconds:0]descriptionWithCalendarFormat:ND_FORMAT];
if([interval iE:@"M"])return [[nscd dateByAddingYears:0 months:0 days:0 hours:0 minutes:amount seconds:0]descriptionWithCalendarFormat:ND_FORMAT];
if([interval iE:@"S"])return [[nscd dateByAddingYears:0 months:0 days:0 hours:0 minutes:0 seconds:amount]descriptionWithCalendarFormat:ND_FORMAT];
if([interval iE:@"wd"]){ // workday int step;
NSString *nd = self;
if(abs(amount)>1000){ LOGS(TRANSLATION(@"max. 1000 Werktage"));
return self;
}
if(amount <0){ step=-1;
}else{ step=1;
}
while(amount!=0){ int wd;
nscd = [nscd dateByAddingYears:0 months:0 days:step hours:0 minutes:0 seconds:0];
nd = [nscd descriptionWithCalendarFormat:ND_FORMAT];
wd = [nscd dayOfWeek];
if((wd==0) || (wd==6))continue;
if([_APP isFeiertag:nd])continue;
amount-=step;
}
return nd;
}
LOG(([NSSWF TRANSLATION(@"ungueltiges interval:%@"),interval]));
return EON;
}
- (NSString *)nd_isWorkday;
{ if(!FILLED(self))return @"N";
{// returned {J,N} int wd = [self nd_weekday];
if((wd == 6) || (wd == 0))return @"N"; // Sa, So
if([_APP isFeiertag:self])return @"N";
return @"J";
}
}
- (int)nd_weekday;
{// returned die Nr. des Wochentages als String
if(!FILLED(self))return 0; // naja
return [[self nd_NSCD] dayOfWeek];
}
- (NSString *)nd_weekdayName;
{ if(!FILLED(self))return EON;
return [[_APP weekdayNames] oai:[self nd_weekday]];
}
- (NSString *)nd_fullWeekdayName;
{ if(!FILLED(self))return EON;
return [[_APP weekdayFullNames] oai:[self nd_weekday]];
}
- (NSString *)nd_withoutTime;
{// macht den Zeit-Anteil auf 0 -> Tagesstart
if(!FILLED(self))return EON;
return [NSSWF @"%@000000",[self secureSubstringToIndex:8]];
}
- (NSString *)nd_guiDate;
{ NSCalendarDate *nscd = [self nd_NSCD];
if(!nscd)return EON;
if([self hasSecureSuffix:@"000000"]){ return [nscd descriptionWithCalendarFormat:ND_GUID_FORMAT]; // nur Tag
}else{ return [nscd descriptionWithCalendarFormat:ND_GUIDT_FORMAT]; // tag und zeit
}
}
- (NSString *)nd_mysql;
{ NSCalendarDate *nscd = [self nd_NSCD];
if(!nscd)return EON;
return [nscd descriptionWithCalendarFormat:ND_MYSQL_FORMAT]; // tag und zeit
}
- (NSString *)nd_day;
{ if(!FILLED(self))return EON;
return [[self secureSubstringFromIndex:6]secureSubstringToIndex:2];
}
- (NSString *)nd_month;
{ if(!FILLED(self))return EON;
return [[self secureSubstringFromIndex:4]secureSubstringToIndex:2];
}
- (NSString *)nd_year;
{ if(!FILLED(self))return EON;
return [self secureSubstringToIndex:4];
}
- (NSString *)nd_second;
{ if(!FILLED(self))return EON;
return [self secureSubstringFromIndex:12];
}
- (NSString *)nd_minute;
{ if(!FILLED(self))return EON;
return [[self secureSubstringFromIndex:10]secureSubstringToIndex:2];
}
- (NSString *)nd_hour;
{ if(!FILLED(self))return EON;
return [[self secureSubstringFromIndex:8]secureSubstringToIndex:2];
}
- (NSString *)nd_firstOfMonth;
{ if(!FILLED(self))return EON;
return [NSSWF @"%@01%@",[self secureSubstringToIndex:6],[self secureSubstringFromIndex:8]];
}
- (NSString *)nd_startOfWeek;
{ NSCalendarDate *nscd = [self nd_NSCD];
int wd;
if(!nscd)return EON;
wd = [nscd dayOfWeek];
if(wd==1)return self; // ist schon Montag
if(!wd)wd=7; //Sonntag am Ende;
return [[nscd dateByAddingYears:0 months:0 days:- (wd - 1) hours:0 minutes:0 seconds:0]descriptionWithCalendarFormat:ND_FORMAT];
}
- (double)nd_deltaSecondsTo:(NSString *)nd1;
{ NSCalendarDate *nscd = [self nd_NSCD];
if(!nscd)return 0;
{ NSCalendarDate *nscd1 = [nd1 nd_NSCD];
if(!nscd1)return 0;
return [nscd1 timeIntervalSinceDate:nscd];
}
}
- (NSString *)nd_isFuture;
{ NSCalendarDate *nscd = [self nd_NSCD];
if(!nscd)return @"N";
if([nscd timeIntervalSinceDate:[NSCalendarDate date]]>0)return @"J";
return @"N";
}
- (NSString *)nd_isHistory;
{ NSCalendarDate *nscd = [self nd_NSCD];
if(!nscd)return @"N";
if([nscd timeIntervalSinceDate:[NSCalendarDate date]]<0)return @"J";
return @"N";
}
/* nd_ = normalized Date; 14 stelliger oder leerer String haelt alle Variablen als substrings
PBDate ersetzen
on demand weitere Methoden implementieren:
nd_weekOfYear // 1 <= woche <= 53
nd_yearForWeek // kann ein anderes sein als Jahr des Datums
nd_weekAndYear
nd_deltaWorkDaysTo:
nd_age; // in jahren
nd_workday
nd_withYear: andWeek:
*/
- (NSString *)initWithString:(NSString *)s calendarFormat:(NSString *)cf;
{//wg. mySQL Bug
return [self initWithString:s];
}
- (int)date_age_days;
{// liefert alter in Tagen
return [[PBDate dbDeltaFrom:self to:[[_APP today]secureSubstringToIndex:8]]doubleValue] / 3600 / 24;
}
- (NSString *)dbDateFromMySQLDate;
{ return [self onlyDigits];
}
- (NSString *)year;
{ return [[self normalizedDate]nd_year];
}
- (NSString *)month;
{ return [[self normalizedDate]nd_month];
}
- (NSString *)guiDate;
{// darf in mysql oder db-Format sein;
if(!FILLED(self))return EON;
return [[self normalizedDate]nd_guiDate];
}
+ (NSString *)timeIntervalDescription:(NSTimeInterval)aTimeInterval;
{ NSString *aTimeIntervalString;
int timeInterval = (int)aTimeInterval;
int days;
int hours;
int minutes;
int seconds;
days = (timeInterval / (60*60*24));
timeInterval = timeInterval - (days * (60*60*24));
hours = (timeInterval / (60*60));
timeInterval = timeInterval - (hours * (60*60));
minutes = (timeInterval / (60));
timeInterval = timeInterval - (minutes * (60));
seconds = timeInterval;
aTimeIntervalString = [NSString stringWithFormat:@"%d Tage, %d Std, %d Min, %d Sec", days, hours, minutes, seconds];
return aTimeIntervalString;
}
- (NSString *)stringByAddingDays:(int)i;
{// muss in dbFormat sein
PBDate *pbd = [PBDate dateWithDBString:self];
[pbd addDay:i];
if([self length]==8){ return [pbd dateAsDBString];
}else{ return [pbd dateAsDBDTString];
}
}
- (NSString *)doubleFromDate;
{ return [NSSWF @"%f",[[[self normalizedDate]nd_NSCD] timeIntervalSinceReferenceDate]];
}
- (PBDate *)pbdateWithDBString;
{// mysqldate oder dbdate format; optional mit Stunden/Minuten/Sec.
return [PBDate dateWithDBString:self];
}
- (PBDate *)pbdate;
{// convenience
// mysqldate oder dbdate format; optional mit Stunden/Minuten/Sec.
return [PBDate dateWithDBString:self];
}
@end
@implementation NSString ( PB3_File )
+ (NSString *)stringWithContentsOfFileUTF8:(NSString *)fn;
{ NSData *data;
if (![myFM fileExistsAtPath: fn]) return nil;
data = [NSData dataWithContentsOfFile:fn];
if(!fn)return nil;
return [NSString stringWithData:data];
}
+ (NSString *)stringWithContentsOfFilePE:(NSString *)fn;
{ NSData *data = [NSData dataWithContentsOfFile:fn];
NSStringEncoding enc = [[_APP currentSession] preferredEncoding];
return [[[NSString alloc] initWithData:data encoding:enc] autorelease];
}
- (NSString *)writeToFilePE:(NSString *)path;
{ BOOL rc = [self WTFPE:path];
return (rc?@"J": @"N");
}
- (NSString *)writeToFile:(NSString *)path;
{ BOOL rc = [self WTF:path];
return (rc?@"J": @"N");
}
- (BOOL)writeToFileUTF8:(NSString *)fn;
{ NSData *data;
if(!fn)return NO;
data = [self dataUsingEncoding:NSUTF8StringEncoding];
return [data writeToFile:fn atomically:YES];
}
- (BOOL)writeToFileLatin1:(NSString *)fn;
{ NSData *data;
if(!fn)return NO;
data = [self dataUsingEncoding:NSWindowsCP1252StringEncoding];
return [data writeToFile:fn atomically:YES];
}
- (BOOL)writeToFilePreferredEncoding:(NSString *)fn;
{ NSData *data;
NSStringEncoding enc;
if(!fn)return NO;
enc = [[_APP currentSession] preferredEncoding];
if ([self canBeConvertedToEncoding: enc]) { data = [self dataUsingEncoding: enc];
} else { LOGS(([NSSWF @"File %@: conversion to encoding %d is lossy!",fn,enc]));
data = [self dataUsingEncoding: enc
allowLossyConversion: YES];
}
return [data writeToFile:fn atomically:YES];
}
@end
@implementation NSString ( PB3_GUI )
+ (NSString *)readableValueOf:(int)i;
{ int j = abs(i);
if(j > 1000000){ return [NSSWF @"%i M",i/1000000];
}
if(j > 1000){ return [NSSWF @"%i K",i/1000];
}
return NSS(i);
}
- (NSString *)readableValue;
{ return [NSString readableValueOf:[self intValue]];
}
- (NSString *)blankWhen0;
{ if([self doubleValue]==0.0)return EON;
return self;
}
- (NSString *)point;
{ char s[128];
char *p;
strncpy(s, [self lossyCString], 127); //nur dezimalzahlen normalerweise
p = s;
while(*p){ if(*p == ','){ *p = '.';
}
p++;
}
return [NSString stringWithCString:s];
}
- (NSString *)comma;
{ char s[128];
char *p;
strncpy(s, [self lossyCString], 127); //nur dezimalzahlen normalerweise
p = s;
while(*p){ if(*p == '.'){ *p = ',';
}
p++;
}
return [NSString stringWithCString:s];
}
+ (NSString *)dottedGuiFromDouble:(double)d nak:(int)nak;
{//nur f. money
NSString *fs,*s;
NSString *ns;
int offset;
int lastlength=(d<0)?4:3;
NSString *ts = @".";
fs = [@"%0." stringByAppendingFormat:@"%if",nak];
s = [NSSWF fs,d];
s=[s comma];
offset = nak?nak+4:3;
if([s length] <= ((d<0)?offset+1:offset))return s; // 123,00 bzw. 123
ns = [s substringFromIndex:[s length]-offset];
s = [s substringToIndex:[s length]-offset];
while([s length] > lastlength){ ns = [[s substringFromIndex:[s length]-3] stringByAppendingFormat:@"%@%@",ts,ns];
s = [s substringToIndex:[s length]-3];
}
ns = [s stringByAppendingFormat:@"%@%@",ts,ns];
return ns;
}
+ (NSString *)guiFromDouble:(double)d;
{ return [[NSString stringWithFormat:@"%0.2f",round2(d)]comma];
}
- (NSString *)guiint;
{ return NSS((int)round0([self doubleValue]));
}
- (NSString *)guiMoney;
{ return [NSString dottedGuiFromDouble:[self doubleValue] nak:2];
}
@end
@implementation NSString ( PB3_CSV )
- (NSArray *)csvRecords;
{ return [self csvRecordsWithSeparator:@"," andEscape:@"\""];
}
- (NSArray *)csvRecordsWithSeparator:(NSString *)sep andEscape:(NSString *)escape;
{// parsen: character fuer character; liefert ein array von records; ein record ist wiederum ein array von feldern
LMAN(records);
NSMutableArray *currentRecord;
NSMutableString *currentField;
BOOL separatorOff = NO;
BOOL escapePending = NO;
int i,j;
NSAutoreleasePool *pool = nil;
currentRecord = [NSMutableArray arrayWithCapacity:30];
[records addObject:currentRecord];
currentField = [NSMutableString stringWithCapacity:100];
[currentField setString:EON];
[currentRecord addObject:currentField];
for(i=0,j=[self length];i<j;i++){ NSString *s;
{ if(!(i%10000)){ [pool release];
pool = [[NSAutoreleasePool alloc]init];
}
}
s = [self charAt:i];
if([self characterAtIndex:i] == 13)continue; // das will man nirgends haben
if(escapePending && ![s iE:escape]){ // wenn nicht unmittelbar nach einem escape, das ein escape escapen soll, ein escape kommt, verfaellt das escapende escape; z.B. ...,"",...
escapePending = NO;
// gleichzeitig ist die Wirkung eines escape am Feldanfang aufgehoben;
separatorOff = NO;
}
// \n beendet record, wenn nicht innerhalb eines mit escape geschuetzten feldes
if([s iE:@"\n"]){ if(separatorOff){ // \n ist normales Zeichen
[currentField appendString:s];
}else{ // neuer Record, neues Feld
currentRecord = [NSMutableArray arrayWithCapacity:30];
[records addObject:currentRecord];
currentField = [NSMutableString stringWithCapacity:100];
[currentField setString:@""];
[currentRecord addObject:currentField];
separatorOff = NO;
escapePending = NO;
}
continue;
}
// escape umschliesst Felder, die separators oder \n enthalten oder immer
if([s iE:escape]){ if(escapePending){ // f. doppelte escape, die ein escape escapen
[currentField appendString:s];
escapePending=NO;
continue;
}
if(!FILLED(currentField) && !separatorOff){ // am Feldanfang wird ein escape verbraucht, um im Feld separators auszuschalten
separatorOff = YES;
continue;
}
escapePending = YES;
continue;
}
if([s iE:sep]){ if(separatorOff){ // Separator ist normales Zeichen
[currentField appendString:s];
}else{ // neues Feld
currentField = [NSMutableString stringWithCapacity:100];
[currentField setString:EON];
[currentRecord addObject:currentField];
escapePending = NO;
separatorOff = NO;
}
continue;
}
[currentField appendString:s];
continue;
}
[pool release];
return records;
}
- (NSArray *)csvFields;
{ return [self csvFieldsWithSeparator:@"," andEscape:@"\""];
}
- (NSArray *)csvFieldsWithSeparator:(NSString *)sep andEscape:(NSString *)escape;
{// parsen: character fuer character; liefert ein array von feldern
LMA;
NSMutableString *currentField;
BOOL separatorOff = NO;
BOOL escapePending = NO;
int i,j;
currentField = [NSMutableString stringWithCapacity:100];
[currentField setString:EON];
[lma addObject:currentField];
for(i=0,j=[self length];i<j;i++){ NSString *s = [self charAt:i];
if([s iE:escape]){ if(escapePending){ [currentField appendString:s];
escapePending=NO;
continue;
}
if(!FILLED(currentField)){ separatorOff = YES;
continue;
}
escapePending = YES;
continue;
}
if([s iE:sep]){ if(separatorOff){ if(escapePending){ currentField = [NSMutableString stringWithCapacity:100];
[currentField setString:EON];
[lma addObject:currentField];
escapePending = NO;
separatorOff = NO;
continue;
}else{ [currentField appendString:s];
continue;
}
}else{ currentField = [NSMutableString stringWithCapacity:100];
[currentField setString:EON];
[lma addObject:currentField];
escapePending = NO;
separatorOff = NO;
continue;
}
}
[currentField appendString:s];
continue;
}
return lma;
}
@end
@implementation NSString ( PB3_Base )
+ (NSString *)stringWithCP1252Char:(unsigned int)i;
{ unsigned char c = i;
return [[[NSString alloc]initWithData:[NSData dataWithBytes:&c length:1] encoding:NSWindowsCP1252StringEncoding]autorelease];
}
+ (NSString *)stringWithUnichar:(unichar)uni;
{ return [NSString stringWithCharacters:&uni length:1];
}
- (NSString *)stringWithoutString:(NSString *)s;
{ return [[self componentsSeparatedByString:s]componentsJoinedByString:EON];
}
- (NSString *)text;
{ return self;
}
+ (NSString *)stringWithFormat:(NSString *)fs andParmStrings:(NSArray *)a;
{//darf %...i u. %@ platzhalter f. int u. strings enthalten
NSMutableString *ms,*fsm;
NSString *c;
int i,j,i1=0,j1=[a count];
BOOL proz=NO;
if(!j1)return fs;
ms = [NSMutableString stringWithCapacity:100];
fsm = [NSMutableString stringWithCapacity:100];
[ms setString:EON];
[fsm setString:@"%"];
for(i=0,j=[fs length];i<j;i++){ c = [fs charAt:i];
if([c iE:@"%"]){ if(!proz){ proz=YES; //in erwartung eines parameters
}else{ [ms appendString:c]; //%% -> escaped %
proz=NO;
[fsm setString:@"%"];
}
continue;
}
if(proz){ if([c iE:@"@"]){ if(i1<j1){ [ms appendString:[a oai:i1++]];
}else{ [ms appendString:@"%@"];
}
proz=NO; //parameter fertig
[fsm setString:@"%"];
continue;
}
if([c iE:@"0"] || [c intValue]>0){ [fsm appendString:c];
continue;
}
if([c iE:@"i"]){ [fsm appendString:c];
if(i1<j1){ [ms appendFormat:fsm,[[a oai:i1++]intValue]];
}else{ [ms appendString:fsm];
}
proz=NO;
[fsm setString:@"%"];
continue;
}
[fsm setString:@"%"];
[ms appendString:@"%"]; //alles andere hebt proz auf;
proz=NO;
continue;
}
[ms appendString:c];
}
return [[ms copy]autorelease]; // muss ein immutable String sein
}
+ (NSString *)stringWith:(int)i timesString:(NSString *)s;
{ if(!s)return @"";
{ LMA;
while(i-->0){ [lma addObject:s];
}
return [lma componentsJoinedByString:@""];
}
}
+ (NSString *)stringWithData:(NSData *)data;
{ NSString *s = nil;
const unsigned char *p,*pend;
unsigned int len;
if(!data)return nil;
len = [data length];
if(!len)return EON;
p = [data bytes];
if(len>=2){ unsigned short i = *p;
i <<= 8;
i+=*(p+1);
if(i == 0xFEFF || i == 0xFFFE){ s = [[NSString alloc]initWithData:data encoding:NSUnicodeStringEncoding];
return [s autorelease];
}
}
if(len>=3){//utf8 maker as used by some editors
if(*p == 0xEF && *(p+1)==0xBB && *(p+2)==0xBF){ data = [NSData dataWithBytes:(p+3) length: len-3];
s = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
return [s autorelease];
}
}
// mit //utf8 erzwingen, dass file als utf8 interpretiert wird
s = [[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]autorelease];
if([s hasSecurePrefix:@"//utf8"]||[s hasSecurePrefix:@"#utf8"]){// LOGS(([NSSWF @"%@: forcing utf8",fn]));
return s;
}
// ein utf8 sequenz starter zeichen ist >= 192, es wird gefolgt von mindestens einem zeichen >= 128 und < 192
// wenn ein zeichen >= 192 von einem Zeichen gefolgt wird, das < 128 oder > 192 ist, ist es kein utf8
// wenn ein zeichen < 128 von einem zeichen gefolgt wird, das zwischen 128 und 192 ist, ist es kein utf8
pend = p + len - 1;
while(p < pend){ unsigned char i = *p, ip1 = *(p + 1);
if(i >= 192 && (ip1 < 128 || ip1 >= 192)){ s = [[NSString alloc]initWithData:data encoding:NSWindowsCP1252StringEncoding];
return [s autorelease];
}
if(i < 128 && (ip1 >= 128 && ip1 < 192)){ s = [[NSString alloc]initWithData:data encoding:NSWindowsCP1252StringEncoding];
return [s autorelease];
}
p++;
}
// es koennte technisch latin1 oder utf8 sein.
// jedoch wenn es die ueblichen latin1 Sonderzeichen enthalten wuerde
// (ae,oe,ue,ss) haetten wir sie oben schon erkannt.
// vermutlich ist es daher utf8 oder ascii
// welches man auch als utf8 interpretieren darf.
s = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
return [s autorelease];
}
- (NSString *)stringValue;
{ return self;
}
- (NSString *)replace:(NSString *)a with:(NSString *)b;
{ NSArray *a1 = [self componentsSeparatedByString:a];
return [a1 componentsJoinedByString:b];
}
- (NSString *)iso8859DecodedString;
{ LMA;
NSArray *a1 = [self componentsSeparatedByString:@"?="];
NSString *s1 = [a1 firstObject];
// =E4abc=F6=FC=C4=D6=DC=DF
// FotoMail f=FCr Dich
int i1,j1;
for(i1=0,j1=[s1 length];i1<j1;i1++){ NSString *ch = [s1 charAt:i1];
if(![ch iE:@"="]){ [lma addObject:ch];
}else{ unichar uni;
uni = [[[s1 secureSubstringFromIndex:i1 + 1]secureSubstringToIndex:2]hexValue];
if(uni){ NSString *s4 = [NSString stringWithCharacters:&uni length:1];
if(s4)[lma addObject:s4];
}
i1+=2;
}
}
// alles was nach dem ?= kam
for(i1=1,j1=[a1 count];i1<j1;i1++){ s1 = [a1 oai:i1];
if(FILLED(s1))[lma addObject:s1];
}
return [lma componentsJoinedByString:@""];
}
- (NSString *)utf8DecodedString;
{ NSMutableData *mdata = [NSMutableData dataWithCapacity:100];
// f=C3=BCr
int i1,j1;
for(i1=0,j1=[self length];i1<j1;i1++){ NSString *ch = [self charAt:i1];
if(![ch iE:@"="]){ [mdata appendData:[ch dataUsingEncoding:NSUTF8StringEncoding]];
}else{ unsigned char c;
c = (unsigned char)[[[self secureSubstringFromIndex:i1 + 1]secureSubstringToIndex:2]hexValue];
[mdata appendBytes:&c length:1];
i1+=2;
}
}
return [[[NSString alloc]initWithData:mdata encoding:NSUTF8StringEncoding]autorelease];
}
- (NSData *)dataUsingCodePage858;
{ NSMapTable *map = [_APP codePage858Map];
unsigned i,length = [self length];
NSMutableData *data = [NSMutableData dataWithLength:length];
char *cp = [data mutableBytes];
const unichar *up = [[self dataUsingEncoding: NSUnicodeStringEncoding] bytes];
up++; //skip BOM
for (i=0;i<length;i++) { *cp = (char)(int)NSMapGet(map,(void *)(int)*up);
if (!*cp) *cp = (char)*up;
cp++;
up++;
}
return data;
}
- (BOOL)containsObject:(id)anObject;
{ return [self containsString:anObject];
}
- (BOOL)containsString:(NSString *)s options:(unsigned int)mask;
{ return [self rangeOfString: s options: mask].length ? YES : NO;
}
- (BOOL)containsString:(NSString *)s;
{ return [self containsString:s options: 0];
}
- (BOOL)containsCharactersFromSet:(NSCharacterSet *)s;
{ return [self rangeOfCharacterFromSet:s].length ? YES : NO;
}
- (char)charValue;
{// f. Kompatiblitaet bei takeValue: forKey:
return [self intValue];
}
- (NSString *)charAt:(int)i;
{ if(i>=[self length])return nil;
if(i<0)return nil;
return [[self substringFromIndex:i]substringToIndex:1];
}
- (BOOL)boolValue;
{ if ([self caseInsensitiveCompare: @"J"] == NSOrderedSame)
{ return YES;
}
if ([self caseInsensitiveCompare: @"YES"] == NSOrderedSame)
{ return YES;
}
if ([self caseInsensitiveCompare: @"true"] == NSOrderedSame)
{ return YES;
}
return [self intValue] != 0 ? YES : NO;
}
- (BOOL)boolValuePB3;
{ return [self boolValue];
}
- (NSString *)string;
{//wg. kompatibilitaet zu PBStringWrapper
return self;
}
@end
@implementation NSString ( PB3_Escaping )
- (NSString *)sqlWildCardEscapedString;
{ BOOL isEscaped = NO;
int i,j;
NSMutableString *ms = [NSMutableString stringWithCapacity:20];
unichar c=0;
[ms setString:EON];
for(i=0,j=[self length];i<j;i++){ c = [self characterAtIndex:i];
if(!isEscaped){ switch(c){ case '%':
[ms appendString:@"\\%"];
continue;
case '_':
[ms appendString:@"\\_"];
continue;
case '\\':
isEscaped = YES;
continue;
}
}else{ isEscaped = NO;
}
[ms appendString:[NSString stringWithCharacters:&c length:1]];
}
return (NSString *)ms;
}
- (NSString *)mysqlEscapedString;
{// fuer Feldinhalte und literals
NSMutableString *ms = [NSMutableString stringWithString:self];
int totalLen = [self length];
int index=0,len=0;
unichar curr;
while(index < totalLen)
{ curr = [self characterAtIndex:index];
switch(curr)
{ case '\n':
case '\'':
case '\\':
case '"':
[ms insertString:@"\\" atIndex:len];
len++;
}
len++;
index++;
}
return (NSString *)ms;
}
- (NSString *)xmlEscapedString;
{ NSMutableString *ms = [NSMutableString stringWithCapacity:[self length]+3];
int i,j;
[ms setString:EON];
for(i=0,j=[self length];i<j;i++){ NSString *s = [self charAt:i];
if([s iE:@"<"]){ [ms appendString:@"<"];
continue;
}
if([s iE:@">"]){ [ms appendString:@">"];
continue;
}
if([s iE:@"&"]){ [ms appendString:@"&"];
continue;
}
if([s iE:@"\""]){ [ms appendString:@""e;"];
continue;
}
if([s iE:@"'"]){ [ms appendString:@"'"];
continue;
}
[ms appendString:s];
}
return ms;
}
- (NSString *)stringBySubstitutingXMLEscapes;
{ NSString *s = [self replace:@"<" with:@"<"];
s = [s replace:@">" with:@">"];
s = [s replace:@"&" with:@"&"];
return s;
}
- (NSString *)stringByEscapingCRTAB;
{// fuer ASCII-Archivierung von EOs
static NSCharacterSet *set=nil;
if (set==nil) set = [[NSCharacterSet characterSetWithCharactersInString:@"\\\n\t"] retain];
if ([self rangeOfCharacterFromSet: set].length)
{ NSString *ns;
unichar *rd, *wr, *st;
NSZone *zone;
unsigned len, i;
len = [self length];
zone = NSDefaultMallocZone();
rd = NSZoneMalloc(zone,sizeof(unichar)*len);
wr = NSZoneMalloc(zone,sizeof(unichar)*len*2);
st = wr;
[self getCharacters: rd];
for (i=0; i<len; i++, rd++) {// the unichar (int16) values of the characters we are looking for
// happen to correspond to the char (int8) values. (\\ \n and \t)
// which makes this code safe. Otherwise we would need to use the unichar
// 0x0000 values in the case statements.
switch (*rd) { case '\\': *wr++='\\'; *wr++='\\'; break;
case '\n': *wr++='\\'; *wr++='n'; break;
case '\t': *wr++='\\'; *wr++='t'; break;
default: *wr++=*rd; break;
}
}
ns = [NSString stringWithCharacters:st length:wr-st];
NSZoneFree(zone,rd-len);
NSZoneFree(zone,st);
return ns;
}
return self;
}
- (NSString *)stringByUnescapingCRTAB;
{ static NSCharacterSet *set=nil;
if (set==nil) set = [[NSCharacterSet characterSetWithCharactersInString:@"\\"] retain];
if ([self rangeOfCharacterFromSet: set].length) { NSString *ns;
unichar *rd, *wr, *st;
NSZone *zone;
unsigned len, i;
len = [self length];
zone = NSDefaultMallocZone();
rd = NSZoneMalloc(zone,sizeof(unichar)*len);
wr = NSZoneMalloc(zone,sizeof(unichar)*len);
st = wr;
[self getCharacters: rd];
for (i=0; i<len; i++, rd++) {// the unichar (int16) values of the characters we are looking for
// happen to correspond to the char (int8) values. (\\ \n and \t)
// which makes this code safe. Otherwise we would need to use the unichar
// 0x0000 values in the case statements.
if (*rd == '\\') { rd++; i++;
switch (*rd) { case '\\': *wr++='\\'; break;
case 'n': *wr++='\n'; break;
case 't': *wr++='\t'; break;
default: *wr++=*rd; break;
}
} else { *wr++=*rd;
}
}
ns = [NSString stringWithCharacters:st length:wr-st];
NSZoneFree(zone,rd-len);
NSZoneFree(zone,st);
return ns;
}
return self;
}
- (NSString *)latexEscapedString;
{ NSMutableString *ms = [NSMutableString stringWithString:@""];
int i,j = [self length];
unichar curr;
for(i=0;i<j;i++){ curr = [self characterAtIndex:i];
switch(curr){ case '$':
[ms appendString:@"\\$"];
continue;
case '&':
[ms appendString:@"\\&"];
continue;
case '%':
[ms appendString:@"\\%"];
continue;
case '#':
[ms appendString:@"\\#"];
continue;
case '_':
[ms appendString:@"\\_"];
continue;
case '{': [ms appendString:@"\\{"]; continue;
case '}':
[ms appendString:@"\\}"];
continue;
case '~':
[ms appendString:@"\\~{}"]; continue;
case '^':
[ms appendString:@"\\^{}"]; continue;
case '"':
[ms appendString:@"\\dq{}"]; continue;
case '\\':
[ms appendString:@"\\textbackslash "];
continue;
case '|':
[ms appendString:@"\\textbar "];
continue;
case '<':
[ms appendString:@"\\textless "];
continue;
case '>':
[ms appendString:@"\\textgreater "];
continue;
}
[ms appendString:[NSString stringWithCharacters:&curr length:1]];
}
return (NSString *)ms;
}
- (NSString *)htmlEscapedString;
{ NSMutableString *ms = [NSMutableString stringWithString:@""];
int i,j = [self length];
unichar curr;
for(i=0;i<j;i++){ curr = [self characterAtIndex:i];
switch(curr){ case '&':
[ms appendString:@"&"];
continue;
case '"':
[ms appendString:@"""];
continue;
case '<':
[ms appendString:@"<"];
continue;
case '>':
[ms appendString:@">"];
continue;
}
[ms appendString:[NSString stringWithCharacters:&curr length:1]];
}
return (NSString *)ms;
// tut nicht; " wird zu ungueltigen zeichen... return [WOResponse stringByEscapingHTMLString:self];
}
- (NSString *)pdfEscapedString;
{ int j = [self length];
int i=0;
NSMutableString *ms = [NSMutableString stringWithCapacity:j];
[ms setString:@"("]; for(i=0,j=[self length];i<j;i++){ unichar ch = [self characterAtIndex:i];
if( (ch == '\\') || (ch == '(') || (ch == ')') ){ [ms appendString:@"\\"];
[ms appendString:[NSString stringWithCharacters:&ch length:1]];
} else if(ch == '\r') { [ms appendString:@"\\"];
[ms appendString:@"r"];
}else{ [ms appendString:[NSString stringWithCharacters:&ch length:1]];
}
}
[ms appendString:@")"];
return ms;
}
@end
@implementation NSString ( PB3_Substring )
- (NSString *)withoutPrefix:(NSString *)pref;
{ if(!pref)return self;
if([self hasPrefix:pref]){ return [self substringFromIndex:[pref length]];
}
return self;
}
- (NSString *)stringWithoutLeadingWhiteSpace;
{ int i,j;
unichar c;
for(i=0,j=[self length];i<j;i++){ c = [self characterAtIndex:i];
if(c != ' ' && c != '\t')return (i?[self substringFromIndex:i]:self);
}
return EON;
}
- (NSString *)stringWithoutLeadingWhiteSpaceCRLF;
{ int i,j;
unichar c;
for(i=0,j=[self length];i<j;i++){ c = [self characterAtIndex:i];
if(c != ' ' && c != '\t' && c != '\n' && c != '\r')return (i?[self substringFromIndex:i]:self);
}
return EON;
}
- (NSString *)stringWithoutTrailingWhiteSpace;
{ int j,i=[self length];
unichar c;
for(j=i-1;j>=0;j--){ c = [self characterAtIndex:j];
if(c != ' ' && c != '\t' && c != '\r')return ((j<(i-1))?[self substringToIndex:j+1]:self);
}
return EON;
}
- (NSString *)stringWithoutTrailingWSC;
{// trailing White Space und Comment weg;
NSRange r = [self rangeOfString:@"//"];
NSString *s = self;
if(r.length)s = [s substringToIndex:r.location];
return [s stringWithoutTrailingWhiteSpace];
}
- (NSString *)stringWithoutSuffix:(NSString *)s;
{ int l = [s length];
if([self length] < l || l==0)return self;
return [self substringToIndex:[self length] - l];
}
- (NSString *)stringWithoutLastChar;
{ return [self secureSubstringToIndex:[self length]-1];
}
- (NSString *)stringByDeletingLastKeypath;
{ LMA;
[lma addObjectsFromArray:[self componentsSeparatedByString:@"."]];
[lma secureRemoveLastObject];
return [lma componentsJoinedByString:@"."];
}
- (BOOL)hasPrefixFrom:(NSArray *)a;
{ int i,j;
if(!a)return NO;
if(!(j=[a count]))return NO;
for(i=0;i<j;i++){ if([self hasPrefix:[a oai:i]])return YES;
}
return NO;
}
- (BOOL)hasSecurePrefix:(NSString *)s;
{ if(s && [self length] >= [s length])return [self hasPrefix:s];
return NO;
}
- (BOOL)hasSecureSuffix:(NSString *)s;
{ if(s && [self length] >= [s length])return [self hasSuffix:s];
return NO;
}
- (NSString *)secureSubstringFromIndex:(int)i;
{ if(!i)return self;
if(i>=[self length] || i<0)return EON;
return [self substringFromIndex:i];
}
- (NSString *)abbreviatedString;
{ return [self abbrevToLength:15]; //in wod zu verwenden, damit auswahllisten nicht zu breit werden
}
- (NSString *)abbreviated30String;
{ return [self abbrevToLength:30]; //in wod zu verwenden, damit strings nicht zu lang werden
}
- (NSString *)abbreviated40String;
{ return [self abbrevToLength:40]; //in wod zu verwenden, damit strings nicht zu lang werden
}
- (NSString *)abbreviated60String;
{ return [self abbrevToLength:60]; //in wod zu verwenden, damit strings nicht zu lang werden
}
- (NSString *)abbreviated80String;
{ return [self abbrevToLength:80]; //in wod zu verwenden, damit strings nicht zu lang werden
}
- (NSString *)abbrevToLength:(int)i;
{ if(i<1)return self;
if([self length]<=i)return self;
return [[self substringToIndex:i]stringByAppendingString:@"..."];
}
- (NSString *)lastChar;
{ int i = [self length];
if(!i)return EON;
return [self substringFromIndex:i-1];
}
- (NSString *)secure0LPaddedSubstringToIndex:(int)i;
{ return [self secureSubstringToIndex:i pad:PAD_LEFT padString:@"0"];
}
- (NSString *)secure0RPaddedSubstringToIndex:(int)i;
{ return [self secureSubstringToIndex:i pad:PAD_RIGHT padString:@"0"];
}
- (NSString *)secureBlankLPaddedSubstringToIndex:(int)i;
{ return [self secureSubstringToIndex:i pad:PAD_LEFT padString:@" "];
}
- (NSString *)secureBlankRPaddedSubstringToIndex:(int)i;
{ return [self secureSubstringToIndex:i pad:PAD_RIGHT padString:@" "];
}
- (NSString *)secureSubstringToIndex:(int)i;
{ int l = [self length];
if(!i)return @"";
if(l<=i)return self;
return [self substringToIndex:i];
}
- (NSString *)secureSubstringToIndex:(int)i pad:(int)pad padString:(NSString *)padString;
{ int l = [self length];
if(l >= i)return [self substringToIndex:i];
if(pad != PAD_NONE){ NSMutableString *ms = [NSMutableString stringWithCapacity:20];
int i1;
if(!padString || [padString length]!=1)padString=@"0";
if(pad == PAD_RIGHT){ [ms setString:self];
for(i1=l;i1<i;i1++){ [ms appendString:padString];
}
return ms;
}
if(pad == PAD_LEFT){ [ms setString:padString];
for(i1=1;i1<i-l;i1++){ [ms appendString:padString];
}
[ms appendString:self];
return ms;
}
}
return self;
}
@end
@implementation NSString ( PB3_Transform )
- (int)nvePruefziffer;
{ /* Die Prüfziffer errechnet sich nach folgendem Verfahren: Zunächst werden die Nutzziffern mit den Gewichten 3 (ungerade Ziffern) und 1 (gerade Ziffern) multipliziert und die Ergebnisse addiert. Ist die letzte Stelle dieser Summe eine 0, so ist auch die Prüfziffer 0, sonst die Differenz aus 10 und der letzten Stelle.
*/
int i = [self length] - 1;
int sum = 0;
int gewichtung = 3;
int pz;
while(i>=0){ sum += [[self charAt:i]intValue] * gewichtung;
if(gewichtung == 3){ gewichtung = 1;
}else{ gewichtung = 3;
}
i--;
}
pz = sum % 10;
if(pz)pz = 10 - pz;
return pz;
}
- (NSString *)ean13String;
{ if([self length]!=12){ LOG(@"kein geeigneter ean13 Code");
return @"";
}
if(![[self onlyDigits]iE:self]){ LOG(@"kein geeigneter ean13 Code, da nicht ausschliesslich numerisch");
return @"";
}
// input: 12 stellig numerisch; 2 stellen Land, 5 stellen Firma, 5 stellen Produkt
// ouput: aufbereitet f. ean13.ttf: 1 Stelle Start, 6 Stellen odd/even, Trenner, 5 Stellen, Pruefziffer, Ende-Kennug
{ unsigned char erg[16]; // mit 0 terminieren dann
const char *s = [self lossyCString];
unsigned char first = *s - '0';
int erg_index = 0;
int pz;
int i;
unsigned char odd_even[10][6] = { {0,0,0,0,0,0}, {0,0,1,0,1,1}, {0,0,1,1,0,1}, {0,0,1,1,1,0}, {0,1,0,0,1,1}, {0,1,1,0,0,1}, {0,1,1,1,0,0}, {0,1,0,1,0,1}, {0,1,0,1,1,0}, {0,1,1,0,1,0} };
erg[erg_index++] = *s;
pz = first;
for(i=1;i<=11;i++){ int digit = *(s + i) - '0';
pz += (digit * ((i % 2)?3:1));
if(i<=6){ erg[erg_index++] = digit + 'A' + (odd_even[first][i - 1] * 10);
if(i==6) erg[erg_index++]=42;
}else{ erg[erg_index++] = digit + 'a';
}
}
pz = pz%10;
if(pz)pz = 10 - pz;
erg[erg_index++] = pz + 'a';
erg[erg_index++] = 43;
erg[erg_index++] = 0;
return [NSString stringWithCString:erg];
}
return @"";
}
- (NSString *)ean128C00String;
{// fuer numerische Nutzdaten
// CP1252
// pruefziffer ermitteln, Nutzdaten kodieren
// Start-C, fnc1, 00, Nutzdaten, Pruefziffer, Pruefzeichen, Stop
int i,ii,j;
int sum = 0;
int gewichtung=2;
int pz;
NSString *s;
NSMutableData *mdata = [NSMutableData dataWithCapacity:100];
unsigned char c;
c = 155; // Start C
sum += 105;
[mdata appendBytes:&c length:1];
c = 152; // FNC1
[mdata appendBytes:&c length:1];
sum += 102;
pz = [self nvePruefziffer];
s = [NSSWF @"00%@%i",self,pz];
// 2er Bloecke in Buchstaben kodieren
for(i=0,j=[s length];i<j;i+=2){ ii = [[[s substringFromIndex:i]secureSubstringToIndex:2]intValue];
sum += ii * gewichtung++;
if(ii==0){ c = 128;
}else{ if(ii<=94){ c = ii + 32;
}else{ c = ii + 50;
}
}
[mdata appendBytes:&c length:1];
}
/*
Pruefzeichen berechnen lt. http://www.fh-gelsenkirchen.de/fb01/laboratorien/02-Informatik/sy/Diplom/SY2-Diplom_2008_9/EAN128_im_Detail.pdf
1 Multipliziere den Wert des Startzeichens und des FN1 Zeichens mit 1. Gewichte den Wert des 3.
Symbolzeichens mit 2 und alle weiteren Werte der Symbolzeichen (auch Hilfszeichen) mit Faktoren in
aufsteigender Reichenfolge (3,4,5,...).
2 Summiere alle gewichteten Werte
3 Dividiere die Summe aus Schritt 2 durch 103
4 Das Symbolprüfzeichen hat den Wert des Divisionsrestes von Schritt 3
*/
ii = sum % 103;
if(ii==0){ c = 128;
}else{ if(ii<=94){ c = ii + 32;
}else{ c = ii + 50;
}
}
[mdata appendBytes:&c length:1];
c = 156; // stop
[mdata appendBytes:&c length:1];
return [[[NSString alloc] initWithData:mdata encoding:NSWindowsCP1252StringEncoding]autorelease];
}
- (NSString *)translatedString;
{ return [[_APP currentSession] transFor:self];
}
- (NSString *)simplyfiedString;
{//nur grossbuchstaben uebriglassen
char s[1024];
char s1[1024];
char *p,*p1;
char c;
char *c1;
c1 = (char *)[self lossyCString]; //f. Bank-suche, Modulsuche
strncpy(s, c1, 1023);
p = s;
p1 = s1;
while((c = *p)){ if(c < '@'){ p++;
continue;
}
if(c > 'z'){ p++;
continue;
}
if(c > 'Z' && c < 'a'){ p++;
continue;
}
if(c >= 'a'){ c-=32; //to upper
}
*p1=c;
p1++;
p++;
}
*p1 = 0; //ergebnis terminieren
return [NSString stringWithCString:s1];
}
- (NSString *)str12;
{ return [self str:12];
}
- (NSString *)str9;
{ return [self str:9];
}
- (NSString *)str7;
{ return [self str:7];
}
- (NSString *)str:(int)l;
{// erzeugt rechtsbuendigen money-formatierten String der laenge l
NSString *s = [self guiMoney];
int i = [s length];
if(i>l)return @"######,##";
if(i==l)return s;
return [NSSWF @"%@%@",[@" " secureSubstringToIndex:(l - i)],s];
}
- (NSString *)strs12;
{ return [self strs:12];
}
- (NSString *)strs9;
{ return [self strs:9];
}
- (NSString *)strs7;
{ return [self strs:7];
}
- (NSString *)strs:(int)l;
{// erzeugt rechtsbuendigen String der laenge l
int i = [self length];
if(i==l)return self;
if(i>l)return [self substringToIndex:l];
return [NSSWF @"%@%@",[@" " secureSubstringToIndex:(l - i)],self];
}
- (NSString *)stl12;
{ return [self stl:12];
}
- (NSString *)stl9;
{ return [self stl:9];
}
- (NSString *)stl7;
{ return [self stl:7];
}
- (NSString *)stl:(int)l;
{// erzeugt linksbuendigen String der laenge l
return [[NSSWF @"%@ ",self] secureSubstringToIndex:l];
}
- (NSString *)rfcRFC1342DecodedString;
{// =?ISO-8859-15?Q?=E4=F6=FC=C4=D6=DC=DF?=blafasel
// =?ISO-8859-1?Q?Question_for_item_#320065132667_-_Einma?= =?ISO-8859-1?Q?liger_Kn=FCller_-_legend=E4res_Sammlerst=FCck?=
NSArray *a = [self componentsSeparatedByString:@"=?ISO-8859-15?Q?"];
int i,j;
LMA;
if([a count]<2)a = [self componentsSeparatedByString:@"=?iso-8859-15?Q?"];
if([a count]<2)a = [self componentsSeparatedByString:@"=?ISO-8859-1?Q?"];
if([a count]<2)a = [self componentsSeparatedByString:@"=?iso-8859-1?Q?"];
if([a count]<2)return self;
for(i=0,j=[a count];i<j;i++){ NSString *s = [a oai:i];
// =E4=F6=FC=C4=D6=DC=DF?=blafasel
// FotoMail f=FCr Dich?=
if(FILLED(s)){ [lma addObject:[s iso8859DecodedString]];
}
}
return [lma componentsJoinedByString:@""];
}
- (NSString *)onlyDigits;
//alles ausser digits strippen; Category
{ char *c,cx;
char c1[20];
int count = 0;
if([self length] < 1) return self;
c = (char *)[self lossyCString]; //interessieren nur digits
while((cx=*c++) && count < 18){ if(!isdigit(cx))continue;
c1[count++]=cx;
}
c1[count]=0;
return [NSString stringWithCString:c1];
}
- (NSString *)normalizedTel;
// Telefonnr. normalisieren
{ char *c,x;
char c1[40];
int count = 0;
NSString *s = [self stringWithoutSpace];
if([s hasSecurePrefix:@"+"]){ s = [NSSWF @"00%@",[s substringFromIndex:1]];
}
if([s length] < 1) return s;
c = (char *)[s lossyCString]; //interessieren nur digits
while((x=*c++) && count < 39){ if(x=='/'){ c1[count++]='-';
continue;
}
if(!(((x)>='0' && (x)<='9') || x == '-'))continue;
c1[count++]=x;
}
c1[count]=0;
return [NSString stringWithCString:c1];
}
- (NSString *)dbMoneyFromGui;
{ return [[[self componentsSeparatedByString:@"."]componentsJoinedByString:EON] point];
}
- (NSString *)stringWithout0xD;
{ return [self stringWithoutString:@"\r"];
}
- (NSString *)stringWithForwardSlashes;
{ return [[self componentsSeparatedByString:@"\\"]componentsJoinedByString:@"/"];
}
- (NSString *)stringWithBackSlashes;
{ return [[self componentsSeparatedByString:@"/"]componentsJoinedByString:@"\\"];
}
+ (NSString *)dbFromDouble:(double)d;
{ return [NSString stringWithFormat:@"%0.2f", round2(d)];
}
+ (NSString *)dbFromDouble:(double)d nak:(int)nak;
{ NSString *fs;
//lt. doku: wird gerundet, precision 0 -> keine Nachkommastellen;
fs = [NSSWF @"%%0.%if",nak];
return [NSSWF fs,d];
}
+ (NSString *)dbFromDouble:(double)d pba:(PBDDAttribute *)pba;
{ switch([pba dataTyp]){ case DT_MONEY:
return [NSString dbFromDouble:d nak:2];
case DT_FLOAT:
return [NSString dbFromDouble:d nak:[pba nak]];
case DT_INT:
return [NSString dbFromDouble:d nak:0];
}
return nil;
}
- (NSString *)stringWithoutTextareaCR;
{ NSString *ns;
unichar *rd, *wr, *st, *rd_save;
NSZone *zone;
unsigned len, i;
BOOL hasContent = NO;
len = [self length];
zone = NSDefaultMallocZone();
rd = NSZoneMalloc(zone,sizeof(unichar)*len);
rd_save = rd;
wr = NSZoneMalloc(zone,sizeof(unichar)*len);
st = wr;
[self getCharacters: rd];
for (i=0; i<len; i++, rd++) {// the unichar (int16) values of the characters we are looking for
// happen to correspond to the char (int8) values. (\\ \n and \t)
// which makes this code safe. Otherwise we would need to use the unichar
// 0x0000 values in the case statements.
switch (*rd) { case 0xd: break;
case 0xf: break;
case 0xa0: break;
case 0xa: *wr++=*rd; break;
default: *wr++=*rd; hasContent = YES; break;
}
}
if(!hasContent){ ns = @"";
}else{ ns = [NSString stringWithCharacters:st length:wr-st];
}
NSZoneFree(zone,rd_save);
NSZoneFree(zone,st);
return ns;
}
- (int)hexValue;
{ int i=[self length];
int hv;
int p = 16;
if(!i)return 0;
hv = [[self lastChar]valueForHexDigit];
i-=2;
while(i >= 0){ hv += ([[self charAt:i]valueForHexDigit] * p);
i--;
p*=16;
}
return hv;
}
- (NSString *)hexFormat;
{ LMA;
int i,j;
for(i=0,j=[self length];i<j;i++){ unichar uni = [self characterAtIndex:i];
[lma addObject:[NSSWF @"%x",(unsigned char)uni]];
}
return [lma componentsJoinedByString:@" "];
}
- (int)valueForHexDigit;
{ NSString *s = [self lowercaseString];
if([s length]!=1)return 0;
if([s iE:@"a"])return 10;
if([s iE:@"b"])return 11;
if([s iE:@"c"])return 12;
if([s iE:@"d"])return 13;
if([s iE:@"e"])return 14;
if([s iE:@"f"])return 15;
return [s intValue];
}
- (NSString *)firstCapitalizedString;
{ if([self length] <= 1)return [self uppercaseString];
return [[[self substringToIndex:1]uppercaseString] sbas:[self substringFromIndex:1]];
}
- (NSString *)stringWithoutWindowsShit;
{ int l = [self length];
if(!l)return self;
if([self characterAtIndex:l-1] == 13)return [self substringToIndex:l-1];
return self;
}
- (NSString *)stringWithoutDigits;
{ NSString *s = [self stringWithoutString:@"0"],*zahl;
int i;
for(i=1;i<10;i++){ zahl = [NSSWF @"%i",i];
s = [s stringWithoutString:zahl];
}
return s;
}
- (NSString *)urlEncodedString;
{ return [self replace:@" " with:@"%20"];
}
- (NSString *)doubleQuotedString;
{ return [NSSWF @"\"%@\"",self];
}
- (NSString *)mysqlCompliantString;
{// fuer Namen in Mysql; feld und Tabellennamen
return [[[self replace:@"." with:@"_"] replace:@"-" with:@"_"]lowercaseString];
}
- (NSString *)sageString;
{// doppelte Hochkomma durch einfach ersetzen, weil Sage kein csv beherrscht
return [self replace:@"\"" with:@"'"];
}
- (NSString *)sageDate;
{// TTMMJJJJ
NSString *s;
if([self rangeOfString:@"-"].length){ s = [self dbDateFromMySQLDate];
}else{ s = self;
}
if([s intValue]==0)return @"30071966";
{ long l = [[s secureSubstringToIndex:8] intValue];
int day = l % 100;
int month = (l / 100) % 100;
int year = l / 10000;
return [NSSWF @"%02i%02i%04i",day,month,year];
}
}
- (NSString *)stringWithoutDatevSonderzeichen;
/* datev Sonderzeichen raus; */
{ char s[255];
unsigned char c;
char s1[255];
char *p,*p1;
NSData *data;
NSString *v;
strncpy(s, [self lossyCString], 254); // Datev egal, ob unicode verluste
p = s;
p1 = s1;
while(*p){ //umlaute umschluesseln wg. datev encoding c=*p;
/*
*/
if(c==0xe4)c=0x84;
if(c==0xf6)c=0x94;
if(c==0xfc)c=0x81;
if(c==0xc4)c=0x8e;
if(c==0xd6)c=0x99;
if(c==0xdc)c=0x9a;
if(c==0xdf)c=0xe1;
if((c < 0x20 && c != 0x15) || (c > 0x5a && c < 0x5f) || (c > 0x7a && c != 0x81 && c != 0x84 && c != 0x8e && c != 0x94 && c != 0x99 && c != 0x9a && c != 0xe1 && c != 0xf9 && c != 0xfe)){ p++;
continue;
}
*p1++ = c;
p++;
}
*p1=0;
data = [[NSData alloc]initWithBytes:s1 length:strlen(s1)];
v = [[NSString alloc] initWithData:data encoding:NSISOLatin1StringEncoding]; //datev ist halt speziell
[data release];
[v autorelease];
return v;
}
- (NSString *)stringWithHTMLTabs;
{ return [[self replace:@"\t" with:@" "]replace:@" " with:@" "];
}
- (NSString *)asciiString;
/* alles kleiner Space auf '_' setzen; */
{ char s[1024];
char *p;
strncpy(s, [self lossyCString], 1023); //sowieso nur ASCII gewollt
p = s;
while(*p){ if(*p < ' '){ *p = '_';
}
p++;
}
return [NSString stringWithCString:s];
}
- (NSString *)umlautExpandedString;
{// fuer Filesysteme, die keine Umlaute koennen
int i,j;
NSMutableString *ms = [NSMutableString stringWithCapacity:100];
[ms setString:@""];
for(i=0,j=[self length];i<j;i++){ unichar ch = [self characterAtIndex:i];
switch(ch){ case 0x00e4: [ms appendString:@"ae"]; continue;
case 0x00f6: [ms appendString:@"oe"]; continue;
case 0x00fc: [ms appendString:@"ue"]; continue;
case 0x00c4: [ms appendString:@"Ae"]; continue;
case 0x00d6: [ms appendString:@"Oe"]; continue;
case 0x00dc: [ms appendString:@"Ue"]; continue;
case 0x00df: [ms appendString:@"ss"]; continue;
default: [ms appendString:[NSString stringWithCharacters:&ch length:1]];
}
}
return ms;
}
- (NSString *)stringWithoutCR;
{ return [[self componentsSeparatedByString:SC_NewLine]componentsJoinedByString:@" "];
}
- (NSString *)stringWithoutSpace;
{ return [self stringWithoutString:@" "];
}
@end
@implementation NSString ( PB3 )
/* Deprecated
- (NSString *)mySQLDateFromDbDate;
{ return [[PBDate dateWithDBString:self]dateAsMysqlDBDTString];
}
- (NSString *)stringByAddingHour:(int)i;
{ NSArray *a;
int h,m;
if([self length]!=5)return @"00:00";
a = [self componentsSeparatedByString:@":"];
if([a count]!=2)return @"00:00";
h = [[a oai:0]intValue];
m = [[a oai:1]intValue];
h += i;
if(h >=24 || h < 0)return @"00:00";
return [NSSWF @"%02i:%02i",h,m];
}
- (int)zeitDifferenz:(NSString *)s;
{ int hh1,mm1,hh2,mm2,i;
//HHMM
if(!s || [s length]!=4 || [self length]!=4)return 0;
hh1=[[self substringToIndex:2]intValue];
hh2=[[s substringToIndex:2]intValue];
mm1=[[self substringFromIndex:2]intValue];
mm2=[[s substringFromIndex:2]intValue];
i=hh2 * 60 + mm2 - hh1 * 60 - mm1;
return i;
}
+ (NSString *)formattedDouble:(double )d;
{ BOOL neg = NO;
NSString *unit=EON;
if(d < 0){ neg =YES;
d*=-1.0;
}
if(d > 10000.0){ if(d<1000000.0){ d /= 1000.0;
unit = @" T";
}else{ d /= 1000000.0;
unit = @" M";
}
}
if(neg)d*=-1.0;
return [[NSString stringWithFormat:@"%0.2f%@",round2(d),unit]comma];
}
- (BOOL)matches:(NSString *)s;
{ NSArray *a;
int i,j;
if(!s)return NO;
if([self iE:s])return YES;
if([self iE:@"*"])return YES;
a = [self componentsSeparatedByString:@","];
j = [a count];
if(j>1){ for(i=0,j=[a count];i<j;i++){ if([[a oai:i]matches:s])return YES;
}
}else{ if([self hasSuffix:@"*"]){ NSString *s1 = [self stringWithoutSuffix:@"*"];
if([s hasSecurePrefix:s1])return YES;
}
}
return NO;
}
- (NSString *)extendWith:(NSString *)s toLength:(int)l;
{ NSMutableString *ms;
if([self length]>=l)return [self substringToIndex:l];
if(!FILLED(s))s=@".";
ms = [NSMutableString stringWithCapacity:l];
[ms setString:self];
while([ms length] < l){ [ms appendString:s];
}
return ms;
}
- (BOOL)matchesAt:(int)i1;
{// * = immer
// 2,3,4,10-20 beliebig viele Einzelwerte und Ranges
NSArray *a = [self componentsSeparatedByString:@","],*a1;
int i,j;
NSString *s;
for(i=0,j=[a count];i<j;i++){ s = [a oai:i];
if([s iE:@"*"])return YES;
if([s intValue]==i1)return YES;
a1 = [self componentsSeparatedByString:@"-"];
if([a1 count]!=2)continue;
if([[a1 oai:0]intValue] <= i1 && [[a1 oai:1]intValue] >= i1)return YES;
}
return NO;
}
- (BOOL)matchesWotag:(NSString *)s1;
{// So,Mo,Di
NSArray *a = [self componentsSeparatedByString:@","];
int i,j;
NSString *s;
for(i=0,j=[a count];i<j;i++){ s = [a oai:i];
if([s iE:@"*"])return YES;
if([[s lowercaseString]iE:[s1 lowercaseString]])return YES;
}
return NO;
}
- (NSString *)beautifiedDescription;
{ NSString *s = [self stringWithoutCR];
if([s length]<2)return s;
return [[s substringToIndex:[s length]-1] substringFromIndex:1];
}
- (NSString *)brForCR;
{ return [[self componentsSeparatedByString:@"\n"]componentsJoinedByString:@"<br>"];
}
- (NSString *)replaceAtSigns;
{ return [[self componentsSeparatedByString:@"&atsign;"]componentsJoinedByString:@"@"];
}
- (NSString *)stringByDeletingCarraigeReturnCtrlO;
{ const char *sb=[self lossyCString],*sp=sb;
char *db=NSZoneMalloc(0,strlen(sb)+1),*dp=db;
NSAssert(db,@"NSZoneMalloc failed.");
for (*dp=0;*sp;sp++) if (*sp!=15 && *sp!=13 && *sp!=10) *dp++=*sp;
return [[[NSString alloc] initWithCStringNoCopy:db length:dp-db freeWhenDone:YES ] autorelease];
}
*/
- (int)levenshtein:(NSString *)s;
{ { if(!FILLED(self))return [s length];
if(!FILLED(s))return [self length];
}
{ char c1[100],c2[100];
char d[100][100];
int n,m;
int i,j,cost,dist1,dist2,dist3;
[self prepareLevenshtein:c1];
[s prepareLevenshtein:c2];
n = strlen(c1);
m = strlen(c2);
if(!n)return m;
if(!m)return n;
for(i=0;i<=n;i++){ d[i][0]=i;
}
for(j=0;j<=m;j++){ d[0][j]=j;
}
for(i=1;i<=n;i++){ for(j=1;j<=m;j++){ if(c1[i-1] == c2[j-1]){ cost=0;
}else{ cost=1;
}
dist1 = d[i-1][j ] + 1;
dist2 = d[i ][j-1] + 1;
dist3 = d[i-1][j-1] + cost;
d[i][j]=MIN(MIN(dist1,dist2),dist3);
}
}
return d[n][m];
}
/*
int LevenshteinDistance(char s[1..n], char t[1..m])
declare int d[0..n,0..m]
declare int i, j, cost
for i := 0 to n
d[i,0] := i
for j := 0 to m
d[0,j] := j
for i := 1 to n
for j := 1 to m
if s[i] = t[j] then cost := 0
else cost := 1
d[i,j] := minimum(d[i-1,j ] + 1, // insertion
d[i, j-1] + 1, // deletion
d[i-1,j-1] + cost) // substitution
return d[n,m]
*/
}
- (void)prepareLevenshtein:(char *)l;
{// l zeigt auf einen max. 100 char. grossen char Buffer
// String moeglichst klein machen fuer Levenshtein
char *p,*l_start = l;
char c;
const char *c1 = [[self lowercaseString] lossyCString];
p = (char *)c1;
while((c = *p) && (l - l_start) < 99){ // nur Ziffern und kleinbuchstaben uebriglassen und die umlaute
if(c < 48){ p++;
continue;
}
if(c > 57 && c < 97){ p++;
continue;
}
*l=c;
l++;
p++;
}
*l = 0; //ergebnis terminieren
}
- (BOOL)isSearchCode;
{// darf nur +,-,=,k,t,& enthalten
NSString *searchCodes = @"+&f";
int i,j;
for(i=0,j=[self length];i<j;i++){ NSString *s = [self charAt:i];
if(![searchCodes rangeOfString:s].length)return NO;
}
return YES;
}
- (NSDictionary *)partsFromEMLPath;
{// mail analysieren
NSFileHandle *fh = [NSFileHandle fileHandleForReadingAtPath:self];
LMD;
if(fh){ NSData *data = [fh readDataOfLength:60 * 1024]; // muss reichen fuer headers und body;
[fh closeFile];
if(data){ NSString *s = [NSString stringWithData:data]; // erraet encoding
NSArray *a = [s componentsSeparatedByString:@"\n"];
int i,j,i1;
LMA; // zeilen f. body
NSString *line;
BOOL isUTF8 = NO;
NSString *llc;
// headers beschaffen
for(i=0,j=[a count];(i<j);i++){ line = [[a oai:i]stringWithoutWindowsShit];
llc = [line lowercaseString];
// Date: Sun, 06 Aug 2006 00:18:03 +0200 (CEST)
// From: Pirmin Braun <pb@seat-1.com>
// Subject: Re: Anfrage ERP-Software =?ISO-8859-1?Q?L=F6sung?=
if([llc hasSecurePrefix:@"date: "]){ NSString *s = [[[[line secureSubstringFromIndex:5]componentsSeparatedByString:@","]lastObject]stringWithoutLeadingWhiteSpace];
NSCalendarDate *date;
date = [NSCalendarDate dateWithString:s calendarFormat:@"%d %b %Y %H:%M:%S %z"];
if(!date){ date = [NSCalendarDate dateWithString:s calendarFormat:@"%d %b %Y %H:%M %z"];
}
if(!date){ date = [NSCalendarDate dateWithString:s calendarFormat:@"%d %b %Y %H:%M"];
}
if(!date){ date = [NSCalendarDate dateWithString:s calendarFormat:@"%d %b %Y %H:%M:%S"];
}
[lmd setSecureObject:[date descriptionWithCalendarFormat:ND_FORMAT] forKey:@"Date:"];
}
if([llc hasSecurePrefix:@"from: "]){ [lmd setSecureObject:[[line secureSubstringFromIndex:[@"From: " length]]rfcRFC1342DecodedString] forKey:@"From:"];
}
if([llc hasSecurePrefix:@"to: "]){ [lmd setSecureObject:[[line secureSubstringFromIndex:[@"to: " length]]rfcRFC1342DecodedString] forKey:@"To:"];
}
if([llc hasSecurePrefix:@"message-id: "]){ [lmd setSecureObject:[[line secureSubstringFromIndex:[@"Message-ID: " length]]rfcRFC1342DecodedString] forKey:@"Message-ID:"];
}
if([llc hasSecurePrefix:@"reply-to: "]){ [lmd setSecureObject:[[line secureSubstringFromIndex:[@"Reply-To: " length]]rfcRFC1342DecodedString] forKey:@"Reply-To:"];
}
if([llc hasSecurePrefix:@"subject: "]){ [lmd setSecureObject:[[line secureSubstringFromIndex:[@"Subject: " length]]rfcRFC1342DecodedString] forKey:@"Subject:"];
}
if([llc hasSecurePrefix:@"in-reply-to: "]){ [lmd setSecureObject:[[line secureSubstringFromIndex:[@"In-Reply-To: " length]]rfcRFC1342DecodedString] forKey:@"In-Reply-To:"];
}
if(!FILLED(llc))break; // erste leerzeile beendet header;
if([llc rangeOfString:@"charset=\"utf-8\""].length)isUTF8 = YES;
if([llc rangeOfString:@"charset=utf-8"].length)isUTF8 = YES;
}
// mit boundary zu arbeiten, ist muehsam; es kann mehrere boundary arten geben;
// ersten Part beschaffen; einfach einen text/plain part suchen; dann nach naechster leerzeile bis zum rest;
// dabei auch encoding ermitteln;
// falls es keinen text/plain gibt, nach erster leerzeile beginnen
// manche mails enthalten auch nur html...
i++;
i1=0;
for(;(i<j);i++){ i1++;
if(i1 > 200)break; // zu lange mails wollen wir nicht; Google Desktop indiziert auch nur den Anfang von Dateien;
line = [[a oai:i]stringWithoutWindowsShit];
llc = [line lowercaseString];
if(i1 < 30){// am Anfang die Steuerzeilen ueberlesen
if(([llc rangeOfString:@"charset=\"utf-8\""].length) || ([llc rangeOfString:@"charset=utf-8"].length)){ isUTF8 = YES;
continue;
}
if([llc rangeOfString:@"--"].length)continue;
if([llc rangeOfString:@"content-type:"].length)continue;
if([llc rangeOfString:@"boundary="].length)continue;
if([llc rangeOfString:@"charset="].length)continue;
if([llc rangeOfString:@"content-transfer-encoding:"].length)continue;
if([llc rangeOfString:@"this is a multi-part message"].length)continue;
}
if([llc rangeOfString:@"content-transfer-encoding: base64"].length)break;
if(!FILLED(line)){ line = @"\n";
}else{ if([line hasSecureSuffix:@"="]){ line = [line stringWithoutLastChar];
}else{ line = [line stringByAppendingString:@"\n"];
}
if(isUTF8){ line = [line utf8DecodedString];
}else{ line = [line iso8859DecodedString];
}
}
[lma addObject:line];
}
[lmd setObject:[lma componentsJoinedByString:@""] forKey:@"body"];
}
}
return lmd;
}
- (BOOL)matchesGruppenstring:(NSString *)gs;
{ int i;
// self sei ein gruppenstring, gs auch;
// ist wenigstens an 1 Stelle gemeinsam ein "x", matchen die Strings
// fuer nix berechtigt
if([gs iE:@"----------"])return NO;
if([self iE:@"----------"])return NO;
for(i=0;i<ANZ_GRUPPEN;i++){ if([[[gs charAt:i]lowercaseString]iE:@"x"] && [[[self charAt:i]lowercaseString]iE:@"x"]) return YES;
}
return NO;
}
- (NSString *)thumbPath;
{ NSString *ext = [self pathExtension];
NSString *s= [[self stringByDeletingPathExtension]stringByAppendingFormat:@"_tn.%@",ext];
return [s stringWithForwardSlashes];
}
- (BOOL)isJ;
{ return [self iE:@"J"];
}
- (BOOL)isFilled;
{ return FILLED(self);
}
/* kann man sich schenken, bringt nix
- (double)doubleValue;
{ double d;
sscanf([self c String],"%lf",&d);
return d;
//wg. Genauigkeit: bringt nur 1 Stelle mehr return [[NSDecimalNumber decimalNumberWithString:self]doubleValue];
}
*/
- (NSComparisonResult)compareCaseInsensitive:(NSString *)s;
{ return [[self lowercaseString]compare:[s lowercaseString]];
}
- (NSComparisonResult)compareCaseInsensitiveD:(NSString *)s;
{ return [[s lowercaseString]compare:[self lowercaseString]];
}
- (NSComparisonResult)compareNumeric:(NSString *)s;
{ double d1,d2;
if(!s)return NSOrderedDescending;
d1 = [self doubleValue];
d2 = [s doubleValue];
if(d1==d2)return NSOrderedSame;
if(d1 > d2) return NSOrderedDescending;
return NSOrderedAscending;
}
- (NSComparisonResult)compareNumericD:(NSString *)s;
{ double d1,d2;
if(!s)return NSOrderedAscending;
d1 = [self doubleValue];
d2 = [s doubleValue];
if(d1==d2)return NSOrderedSame;
if(d1 > d2) return NSOrderedAscending;
return NSOrderedDescending;
}
- (NSComparisonResult)compareBySecondIntField:(NSString *)s;
{ NSArray *a1,*a2;
int i1,i2;
a1 = [self componentsSeparatedByString:@"|"];
a2 = [s componentsSeparatedByString:@"|"];
if([a1 count]!=3)return NSOrderedDescending;
if([a2 count]!=3)return NSOrderedAscending;
i1 = [[a1 oai:1] intValue];
i2 = [[a2 oai:1] intValue];
if(i1 > i2)return NSOrderedDescending;
if(i1 < i2)return NSOrderedAscending;
return [(NSString *)[a1 oai:2] compare:(NSString *)[a2 oai:2]];
}
- (NSComparisonResult)compareHierarchie:(NSString *)s;
{// ...2.. ...10...
// 002 010
NSArray *a;
int i,j;
LMA;
NSString *si,*s1,*s2;
a = [self componentsSeparatedByString:@"."];
for(i=0,j=[a count];i<j;i++){ si = [NSSWF @"%03i",[[a oai:i]intValue]];
[lma addObject:si];
}
s1 = [lma componentsJoinedByString:EON];
[lma removeAllObjects];
a = [s componentsSeparatedByString:@"."];
for(i=0,j=[a count];i<j;i++){ si = [NSSWF @"%03i",[[a oai:i]intValue]];
[lma addObject:si];
}
s2 = [lma componentsJoinedByString:EON];
// LOGS(([NSSWF @"%@ %@",s1,s2]));
return [s1 compare:s2];
}
- (BOOL)isNumeric;
// enthaelt nur ziffern
{ char *c,cx;
if([self length] < 1) return NO;
c = (char *)[self lossyCString]; //interessieren nur digits
while((cx=*c++)){ if(!isdigit(cx))return NO;
}
return YES;
}
@end
#ifndef GNUSTEP
@interface NSCalendarDate_ODBugfix : NSCalendarDate
@end
@implementation NSCalendarDate_ODBugfix
static IMP original = NULL;
#define sel @selector(dateByAddingYears:months:days:hours:minutes:seconds:)
+ (void)load
{ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
Class superclass = [self superclass];
original = [superclass instanceMethodForSelector:sel];
[self poseAsClass:superclass];
[pool release];
}
static id _addToDate(NSCalendarDate *date, int y, int m, int d, int hh, int
mm, int ss)
{ /* [dateByAddingYears:...] hangs for any Jan 1st later than 2001 */
if ([date yearOfCommonEra] > 2001 && [date dayOfYear] == 1) { date = [date addTimeInterval:60 * 60 * 24];
d--;
}
return original(date, sel, y, m, d, hh, mm, ss);
}
/* ([self monthOfYear] + month) must be within the range from -128 to +127
for the original implementation to work correctly. The same restriction
applys to ([self dayOfMonth] + day) */
#define MAX_MONTHS_ADD 115 /* (max. monthOfYear) 12 + 115 = 127 */
#define MAX_MONTHS_SUB -129 /* (min. monthOfYear) 1 - 129 = -128 */
#define MAX_DAYS_ADD 96 /* (max. dayOfMonth) 31 + 96 = 127 */
#define MAX_DAYS_SUB -129 /* (min. dayOfMonth) 1 - 129 = -128 */
- (NSCalendarDate *)dateByAddingYears:(int)year
months:(int)month
days:(int)day
hours:(int)hour
minutes:(int)minute
seconds:(int)second
{ NSCalendarDate *date = self;
while (month > MAX_MONTHS_ADD) { date = _addToDate(date, 0, MAX_MONTHS_ADD, 0, 0, 0, 0);
month -= MAX_MONTHS_ADD;
}
while (month < MAX_MONTHS_SUB) { date = _addToDate(date, 0, MAX_MONTHS_SUB, 0, 0, 0, 0);
month -= MAX_MONTHS_SUB;
}
while (day > MAX_DAYS_ADD) { date = _addToDate(date, 0, 0, MAX_DAYS_ADD, 0, 0, 0);
day -= MAX_DAYS_ADD;
}
while (day < MAX_DAYS_SUB) { date = _addToDate(date, 0, 0, MAX_DAYS_SUB, 0, 0, 0);
day -= MAX_DAYS_SUB;
}
return _addToDate(date, year, month, day, hour, minute, second);
}
@end
#endif
@implementation NSFileManager (PB3)
- (NSArray *)directoriesAtPath:(NSString *)path;
{ LMA;
NSArray *a = [self directoryContentsAtPath:path];
NSString *s;
int i,j=[a count];
NSDictionary *d;
for(i=0;i<j;i++){ s = [a oai:i];
if(!(d = [myFM fileAttributesAtPath:[path stringByAppendingPathComponent:s] traverseLink:NO]))continue;
if([[d ofk:NSFileType]iE:NSFileTypeDirectory]){ [lma addObject:s];
}
}
return lma;
}
- (NSArray *)directoryContentsAtPath:(NSString *)path suffix:(NSString *)suffix fullName:(BOOL)fullName;
{ if(!suffix) return [self directoryContentsAtPath:path suffixes:nil skips:nil fullName:fullName];
return [self directoryContentsAtPath:path suffixes:[NSArray arrayWithObject:suffix] skips:nil fullName:fullName];
}
- (NSArray *)directoryContentsAtPath:(NSString *)path suffixes:(NSArray *)suffixes skips:(NSArray *)skips fullName:(BOOL)fullName;
{// fullName bedeutet "mit extension"; es wird immer nur der filename geliefert, ohne pfad;
LMA;
NSArray *a = [self directoryContentsAtPath:path];
NSString *s,*suffix;
int i,ii,j=[a count],jj=[suffixes count];
for(i=0;i<j;i++){ s = [a oai:i];
if([s hasPrefixFrom:skips])continue;
if(!jj){ if(fullName){ [lma addObject:s];
}
}else{ for(ii=0;ii<jj;ii++){ suffix = [suffixes oai:ii];
if([s hasSuffix:suffix]){ if(fullName){ [lma addObject:s];
}else{ [lma addObject:[s substringToIndex:[s length]-[suffix length]]];
}
}
}
}
}
return lma;
}
- (NSArray *)directoryDeepContentsAtPath:(NSString *)path suffixes:(NSArray *)suffixes skips:(NSArray *)skips fullName:(BOOL)yn;
{ return [self directoryDeepContentsAtPath:path suffixes:suffixes skips:skips fullName:yn newer:nil];
}
- (NSArray *)directoryDeepContentsAtPath:(NSString *)path suffixes:(NSArray *)suffixes skips:(NSArray *)skips fullName:(BOOL)yn newer:(NSDate *)newer;
{ //geht subdirectories nach
LMA;
NSString *s,*suffix;
int ii,jj=[suffixes count];
NSDirectoryEnumerator *e = [self enumeratorAtPath:path];
while ((s = [e nextObject])) { if([s hasPrefixFrom:skips])continue;
for(ii=0;ii<jj;ii++){ suffix = [suffixes oai:ii];
if([s hasSuffix:suffix]){ if(newer){ NSDate *fd = [[myFM fileAttributesAtPath:[NSSWF @"%@/%@",path,s] traverseLink:NO] fileModificationDate];
if([fd compare:newer]==NSOrderedAscending)continue;
}
if(yn){ [lma addObject:s];
}else{ [lma addObject:[s substringToIndex:[s length]-[suffix length]]];
}
}
}
}
return lma;
}
- (NSArray *)sourceFilesWith:(NSString *)s atPath:(NSString *)path;
{ NSArray *a = [self directoryContentsAtPath:path suffixes:[NSArray arrayWithObjects:@".m",@".h",nil] skips:nil fullName:YES];
int i,j=[a count];
NSMutableArray *ma = [NSMutableArray arrayWithCapacity:j];
NSString *fn,*file;
NSRange r1;
if(!FILLED(s))return (NSArray *)ma;
for(i=0;i<j;i++){ fn = [a oai:i];
file = [NSString stringWithContentsOfFile:[path stringByAppendingPathComponent:fn]];
if(!file)continue;
r1 = [file rangeOfString:s options:NSCaseInsensitiveSearch];
if(!(r1.length))continue;
[ma addObject:fn];
}
return (NSArray *)ma;
}
- (void)copyPathWithDir:(NSString *)path toPath:(NSString *)to;
{ NSString *dirName;
if(!FILLED(path))return;
if(!FILLED(to))return;
dirName = [to stringByDeletingLastPathComponent];
if(![self fileExistsAtPath:dirName]){ if(![self createAllDirsAtPath:dirName]){ LOGS(([NSSWF @"copyPathWithDir: Directory %@ konnte nicht angelegt werden",dirName]));
return;
}
}
[self copyPath:path toPath:to handler:nil];
}
- (BOOL)createAllDirsAtPath:(NSString *)dirName;
{ NSArray *a = [[dirName stringWithForwardSlashes] componentsSeparatedByString:@"/"];
int i,j;
NSString *s;
j=[a count];
if(j<2)return YES;
i=1;
s = [a firstObject];
if([s hasSuffix:@":"]){ s = [s sbas:@"/"];
}else{ s = @"/";
}
s = [s sbas:[a oai:i++]];
while([self fileExistsAtPath:s]){ if(i>=j)break;
s = [s stringByAppendingFormat:@"/%@",[a oai:i++]];
}
while([self createDirectoryAtPath:s attributes:nil]){ if(i>=j)break;
s = [s stringByAppendingFormat:@"/%@",[a oai:i++]];
}
if(i==j)return YES;
return NO;
}
@end
@implementation NSData (PB3)
- (NSString *)string;
{ return [NSString stringWithData:self];
}
- (BOOL)writeToFile:(NSString *)path;
{ return [self writeToFile:path atomically:YES];
}
- (char)charAt:(int)i;
{ char *p;
if(i>=[self length])return 0;
p = ((char *)[self bytes] + i);
return *p;
}
- (NSString *)hexFormat;
{ int i,j;
unsigned char *pin = (unsigned char *)[self bytes];
unsigned char ch;
NSString *hex[16] = {@"0",@"1",@"2",@"3",@"4",@"5",@"6",@"7",@"8",@"9",@"A",@"B",@"C",@"D",@"E",@"F"}; NSMutableString *ms = [NSMutableString stringWithCapacity:10];
for(i=0,j=[self length]; i < j; i++) { ch = *pin >> 4;
[ms appendString:hex[ch]];
ch = *pin++ & 0x0f;
[ms appendString:hex[ch]];
}
return ms;
}
@end