inweb-bootstrap/docs/foundation-module/1-pp.html
2019-02-10 23:08:53 +00:00

503 lines
44 KiB
HTML

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>1/fnd</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta http-equiv="Content-Language" content="en-gb">
<link href="inweb.css" rel="stylesheet" rev="stylesheet" type="text/css">
</head>
<body>
<!--Weave of '1/pp' generated by 7-->
<ul class="crumbs"><li><a href="../webs.html">&#9733;</a></li><li><a href="index.html">foundation</a></li><li><a href="index.html#1">Chapter 1: Setting Up</a></li><li><b>POSIX Platforms</b></li></ul><p class="purpose">A version of our operating system interface suitable for POSIX-compliant operating systems.</p>
<ul class="toc"><li><a href="#SP3">&#167;3. Mac OS X</a></li><li><a href="#SP4">&#167;4. Generic Unix</a></li><li><a href="#SP5">&#167;5. Linux</a></li><li><a href="#SP6">&#167;6. Android</a></li><li><a href="#SP7">&#167;7. Locale</a></li><li><a href="#SP8">&#167;8. Environment variables</a></li><li><a href="#SP9">&#167;9. Executable location</a></li><li><a href="#SP10">&#167;10. Shell commands</a></li><li><a href="#SP11">&#167;11. Directory handling</a></li><li><a href="#SP12">&#167;12. Sleep</a></li><li><a href="#SP13">&#167;13. Notifications</a></li><li><a href="#SP15">&#167;15. Concurrency</a></li><li><a href="#SP17">&#167;17. Mutexes</a></li></ul><hr class="tocbar">
<p class="inwebparagraph"><a id="SP1"></a><b>&#167;1. </b>The C standard library leaves many questions unanswered about how to deal
with the host operating system: for example, it knows very little about
directories, or about concurrency. The POSIX standard ("Portable Operating
System Interface") aims to fill these gaps by providing facilities which
ought to exist across any Unix-like system. POSIX is neither fully present
on Unix-like systems nor fully absent from Windows, but for the limited
purposes we need here, it's simplest to divide all operating systems into
two groups: the POSIX group, and Windows.
</p>
<p class="inwebparagraph">This Foundation module therefore comes with two variant versions of the
<code class="display"><span class="extract">Platform::</span></code> section of code. The one you're reading compiles on a POSIX
operating system, and the other one on Windows.
</p>
<p class="endnote">This paragraph is used only if PLATFORM_POSIX is defined.</p>
<p class="inwebparagraph"><a id="SP2"></a><b>&#167;2. </b>Some basics that apply to all POSIX-supporting systems.
</p>
<pre class="definitions">
<span class="definitionkeyword">define</span> <span class="constant">FOLDER_SEPARATOR</span><span class="plain"> </span><span class="character">'/'</span>
<span class="definitionkeyword">define</span> <span class="constant">SHELL_QUOTE_CHARACTER</span><span class="plain"> </span><span class="character">'\</span><span class="plain">'</span><span class="character">'</span>
</pre>
<pre class="display">
<span class="plain">#</span><span class="identifier">include</span><span class="plain"> &lt;</span><span class="identifier">sys</span><span class="plain">/</span><span class="identifier">stat</span><span class="plain">.</span><span class="identifier">h</span><span class="plain">&gt;</span>
<span class="plain">#</span><span class="identifier">include</span><span class="plain"> &lt;</span><span class="identifier">sys</span><span class="plain">/</span><span class="identifier">types</span><span class="plain">.</span><span class="identifier">h</span><span class="plain">&gt;</span>
<span class="plain">#</span><span class="identifier">include</span><span class="plain"> &lt;</span><span class="identifier">errno</span><span class="plain">.</span><span class="identifier">h</span><span class="plain">&gt;</span>
<span class="plain">#</span><span class="identifier">include</span><span class="plain"> &lt;</span><span class="identifier">dirent</span><span class="plain">.</span><span class="identifier">h</span><span class="plain">&gt;</span>
<span class="plain">#</span><span class="identifier">include</span><span class="plain"> &lt;</span><span class="identifier">pthread</span><span class="plain">.</span><span class="identifier">h</span><span class="plain">&gt;</span>
<span class="plain">#</span><span class="identifier">include</span><span class="plain"> &lt;</span><span class="identifier">limits</span><span class="plain">.</span><span class="identifier">h</span><span class="plain">&gt;</span>
<span class="plain">#</span><span class="identifier">include</span><span class="plain"> &lt;</span><span class="identifier">unistd</span><span class="plain">.</span><span class="identifier">h</span><span class="plain">&gt;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This paragraph is used only if PLATFORM_POSIX is defined.</p>
<p class="inwebparagraph"><a id="SP3"></a><b>&#167;3. Mac OS X. </b></p>
<pre class="definitions">
<span class="definitionkeyword">define</span> <span class="constant">PLATFORM_STRING</span><span class="plain"> </span><span class="string">"macos"</span>
<span class="definitionkeyword">define</span> <span class="constant">SHELL_QUOTE_CHARACTER</span><span class="plain"> </span><span class="character">'\</span><span class="plain">'</span><span class="character">'</span>
<span class="definitionkeyword">define</span> <span class="constant">INFORM_FOLDER_RELATIVE_TO_HOME</span><span class="plain"> </span><span class="string">"Library"</span>
</pre>
<p class="endnote">This paragraph is used only if PLATFORM_MACOS and PLATFORM_POSIX are defined.</p>
<p class="inwebparagraph"><a id="SP4"></a><b>&#167;4. Generic Unix. </b>These settings are used both for the Linux versions (both command-line, by
Adam Thornton, and for Ubuntu, Fedora, Debian and so forth, by Philip
Chimento) and also for Solaris variants: they can probably be used for any
Unix-based system.
</p>
<pre class="definitions">
<span class="definitionkeyword">define</span> <span class="constant">PLATFORM_STRING</span><span class="plain"> </span><span class="string">"unix"</span>
<span class="definitionkeyword">define</span> <span class="constant">INFORM_FOLDER_RELATIVE_TO_HOME</span><span class="plain"> </span><span class="string">""</span>
</pre>
<pre class="display">
<span class="plain">#</span><span class="identifier">include</span><span class="plain"> &lt;</span><span class="identifier">strings</span><span class="plain">.</span><span class="identifier">h</span><span class="plain">&gt;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This paragraph is used only if PLATFORM_UNIX and PLATFORM_POSIX are defined.</p>
<p class="inwebparagraph"><a id="SP5"></a><b>&#167;5. Linux. </b>These settings are used both for the Linux versions (both command-line, by
Adam Thornton, and for Ubuntu, Fedora, Debian and so forth, by Philip
Chimento) and also for Solaris variants: they can probably be used for any
Unix-based system.
</p>
<pre class="definitions">
<span class="definitionkeyword">define</span> <span class="constant">PLATFORM_STRING</span><span class="plain"> </span><span class="string">"linux"</span>
<span class="definitionkeyword">define</span> <span class="constant">INFORM_FOLDER_RELATIVE_TO_HOME</span><span class="plain"> </span><span class="string">""</span>
</pre>
<pre class="display">
<span class="plain">#</span><span class="identifier">include</span><span class="plain"> &lt;</span><span class="identifier">strings</span><span class="plain">.</span><span class="identifier">h</span><span class="plain">&gt;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This paragraph is used only if PLATFORM_LINUX and PLATFORM_POSIX are defined.</p>
<p class="inwebparagraph"><a id="SP6"></a><b>&#167;6. Android. </b>These settings are used for Nathan Summers's Android versions.
</p>
<pre class="definitions">
<span class="definitionkeyword">define</span> <span class="constant">PLATFORM_STRING</span><span class="plain"> </span><span class="string">"android"</span>
<span class="definitionkeyword">define</span> <span class="constant">SUPPRESS_MAIN</span>
<span class="definitionkeyword">define</span> <span class="constant">INFORM_FOLDER_RELATIVE_TO_HOME</span><span class="plain"> </span><span class="string">""</span>
</pre>
<pre class="display">
<span class="plain">#</span><span class="identifier">include</span><span class="plain"> &lt;</span><span class="identifier">strings</span><span class="plain">.</span><span class="identifier">h</span><span class="plain">&gt;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This paragraph is used only if PLATFORM_ANDROID and PLATFORM_POSIX are defined.</p>
<p class="inwebparagraph"><a id="SP7"></a><b>&#167;7. Locale. </b>The following definition handles possible differences of text encoding
in filenames, which depend on the current "locale". Locale is an odd piece
of old Unix terminology, but one thing it includes is how the textual names
of files are encoded (as ASCII, as ISO Latin-1, as UTF-8, etc.). The default
here is UTF-8 since OS X and Linux both adopt this.
</p>
<pre class="display">
<span class="plain">#</span><span class="identifier">ifndef</span><span class="plain"> </span><span class="constant">LOCALE_IS_ISO</span>
<span class="plain">#</span><span class="identifier">ifndef</span><span class="plain"> </span><span class="identifier">LOCALE_IS_UTF8</span>
<span class="plain">#</span><span class="identifier">define</span><span class="plain"> </span><span class="identifier">LOCALE_IS_UTF8</span><span class="plain"> 1</span>
<span class="plain">#</span><span class="identifier">endif</span>
<span class="plain">#</span><span class="identifier">endif</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This paragraph is used only if PLATFORM_POSIX is defined.</p>
<p class="inwebparagraph"><a id="SP8"></a><b>&#167;8. Environment variables. </b></p>
<pre class="display">
<span class="reserved">char</span><span class="plain"> *</span><span class="functiontext">Platform::getenv</span><span class="plain">(</span><span class="reserved">const</span><span class="plain"> </span><span class="reserved">char</span><span class="plain"> *</span><span class="identifier">name</span><span class="plain">) {</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">getenv</span><span class="plain">(</span><span class="identifier">name</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This paragraph is used only if PLATFORM_POSIX is defined.</p>
<p class="endnote">The function Platform::getenv is used in 1/wp (<a href="1-wp.html#SP4">&#167;4</a>), 3/pth (<a href="3-pth.html#SP2">&#167;2</a>, <a href="3-pth.html#SP3">&#167;3</a>).</p>
<p class="inwebparagraph"><a id="SP9"></a><b>&#167;9. Executable location. </b>Fill the wide-char buffer <code class="display"><span class="extract">p</span></code> with the path to the current executable, up to
length <code class="display"><span class="extract">length</span></code>. This function is guaranteed to be called from only one
thread. Should the information be unavailable, or fail to fit into <code class="display"><span class="extract">p</span></code>,
truncate <code class="display"><span class="extract">p</span></code> to zero length. (On some platforms, the information will
always be unavailable: that doesn't mean we can't run on those platforms,
just that installation and use of Foundation-built tools is less convenient.)
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Platform::where_am_i</span><span class="plain">(</span><span class="identifier">wchar_t</span><span class="plain"> *</span><span class="identifier">p</span><span class="plain">, </span><span class="identifier">size_t</span><span class="plain"> </span><span class="identifier">length</span><span class="plain">) {</span>
<span class="reserved">char</span><span class="plain"> </span><span class="identifier">buffer</span><span class="plain">[</span><span class="identifier">PATH_MAX</span><span class="plain"> + 1];</span>
&lt;<span class="cwebmacro">Follow the proc filesystem symlink to the real filesystem's file</span> <span class="cwebmacronumber">9.1</span>&gt;<span class="character">;</span>
&lt;<span class="cwebmacro">Transcode buffer, which is locale-encoded, into the wide-char buffer</span> <span class="cwebmacronumber">9.2</span>&gt;<span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This paragraph is used only if PLATFORM_LINUX and PLATFORM_POSIX are defined.</p>
<p class="endnote">The function Platform::where_am_i is used in <a href="#SP9_1_1">&#167;9.1.1</a>, <a href="#SP9_1_2">&#167;9.1.2</a>, <a href="#SP9_1_3">&#167;9.1.3</a>, 1/wp (<a href="1-wp.html#SP5">&#167;5</a>), 3/pth (<a href="3-pth.html#SP3">&#167;3</a>).</p>
<p class="inwebparagraph"><a id="SP9_1"></a><b>&#167;9.1. </b>On Linux, <code class="display"><span class="extract">/proc/self/exe</span></code> is a symlink to the current process's executable.
Follow that link to find the path. Normally when reading a symlink, one uses
<code class="display"><span class="extract">lstat()</span></code> to find the path length instead of guessing <code class="display"><span class="extract">PATH_MAX</span></code>, but the
symlinks in <code class="display"><span class="extract">/proc</span></code> are special and don't provide a length to <code class="display"><span class="extract">lstat()</span></code>.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Follow the proc filesystem symlink to the real filesystem's file</span> <span class="cwebmacronumber">9.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">ssize_t</span><span class="plain"> </span><span class="identifier">link_len</span><span class="plain"> = </span><span class="identifier">readlink</span><span class="plain">(</span><span class="string">"/proc/self/exe"</span><span class="plain">, </span><span class="identifier">buffer</span><span class="plain">, </span><span class="identifier">PATH_MAX</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">link_len</span><span class="plain"> &lt; 0) </span>&lt;<span class="cwebmacro">Fail</span> <span class="cwebmacronumber">9.1.4</span>&gt;<span class="plain">; </span> <span class="comment">unable to find</span>
<span class="identifier">buffer</span><span class="plain">[</span><span class="identifier">link_len</span><span class="plain">] = </span><span class="character">'\</span><span class="plain">0</span><span class="character">'</span><span class="plain">;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This paragraph is used only if PLATFORM_POSIX is defined.</p>
<p class="endnote">This code is used in <a href="#SP9">&#167;9</a>.</p>
<p class="inwebparagraph"><a id="SP9_2"></a><b>&#167;9.2. </b>Next, convert the obtained buffer (which is a string in the local filename
encoding, and possibly in a multibyte encoding such as UTF-8) to a wide-char
string.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Transcode buffer, which is locale-encoded, into the wide-char buffer</span> <span class="cwebmacronumber">9.2</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">size_t</span><span class="plain"> </span><span class="identifier">convert_len</span><span class="plain"> = </span><span class="identifier">mbstowcs</span><span class="plain">(</span><span class="identifier">p</span><span class="plain">, </span><span class="identifier">buffer</span><span class="plain">, </span><span class="identifier">length</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">convert_len</span><span class="plain"> == (</span><span class="identifier">size_t</span><span class="plain">)-1) </span>&lt;<span class="cwebmacro">Fail</span> <span class="cwebmacronumber">9.1.4</span>&gt;<span class="plain">; </span> <span class="comment">wouldn't fit</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This paragraph is used only if PLATFORM_POSIX is defined.</p>
<p class="endnote">This code is used in <a href="#SP9">&#167;9</a>.</p>
<p class="inwebparagraph"><a id="SP9_1_1"></a><b>&#167;9.1.1. </b>And now the Mac version:
</p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">_NSGetExecutablePath</span><span class="plain">(</span><span class="reserved">char</span><span class="plain">* </span><span class="identifier">buf</span><span class="plain">, </span><span class="identifier">uint32_t</span><span class="plain">* </span><span class="identifier">bufsize</span><span class="plain">);</span>
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Platform::where_am_i</span><span class="plain">(</span><span class="identifier">wchar_t</span><span class="plain"> *</span><span class="identifier">p</span><span class="plain">, </span><span class="identifier">size_t</span><span class="plain"> </span><span class="identifier">length</span><span class="plain">) {</span>
<span class="reserved">char</span><span class="plain"> </span><span class="identifier">relative_path</span><span class="plain">[4 * </span><span class="identifier">PATH_MAX</span><span class="plain"> + 1];</span>
<span class="reserved">char</span><span class="plain"> </span><span class="identifier">absolute_path</span><span class="plain">[</span><span class="identifier">PATH_MAX</span><span class="plain"> + 1];</span>
<span class="identifier">size_t</span><span class="plain"> </span><span class="identifier">convert_len</span><span class="plain">;</span>
<span class="identifier">uint32_t</span><span class="plain"> </span><span class="identifier">pathsize</span><span class="plain"> = </span><span class="reserved">sizeof</span><span class="plain">(</span><span class="identifier">relative_path</span><span class="plain">);</span>
<span class="identifier">uint32_t</span><span class="plain"> </span><span class="identifier">tempsize</span><span class="plain"> = </span><span class="identifier">pathsize</span><span class="plain">;</span>
<span class="comment">Get "a path" to the executable</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">_NSGetExecutablePath</span><span class="plain">(</span><span class="identifier">relative_path</span><span class="plain">, &amp;</span><span class="identifier">tempsize</span><span class="plain">) != 0) </span>&lt;<span class="cwebmacro">Fail</span> <span class="cwebmacronumber">9.1.4</span>&gt;<span class="plain">;</span>
<span class="comment">Convert to canonical absolute path</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">realpath</span><span class="plain">(</span><span class="identifier">relative_path</span><span class="plain">, </span><span class="identifier">absolute_path</span><span class="plain">) == </span><span class="identifier">NULL</span><span class="plain">) </span>&lt;<span class="cwebmacro">Fail</span> <span class="cwebmacronumber">9.1.4</span>&gt;<span class="plain">;</span>
<span class="plain">* </span><span class="reserved">filename</span><span class="plain"> </span><span class="identifier">encoding</span><span class="plain">, </span><span class="identifier">possibly</span><span class="plain"> </span><span class="identifier">multibyte</span><span class="plain">) </span><span class="identifier">to</span><span class="plain"> </span><span class="identifier">a</span><span class="plain"> </span><span class="identifier">wide</span><span class="plain">-</span><span class="reserved">char</span><span class="plain"> </span><span class="identifier">string</span><span class="plain">. */</span>
<span class="identifier">convert_len</span><span class="plain"> = </span><span class="identifier">mbstowcs</span><span class="plain">(</span><span class="identifier">p</span><span class="plain">, </span><span class="identifier">absolute_path</span><span class="plain">, </span><span class="identifier">length</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">convert_len</span><span class="plain"> == (</span><span class="identifier">size_t</span><span class="plain">)-1) </span>&lt;<span class="cwebmacro">Fail</span> <span class="cwebmacronumber">9.1.4</span>&gt;<span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This paragraph is used only if PLATFORM_MACOS and PLATFORM_POSIX are defined.</p>
<p class="endnote">The function _NSGetExecutablePath appears nowhere else.</p>
<p class="endnote">The function Platform::where_am_i is used in <a href="#SP9">&#167;9</a>, <a href="#SP9_1_2">&#167;9.1.2</a>, <a href="#SP9_1_3">&#167;9.1.3</a>, 1/wp (<a href="1-wp.html#SP5">&#167;5</a>), 3/pth (<a href="3-pth.html#SP3">&#167;3</a>).</p>
<p class="inwebparagraph"><a id="SP9_1_2"></a><b>&#167;9.1.2. </b>For Unix, there's nothing we can generically do.
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Platform::where_am_i</span><span class="plain">(</span><span class="identifier">wchar_t</span><span class="plain"> *</span><span class="identifier">p</span><span class="plain">, </span><span class="identifier">size_t</span><span class="plain"> </span><span class="identifier">length</span><span class="plain">) {</span>
&lt;<span class="cwebmacro">Fail</span> <span class="cwebmacronumber">9.1.4</span>&gt;<span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This paragraph is used only if PLATFORM_UNIX and PLATFORM_POSIX are defined.</p>
<p class="endnote">The function Platform::where_am_i is used in <a href="#SP9">&#167;9</a>, <a href="#SP9_1_1">&#167;9.1.1</a>, <a href="#SP9_1_3">&#167;9.1.3</a>, 1/wp (<a href="1-wp.html#SP5">&#167;5</a>), 3/pth (<a href="3-pth.html#SP3">&#167;3</a>).</p>
<p class="inwebparagraph"><a id="SP9_1_3"></a><b>&#167;9.1.3. </b>On Android, there's no real need for this.
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Platform::where_am_i</span><span class="plain">(</span><span class="identifier">wchar_t</span><span class="plain"> *</span><span class="identifier">p</span><span class="plain">, </span><span class="identifier">size_t</span><span class="plain"> </span><span class="identifier">length</span><span class="plain">) {</span>
&lt;<span class="cwebmacro">Fail</span> <span class="cwebmacronumber">9.1.4</span>&gt;<span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This paragraph is used only if PLATFORM_ANDROID and PLATFORM_POSIX are defined.</p>
<p class="endnote">The function Platform::where_am_i is used in <a href="#SP9">&#167;9</a>, <a href="#SP9_1_1">&#167;9.1.1</a>, <a href="#SP9_1_2">&#167;9.1.2</a>, 1/wp (<a href="1-wp.html#SP5">&#167;5</a>), 3/pth (<a href="3-pth.html#SP3">&#167;3</a>).</p>
<p class="inwebparagraph"><a id="SP9_1_4"></a><b>&#167;9.1.4. </b>All of the above make use of:
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Fail</span> <span class="cwebmacronumber">9.1.4</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">p</span><span class="plain">[0] = </span><span class="character">'\</span><span class="plain">0</span><span class="character">'</span><span class="plain">;</span>
<span class="reserved">return</span><span class="plain">;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This paragraph is used only if PLATFORM_POSIX is defined.</p>
<p class="endnote">This code is used in <a href="#SP9_1">&#167;9.1</a>, <a href="#SP9_2">&#167;9.2</a>, <a href="#SP9_1_1">&#167;9.1.1</a> (three times), <a href="#SP9_1_2">&#167;9.1.2</a>, <a href="#SP9_1_3">&#167;9.1.3</a>.</p>
<p class="inwebparagraph"><a id="SP10"></a><b>&#167;10. Shell commands. </b></p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">Platform::system</span><span class="plain">(</span><span class="reserved">const</span><span class="plain"> </span><span class="reserved">char</span><span class="plain"> *</span><span class="identifier">cmd</span><span class="plain">) {</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">system</span><span class="plain">(</span><span class="identifier">cmd</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This paragraph is used only if PLATFORM_POSIX is defined.</p>
<p class="endnote">The function Platform::system is used in 1/wp (<a href="1-wp.html#SP6">&#167;6</a>), 3/shl (<a href="3-shl.html#SP5">&#167;5</a>).</p>
<p class="inwebparagraph"><a id="SP11"></a><b>&#167;11. Directory handling. </b></p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">Platform::mkdir</span><span class="plain">(</span><span class="reserved">char</span><span class="plain"> *</span><span class="identifier">transcoded_pathname</span><span class="plain">) {</span>
<span class="identifier">errno</span><span class="plain"> = 0;</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">rv</span><span class="plain"> = </span><span class="identifier">mkdir</span><span class="plain">(</span><span class="identifier">transcoded_pathname</span><span class="plain">, </span><span class="identifier">S_IRWXU</span><span class="plain"> | </span><span class="identifier">S_IRWXG</span><span class="plain"> | </span><span class="identifier">S_IROTH</span><span class="plain"> | </span><span class="identifier">S_IXOTH</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">rv</span><span class="plain"> == 0) </span><span class="reserved">return</span><span class="plain"> </span><span class="constant">TRUE</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">errno</span><span class="plain"> == </span><span class="identifier">EEXIST</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> </span><span class="constant">TRUE</span><span class="plain">;</span>
<span class="reserved">return</span><span class="plain"> </span><span class="constant">FALSE</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">void</span><span class="plain"> *</span><span class="functiontext">Platform::opendir</span><span class="plain">(</span><span class="reserved">char</span><span class="plain"> *</span><span class="identifier">path_to_folder</span><span class="plain">) {</span>
<span class="identifier">DIR</span><span class="plain"> *</span><span class="identifier">dirp</span><span class="plain"> = </span><span class="identifier">opendir</span><span class="plain">(</span><span class="identifier">path_to_folder</span><span class="plain">);</span>
<span class="reserved">return</span><span class="plain"> (</span><span class="reserved">void</span><span class="plain"> *) </span><span class="identifier">dirp</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">Platform::readdir</span><span class="plain">(</span><span class="reserved">void</span><span class="plain"> *</span><span class="identifier">folder</span><span class="plain">, </span><span class="reserved">char</span><span class="plain"> *</span><span class="identifier">path_to_folder</span><span class="plain">, </span><span class="reserved">char</span><span class="plain"> *</span><span class="identifier">leafname</span><span class="plain">) {</span>
<span class="reserved">char</span><span class="plain"> </span><span class="identifier">path_to</span><span class="plain">[2*</span><span class="constant">MAX_FILENAME_LENGTH</span><span class="plain">+2];</span>
<span class="reserved">struct</span><span class="plain"> </span><span class="identifier">stat</span><span class="plain"> </span><span class="identifier">file_status</span><span class="plain">;</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">rv</span><span class="plain">;</span>
<span class="identifier">DIR</span><span class="plain"> *</span><span class="identifier">dirp</span><span class="plain"> = (</span><span class="identifier">DIR</span><span class="plain"> *) </span><span class="identifier">folder</span><span class="plain">;</span>
<span class="reserved">struct</span><span class="plain"> </span><span class="identifier">dirent</span><span class="plain"> *</span><span class="identifier">dp</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">dp</span><span class="plain"> = </span><span class="identifier">readdir</span><span class="plain">(</span><span class="identifier">dirp</span><span class="plain">)) == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> </span><span class="constant">FALSE</span><span class="plain">;</span>
<span class="identifier">sprintf</span><span class="plain">(</span><span class="identifier">path_to</span><span class="plain">, </span><span class="string">"%s%c%s"</span><span class="plain">, </span><span class="identifier">path_to_folder</span><span class="plain">, </span><span class="constant">FOLDER_SEPARATOR</span><span class="plain">, </span><span class="identifier">dp</span><span class="plain">-&gt;</span><span class="identifier">d_name</span><span class="plain">);</span>
<span class="identifier">rv</span><span class="plain"> = </span><span class="identifier">stat</span><span class="plain">(</span><span class="identifier">path_to</span><span class="plain">, &amp;</span><span class="identifier">file_status</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">rv</span><span class="plain"> != 0) </span><span class="reserved">return</span><span class="plain"> </span><span class="constant">FALSE</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">S_ISDIR</span><span class="plain">(</span><span class="identifier">file_status</span><span class="plain">.</span><span class="identifier">st_mode</span><span class="plain">)) </span><span class="identifier">sprintf</span><span class="plain">(</span><span class="identifier">leafname</span><span class="plain">, </span><span class="string">"%s/"</span><span class="plain">, </span><span class="identifier">dp</span><span class="plain">-&gt;</span><span class="identifier">d_name</span><span class="plain">);</span>
<span class="reserved">else</span><span class="plain"> </span><span class="identifier">strcpy</span><span class="plain">(</span><span class="identifier">leafname</span><span class="plain">, </span><span class="identifier">dp</span><span class="plain">-&gt;</span><span class="identifier">d_name</span><span class="plain">);</span>
<span class="reserved">return</span><span class="plain"> </span><span class="constant">TRUE</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Platform::closedir</span><span class="plain">(</span><span class="reserved">void</span><span class="plain"> *</span><span class="identifier">folder</span><span class="plain">) {</span>
<span class="identifier">DIR</span><span class="plain"> *</span><span class="identifier">dirp</span><span class="plain"> = (</span><span class="identifier">DIR</span><span class="plain"> *) </span><span class="identifier">folder</span><span class="plain">;</span>
<span class="identifier">closedir</span><span class="plain">(</span><span class="identifier">dirp</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This paragraph is used only if PLATFORM_POSIX is defined.</p>
<p class="endnote">The function Platform::mkdir is used in 1/wp (<a href="1-wp.html#SP7">&#167;7</a>), 3/pth (<a href="3-pth.html#SP8">&#167;8</a>).</p>
<p class="endnote">The function Platform::opendir is used in 1/wp (<a href="1-wp.html#SP7">&#167;7</a>), 3/drc (<a href="3-drc.html#SP2">&#167;2</a>).</p>
<p class="endnote">The function Platform::readdir is used in 1/wp (<a href="1-wp.html#SP7">&#167;7</a>), 3/drc (<a href="3-drc.html#SP2">&#167;2</a>).</p>
<p class="endnote">The function Platform::closedir is used in 1/wp (<a href="1-wp.html#SP7">&#167;7</a>), 3/drc (<a href="3-drc.html#SP2">&#167;2</a>).</p>
<p class="inwebparagraph"><a id="SP12"></a><b>&#167;12. Sleep. </b></p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Platform::sleep</span><span class="plain">(</span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">seconds</span><span class="plain">) {</span>
<span class="identifier">sleep</span><span class="plain">((</span><span class="reserved">unsigned</span><span class="plain"> </span><span class="reserved">int</span><span class="plain">) </span><span class="identifier">seconds</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This paragraph is used only if PLATFORM_POSIX is defined.</p>
<p class="endnote">The function Platform::sleep is used in 1/wp (<a href="1-wp.html#SP8">&#167;8</a>).</p>
<p class="inwebparagraph"><a id="SP13"></a><b>&#167;13. Notifications. </b>The "submarine" sound is a gloomy thunk; the "bell" is the three-tone rising
alert noise which iPhones make when they receive texts, but which hackers of a
certain age will remember as the "I have ripped your music CD now" alert from
SoundJam, the program which Apple bought and rebranded as iTunes. Apple now
seems to consider this alert a general-purpose "something good has happened".
</p>
<p class="inwebparagraph">It is anybody's guess how long Apple will permit the shell command <code class="display"><span class="extract">osascript</span></code>
to survive, given the MacOS team's current hostility to scripting; we're
actually running a one-line AppleScript here.
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Platform::notification</span><span class="plain">(</span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">text</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">happy</span><span class="plain">) {</span>
<span class="reserved">char</span><span class="plain"> *</span><span class="identifier">sound_name</span><span class="plain"> = </span><span class="string">"Bell.aiff"</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">happy</span><span class="plain"> == </span><span class="constant">FALSE</span><span class="plain">) </span><span class="identifier">sound_name</span><span class="plain"> = </span><span class="string">"Submarine.aiff"</span><span class="plain">;</span>
<span class="identifier">TEMPORARY_TEXT</span><span class="plain">(</span><span class="identifier">TEMP</span><span class="plain">)</span>
<span class="identifier">WRITE_TO</span><span class="plain">(</span><span class="identifier">TEMP</span><span class="plain">, </span><span class="string">"osascript -e 'display notification \</span><span class="plain">"</span><span class="string">%S\</span><span class="plain">"</span><span class="string"> "</span>
<span class="string">"sound name \</span><span class="plain">"</span><span class="string">%s\</span><span class="plain">"</span><span class="string"> with title \</span><span class="plain">"</span><span class="string">intest Results\</span><span class="plain">"</span><span class="string">'"</span><span class="plain">, </span><span class="identifier">text</span><span class="plain">, </span><span class="identifier">sound_name</span><span class="plain">);</span>
<span class="functiontext">Shell::run</span><span class="plain">(</span><span class="identifier">TEMP</span><span class="plain">);</span>
<span class="identifier">DISCARD_TEXT</span><span class="plain">(</span><span class="identifier">TEMP</span><span class="plain">)</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This paragraph is used only if PLATFORM_MACOS and PLATFORM_POSIX are defined.</p>
<p class="endnote">The function Platform::notification is used in <a href="#SP14">&#167;14</a>, 1/wp (<a href="1-wp.html#SP9">&#167;9</a>).</p>
<p class="inwebparagraph"><a id="SP14"></a><b>&#167;14. </b></p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Platform::notification</span><span class="plain">(</span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">text</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">happy</span><span class="plain">) {</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This paragraph is used only if PLATFORM_POSIX is defined and if PLATFORM_MACOS is undefined.</p>
<p class="endnote">The function Platform::notification is used in <a href="#SP13">&#167;13</a>, 1/wp (<a href="1-wp.html#SP9">&#167;9</a>).</p>
<p class="inwebparagraph"><a id="SP15"></a><b>&#167;15. Concurrency. </b></p>
<pre class="display">
<span class="reserved">typedef</span><span class="plain"> </span><span class="identifier">pthread_t</span><span class="plain"> </span><span class="identifier">foundation_thread</span><span class="plain">;</span>
<span class="reserved">typedef</span><span class="plain"> </span><span class="identifier">pthread_attr_t</span><span class="plain"> </span><span class="identifier">foundation_thread_attributes</span><span class="plain">;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This paragraph is used only if PLATFORM_POSIX is defined.</p>
<p class="inwebparagraph"><a id="SP16"></a><b>&#167;16. </b></p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">Platform::create_thread</span><span class="plain">(</span><span class="identifier">foundation_thread</span><span class="plain"> *</span><span class="identifier">pt</span><span class="plain">,</span>
<span class="reserved">const</span><span class="plain"> </span><span class="identifier">foundation_thread_attributes</span><span class="plain"> *</span><span class="identifier">pa</span><span class="plain">, </span><span class="reserved">void</span><span class="plain"> *(*</span><span class="identifier">fn</span><span class="plain">)(</span><span class="reserved">void</span><span class="plain"> *), </span><span class="reserved">void</span><span class="plain"> *</span><span class="identifier">arg</span><span class="plain">) {</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">pthread_create</span><span class="plain">(</span><span class="identifier">pt</span><span class="plain">, </span><span class="identifier">pa</span><span class="plain">, </span><span class="identifier">fn</span><span class="plain">, </span><span class="identifier">arg</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">Platform::join_thread</span><span class="plain">(</span><span class="identifier">pthread_t</span><span class="plain"> </span><span class="identifier">pt</span><span class="plain">, </span><span class="reserved">void</span><span class="plain">** </span><span class="identifier">rv</span><span class="plain">) {</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">pthread_join</span><span class="plain">(</span><span class="identifier">pt</span><span class="plain">, </span><span class="identifier">rv</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Platform::init_thread</span><span class="plain">(</span><span class="identifier">pthread_attr_t</span><span class="plain">* </span><span class="identifier">pa</span><span class="plain">, </span><span class="identifier">size_t</span><span class="plain"> </span><span class="identifier">size</span><span class="plain">) {</span>
<span class="identifier">pthread_attr_init</span><span class="plain">(</span><span class="identifier">pa</span><span class="plain">);</span>
<span class="identifier">pthread_attr_setstacksize</span><span class="plain">(</span><span class="identifier">pa</span><span class="plain">, </span><span class="identifier">size</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="identifier">size_t</span><span class="plain"> </span><span class="functiontext">Platform::get_thread_stack_size</span><span class="plain">(</span><span class="identifier">pthread_attr_t</span><span class="plain">* </span><span class="identifier">pa</span><span class="plain">) {</span>
<span class="identifier">size_t</span><span class="plain"> </span><span class="identifier">mystacksize</span><span class="plain">;</span>
<span class="identifier">pthread_attr_getstacksize</span><span class="plain">(</span><span class="identifier">pa</span><span class="plain">, &amp;</span><span class="identifier">mystacksize</span><span class="plain">);</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">mystacksize</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This paragraph is used only if PLATFORM_POSIX is defined.</p>
<p class="endnote">The function Platform::create_thread is used in 1/wp (<a href="1-wp.html#SP11">&#167;11</a>).</p>
<p class="endnote">The function Platform::join_thread is used in 1/wp (<a href="1-wp.html#SP11">&#167;11</a>).</p>
<p class="endnote">The function Platform::init_thread is used in 1/wp (<a href="1-wp.html#SP11">&#167;11</a>).</p>
<p class="endnote">The function Platform::get_thread_stack_size is used in 1/wp (<a href="1-wp.html#SP11">&#167;11</a>).</p>
<p class="inwebparagraph"><a id="SP17"></a><b>&#167;17. Mutexes. </b></p>
<pre class="definitions">
<span class="definitionkeyword">define</span> <span class="identifier">CREATE_MUTEX</span><span class="plain">(</span><span class="identifier">name</span><span class="plain">)</span>
<span class="reserved">static</span><span class="plain"> </span><span class="identifier">pthread_mutex_t</span><span class="plain"> </span><span class="identifier">name</span><span class="plain"> = </span><span class="identifier">PTHREAD_MUTEX_INITIALIZER</span><span class="plain">;</span>
<span class="definitionkeyword">define</span> <span class="identifier">LOCK_MUTEX</span><span class="plain">(</span><span class="identifier">name</span><span class="plain">) </span><span class="identifier">pthread_mutex_lock</span><span class="plain">(&amp;</span><span class="identifier">name</span><span class="plain">);</span>
<span class="definitionkeyword">define</span> <span class="identifier">UNLOCK_MUTEX</span><span class="plain">(</span><span class="identifier">name</span><span class="plain">) </span><span class="identifier">pthread_mutex_unlock</span><span class="plain">(&amp;</span><span class="identifier">name</span><span class="plain">);</span>
</pre>
<p class="endnote">This paragraph is used only if PLATFORM_POSIX is defined.</p>
<!--End of weave: 284 lines from a web of 9279-->
</body>
</html>