<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Vincent Gable's Blog &#187; UNIX</title>
	<atom:link href="http://vgable.com/blog/category/unix/feed/" rel="self" type="application/rss+xml" />
	<link>http://vgable.com/blog</link>
	<description>my weblog.</description>
	<lastBuildDate>Tue, 29 Nov 2011 22:20:23 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Competing Software Engineering Approaches</title>
		<link>http://vgable.com/blog/2009/02/18/competing-software-engineering-approaches/</link>
		<comments>http://vgable.com/blog/2009/02/18/competing-software-engineering-approaches/#comments</comments>
		<pubDate>Wed, 18 Feb 2009 23:18:20 +0000</pubDate>
		<dc:creator>Vincent Gable</dc:creator>
				<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Quotes]]></category>
		<category><![CDATA[UNIX]]></category>
		<category><![CDATA[Android]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[Mobility]]></category>
		<category><![CDATA[Palm]]></category>
		<category><![CDATA[Software Development]]></category>
		<category><![CDATA[Windows]]></category>

		<guid isPermaLink="false">http://vgable.com/blog/2009/02/18/competing-software-engineering-approaches/</guid>
		<description><![CDATA[Tim Bray, &#8230;Palm&#x2019;s approach is radically different from both Android&#x2019;s and Apple&#x2019;s. Since they&#x2019;re all here at more or less the same time, running the same Web browser on roughly equivalent hardware, this represents an unprecedented experiment in competitive software-engineering approaches. Language Framework Notes Apple Objective-C Cocoa Old-school object-oriented language compiled to the metal; general-purpose [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.tbray.org/ongoing/When/200x/2009/02/18/Engineering-Experiment">Tim Bray</a>,</p>
<blockquote>
<p>&#8230;Palm&#x2019;s approach is<br />
radically different from both Android&#x2019;s and Apple&#x2019;s.  Since they&#x2019;re all here<br />
at more or less the same time, running the<br />
<a href='http://webkit.org/'>same Web browser</a> on roughly<br />
equivalent hardware, this represents an unprecedented experiment in<br />
competitive software-engineering approaches.</p>
<table cellpadding="5">
<tr align="left" valign="top">
<td class="empty"></td>
<th>Language</th>
<th>Framework</th>
<th>Notes</th>
</tr>
<tr align="left" valign="top">
<th>Apple</th>
<td>Objective-C</td>
<td>Cocoa</td>
<td>Old-school object-oriented language compiled to the metal; general-purpose UI<br />
framework with roots reaching back to NeXT.</td>
</tr>
<tr align="left" valign="top">
<th>Android</th>
<td>Java</td>
<td>Android</td>
<td>Java language, custom VM, built-from-scratch UI<br />
framework aimed at small-form-factor devices, fairly abstraction-free, based<br />
on &#x201c;Actions&#x201d; and &#x201c;Intents&#x201d;.</td>
</tr>
<tr align="left" valign="top">
<th>web OS</th>
<td>JavaScript</td>
<td>&#x201c;Mojo&#x201d;</td>
<td>All Web technology all the time. Innovative and visually-impressive<br />
&#x201c;card&#x201d;-based UI.</td>
</tr>
</table>
<p><em>(I think it&#8217;s interesting to see Windows Mobile on the list:</p>
<table cellpadding="5">
<tr align="left" valign="top">
<th>Windows Mobile</th>
<td>C/C++</td>
<td>Windows CE/.NET Micro</td>
<td>Philosophically tries to bring Windows to the phone. When I did WinCE development it felt like doing C++ for a Windows OS from the past.</td>
</tr>
</table>
<p>)</em>
</p></blockquote>
<p>I see way too many other factors to attribute success/failure of the devices to the language.  So I wouldn&#8217;t call this an experiment.</p>
<p>But it is interesting how much development for each platform diverges at a fundamental level!</p>
<p>Historically most operating systems &#8212;<br />
UNIX, OS/2, Linux, Windows, Solaris, Mac (Classic and OS X) &#8212; were predominantly, written in C/C++.  While each platform has it&#8217;s own frameworks, they all have strong support for C++ development.  (Although Mac OS X has <a href="http://arstechnica.com/apple/news/2007/06/64-bit-support-in-leopard-no-carbon-love.ars">is slowly dropping support for it&#8217;s C/C++ &#8220;Carbon&#8221; API</a>, and Windows wants to be moving to C# .NET)</p>
<p>It&#8217;s really cool to see mobile platforms doing something radically different from each other.  There are good arguments for each approach &#8212; may the best one win.</p>
]]></content:encoded>
			<wfw:commentRss>http://vgable.com/blog/2009/02/18/competing-software-engineering-approaches/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Restarting Your Mac OS X Cocoa Application</title>
		<link>http://vgable.com/blog/2008/10/05/restarting-your-cocoa-application/</link>
		<comments>http://vgable.com/blog/2008/10/05/restarting-your-cocoa-application/#comments</comments>
		<pubDate>Mon, 06 Oct 2008 00:35:09 +0000</pubDate>
		<dc:creator>Vincent Gable</dc:creator>
				<category><![CDATA[Bug Bite]]></category>
		<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[MacOSX]]></category>
		<category><![CDATA[Objective-C]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[UNIX]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[NSTask]]></category>
		<category><![CDATA[NSUserDefaults]]></category>

		<guid isPermaLink="false">http://vgable.com/blog/2008/10/05/restarting-your-cocoa-application/</guid>
		<description><![CDATA[Restarting your own application is a tricky thing to do, because you can&#8217;t tell yourself to start up when you aren&#8217;t running. Here is one solution, use NSTask to run a very short script that you can embed right in your Objective-C code: kill -9 YourPID open PathToYourApp Something to be aware of, kill -9 [...]]]></description>
			<content:encoded><![CDATA[<p>Restarting your own application is a tricky thing to do, because you can&#8217;t tell yourself to start up when you aren&#8217;t running.  Here is one solution, use <code><a href="http://vgable.com/blog/2008/03/05/calling-the-command-line-from-cocoa/">NSTask</a></code> to run a very short script that you can embed right in your Objective-C code:<br />
<code>kill -9 <em>YourPID</em><br />
open <em>PathToYourApp</em></code><br />
Something to be aware of, <code>kill -9</code> will immediately terminate your application, without going through the usual <code><a href="http://developer.apple.com/documentation/Cocoa/Reference/ApplicationKit/Classes/NSApplication_Class/Reference/Reference.html#//apple_ref/doc/uid/20000012-CACBFGDB">applicationWillTerminate:</a></code> business that happens when an application quits more gracefully.</p>
<p><code>- (void) restartOurselves<br />{<br />&nbsp;&nbsp;&nbsp;//$N = argv[N]<br />&nbsp;&nbsp;&nbsp;NSString *killArg1AndOpenArg2Script = @"kill -9 $1 \n open \"$2\"";<br />&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;//NSTask needs its arguments to be strings<br />&nbsp;&nbsp;&nbsp;NSString *ourPID = [NSString stringWithFormat:@"%d",<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[[NSProcessInfo processInfo] processIdentifier]];<br />&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;//this will be the path to the .app bundle,<br />&nbsp;&nbsp;&nbsp;//not the executable inside it; exactly what `open` wants<br />&nbsp;&nbsp;&nbsp;NSString * pathToUs = [[NSBundle mainBundle] bundlePath];<br />&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;NSArray *shArgs = [NSArray arrayWithObjects:@"-c", // -c tells sh to execute the next argument, passing it the remaining arguments.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   killArg1AndOpenArg2Script,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   @"", //$0 path to script (ignored)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   ourPID, //$1 in restartScript<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   pathToUs, //$2 in the restartScript<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   nil];<br />&nbsp;&nbsp;&nbsp;NSTask *restartTask = [NSTask launchedTaskWithLaunchPath:@"/bin/sh" arguments:shArgs];<br />&nbsp;&nbsp;&nbsp;[restartTask waitUntilExit]; //wait for killArg1AndOpenArg2Script to finish<br />&nbsp;&nbsp;&nbsp;NSLog(@"*** ERROR: %@ should have been terminated, but we are still running", pathToUs);<br />&nbsp;&nbsp;&nbsp;assert(!"We should not be running!");<br />}<br /></code></p>
<p><strong>WARNING:</strong> don&#8217;t make the same mistake that I did and test <code>restartOurselves</code> without some kind of guard to keep your application from restarting forever.  It is <em>very</em> difficult to kill such a beast, because whenever it starts up it takes keyboard focus away from what you are doing&#8230;. well I&#8217;m sure you get <a href="http://www.youtube.com/watch?v=LD8HDta7Z_4">the idea</a>.</p>
<p><code>- (BOOL) weHaveRunBefore {<br />
&nbsp;&nbsp;&nbsp;NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];<br />
&nbsp;&nbsp;&nbsp;BOOL weHaveRunBefore = [prefs boolForKey:@"weHaveRunBefore"];<br />
&nbsp;&nbsp;&nbsp;[prefs setBool:YESs forKey:@"weHaveRunBefore"];<br />
&nbsp;&nbsp;&nbsp;[prefs synchronize];<br />
&nbsp;&nbsp;&nbsp;return weHaveRunBefore;<br />
}<br />
</code></p>
]]></content:encoded>
			<wfw:commentRss>http://vgable.com/blog/2008/10/05/restarting-your-cocoa-application/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Is an Application Running?</title>
		<link>http://vgable.com/blog/2008/08/22/is-an-application-running/</link>
		<comments>http://vgable.com/blog/2008/08/22/is-an-application-running/#comments</comments>
		<pubDate>Sat, 23 Aug 2008 00:22:33 +0000</pubDate>
		<dc:creator>Vincent Gable</dc:creator>
				<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[MacOSX]]></category>
		<category><![CDATA[Objective-C]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Sample Code]]></category>
		<category><![CDATA[UNIX]]></category>
		<category><![CDATA[Carbon]]></category>
		<category><![CDATA[Process Manager]]></category>

		<guid isPermaLink="false">http://vgable.com/blog/2008/08/22/is-an-application-running/</guid>
		<description><![CDATA[UPDATED 2009-01-13 to correctly detect background applications. Pass in the bundle-identfier of an application, and this will tell you if it&#8217;s currently running or not: - (BOOL) ThereIsARunningApplicationWithBundleID:(NSString*)bundleID; { &#160;&#160;&#160;ProcessSerialNumber PSN = {kNoProcess}; &#160;&#160;&#160;while(GetNextProcess(&#038;PSN) == noErr) { &#160;&#160;&#160;&#160;&#160;&#160;CFDictionaryRef info = ProcessInformationCopyDictionary(&#038;PSN,kProcessDictionaryIncludeAllInformationMask); &#160;&#160;&#160;&#160;&#160;&#160;if(info) { &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;NSString *theirBundleID = (NSString*)CFDictionaryGetValue(info, kIOBundleIdentifierKey); &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;BOOL bundleIDMatches = [bundleID isEqualTo:(NSString*)theirBundleID]; &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;CFRelease(info); &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;if(bundleIDMatches) [...]]]></description>
			<content:encoded><![CDATA[<p>UPDATED 2009-01-13 to correctly detect <a href="http://vgable.com/blog/2009/01/13/running-in-the-background/">background applications</a>.</p>
<p>Pass in the <a href="http://developer.apple.com/documentation/CoreFoundation/Conceptual/CFBundles/Tasks/locating.html#//apple_ref/doc/uid/20001123-123081">bundle-identfier</a> of an application, and this will tell you if it&#8217;s currently running or not:<br />
<code>- (BOOL) ThereIsARunningApplicationWithBundleID:(NSString*)bundleID; {<br />
&nbsp;&nbsp;&nbsp;ProcessSerialNumber	PSN = {kNoProcess};<br />
&nbsp;&nbsp;&nbsp;while(GetNextProcess(&#038;PSN) == noErr) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CFDictionaryRef info = ProcessInformationCopyDictionary(&#038;PSN,kProcessDictionaryIncludeAllInformationMask);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(info) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NSString *theirBundleID = (NSString*)CFDictionaryGetValue(info, kIOBundleIdentifierKey);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BOOL bundleIDMatches = [bundleID isEqualTo:(NSString*)theirBundleID];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CFRelease(info);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(bundleIDMatches)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return YES;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;return NO;<br />
}</code></p>
<p>(It&#8217;s a good idea to test if an application is running before sending it an AppleEvent, because that will launch it.)</p>
<p>Interestingly, none of the the <a href="http://developer.apple.com/documentation/Carbon/Reference/Process_Manager/Reference/reference.html">Process Manager</a> APIs can see into <a href="http://developer.apple.com/documentation/MacOSX/Conceptual/BPMultipleUsers/BPMultipleUsers.html">another user&#8217;s process-space</a>; but <a href="http://developer.apple.com/documentation/Darwin/Reference/ManPages/man1/ps.1.html"><code>ps</code></a> can; at least on OS X 10.5 and 10.4.</p>
]]></content:encoded>
			<wfw:commentRss>http://vgable.com/blog/2008/08/22/is-an-application-running/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>launchctl Gotcha</title>
		<link>http://vgable.com/blog/2008/08/17/launchctl-gotcha/</link>
		<comments>http://vgable.com/blog/2008/08/17/launchctl-gotcha/#comments</comments>
		<pubDate>Mon, 18 Aug 2008 02:43:20 +0000</pubDate>
		<dc:creator>Vincent Gable</dc:creator>
				<category><![CDATA[Bug Bite]]></category>
		<category><![CDATA[MacOSX]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[UNIX]]></category>
		<category><![CDATA[launchctl]]></category>
		<category><![CDATA[launchd]]></category>
		<category><![CDATA[root]]></category>

		<guid isPermaLink="false">http://vgable.com/blog/2008/08/17/launchctl-gotcha/</guid>
		<description><![CDATA[On Mac OS X 10.5, the launchd you talk to as non-root user is not the same launchd you talk to when root. So $ launchctl list $ sudo launchctl list print out different lists, and the unprivileged `launchctl list` contains processes that the root-`launchctl list` does not know about. So running a launctl command [...]]]></description>
			<content:encoded><![CDATA[<p>On Mac OS X 10.5, the <code><a href="http://developer.apple.com/macosx/launchd.html">launchd</a></code> you talk to as non-root user is <em>not</em> the same <code>launchd</code> you talk to when root.  So<br />
<code>$ launchctl list</code><br />
<code>$ sudo launchctl list</code><br />
print out different lists, and <strong>the unprivileged `<code>launchctl list</code>` contains processes that the root-`<code>launchctl list</code>`  does <em>not</em> know about</strong>.  So running a <code>launctl</code> command as root may cause it to fail.</p>
<p>I have never seen another UNIX-ish tool that would fail when run as root, but succeed otherwise.</p>
]]></content:encoded>
			<wfw:commentRss>http://vgable.com/blog/2008/08/17/launchctl-gotcha/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Programatically Excluding Things from Time Machine Backups</title>
		<link>http://vgable.com/blog/2008/07/07/programatically-excluding-things-from-time-machine-backups/</link>
		<comments>http://vgable.com/blog/2008/07/07/programatically-excluding-things-from-time-machine-backups/#comments</comments>
		<pubDate>Mon, 07 Jul 2008 23:55:18 +0000</pubDate>
		<dc:creator>Vincent Gable</dc:creator>
				<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[MacOSX]]></category>
		<category><![CDATA[Objective-C]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[UNIX]]></category>
		<category><![CDATA[Command-Line]]></category>
		<category><![CDATA[Leopard]]></category>
		<category><![CDATA[Time Machine]]></category>

		<guid isPermaLink="false">http://vgable.com/blog/2008/07/07/programatically-excluding-things-from-time-machine-backups/</guid>
		<description><![CDATA[To exclude files/folders from a Time Machine backup, you can use the C-function CSBackupSetItemExcluded(). As far as I know there isn&#8217;t an official way to do this from the command-line or a shell script. As near as I can tell, the safest way to it without using compiled C-code is: sudo defaults write /Library/Preferences/com.apple.TimeMachine \ [...]]]></description>
			<content:encoded><![CDATA[<p>To exclude files/folders from a Time Machine backup, you can use the C-function <a href="http://developer.apple.com/documentation/MacOSX/Reference/Backup/Reference/reference.html"><code>CSBackupSetItemExcluded()</code></a>.</p>
<p>As far as I know there isn&#8217;t an <em>official</em> way to do this from the command-line or a shell script.  As near as I can tell, the <em>safest</em> way to it without using compiled C-code is:</p>
<p><code>sudo defaults write /Library/Preferences/com.apple.TimeMachine \<br />
SkipPaths -array-add "PATH-ONE" "PATH-TWO"</code><br />
where <code>"PATH-ONE" "PATH-TWO"</code> are of course paths to items you want to exclude.</p>
<p>Credit to <a href="http://www.makemacwork.com/">Ellis Jordan Bojar</a> for this solution. (<a href="http://www.makemacwork.com/command-time-machine.htm">original article</a>)  Using <code><a href="http://developer.apple.com/documentation/Darwin/Reference/ManPages/man1/defaults.1.html">defaults</a></code> instead of tinkering with .plist files directly is really the way to go!</p>
]]></content:encoded>
			<wfw:commentRss>http://vgable.com/blog/2008/07/07/programatically-excluding-things-from-time-machine-backups/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Getting Mac OS X Version Information</title>
		<link>http://vgable.com/blog/2008/05/04/getting-mac-os-x-version-information/</link>
		<comments>http://vgable.com/blog/2008/05/04/getting-mac-os-x-version-information/#comments</comments>
		<pubDate>Sun, 04 May 2008 08:28:00 +0000</pubDate>
		<dc:creator>Vincent Gable</dc:creator>
				<category><![CDATA[MacOSX]]></category>
		<category><![CDATA[Objective-C]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Sample Code]]></category>
		<category><![CDATA[UNIX]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Mac OS X]]></category>
		<category><![CDATA[Scripting]]></category>

		<guid isPermaLink="false">http://vgable.com/blog/2008/05/04/getting-mac-os-x-version-information/</guid>
		<description><![CDATA[Cocoa For a human-readable string, use [[NSProcessInfo processInfo] operatingSystemVersionString]. It looks like &#8220;Version 10.5 (Build 9A581)&#8221;, but that format might change in the future. NSProcessInfo.h explicitly warns against using it for parsing. It will always be human-readable though. For machine-friendly numbers, use the Gestalt function, with one of the selectors: gestaltSystemVersionMajor (in 10.4.17 this would [...]]]></description>
			<content:encoded><![CDATA[<h3>Cocoa</h3>
<p>For a <strong>human-readable string</strong>, use <code>[[NSProcessInfo processInfo] operatingSystemVersionString]</code>.  It looks like &#8220;Version 10.5 (Build 9A581)&#8221;, but that format might change in the future.  NSProcessInfo.h explicitly warns against using it for parsing.  It will always be <em>human</em>-readable though.</p>
<p>For <strong>machine-friendly numbers</strong>, use the <a href="http://developer.apple.com/documentation/Carbon/Reference/Gestalt_Manager/Reference/reference.html">Gestalt</a> function, with one of the selectors:<br />
<code>gestaltSystemVersionMajor</code> (in 10.4.17 this would be the decimal value 10)<br />
<code>gestaltSystemVersionMinor</code> (in 10.4.17 this would be the decimal value 4)<br />
<code>gestaltSystemVersionBugFix</code> (in 10.4.17 this would be the decimal value 17)<br />
<strong>Do <em>not</em> use <a href="http://developer.apple.com/documentation/Carbon/Reference/Gestalt_Manager/Reference/reference.html#//apple_ref/doc/c_ref/gestaltSystemVersion"><code>gestaltSystemVersion</code></a> unless your code needs to run on OS X 10.2 or earlier.</strong>  It&#8217;s a legacy function that can&#8217;t report minor/bugfix versions > 9; meaning it can&#8217;t distinguish between 10.4.9 and 10.4.11.  The CocoaDev wiki has <a href="http://www.cocoadev.com/index.pl?DeterminingOSVersion">example code that works in 10.0</a> if you need to go that route.</p>
<p>Here&#8217;s a simpler example of using Gestalt:<br /><code><br />
- (BOOL) usingLeopard {<br />
&nbsp;&nbsp;long minorVersion, majorVersion;<br />
&nbsp;&nbsp;Gestalt(gestaltSystemVersionMajor, &amp;majorVersion);<br />
&nbsp;&nbsp;Gestalt(gestaltSystemVersionMinor, &amp;minorVersion);<br />
&nbsp;&nbsp;return majorVersion  == 10 &amp;&amp; minorVersion == 5;<br />
}</code></p>
<h3>Scripts</h3>
<p>For <strong>scripts and command-line work</strong>, there is the <a href="http://developer.apple.com/DOCUMENTATION/Darwin/Reference/ManPages/man1/sw_vers.1.html">sw_vers</a> command. <code><br />
$ sw_vers<br />
ProductName:	Mac OS X<br />
ProductVersion:	10.5<br />
BuildVersion:	9A581<br />
$ sw_vers -productName<br />
Mac OS X<br />
$ sw_vers -productVersion<br />
10.5<br />
$ sw_vers -buildVersion<br />
9A581<br />
</code></p>
<h3>Java</h3>
<p>Check the value of:</p>
<pre>System.getProperty("os.name");
System.getProperty("os.version");
</pre>
<h3>Fallback</h3>
<p>Finally, if you must, you can parse <code>/System/Library/CoreServices/SystemVersion.plist</code> &#8212; but  I don&#8217;t like the idea of doing that.  There&#8217;s a chance that the file could have been corrupted or maliciously altered.  It seems  safer, and less complicated, to directly ask the operating system it&#8217;s version.</p>
<h3>Minimum OS Requirements</h3>
<p>To enforce a minimum OS requirement for your application, you can set the <a href="http://developer.apple.com/documentation/MacOSX/Conceptual/BPRuntimeConfig/Articles/PListKeys.html#//apple_ref/doc/uid/20001431-113253">LSMinimumSystemVersion</a> key in the <a href="http://developer.apple.com/documentation/MacOSX/Conceptual/BPRuntimeConfig/Articles/ConfigFiles.html">Info.plist</a> file.  Big Nerd Ranch has a <a href="http://weblog.bignerdranch.com/?p=13">more robust, user-friendly, but complicated solution</a> for older legacy systems.</p>
]]></content:encoded>
			<wfw:commentRss>http://vgable.com/blog/2008/05/04/getting-mac-os-x-version-information/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Finding your laptop’s location with a shell command</title>
		<link>http://vgable.com/blog/2008/03/18/finding-your-laptop%e2%80%99s-location-with-a-shell-command/</link>
		<comments>http://vgable.com/blog/2008/03/18/finding-your-laptop%e2%80%99s-location-with-a-shell-command/#comments</comments>
		<pubDate>Tue, 18 Mar 2008 13:53:23 +0000</pubDate>
		<dc:creator>Vincent Gable</dc:creator>
				<category><![CDATA[MacOSX]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Sample Code]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[UNIX]]></category>
		<category><![CDATA[location]]></category>
		<category><![CDATA[Perl]]></category>

		<guid isPermaLink="false">http://vgable.com/blog/2008/03/18/finding-your-laptop%e2%80%99s-location-with-a-shell-command/</guid>
		<description><![CDATA[Every wireless access point has a MAC address &#8212; a 48 bit number that uniquely identifies it. By checking the MAC address of the wireless access point your computer is connected to, you can figure out if it is being used at home, in your office, etc. You can read this value from the shell [...]]]></description>
			<content:encoded><![CDATA[<p>Every wireless access point has a <a href="http://en.wikipedia.org/wiki/MAC_Address">MAC address</a> &#8212; a 48 bit number that uniquely identifies it.  By checking the MAC address of the wireless access point your computer is connected to, you can figure out if it is being used at home, in your office, etc.</p>
<p>You can read this value from the shell with the command:<br />
<code>arp `ipconfig getoption en1 router`</code><br />
Here&#8217;s how it works.  The command <code>ipconfig getoption en1 router</code> gets the IP address of the router for the interface <code>en1</code>, which is the name of the Airport interface.  If you want to get the router connected to the ethernet port use <code>en0</code>.  The output of the command looks like:<br />
128.62.96.1</p>
<p><code>arp</code> prints information about the IP address, including the MAC address.  <code>arp</code> is a little tricky in that it needs to take the address as an argument, you can&#8217;t pipe the output from ipconfig into it &#8212; that&#8217;s why <code>ipconfig getoption en1 router</code> is surrounded in &#8220;.  Output from <code>arp 128.62.96.1</code> looks like:<br />
cisco-128-62-96-1.public.utexas.edu (128.62.96.1) at 0:12:44:f:5f:0 on en1 [ethernet]</p>
<p>The MAC address is in there, but you may need to use a regular expression to get at it.  Here is an example of a perl script which prints just the MAC address of the wireless access point, or an error message.<br />
<code><br />
if (qx{arp `ipconfig getoption en1 router`} =~ /([0-9A-Fa-f]{1,2}:[0-9A-Fa-f]{1,2}:[0-9A-Fa-f]{1,2}:[0-9A-Fa-f]{1,2}:[0-9A-Fa-f]{1,2}:[0-9A-Fa-f]{1,2})/){<br />
&nbsp;&nbsp;&nbsp;print "$1\n";<br />
} else {<br />
&nbsp;&nbsp;&nbsp;print "Error; wireless internet is most likely unavailable\n";<br />
}<br />
</code></p>
<p>This is essentially how <a href="http://vgable.com/imlocation/">IMLocation</a> determines location.</p>
<p>In summary: Using the shell commands: <code>arp `ipconfig getoption en1 router`</code>, and the regular expression <code>([0-9A-Fa-f]{1,2}:[0-9A-Fa-f]{1,2}:[0-9A-Fa-f]{1,2}:[0-9A-Fa-f]{1,2}:[0-9A-Fa-f]{1,2}:[0-9A-Fa-f]{1,2})</code> on it&#8217;s output, you can get the MAC-address of the wireless access point your computer is using.  This gives you the computer&#8217;s location in about a 150 foot radius.</p>
<p>EDITED TO ADD: Another way to get this information is to use the private tool: <code>/System/Library/PrivateFrameworks/Apple80211.framework/Resources/airport</code><br />
<code>-s</code> gives a list of surrounding networks; <code> -I</code> gives information about the current network.<br />
Try <code>/System/Library/PrivateFrameworks/Apple80211.framework/Resources/airport --help</code> for more information.</p>
<p>You can even get the MAC address of all visible base-stations this way.  Unfortunately, any system update could change the Apple80211.framework enough to break your code.</p>
]]></content:encoded>
			<wfw:commentRss>http://vgable.com/blog/2008/03/18/finding-your-laptop%e2%80%99s-location-with-a-shell-command/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Useful Mac OS X Text-Editing Shortcuts</title>
		<link>http://vgable.com/blog/2008/03/13/useful-mac-os-x-text-editing-shortcuts/</link>
		<comments>http://vgable.com/blog/2008/03/13/useful-mac-os-x-text-editing-shortcuts/#comments</comments>
		<pubDate>Thu, 13 Mar 2008 08:32:06 +0000</pubDate>
		<dc:creator>Vincent Gable</dc:creator>
				<category><![CDATA[MacOSX]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[UNIX]]></category>
		<category><![CDATA[Usability]]></category>
		<category><![CDATA[Command-Line]]></category>
		<category><![CDATA[Emacs]]></category>
		<category><![CDATA[Terminal]]></category>
		<category><![CDATA[Text]]></category>

		<guid isPermaLink="false">http://vgable.com/blog/2008/03/13/useful-mac-os-x-text-editing-shortcuts/</guid>
		<description><![CDATA[Here is a handful of lesser-known Mac OS X keyboard shortcuts that I&#8217;ve found to be very useful for working with text. They work in all standard text-fields, which means they work in most programs. Sadly, they don&#8217;t work in Microsoft products, and a few other apps that use non-standard text fields. option = you [...]]]></description>
			<content:encoded><![CDATA[<p>Here is a handful of lesser-known Mac OS X keyboard shortcuts that I&#8217;ve found to be <em>very</em> useful for working with text.  They work in all standard text-fields, which means they work in <em>most</em> programs.  Sadly, they don&#8217;t work in Microsoft products, and a few other apps that use non-standard text fields.</p>
<p><strong>option</strong> = you will see the mouse cursor into a + , and you can now select columns of text!  Unfortunately it only seems to work in editable text-fields, which is a great shame.</p>
<p><strong>ctrl + d</strong> = forward delete, even if you don&#8217;t have it on your MacBook&#8217;s keyboard.</p>
<p><strong>ctrl + a</strong> =  Go to the beginning of the line the insertion-point is on.</p>
<p><strong>ctrl + e</strong> = Go to the beginning end of the line line the insertion-point is on.</p>
<p><strong>ctrl + k</strong> = &#8220;kill the current line&#8221;, deletes everything from the right of the insertion point to the next newline.  This is very useful in Terminal, because you can delete the tail of a long command</p>
<p><strong>command + delete</strong> = &#8220;Delete To Beginning Of Line&#8221;.  Just like ctrl+k, but backwards, not forwards.  (It even puts the killed text on the yank-pasteboard &#8212; don&#8217;t worry if that makes no sense, it&#8217;s an <a href="http://zoo.cs.yale.edu/classes/cs210/help/emacs.html">emacs</a>-ism I don&#8217;t find useful.)</p>
<p>And yes, that&#8217;s ctrl, not command, because these are shortcuts inherited from the old UNIX text-editor <a href="http://zoo.cs.yale.edu/classes/cs210/help/emacs.html">emacs</a>.  There are more emacs &#8220;key bindings&#8221; that are available, but I have never found them useful.  This <a href="http://www.danrodney.com/mac/index.html">long list of Mac OS X keyboard shortcuts</a> includes them.</p>
<p><strong>command + ctrl + d</strong> = look up the word under the mouse in the dictionary.  I can&#8217;t believe that other operating systems haven&#8217;t done this for decades, it&#8217;s that useful.</p>
<p>It is unfortunate when programs use text-fields that do not support commands the operating system should give to every application.  It&#8217;s always a mistake.  Fundamentally, not supporting ctrl+a (go to beginning) is no different then not supporting command+c (copy).</p>
<p>If you find these commands useful, please teach them, and let developers know it&#8217;s a problem when you can&#8217;t use them.  That will improve computing for everyone.</p>
]]></content:encoded>
			<wfw:commentRss>http://vgable.com/blog/2008/03/13/useful-mac-os-x-text-editing-shortcuts/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Calling the Command Line from Cocoa</title>
		<link>http://vgable.com/blog/2008/03/05/calling-the-command-line-from-cocoa/</link>
		<comments>http://vgable.com/blog/2008/03/05/calling-the-command-line-from-cocoa/#comments</comments>
		<pubDate>Wed, 05 Mar 2008 23:21:16 +0000</pubDate>
		<dc:creator>Vincent Gable</dc:creator>
				<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[MacOSX]]></category>
		<category><![CDATA[Objective-C]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[UNIX]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[Command-Line]]></category>
		<category><![CDATA[NSTask]]></category>
		<category><![CDATA[sh]]></category>

		<guid isPermaLink="false">http://vgable.com/blog/2008/03/05/calling-the-command-line-from-cocoa/</guid>
		<description><![CDATA[The best way to call a shell-command from Coca is by using an NSTask. Here are the three resources on using an NSTask that I found the most helpful: CocoDev&#8217;s write up A few quick exaples NSTask Class Refrence And here is some sample code to do it for you. You are free to use [...]]]></description>
			<content:encoded><![CDATA[<p>The best way to call a shell-command from Coca is by using an <a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSTask_Class/Reference/Reference.html">NSTask</a>.  Here are the three resources on using an NSTask that I found the most helpful:<br />
<a href="http://www.cocoadev.com/index.pl?NSTask">CocoDev&#8217;s write up</a><br />
<a href="http://www.borkware.com/quickies/one?topic=NSTask">A few quick exaples</a><br />
<a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSTask_Class/Reference/Reference.html">NSTask Class Refrence</a></p>
<p><a href="http://www.vgable.com/code/ShellTask.zip">And here is some sample code to do it for you.</a>  You are free to use this code however you please, but attribution is always appreciated.  The two principle functions are:</p>
<p><code>+ (NSString*) executeShellCommandSynchronously:(NSString*)command</code> executes the command &#8220;command&#8221; with <a href="http://en.wikipedia.org/wiki/Bourne_shell">sh</a>, wait until it finishes, and return whatever it printed to stdout and stderr as an NSString.<br />
CAUTION: may deadlock under some circumstances if the output gets so big it fills the pipe.  See <a href="http://dev.notoptimal.net/search/label/NSTask"> http://dev.notoptimal.net/search/label/NSTask</a> for an overview of the problem, and a solution.  I have not experienced the problem myself, so I can&#8217;t comment.</p>
<p><code>executeShellCommandAsynchronously:</code> will have <a href="http://en.wikipedia.org/wiki/Bourne_shell">sh</a> execute <code>command</code> in the background, without blocking anything.</p>
<p>For quick hacks, the POSIX <a href="http://www.hmug.org/man/3/system.php"><code>int system(const char* command)</code></a> function, might be a good one-line solution.  It synchronously evaluates <code>command</code> with <a href="http://en.wikipedia.org/wiki/Bourne_shell">sh</a>.</p>
<p>Enjoy!</p>
<p>EDITED 2009-11-29: this code probably <em>won&#8217;t</em> have the same <code>$PATH</code> you would get if you used Terminal. See <a href="http://stackoverflow.com/questions/386783/nstask-not-picking-up-the-expected-path-from-the-users-environment/1817870#1817870">this question on stackoverflow</a> for more details. A solution that seems to work is to do,</p>
<pre>
    [task setLaunchPath:@"/bin/bash"];
    NSArray	*args = [NSArray arrayWithObjects:@"-l",
    				 @"-c",
    				 <strong>commandlineHere</strong>,
    				 nil];
    [task setArguments: args];
</pre>
<p>This launches <code>bash</code> (<em>not</em> in <code>sh</code> compatibility mode), and -l (lowercase L) tells it to  &#8220;act as if it had been invoked as a login shell&#8221;. I haven&#8217;t tested this on systems where <code>bash</code> isn&#8217;t the default shell. There are lots of ways <code>$PATH</code> could be set, and I haven&#8217;t tested them all. But you are almost certainly going to be OK if everything you refer to is in <code>/usr/bin:/bin:/usr/sbin:/sbin</code>.</p>
]]></content:encoded>
			<wfw:commentRss>http://vgable.com/blog/2008/03/05/calling-the-command-line-from-cocoa/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Useful MacOSX Terminal Commands</title>
		<link>http://vgable.com/blog/2008/02/28/useful-macosx-terminal-commands/</link>
		<comments>http://vgable.com/blog/2008/02/28/useful-macosx-terminal-commands/#comments</comments>
		<pubDate>Thu, 28 Feb 2008 23:41:19 +0000</pubDate>
		<dc:creator>Vincent Gable</dc:creator>
				<category><![CDATA[MacOSX]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[UNIX]]></category>
		<category><![CDATA[Apple]]></category>
		<category><![CDATA[Command-Line]]></category>
		<category><![CDATA[Terminal]]></category>

		<guid isPermaLink="false">http://vgable.com/blog/2008/02/28/useful-macosx-terminal-commands/</guid>
		<description><![CDATA[Here are some OS X specific terminal commands that I have found useful, and you might not be aware of. Running man command in the Terminal will give you more information about command as it is on your system. open open file will open file the same way it would have been opened if you [...]]]></description>
			<content:encoded><![CDATA[<p>Here are some OS X specific terminal commands that I have found useful, and you might not be aware of.  Running <code>man command</code> in the Terminal will give you more information about <code>command</code> as it is on your system.</p>
<p><b><a href="http://www.hmug.org/man/2/open.php">open</a></b><br />
open file will open file the same way it would have been opened if you double-clicked it in the Finder.  You can also specify what program to use to open the file.</p>
<p><b><a href="http://www.hmug.org/man/1/pbcopy.php">pbcopy, pbpaste</a></b><br />
Bridges the clipboard and the command line; you can pipe the clipboard into stdout, or pipe stdout into the clipboard.</p>
<p><b><a href="http://www.hmug.org/man/1/ps.php">ps -axww</a></b><br />
Lists every process running on the system, and gives the full-path to them, and their PSN.  I almost never use any other arguments to ps.</p>
<p><b><a href="http://www.hmug.org/man/1/osascript.php">osascript</a></b><br />
Execute an AppleScript. osascript -e &#8220;code-goes-here&#8221;, will execute the AppleScript inside the &#8220;&#8221;. This is a great way to get AppleScript functionality in a good scripting language.</p>
<p><b><a href="http://www.hmug.org/man/1/ditto.php">ditto</a></b><br />
Can do the work of <a href="http://www.hmug.org/man/1/cp.php">cp</a> or <a href="http://www.hmug.org/man/1/zip.php">zip</a>, but it does the right thing on OS X, and won&#8217;t throw away Mac-specific bits.<br />
<code>ditto -ckX --rsrc --keepParent path_to_a_bundledFile.bundle bundledFile.bundle.zip</code> will compress <code>path_to_a_bundledFile.bundle</code>, and keep all the Mac-bits intact.</p>
<p><b><a href="http://www.hmug.org/man/1/hdiutil.php">hdiutil</a></b><br />
Create and manipulate disk-images; you can even use it to burn a disk-image to CD/DVD.<br />
Inside a perl-script I do:<code><br />
hdiutil create -ov -fs HFS+ -format UDBZ -volname \&#8221;IMLocation v$version (beta)\&#8221; -srcfolder $IMLBuildDir ~/Projects/Website/imlocation/IMLocation.dmg</code><br />
To  make the disk-image for <a href="http://vgable.com/imlocation/">IMLocation</a> out of the contents of the directory $IMLBuildDir.</p>
<p><b><a href="http://www.hmug.org/man/1/screencapture.php">screencapture</a></b><br />
Lets you take a screenshot.  Unfortunately not very well documented.<br />
<code>screencapture -x /tmp/screen.png</code><br />
Will <i>silently</i> take a screenshot, and save it to /tmp/screen.png.<br />
I think this could be great for bug-reporting.</p>
<p><b><a href="http://www.hmug.org/man/8/system_profiler.php">system_profiler</a></b><br />
Reports system hardware and software configuration; with no arguments it reports everything.  Obviously great for bug reports and research.</p>
<p><b><a href="http://developer.apple.com/DOCUMENTATION/Darwin/Reference/ManPages/man1/sw_vers.1.html">sw_vers</a></b><br />
Prints version information about the Mac OS X.<code><br />
$ sw_vers<br />
ProductName:	Mac OS X<br />
ProductVersion:	10.5<br />
BuildVersion:	9A581<br />
$ sw_vers -productName<br />
Mac OS X<br />
$ sw_vers -productVersion<br />
10.5<br />
$ sw_vers -buildVersion<br />
9A581</code></p>
<p><b><a href="http://developer.apple.com/documentation/Darwin/Reference/ManPages/man8/systemsetup.8.html">systemsetup</a></b><br />
Configuration tool for certain machine settings in System Preferences.</p>
<p><b><a href="http://www.hmug.org/man/1/defaults.php">defaults</a></b><br />
Read and write application preferences.  You can use it to discover and activate hidden settings, like <a href="http://www.macosxhints.com/article.php?story=20030110063041629">Safari&#8217;s Debug menu</a>. <code>defaults read &gt; all_defaults.txt</code>  will give you a <a href="http://en.wikipedia.org/wiki/Grep">grep-able</a> text-file with every default on your system.  It&#8217;s also a useful tool for automated testing, since you can twiddle configurations.</p>
<p><b><a href="http://www.codethecode.com/Projects/class-dump/download.html">class-dump</a></b> (3rd party tool)<br />
Makes .h files from a binary.  Great for reverse-engineering.</p>
<p>In addition to standard UNIX commands, Mac OS X includes many powerful command-line tools.  This article only scratches the surface, and ignores many tools like <a href="http://developer.apple.com/documentation/Darwin/Reference/ManPages/man1/podcast.1.html">podcast</a> that are probably very useful, but aren&#8217;t part of my workflow.</p>
]]></content:encoded>
			<wfw:commentRss>http://vgable.com/blog/2008/02/28/useful-macosx-terminal-commands/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

