Sometimes it is useful to lookup the operating system version that your code is running on. On the Mac OS X, this information can be retrieved in several ways. We will be adding Factor support for using the Gestalt
function (available as part of the Gestalt Manager in the CoreServices.framework
since Mac OS X 10.0).
First, we create a namespace and list of vocabularies we will be using:
USING: alien.data alien.syntax combinators core-foundation formatting io.binary kernel math ; IN: gestalt
Using Factor's C library interface, we can declare the function and its types:
TYPEDEF: SInt16 OSErr TYPEDEF: UInt32 OSType FUNCTION: OSErr Gestalt ( OSType selector, SInt32* response ) ;
Using this, we can create the gestalt
word, which calls the function, checks for errors, and returns the result:
: gestalt ( selector -- response ) { SInt32 } [ Gestalt 0 assert= ] with-out-parameters ;
Looking at Gestalt.h
, we can see several enum
definitions that can be used to retrieve system version information:
enum { gestaltSystemVersion = 'sysv', gestaltSystemVersionMajor = 'sys1', gestaltSystemVersionMinor = 'sys2', gestaltSystemVersionBugFix = 'sys3' };
Knowing these, we can create words for accessing the various system versions exposed by Gestalt
.
: system-version ( -- n ) "sysv" be> gestalt ; : system-version-major ( -- n ) "sys1" be> gestalt ; : system-version-minor ( -- n ) "sys2" be> gestalt ; : system-version-bugfix ( -- n ) "sys3" be> gestalt ;
However, we see a comment in Gestalt.h
which says:
If the values of the minor or bug fix revision are larger than 9, then gestaltSystemVersion will substitute the value 9 for them. For example, Mac OS X 10.3.15 will be returned as 0x1039, and Mac OS X 10.10.5 will return 0x1095. A better way to get version information on Mac OS X would be to use the new gestaltSystemVersionMajor, gestaltSystemVersionMinor, and gestaltSystemVersionBugFix selectors, which don't have arbitrary limits on the values returned.
With this limitation, we could still use the system-version
to retrieve Apple's "code name" for the version of Mac OS X you are running (since it works for all of the released Mac OS X versions):
: system-code-name ( -- str ) system-version HEX: FFF0 bitand { { HEX: 1070 [ "Lion" ] } { HEX: 1060 [ "Snow Leopard" ] } { HEX: 1050 [ "Leopard" ] } { HEX: 1040 [ "Tiger" ] } { HEX: 1030 [ "Panther" ] } { HEX: 1020 [ "Jaguar" ] } { HEX: 1010 [ "Puma" ] } { HEX: 1000 [ "Cheetah" ] } [ drop "Unknown" ] } case ;
And then, we can make a version string using each of the major, minor, and bugfix values:
: system-version-string ( -- str ) system-version-major system-version-minor system-version-bugfix "%s.%s.%s" sprintf ;
Using this, we can see which version of Mac OS X is running on my laptop:
( scratchpad ) system-version-string system-code-name "%s (%s)\n" printf 10.6.6 (Snow Leopard)
By the way, another comment in Gestalt.h
says:
If you want to know the product build version string, product name, or the user visible version string you should read in the system version information from the file /System/Library/CoreServices/SystemVersion.plist.
Using the cocoa.plist
vocabulary, we can do just that:
( scratchpad ) USE: cocoa.plist ( scratchpad ) "/System/Library/CoreServices/SystemVersion.plist" read-plist . H{ { "ProductVersion" "10.6.6" } { "ProductName" "Mac OS X" } { "ProductBuildVersion" "10J567" } { "ProductUserVisibleVersion" "10.6.6" } { "ProductCopyright" "1983-2011 Apple Inc." } }
The code for this is on my Github.