diff --git a/ChangeLog b/ChangeLog index 235809b1c..312faa418 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,22 @@ +Mon Dec 13 12:20:00 1999 Richard Frith-Macdonald + + Fixes for cball's changes (who is cball?, and why didn't s/he produce + a ChangeLog entry or conform to GNU indentation? It took me hours to + tidy this up). + * Source/NSDate.m: ([NSGDate -addTimeInterval:]) removed bogus + implementation of method (inherits from NSDate). + * Source/NSCalendarDate.m: Added implementation of ([-addTimeInterval:]) + with specific code for NSCalendarDate. Reformatted code to GNUstep + style. + * Source/NSGArray.m: ([-removeObjectIdenticalTo:]) and + ([-removeObjectIdenticalTo:inRange:]) reverted to correct code. + ([-removeObject:]) and ([-removeObjectIdenticalTo:inRange:]) removed + changes and added fixes so that methods are safe where multiple objects + equal to the object to be removed are present in the array. + * Source/NSArray.m: Similar fixes for object removal. + * Source/NSObject.m: Rewritten mutex code so that mutexes are not used + for retain/release unless the app is multi-threaded. + Wed Dec 1 19:36:00 1999 Richard Frith-Macdonald * Source/NSArray.m: When sorting, treat illegal return values from the diff --git a/Source/NSArray.m b/Source/NSArray.m index 81907f2dc..0690e0ffc 100644 --- a/Source/NSArray.m +++ b/Source/NSArray.m @@ -898,13 +898,10 @@ static NSString *indentStrings[] = { if (o == anObject) { if (rem == 0) - rem = [self methodForSelector: remSel]; + { + rem = [self methodForSelector: remSel]; + } (*rem)(self, remSel, i); - /* - * Bail out now or run the risk of comparing against a garbage - * pointer. - */ - return; } } } @@ -942,15 +939,24 @@ static NSString *indentStrings[] = { if (o == anObject || (*eq)(anObject, eqSel, o) == YES) { if (rem == 0) - rem = [self methodForSelector: remSel]; + { + rem = [self methodForSelector: remSel]; + /* + * We need to retain the object so that when we remove the + * first equal object we don't get left with a bad object + * pointer for later comparisons. + */ + RETAIN(anObject); + } (*rem)(self, remSel, i); - /* - * Bail out now or run the risk of comparing against a garbage - * pointer. - */ - return; } } +#ifndef GS_WITH_GC + if (rem != 0) + { + RELEASE(anObject); + } +#endif } } @@ -984,13 +990,10 @@ static NSString *indentStrings[] = { if (o == anObject) { if (rem == 0) - rem = [self methodForSelector: remSel]; + { + rem = [self methodForSelector: remSel]; + } (*rem)(self, remSel, i); - /* - * Bail out now or run the risk of comparing against a garbage - * pointer. - */ - return; } } } @@ -1020,15 +1023,24 @@ static NSString *indentStrings[] = { if (o == anObject || (*eq)(anObject, eqSel, o) == YES) { if (rem == 0) - rem = [self methodForSelector: remSel]; + { + rem = [self methodForSelector: remSel]; + /* + * We need to retain the object so that when we remove the + * first equal object we don't get left with a bad object + * pointer for later comparisons. + */ + RETAIN(anObject); + } (*rem)(self, remSel, i); - /* - * Bail out now or run the risk of comparing against a garbage - * pointer. - */ - return; } } +#ifndef GS_WITH_GC + if (rem != 0) + { + RELEASE(anObject); + } +#endif } } @@ -1041,7 +1053,9 @@ static NSString *indentStrings[] = { IMP remLast = [self methodForSelector: rlSel]; while (c--) - (*remLast)(self, rlSel); + { + (*remLast)(self, rlSel); + } } } @@ -1149,7 +1163,9 @@ static NSString *indentStrings[] = { IMP rem = [self methodForSelector: remSel]; while (i-- > s) - (*rem)(self, remSel, i); + { + (*rem)(self, remSel, i); + } } } diff --git a/Source/NSCalendarDate.m b/Source/NSCalendarDate.m index 83f4db4dc..54de1b554 100644 --- a/Source/NSCalendarDate.m +++ b/Source/NSCalendarDate.m @@ -117,6 +117,16 @@ return AUTORELEASE(d); } +- (id) addTimeInterval: (NSTimeInterval)seconds +{ + id newObj = [[self class] dateWithTimeIntervalSinceReferenceDate: + [self timeIntervalSinceReferenceDate] + seconds]; + + [newObj setTimeZone: [self timeZoneDetail]]; + + return newObj; +} + - (Class) classForPortCoder { return [self class]; @@ -129,14 +139,16 @@ - (void) encodeWithCoder: (NSCoder*)coder { - [coder encodeValueOfObjCType: @encode(NSTimeInterval) at: &_seconds_since_ref]; + [coder encodeValueOfObjCType: @encode(NSTimeInterval) + at: &_seconds_since_ref]; [coder encodeObject: _calendar_format]; [coder encodeObject: _time_zone]; } - (id) initWithCoder: (NSCoder*)coder { - [coder decodeValueOfObjCType: @encode(NSTimeInterval) at: &_seconds_since_ref]; + [coder decodeValueOfObjCType: @encode(NSTimeInterval) + at: &_seconds_since_ref]; [coder decodeValueOfObjCType: @encode(id) at: &_calendar_format]; [coder decodeValueOfObjCType: @encode(id) at: &_time_zone]; return self; @@ -174,32 +186,29 @@ calendarFormat: (NSString *)fmt locale: (NSDictionary *)locale { - int year = 0, month = 1, day = 1, hour = 0, min = 0, sec = 0; - NSTimeZone *tz = [NSTimeZone localTimeZone]; - - int ampm = 0, twelveHrClock = 0; - int julianWeeks = -1, weekStartsMonday = 0, dayOfWeek = -1; - - const char *source = [description cString]; - int sourceLen = strlen(source); - const char *format = [fmt cString]; - int formatLen = strlen(format); - - int formatIdx = 0; - int sourceIdx = 0; - - char tmpStr[20]; - int tmpIdx; + int year = 0, month = 1, day = 1, hour = 0, min = 0, sec = 0; + NSTimeZone *tz = [NSTimeZone localTimeZone]; + BOOL ampm = NO; + BOOL twelveHrClock = NO; + int julianWeeks = -1, weekStartsMonday = 0, dayOfWeek = -1; + const char *source = [description cString]; + int sourceLen = strlen(source); + const char *format = [fmt cString]; + int formatLen = strlen(format); + int formatIdx = 0; + int sourceIdx = 0; + char tmpStr[20]; + int tmpIdx; if (locale == nil) - { - locale = [[NSUserDefaults standardUserDefaults] dictionaryRepresentation]; - } + { + locale = [[NSUserDefaults standardUserDefaults] dictionaryRepresentation]; + } if (fmt == nil) - { + { format = [[locale objectForKey: NSTimeDateFormatString] cString]; formatLen = strlen(format); - } + } // // WARNING: @@ -236,299 +245,357 @@ // %Y year as a decimal number with century // %z time zone offset in hours and minutes from GMT (HHMM) // %Z time zone abbreviation - while ( formatIdx < formatLen ) + + while (formatIdx < formatLen) + { + if (format[formatIdx] != '%') { - if ( format[formatIdx] != '%' ) - { - // If it's not a format specifier, ignore it. - sourceIdx++; - } else { - - // Skip '%' - formatIdx++; - - switch (format[formatIdx]) - { - case '%': - // skip literal % - sourceIdx++; - break; - - case 'a': - // Are Short names three chars in all locales????? - tmpStr[0] = toupper( source[sourceIdx++] ); - tmpStr[1] = tolower( source[sourceIdx++] ); - tmpStr[2] = tolower( source[sourceIdx++] ); - tmpStr[3] = '\0'; - { - NSString *currDay = [NSString stringWithCString: tmpStr]; - NSArray *dayNames = [locale objectForKey: NSShortWeekDayNameArray]; - - for (tmpIdx = 0; tmpIdx < 7; tmpIdx++) - if ([[dayNames objectAtIndex: tmpIdx] isEqual: currDay] == YES) - break; - dayOfWeek = tmpIdx; - } - break; - - case 'A': - for ( tmpIdx = sourceIdx; tmpIdx < sourceLen; tmpIdx++ ) - { - if ( isalpha( source[tmpIdx] ) ) - { - tmpStr[tmpIdx - sourceIdx] = source[tmpIdx]; - } else { - break; - } - } - tmpStr[tmpIdx - sourceIdx] = '\0'; - sourceIdx += tmpIdx - sourceIdx; - { - NSString *currDay = [NSString stringWithCString: tmpStr]; - NSArray *dayNames = [locale objectForKey: NSWeekDayNameArray]; - - for (tmpIdx = 0; tmpIdx < 7; tmpIdx++) - if ([[dayNames objectAtIndex: tmpIdx] isEqual: currDay] == YES) - break; - dayOfWeek = tmpIdx; - } - break; - - case 'b': - // Are Short names three chars in all locales????? - tmpStr[0] = toupper( source[sourceIdx++] ); - tmpStr[1] = tolower( source[sourceIdx++] ); - tmpStr[2] = tolower( source[sourceIdx++] ); - tmpStr[3] = '\0'; - { - NSString *currMonth = [NSString stringWithCString: tmpStr]; - NSArray *monthNames = [locale objectForKey: NSShortMonthNameArray]; - - for (tmpIdx = 0; tmpIdx < 12; tmpIdx++) - { - if ([[monthNames objectAtIndex: tmpIdx] isEqual: currMonth] == YES) - break; - } - month = tmpIdx+1; - } - break; - - case 'B': - for ( tmpIdx = sourceIdx; tmpIdx < sourceLen; tmpIdx++ ) - { - if ( isalpha( source[tmpIdx] ) ) - { - tmpStr[tmpIdx - sourceIdx] = source[tmpIdx]; - } else { - break; - } - } - tmpStr[tmpIdx - sourceIdx] = '\0'; - sourceIdx += tmpIdx - sourceIdx; - { - NSString *currMonth = [NSString stringWithCString: tmpStr]; - NSArray *monthNames = [locale objectForKey: NSMonthNameArray]; - - for (tmpIdx = 0; tmpIdx < 12; tmpIdx++) - if ([[monthNames objectAtIndex: tmpIdx] isEqual: currMonth] == YES) - break; - month = tmpIdx+1; - - } - break; - -// case 'c': -// break; - - case 'd': // fall through - case 'e': - memcpy( tmpStr, &source[sourceIdx], 2 ); - tmpStr[2] = '\0'; - sourceIdx += 2; - day = atoi( tmpStr ); - break; - -// case 'F': -// break; - - case 'I': // fall through - twelveHrClock = 1; - case 'H': - memcpy( tmpStr, &source[sourceIdx], 2 ); - tmpStr[2] = '\0'; - sourceIdx += 2; - hour = atoi( tmpStr ); - break; - - case 'j': - memcpy( tmpStr, &source[sourceIdx], 3 ); - tmpStr[3] = '\0'; - sourceIdx += 3; - day = atoi( tmpStr ); - break; - - case 'm': - memcpy( tmpStr, &source[sourceIdx], 2 ); - tmpStr[2] = '\0'; - sourceIdx += 2; - month = atoi( tmpStr ); - break; - - case 'M': - memcpy( tmpStr, &source[sourceIdx], 2 ); - tmpStr[2] = '\0'; - sourceIdx += 2; - min = atoi( tmpStr ); - break; - - case 'p': - // Questionable assumption that all am/pm indicators are 2 - // characters and in upper case.... - tmpStr[0] = toupper( source[sourceIdx++] ); - tmpStr[1] = toupper( source[sourceIdx++] ); - tmpStr[2] = '\0'; - { - NSString *currAMPM = [NSString stringWithCString: tmpStr]; - NSArray *amPMNames = [locale objectForKey: NSAMPMDesignation]; - - /* - * The time addition is handled below because this - * indicator only modifies the time on a 12hour clock. - */ - if ([[amPMNames objectAtIndex: 1] isEqual: currAMPM] == YES) - ampm = 1; - - } - break; - - case 'S': - memcpy( tmpStr, &source[sourceIdx], 2 ); - tmpStr[2] = '\0'; - sourceIdx += 2; - sec = atoi( tmpStr ); - break; - - case 'w': - tmpStr[0] = source[sourceIdx++]; - tmpStr[1] = '\0'; - dayOfWeek = atoi( tmpStr ); - break; - - case 'W': // Fall through - weekStartsMonday = 1; - case 'U': - memcpy( tmpStr, &source[sourceIdx], 2 ); - tmpStr[2] = '\0'; - sourceIdx += 2; - julianWeeks = atoi( tmpStr ); - break; - -// case 'x': -// break; - -// case 'X': -// break; - - case 'y': - memcpy( tmpStr, &source[sourceIdx], 2 ); - tmpStr[2] = '\0'; - sourceIdx += 2; - year = atoi( tmpStr ); - if ( year >= 70 ) - { - year += 1900; - } else { - year += 2000; - } - break; - - case 'Y': - memcpy( tmpStr, &source[sourceIdx], 4 ); - tmpStr[4] = '\0'; - sourceIdx += 4; - year = atoi( tmpStr ); - break; - - case 'z': - tmpStr[0] = toupper( source[sourceIdx++] ); - tmpStr[1] = tolower( source[sourceIdx++] ); - tmpStr[2] = tolower( source[sourceIdx++] ); - tmpStr[3] = tolower( source[sourceIdx++] ); - tmpStr[4] = '\0'; - { - int zone; - zone = atoi( tmpStr ); - if ((tz = [NSTimeZone timeZoneForSecondsFromGMT: - (zone / 100 * 60 + (zone % 100) ) * 60] ) == nil ) - { - tz = [NSTimeZone localTimeZone]; - } - } - break; - - case 'Z': - for ( tmpIdx = sourceIdx; tmpIdx < sourceLen; tmpIdx++ ) - { - if ( isalpha( source[tmpIdx] ) || source[tmpIdx] == '-' || source[tmpIdx] == '+' ) - { - tmpStr[tmpIdx - sourceIdx] = source[tmpIdx]; - } else { - break; - } - } - tmpStr[tmpIdx - sourceIdx] = '\0'; - sourceIdx += tmpIdx - sourceIdx; - { - if ( (tz = [NSTimeZone timeZoneWithAbbreviation: - [NSString stringWithCString: tmpStr]]) == nil) - { - tz = [NSTimeZone localTimeZone]; - } - } - break; - - default: - [NSException raise: NSInvalidArgumentException - format: @"Invalid NSCalendar date, specifier %c not recognized in format %s", - format[formatIdx], format]; - } - } - formatIdx++; + // If it's not a format specifier, ignore it. + sourceIdx++; } + else + { + // Skip '%' + formatIdx++; - if ( twelveHrClock ) - { - if ( ampm && hour != 12 ) - { - hour += 12; - } - } + switch (format[formatIdx]) + { + case '%': + // skip literal % + sourceIdx++; + break; - if ( julianWeeks != -1 ) - { - int currDay = [[[[NSCalendarDate alloc] initWithYear: year month: 1 day: 1 hour: 0 minute: 0 - second: 0 timeZone: [NSTimeZone timeZoneForSecondsFromGMT: 0]] autorelease] dayOfWeek]; + case 'a': + // Are Short names three chars in all locales????? + tmpStr[0] = toupper(source[sourceIdx++]); + tmpStr[1] = tolower(source[sourceIdx++]); + tmpStr[2] = tolower(source[sourceIdx++]); + tmpStr[3] = '\0'; + { + NSString *currDay; + NSArray *dayNames; - /* - * The julian weeks are either sunday relative or monday relative but all - * of the day of week specifiers are sunday relative. This means that if - * no day of week specifier was used the week starts on monday. - */ - if ( dayOfWeek == -1 ) - { - if ( weekStartsMonday ) + currDay = [NSString stringWithCString: tmpStr]; + dayNames = [locale objectForKey: NSShortWeekDayNameArray]; + for (tmpIdx = 0; tmpIdx < 7; tmpIdx++) + { + if ([[dayNames objectAtIndex: tmpIdx] isEqual: currDay] + == YES) + { + break; + } + } + dayOfWeek = tmpIdx; + } + break; + + case 'A': + for (tmpIdx = sourceIdx; tmpIdx < sourceLen; tmpIdx++) { - dayOfWeek = 1; - } else { - dayOfWeek = 0; + if (isalpha(source[tmpIdx])) + { + tmpStr[tmpIdx - sourceIdx] = source[tmpIdx]; + } + else + { + break; + } } - } - day = dayOfWeek + (julianWeeks * 7 - (currDay - 1)); - } + tmpStr[tmpIdx - sourceIdx] = '\0'; + sourceIdx += tmpIdx - sourceIdx; + { + NSString *currDay; + NSArray *dayNames; - return [[NSCalendarDate alloc] initWithYear: year month: month day: day hour: hour - minute: min second: sec - timeZone: tz]; + currDay = [NSString stringWithCString: tmpStr]; + dayNames = [locale objectForKey: NSWeekDayNameArray]; + for (tmpIdx = 0; tmpIdx < 7; tmpIdx++) + { + if ([[dayNames objectAtIndex: tmpIdx] isEqual: currDay] + == YES) + { + break; + } + } + dayOfWeek = tmpIdx; + } + break; + + case 'b': + // Are Short names three chars in all locales????? + tmpStr[0] = toupper(source[sourceIdx++]); + tmpStr[1] = tolower(source[sourceIdx++]); + tmpStr[2] = tolower(source[sourceIdx++]); + tmpStr[3] = '\0'; + { + NSString *currMonth; + NSArray *monthNames; + + currMonth = [NSString stringWithCString: tmpStr]; + monthNames = [locale objectForKey: NSShortMonthNameArray]; + + for (tmpIdx = 0; tmpIdx < 12; tmpIdx++) + { + if ([[monthNames objectAtIndex: tmpIdx] + isEqual: currMonth] == YES) + { + break; + } + } + month = tmpIdx+1; + } + break; + + case 'B': + for (tmpIdx = sourceIdx; tmpIdx < sourceLen; tmpIdx++) + { + if (isalpha(source[tmpIdx])) + { + tmpStr[tmpIdx - sourceIdx] = source[tmpIdx]; + } + else + { + break; + } + } + tmpStr[tmpIdx - sourceIdx] = '\0'; + sourceIdx += tmpIdx - sourceIdx; + { + NSString *currMonth; + NSArray *monthNames; + + currMonth = [NSString stringWithCString: tmpStr]; + monthNames = [locale objectForKey: NSMonthNameArray]; + + for (tmpIdx = 0; tmpIdx < 12; tmpIdx++) + { + if ([[monthNames objectAtIndex: tmpIdx] + isEqual: currMonth] == YES) + { + break; + } + } + month = tmpIdx+1; + } + break; + +// case 'c': +// break; + + case 'd': // fall through + case 'e': + memcpy(tmpStr, &source[sourceIdx], 2); + tmpStr[2] = '\0'; + sourceIdx += 2; + day = atoi(tmpStr); + break; + +// case 'F': +// break; + + case 'I': // fall through + twelveHrClock = YES; + case 'H': + memcpy(tmpStr, &source[sourceIdx], 2); + tmpStr[2] = '\0'; + sourceIdx += 2; + hour = atoi(tmpStr); + break; + + case 'j': + memcpy(tmpStr, &source[sourceIdx], 3); + tmpStr[3] = '\0'; + sourceIdx += 3; + day = atoi(tmpStr); + break; + + case 'm': + memcpy(tmpStr, &source[sourceIdx], 2); + tmpStr[2] = '\0'; + sourceIdx += 2; + month = atoi(tmpStr); + break; + + case 'M': + memcpy(tmpStr, &source[sourceIdx], 2); + tmpStr[2] = '\0'; + sourceIdx += 2; + min = atoi(tmpStr); + break; + + case 'p': + // Questionable assumption that all am/pm indicators are 2 + // characters and in upper case.... + tmpStr[0] = toupper(source[sourceIdx++]); + tmpStr[1] = toupper(source[sourceIdx++]); + tmpStr[2] = '\0'; + { + NSString *currAMPM; + NSArray *amPMNames; + + currAMPM = [NSString stringWithCString: tmpStr]; + amPMNames = [locale objectForKey: NSAMPMDesignation]; + + /* + * The time addition is handled below because this + * indicator only modifies the time on a 12hour clock. + */ + if ([[amPMNames objectAtIndex: 1] isEqual: currAMPM] == YES) + { + ampm = YES; + } + } + break; + + case 'S': + memcpy(tmpStr, &source[sourceIdx], 2); + tmpStr[2] = '\0'; + sourceIdx += 2; + sec = atoi(tmpStr); + break; + + case 'w': + tmpStr[0] = source[sourceIdx++]; + tmpStr[1] = '\0'; + dayOfWeek = atoi(tmpStr); + break; + + case 'W': // Fall through + weekStartsMonday = 1; + case 'U': + memcpy(tmpStr, &source[sourceIdx], 2); + tmpStr[2] = '\0'; + sourceIdx += 2; + julianWeeks = atoi(tmpStr); + break; + +// case 'x': +// break; + +// case 'X': +// break; + + case 'y': + memcpy(tmpStr, &source[sourceIdx], 2); + tmpStr[2] = '\0'; + sourceIdx += 2; + year = atoi(tmpStr); + if (year >= 70) + { + year += 1900; + } + else + { + year += 2000; + } + break; + + case 'Y': + memcpy(tmpStr, &source[sourceIdx], 4); + tmpStr[4] = '\0'; + sourceIdx += 4; + year = atoi(tmpStr); + break; + + case 'z': + tmpStr[0] = toupper(source[sourceIdx++]); + tmpStr[1] = tolower(source[sourceIdx++]); + tmpStr[2] = tolower(source[sourceIdx++]); + tmpStr[3] = tolower(source[sourceIdx++]); + tmpStr[4] = '\0'; + { + int zone = atoi(tmpStr); + + if ((tz = [NSTimeZone timeZoneForSecondsFromGMT: + (zone / 100 * 60 + (zone % 100)) * 60]) == nil) + { + tz = [NSTimeZone localTimeZone]; + } + } + break; + + case 'Z': + for (tmpIdx = sourceIdx; tmpIdx < sourceLen; tmpIdx++) + { + if (isalpha(source[tmpIdx]) || source[tmpIdx] == '-' + || source[tmpIdx] == '+') + { + tmpStr[tmpIdx - sourceIdx] = source[tmpIdx]; + } + else + { + break; + } + } + tmpStr[tmpIdx - sourceIdx] = '\0'; + sourceIdx += tmpIdx - sourceIdx; + { + if ((tz = [NSTimeZone timeZoneWithAbbreviation: + [NSString stringWithCString: tmpStr]]) == nil) + { + tz = [NSTimeZone localTimeZone]; + } + } + break; + + default: + [NSException raise: NSInvalidArgumentException format: + @"Invalid NSCalendar date, specifier %c not recognized in format %s", format[formatIdx], format]; + } + } + formatIdx++; + } + + if (twelveHrClock == YES) + { + if (ampm == YES && hour != 12) + { + hour += 12; + } + } + + if (julianWeeks != -1) + { + NSTimeZone *gmtZone; + NSCalendarDate *d; + int currDay; + + gmtZone = [NSTimeZone timeZoneForSecondsFromGMT: 0]; + d = [NSCalendarDate dateWithYear: year + month: 1 + day: 1 + hour: 0 + minute: 0 + second: 0 + timeZone: gmtZone]; + currDay = [d dayOfWeek]; + + /* + * The julian weeks are either sunday relative or monday relative but all + * of the day of week specifiers are sunday relative. This means that if + * no day of week specifier was used the week starts on monday. + */ + if (dayOfWeek == -1) + { + if (weekStartsMonday) + { + dayOfWeek = 1; + } + else + { + dayOfWeek = 0; + } + } + day = dayOfWeek + (julianWeeks * 7 - (currDay - 1)); + } + + return [[NSCalendarDate alloc] initWithYear: year + month: month + day: day + hour: hour + minute: min + second: sec + timeZone: tz]; } diff --git a/Source/NSDate.m b/Source/NSDate.m index 7a38ed537..ad75f07b7 100644 --- a/Source/NSDate.m +++ b/Source/NSDate.m @@ -1115,18 +1115,6 @@ GSTimeNow() // Adding and getting intervals -- (id) addTimeInterval: (NSTimeInterval)seconds -{ - /* xxx We need to check for overflow? */ - id newObj = [[self class] dateWithTimeIntervalSinceReferenceDate: - _seconds_since_ref + seconds]; - - if ([self isKindOfClass: [NSCalendarDate class]]) - [newObj setTimeZone: [(NSCalendarDate *) self timeZoneDetail]]; - - return newObj; -} - - (NSTimeInterval) timeIntervalSince1970 { return _seconds_since_ref - UNIX_REFERENCE_INTERVAL; diff --git a/Source/NSGArray.m b/Source/NSGArray.m index fb71e6b0a..4b8229c47 100644 --- a/Source/NSGArray.m +++ b/Source/NSGArray.m @@ -432,17 +432,26 @@ static SEL eqSel = @selector(isEqual:); index = _count; if (index > 0) { - BOOL (*imp)(id,SEL,id); + BOOL (*imp)(id,SEL,id); +#if GS_WITH_GC == 0 + BOOL retained = NO; +#endif imp = (BOOL (*)(id,SEL,id))[anObject methodForSelector: eqSel]; while (index-- > 0) { if ((*imp)(anObject, eqSel, _contents_array[index]) == YES) { + unsigned pos = index; #if GS_WITH_GC == 0 id obj = _contents_array[index]; + + if (retained == NO) + { + RETAIN(anObject); + retained = YES; + } #endif - unsigned pos = index; while (++pos < _count) { @@ -450,13 +459,14 @@ static SEL eqSel = @selector(isEqual:); } _count--; RELEASE(obj); - /* - * Bail out now or run the risk of comparing against a garbage - * pointer. - */ - return; } } +#if GS_WITH_GC == 0 + if (retained == YES) + { + RELEASE(anObject); + } +#endif } } @@ -505,11 +515,6 @@ static SEL eqSel = @selector(isEqual:); } _count--; RELEASE(obj); - /* - * Bail out now or run the risk of comparing against a garbage - * pointer. - */ - return; } } } diff --git a/Source/NSLock.m b/Source/NSLock.m index 74fa7a291..63cd07a57 100644 --- a/Source/NSLock.m +++ b/Source/NSLock.m @@ -97,41 +97,43 @@ NSString *NSRecursiveLockException = @"NSRecursiveLockException"; { // Ask the runtime to acquire a lock on the mutex if (objc_mutex_trylock(_mutex) == -1) - { + { return NO; - } else { - /* - * The recursive lock check goes here to support openstep's - * implementation. In openstep you can lock in one thread trylock in the - * same thread and have another thread release the lock. - * - * This is dangerous and broken IMHO. - */ - CHECK_RECURSIVE_LOCK(_mutex); - return YES; - } + } + else + { + /* + * The recursive lock check goes here to support openstep's + * implementation. In openstep you can lock in one thread trylock in the + * same thread and have another thread release the lock. + * + * This is dangerous and broken IMHO. + */ + CHECK_RECURSIVE_LOCK(_mutex); + return YES; + } } - (BOOL) lockBeforeDate: (NSDate *)limit { int x; - while ((x = objc_mutex_trylock (_mutex)) == -1 ) + while ((x = objc_mutex_trylock(_mutex)) == -1) + { + NSDate *current = [NSDate date]; + NSComparisonResult compare; + + compare = [current compare: limit]; + if (compare == NSOrderedSame || compare == NSOrderedDescending) { - NSDate *current = [NSDate date]; - NSComparisonResult compare; - - compare = [current compare: limit]; - if ( compare == NSOrderedSame || compare == NSOrderedDescending ) - { - return NO; - } - /* - * This should probably be more accurate like usleep(250) - * but usleep is known to NOT be thread safe under all architectures. - */ - sleep(1); + return NO; } + /* + * This should probably be more accurate like usleep(250) + * but usleep is known to NOT be thread safe under all architectures. + */ + sleep(1); + } /* * The recursive lock check goes here to support openstep's implementation. * In openstep you can lock in one thread trylock in the same thread and have @@ -334,22 +336,22 @@ NSString *NSRecursiveLockException = @"NSRecursiveLockException"; { CHECK_RECURSIVE_CONDITION_LOCK(_mutex); - while ( objc_mutex_trylock (_mutex) == -1 ) + while (objc_mutex_trylock(_mutex) == -1) + { + NSDate *current = [NSDate date]; + NSComparisonResult compare; + + compare = [current compare: limit]; + if (compare == NSOrderedSame || compare == NSOrderedDescending) { - NSDate *current = [NSDate date]; - NSComparisonResult compare; - - compare = [current compare: limit]; - if ( compare == NSOrderedSame || compare == NSOrderedDescending ) - { - return NO; - } - /* - * This should probably be more accurate like usleep(250) - * but usleep is known to NOT be thread safe under all architectures. - */ - sleep(1); + return NO; } + /* + * This should probably be more accurate like usleep(250) + * but usleep is known to NOT be thread safe under all architectures. + */ + sleep(1); + } return YES; } @@ -378,22 +380,22 @@ NSString *NSRecursiveLockException = @"NSRecursiveLockException"; endtime.tv_nsec = (unsigned int)((atimeinterval - (float)endtime.tv_sec) * 1000000000.0); - while( _condition_value != condition_to_meet) + while (_condition_value != condition_to_meet) { - switch(objc_condition_timedwait(_condition, _mutex, &endtime)) + switch (objc_condition_timedwait(_condition, _mutex, &endtime)) { - case 0: - break; - case EINTR: - break; - case ETIMEDOUT : - [self unlock]; - return NO; - default: - [NSException raise:NSConditionLockException - format:@"objc_condition_timedwait failed"]; - [self unlock]; - return NO; + case 0: + break; + case EINTR: + break; + case ETIMEDOUT : + [self unlock]; + return NO; + default: + [NSException raise:NSConditionLockException + format:@"objc_condition_timedwait failed"]; + [self unlock]; + return NO; } } return YES; @@ -488,22 +490,22 @@ NSString *NSRecursiveLockException = @"NSRecursiveLockException"; - (BOOL) lockBeforeDate: (NSDate *)limit { - while ( objc_mutex_trylock (_mutex) == -1 ) + while (objc_mutex_trylock(_mutex) == -1) + { + NSDate *current = [NSDate date]; + NSComparisonResult compare; + + compare = [current compare: limit]; + if (compare == NSOrderedSame || compare == NSOrderedDescending) { - NSDate *current = [NSDate date]; - NSComparisonResult compare; - - compare = [current compare: limit]; - if ( compare == NSOrderedSame || compare == NSOrderedDescending ) - { - return NO; - } - /* - * This should probably be more accurate like usleep(250) - * but usleep is known to NOT be thread safe under all architectures. - */ - sleep(1); + return NO; } + /* + * This should probably be more accurate like usleep(250) + * but usleep is known to NOT be thread safe under all architectures. + */ + sleep(1); + } return YES; } diff --git a/Source/NSObject.m b/Source/NSObject.m index cc4769cd8..8c9656095 100644 --- a/Source/NSObject.m +++ b/Source/NSObject.m @@ -39,6 +39,8 @@ #include #include #include +#include +#include #include #include @@ -103,6 +105,12 @@ void _fastBuildCache() * correct zone to free memory very fast. */ +/* + * retain_counts_gate is needed when running multi-threaded for retain/release + * to work reliably. + */ +static objc_mutex_t retain_counts_gate = NULL; + #if GS_WITH_GC == 0 #define REFCNT_LOCAL 1 #define CACHE_ZONE 1 @@ -182,33 +190,62 @@ NSExtraRefCount(id anObject) return ((obj)anObject)[-1].retained; } -static objc_mutex_t retain_counts_gate = NULL; - void NSIncrementExtraRefCount(id anObject) { - objc_mutex_lock (retain_counts_gate); - ((obj)anObject)[-1].retained++; - objc_mutex_unlock (retain_counts_gate); + if (retain_counts_gate != 0) + { + objc_mutex_lock(retain_counts_gate); + ((obj)anObject)[-1].retained++; + objc_mutex_unlock (retain_counts_gate); + } + else + { + ((obj)anObject)[-1].retained++; + } } -#define NSIncrementExtraRefCount(X) \ - objc_mutex_lock (retain_counts_gate); \ - ((obj)(X))[-1].retained++; \ - objc_mutex_unlock (retain_counts_gate) +#define NSIncrementExtraRefCount(X) ({ \ + if (retain_counts_gate != 0) \ + { \ + objc_mutex_lock(retain_counts_gate); \ + ((obj)(X))[-1].retained++; \ + objc_mutex_unlock(retain_counts_gate); \ + } \ + else \ + { \ + ((obj)X)[-1].retained++; \ + } \ +}) BOOL NSDecrementExtraRefCountWasZero(id anObject) { - objc_mutex_lock (retain_counts_gate); - if (((obj)anObject)[-1].retained-- == 0) + if (retain_counts_gate != 0) + { + objc_mutex_lock(retain_counts_gate); + if (((obj)anObject)[-1].retained-- == 0) { - objc_mutex_unlock (retain_counts_gate); + objc_mutex_unlock(retain_counts_gate); return YES; - } else { - objc_mutex_unlock (retain_counts_gate); + } + else + { + objc_mutex_unlock(retain_counts_gate); return NO; } + } + else + { + if (((obj)anObject)[-1].retained-- == 0) + { + return YES; + } + else + { + return NO; + } + } } @@ -218,22 +255,31 @@ NSDecrementExtraRefCountWasZero(id anObject) /* The maptable of retain counts on objects */ static o_map_t *retain_counts = NULL; -/* The mutex lock to protect multi-threaded use of `retain_counts' */ -static objc_mutex_t retain_counts_gate = NULL; void NSIncrementExtraRefCount (id anObject) { o_map_node_t *node; - extern o_map_node_t *o_map_node_for_key (o_map_t *m, const void *k); + extern o_map_node_t *o_map_node_for_key(o_map_t *m, const void *k); - objc_mutex_lock (retain_counts_gate); - node = o_map_node_for_key (retain_counts, anObject); - if (node) - ((int)(node->value))++; + if (retain_counts_gate != 0) + { + objc_mutex_lock(retain_counts_gate); + node = o_map_node_for_key (retain_counts, anObject); + if (node) + ((int)(node->value))++; + else + o_map_at_key_put_value_known_absent (retain_counts, anObject, (void*)1); + objc_mutex_unlock(retain_counts_gate); + } else - o_map_at_key_put_value_known_absent (retain_counts, anObject, (void*)1); - objc_mutex_unlock (retain_counts_gate); + { + node = o_map_node_for_key (retain_counts, anObject); + if (node) + ((int)(node->value))++; + else + o_map_at_key_put_value_known_absent (retain_counts, anObject, (void*)1); + } } BOOL @@ -243,17 +289,35 @@ NSDecrementExtraRefCountWasZero (id anObject) extern o_map_node_t *o_map_node_for_key (o_map_t *m, const void *k); extern void o_map_remove_node (o_map_node_t *node); - objc_mutex_lock (retain_counts_gate); - node = o_map_node_for_key (retain_counts, anObject); - if (!node) + if (retain_counts_gate != 0) { - objc_mutex_unlock (retain_counts_gate); - return YES; + objc_mutex_lock(retain_counts_gate); + node = o_map_node_for_key (retain_counts, anObject); + if (!node) + { + objc_mutex_unlock(retain_counts_gate); + return YES; + } + NSAssert((int)(node->value) > 0, NSInternalInconsistencyException); + if (!--((int)(node->value))) + { + o_map_remove_node (node); + } + objc_mutex_unlock(retain_counts_gate); + } + else + { + node = o_map_node_for_key (retain_counts, anObject); + if (!node) + { + return YES; + } + NSAssert((int)(node->value) > 0, NSInternalInconsistencyException); + if (!--((int)(node->value))) + { + o_map_remove_node (node); + } } - NSAssert((int)(node->value) > 0, NSInternalInconsistencyException); - if (!--((int)(node->value))) - o_map_remove_node (node); - objc_mutex_unlock (retain_counts_gate); return NO; } @@ -262,11 +326,26 @@ NSExtraRefCount (id anObject) { unsigned ret; - objc_mutex_lock (retain_counts_gate); - ret = (unsigned) o_map_value_at_key (retain_counts, anObject); - if (ret == (unsigned)o_map_not_a_key_marker(retain_counts) || - ret == (unsigned)o_map_not_a_value_marker(retain_counts)) ret = 0; - objc_mutex_unlock (retain_counts_gate); + if (retain_counts_gate != 0) + { + objc_mutex_lock(retain_counts_gate); + ret = (unsigned) o_map_value_at_key(retain_counts, anObject); + if (ret == (unsigned)o_map_not_a_key_marker(retain_counts) + || ret == (unsigned)o_map_not_a_value_marker(retain_counts)) + { + ret = 0; + } + objc_mutex_unlock(retain_counts_gate); + } + else + { + ret = (unsigned) o_map_value_at_key(retain_counts, anObject); + if (ret == (unsigned)o_map_not_a_key_marker(retain_counts) + || ret == (unsigned)o_map_not_a_value_marker(retain_counts)) + { + ret = 0; + } + } return ret; /* ExtraRefCount + 1 */ } @@ -501,9 +580,18 @@ static IMP autorelease_imp = 0; This does not need mutex protection. */ static BOOL double_release_check_enabled = NO; + @implementation NSObject ++ (void) _becomeMultiThreaded: (NSNotification)aNotification +{ + if (retain_counts_gate == 0) + { + retain_counts_gate = objc_mutex_allocate(); + } +} + + (void) initialize { if (self == [NSObject class]) @@ -529,16 +617,16 @@ static BOOL double_release_check_enabled = NO; retain_counts = o_map_with_callbacks (o_callbacks_for_non_owned_void_p, o_callbacks_for_int); #endif - /* - * retain_counts_gate is needed on SMP machines for release to work - * reliably. - */ - retain_counts_gate = objc_mutex_allocate (); fastMallocOffset = fastMallocClass->instance_size % ALIGN; #else fastMallocOffset = 0; #endif _fastBuildCache(); + [[NSNotificationCenter defaultCenter] + addObserver: self + selector: @selector(_becomeMultiThreaded:) + name: NSWillBecomeMultiThreadedNotification + object: nil]; } return; } @@ -674,13 +762,13 @@ static BOOL double_release_check_enabled = NO; - (NSString*) description { - return [NSString stringWithFormat: @"<%s %lx>", + return [NSString stringWithFormat: @"<%s: %lx>", object_get_class_name(self), (unsigned long)self]; } + (NSString*) description { - return [NSString stringWithFormat: @"<%s>", object_get_class_name(self)]; + return [NSString stringWithCString: object_get_class_name(self)]; } - (void) descriptionTo: (id)output @@ -781,7 +869,7 @@ static BOOL double_release_check_enabled = NO; /* NSObject protocol */ -- autorelease +- (id) autorelease { #if GS_WITH_GC == 0 if (double_release_check_enabled) diff --git a/Source/NSTimeZone.m b/Source/NSTimeZone.m index 47903aeb5..b94f3c219 100644 --- a/Source/NSTimeZone.m +++ b/Source/NSTimeZone.m @@ -972,20 +972,18 @@ static NSMapTable *absolutes = 0; + (NSString*) getTimeZoneFile: (NSString *)name { - /* - * OpenStep does NOT put all the GMT+-* timezones in the Etc directory so all - * the OpenStep software will fail to work without this extra hack. - */ - NSString *fileName = [NSString stringWithFormat: @"%@%@", - ZONES_DIR, name]; + NSString *fileName = [NSString stringWithFormat: @"%@%@", ZONES_DIR, name]; NSString *path = [NSBundle pathForGNUstepResource: fileName - ofType: @"" - inDirectory: TIME_ZONE_DIR]; + ofType: @"" + inDirectory: TIME_ZONE_DIR]; - if ( !path ) - { - return [self getTimeZoneFile: [NSString stringWithFormat: @"Etc/%@", name]]; - } + /* + * Hack for OPENSTEP storing zones in Etc? + */ + if (path == nil) + { + path=[self getTimeZoneFile: [NSString stringWithFormat: @"Etc/%@", name]]; + } return path; }