Gestalt
Monday, February 21, 2011
Sometimes it is useful to lookup the operating system version that your
code is running on. On the Mac OS, 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 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 10.3.15 will be returned
as 0x1039, and Mac OS 10.10.5 will return 0x1095.
A better way to get version information on Mac OS
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 you are running
(since it works for all of the released Mac OS
versions):
: system-code-name ( -- str )
system-version 0xFFF0 bitand {
{ 0x1070 [ "Lion" ] }
{ 0x1060 [ "Snow Leopard" ] }
{ 0x1050 [ "Leopard" ] }
{ 0x1040 [ "Tiger" ] }
{ 0x1030 [ "Panther" ] }
{ 0x1020 [ "Jaguar" ] }
{ 0x1010 [ "Puma" ] }
{ 0x1000 [ "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 is running on my laptop:
IN: 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:
IN: scratchpad USE: cocoa.plist
IN: scratchpad "/System/Library/CoreServices/SystemVersion.plist"
read-plist .
H{
{ "ProductVersion" "10.6.6" }
{ "ProductName" "Mac OS" }
{ "ProductBuildVersion" "10J567" }
{ "ProductUserVisibleVersion" "10.6.6" }
{ "ProductCopyright" "1983-2011 Apple Inc." }
}
The code for this is on my GitHub.