File: programming/cocoa/UKCrashReporter.zip/UKCrashReporter/UKSystemInfo.m


//
//  UKSystemInfo.m
//  UKSystemInfo
//
//  Created by Uli Kusterer on 23.09.04.
//  Copyright 2004 M. Uli Kusterer. All rights reserved.
//
 
#import "UKSystemInfo.h"
#include <Carbon/Carbon.h>
#include <sys/types.h>
#include <sys/sysctl.h>
 
unsigned	UKPhysicalRAMSize()
{
	long		ramSize;
	
	if( Gestalt( gestaltPhysicalRAMSizeInMegabytes, &ramSize ) == noErr )
		return ramSize;
	else
		return 0;
}
 
 
NSString*	UKSystemVersionString()
{
	long		vMajor = 10, vMinor = 0, vBugfix = 0;
	UKGetSystemVersionComponents( &vMajor, &vMinor, &vBugfix );
	
	return [NSString stringWithFormat: @"%ld.%ld.%ld", vMajor, vMinor, vBugfix];
}
 
 
void	UKGetSystemVersionComponents( long* outMajor, long* outMinor, long* outBugfix )
{
	long		sysVersion = UKSystemVersion();
	if( sysVersion >= MAC_OS_X_VERSION_10_4 )
	{
		Gestalt( gestaltSystemVersionMajor, outMajor );
		Gestalt( gestaltSystemVersionMinor, outMinor );
		Gestalt( gestaltSystemVersionBugFix, outBugfix );
	}
	else
	{
		*outMajor = ((sysVersion & 0x0000F000) >> 12) * 10 + ((sysVersion & 0x00000F00) >> 8);
		*outMinor = (sysVersion & 0x000000F0) >> 4;
		*outBugfix = sysVersion & 0x0000000F;
	}
}
 
 
long	UKSystemVersion()
{
	long		sysVersion;
	
	if( Gestalt( gestaltSystemVersion, &sysVersion ) != noErr )
		return 0;
	
	return sysVersion;
}
 
 
unsigned	UKClockSpeed()
{
	long		speed;
	
	if( Gestalt( gestaltProcClkSpeed, &speed ) == noErr )
		return speed / 1000000;
	else
		return 0;
}
 
 
unsigned	UKCountCores()
{
	unsigned	count = 0;
	size_t		size = sizeof(count);
 
	if( sysctlbyname( "hw.ncpu", &count, &size, NULL, 0 ) )
		return 1;
 
	return count;
}
 
 
NSString*	UKMachineName()
{
	static NSString*	cpuName = nil;
	if( cpuName )
		return cpuName;
	
	char*				machineName = NULL;
	
	if( Gestalt( gestaltUserVisibleMachineName, (long*) &machineName ) == noErr )
	{
		NSString*	internalName = [NSString stringWithCString: machineName +1 length: machineName[0]];
		
		NSDictionary* translationDictionary = [[NSDictionary alloc] initWithObjectsAndKeys:
					@"PowerMac 8500/8600",@"AAPL,8500",
					@"PowerMac 9500/9600",@"AAPL,9500",
					@"PowerMac 7200",@"AAPL,7200",
					@"PowerMac 7200/7300",@"AAPL,7300",
					@"PowerMac 7500",@"AAPL,7500",
					@"Apple Network Server",@"AAPL,ShinerESB",
					@"Alchemy(Performa 6400 logic-board design)",@"AAPL,e407",
					@"Gazelle(5500)",@"AAPL,e411",
					@"PowerBook 3400",@"AAPL,3400/2400",
					@"PowerBook 3500",@"AAPL,3500",
					@"PowerMac G3 (Gossamer)",@"AAPL,Gossamer",
					@"PowerMac G3 (Silk)",@"AAPL,PowerMac G3",
					@"PowerBook G3 (Wallstreet)",@"AAPL,PowerBook1998",
					@"Yikes! Old machine",@"AAPL",		// generic.
					
					@"iMac (first generation)",@"iMac,1",
					@"iMac",@"iMac",					// generic.
					
					@"PowerBook G3 (Lombard)",@"PowerBook1,1",
					@"iBook (clamshell)",@"PowerBook2,1",
					@"iBook FireWire (clamshell)",@"PowerBook2,2",
					@"PowerBook G3 (Pismo)",@"PowerBook3,1",
					@"PowerBook G4 (Titanium)",@"PowerBook3,2",
					@"PowerBook G4 (Titanium w/ Gigabit Ethernet)",@"PowerBook3,3",
					@"PowerBook G4 (Titanium w/ DVI)",@"PowerBook3,4",
					@"PowerBook G4 (Titanium 1GHZ)",@"PowerBook3,5",
					@"iBook (12in May 2001)",@"PowerBook4,1",
					@"iBook (May 2002)",@"PowerBook4,2",
					@"iBook 2 rev. 2 (w/ or w/o 14in LCD) (Nov 2002)",@"PowerBook4,3",
					@"iBook 2 (w/ or w/o 14in LDC)",@"PowerBook4,4",
					@"PowerBook G4 (Aluminum 17in)",@"PowerBook5,1",
					@"PowerBook G4 (Aluminum 15in)",@"PowerBook5,2",
					@"PowerBook G4 (Aluminum 17in rev. 2)",@"PowerBook5,3",
					@"PowerBook G4 (Aluminum 12in)",@"PowerBook6,1",
					@"PowerBook G4 (Aluminum 12in)",@"PowerBook6,2",
					@"iBook G4",@"PowerBook6,3",
					@"PowerBook or iBook",@"PowerBook",	// generic.
					
					@"Blue & White G3",@"PowerMac1,1",
					@"PowerMac G4 PCI Graphics",@"PowerMac1,2",
					@"iMac FireWire (CRT)",@"PowerMac2,1",
					@"iMac FireWire (CRT)",@"PowerMac2,2",
					@"PowerMac G4 AGP Graphics",@"PowerMac3,1",
					@"PowerMac G4 AGP Graphics",@"PowerMac3,2",
					@"PowerMac G4 AGP Graphics",@"PowerMac3,3",
					@"PowerMac G4 (QuickSilver)",@"PowerMac3,4",
					@"PowerMac G4 (QuickSilver)",@"PowerMac3,5",
					@"PowerMac G4 (MDD/Windtunnel)",@"PowerMac3,6",
					@"iMac (Flower Power)",@"PowerMac4,1",
					@"iMac (Flat Panel 15in)",@"PowerMac4,2",
					@"eMac",@"PowerMac4,4",
					@"iMac (Flat Panel 17in)",@"PowerMac4,5",
					@"PowerMac G4 Cube",@"PowerMac5,1",
					@"PowerMac G4 Cube",@"PowerMac5,2",
					@"iMac (Flat Panel 17in)",@"PowerMac6,1",
					@"PowerMac G5",@"PowerMac7,2",
					@"PowerMac G5",@"PowerMac7,3",
					@"PowerMac",@"PowerMac",	// generic.
					
					@"XServe",@"RackMac1,1",
					@"XServe rev. 2",@"RackMac1,2",
					@"XServe G5",@"RackMac3,1",
					@"XServe",@"RackMac",
					
					@"Mac Mini",@"Macmini1,1",	// Core Duo?
					@"Mac Mini",@"Macmini",		// generic
					
					nil];
		
		NSRange			r;
		NSString*		aKey;
		NSString*		foundKey = nil;
		NSString*		humanReadableName = nil;
		
		// Find the corresponding entry in the NSDictionary
		//	Keys should be sorted to distinguish 'generic' from 'specific' names.
		//	So we can overwrite generic names with the more specific ones as we
		//	progress through the list.
		NSEnumerator	*e=[[[translationDictionary allKeys]
									sortedArrayUsingSelector:@selector(compare:)]
									objectEnumerator];
		while( aKey = [e nextObject] )
		{
			r = [internalName rangeOfString: aKey];
			if( r.location != NSNotFound )
			{
				if( humanReadableName == nil || [foundKey length] != [internalName length] )	// We didn't have an exact match yet?
				{
					humanReadableName = [translationDictionary objectForKey:aKey];
					foundKey = aKey;
				}
			}
		}
		
		// If it was a generic name, include the ugly name so we can add it to the list:
		if( [foundKey rangeOfString: @","].location == NSNotFound )
			humanReadableName = [[NSString stringWithFormat: @"%@ (%@)", humanReadableName, foundKey] retain];
		// If nothing was found, at least show the ugly name so we have some hint:
		if( humanReadableName == nil )
			cpuName = [[NSString stringWithFormat: @"Unknown (%@)", internalName] retain];
		else
			cpuName = humanReadableName;
	}
	
	return cpuName;
}
 
 
NSString*	UKCPUName()
{
	return UKAutoreleasedCPUName( NO );
}
 
 
NSString*	UKAutoreleasedCPUName( BOOL releaseIt )
{
	long				cpu;
	static NSString*	cpuName = nil;
	
	if( Gestalt( gestaltNativeCPUtype, &cpu ) == noErr )
	{
		if( !cpuName )
		{
			NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys:
										@"Motorola 68000", [NSNumber numberWithLong: gestaltCPU68000],
										@"Motorola 68010", [NSNumber numberWithLong: gestaltCPU68010],
										@"Motorola 68020", [NSNumber numberWithLong: gestaltCPU68020],
										@"Motorola 68030", [NSNumber numberWithLong: gestaltCPU68030],
										@"Motorola 68040", [NSNumber numberWithLong: gestaltCPU68040],
										@"PowerPC 601", [NSNumber numberWithLong: gestaltCPU601],
										@"PowerPC 603", [NSNumber numberWithLong: gestaltCPU603],
										@"PowerPC 604", [NSNumber numberWithLong: gestaltCPU604],
										@"PowerPC 603e", [NSNumber numberWithLong: gestaltCPU603e],
										@"PowerPC 603ev", [NSNumber numberWithLong: gestaltCPU603ev],
										@"PowerPC G3", [NSNumber numberWithLong: gestaltCPU750],
										@"PowerPC 604e", [NSNumber numberWithLong: gestaltCPU604e],
										@"PowerPC 604ev", [NSNumber numberWithLong: gestaltCPU604ev],
										@"PowerPC G4", [NSNumber numberWithLong: gestaltCPUG4],
										@"PowerPC G4", [NSNumber numberWithLong: gestaltCPUG47450],
										nil
									];
			cpuName = [dict objectForKey: [NSNumber numberWithLong: cpu]];
		}
		if( cpuName == nil )
		{
			char	cpuCStr[5] = { 0 };
			memmove( cpuCStr, &cpu, 4 );
			if( (cpu & 0xff000000) >= 0x20000000 && (cpu & 0x00ff0000) >= 0x00200000
				&& (cpu & 0x0000ff00) >= 0x00002000 && (cpu & 0x000000ff) >= 0x00000020)	// All valid as characters?
				cpuName = [NSString stringWithFormat: @"Unknown (%d/%s)", cpu, &cpu];
			else
				cpuName = [NSString stringWithFormat: @"Unknown (%d)", cpu, &cpu];
		}
		[cpuName retain];		// Yeah, I know, I'm paranoid.
	}
 
	if( releaseIt )
	{
		NSString*	cn = cpuName;
		[cpuName autorelease];
		cpuName = nil;
		return cn;
	}
	
	return cpuName;
}
 
 
/*NSString*	UKSystemSerialNumber()
{
	mach_port_t				masterPort;
	kern_return_t			kr = noErr;
	io_registry_entry_t		entry;
	CFTypeRef				prop;
	CFTypeID				propID;
	NSString*				str = nil;
 
	kr = IOMasterPort(MACH_PORT_NULL, &masterPort);
	if( kr != noErr )
		goto cleanup;
	entry = IORegistryGetRootEntry( masterPort );
	if( entry == MACH_PORT_NULL )
		goto cleanup;
	prop = IORegistryEntrySearchCFProperty(entry, kIODeviceTreePlane, CFSTR("serial-number"), nil, kIORegistryIterateRecursively);
	if( prop == nil )
		goto cleanup;
	propID = CFGetTypeID( prop );
	if( propID != CFDataGetTypeID() )
		goto cleanup;
	
	const char*	buf = [(NSData*)prop bytes];
	int			len = [(NSData*)prop length],
				 x;
	
	char	secondPart[256];
	char	firstPart[256];
	char*	currStr = secondPart;
	int		y = 0;
	
	for( x = 0; x < len; x++ )
	{
		if( buf[x] > 0 && (y < 255) )
			currStr[y++] = buf[x];
		else if( currStr == secondPart )
		{
			currStr[y] = 0;		// Terminate string.
			currStr = firstPart;
			y = 0;
		}
	}
	currStr[y] = 0;	// Terminate string.
	
	str = [NSString stringWithFormat: @"%s%s", firstPart, secondPart];
	
cleanup:
	mach_port_deallocate( mach_task_self(), masterPort );
	
	return str;
}*/
 

This code uses the PclZip Zip File reading code, which is subject to the GNU LGPL. It also uses the GeSHi syntax highlighter, subject to the GPL. Ask if you want this for your own web site, it's free.