639 lines
61 KiB
HTML
639 lines
61 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 name="viewport" content="width=device-width initial-scale=1">
|
|
<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>
|
|
<nav role="navigation">
|
|
<h1><a href="../webs.html">Sources</a></h1>
|
|
<ul>
|
|
<li><a href="../inweb/index.html">inweb</a></li>
|
|
</ul>
|
|
<h2>Foundation</h2>
|
|
<ul>
|
|
<li><a href="../foundation-module/index.html">foundation-module</a></li>
|
|
<li><a href="../foundation-test/index.html">foundation-test</a></li>
|
|
</ul>
|
|
|
|
|
|
</nav>
|
|
<main role="main">
|
|
|
|
<!--Weave of '1/pp' generated by 7-->
|
|
<ul class="crumbs"><li><a href="../webs.html">Source</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">§3. Mac OS X</a></li><li><a href="#SP4">§4. Generic Unix</a></li><li><a href="#SP5">§5. Linux</a></li><li><a href="#SP6">§6. Android</a></li><li><a href="#SP7">§7. Locale</a></li><li><a href="#SP8">§8. Environment variables</a></li><li><a href="#SP9">§9. Executable location</a></li><li><a href="#SP10">§10. Shell commands</a></li><li><a href="#SP12">§12. Directory handling</a></li><li><a href="#SP13">§13. Timestamp</a></li><li><a href="#SP14">§14. Sync</a></li><li><a href="#SP15">§15. Sleep</a></li><li><a href="#SP16">§16. Notifications</a></li><li><a href="#SP18">§18. Concurrency</a></li><li><a href="#SP20">§20. Mutexes</a></li></ul><hr class="tocbar">
|
|
|
|
<p class="inwebparagraph"><a id="SP1"></a><b>§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>§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"> <</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">></span>
|
|
<span class="plain">#</span><span class="identifier">include</span><span class="plain"> <</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">></span>
|
|
<span class="plain">#</span><span class="identifier">include</span><span class="plain"> <</span><span class="identifier">errno</span><span class="plain">.</span><span class="identifier">h</span><span class="plain">></span>
|
|
<span class="plain">#</span><span class="identifier">include</span><span class="plain"> <</span><span class="identifier">dirent</span><span class="plain">.</span><span class="identifier">h</span><span class="plain">></span>
|
|
<span class="plain">#</span><span class="identifier">include</span><span class="plain"> <</span><span class="identifier">pthread</span><span class="plain">.</span><span class="identifier">h</span><span class="plain">></span>
|
|
<span class="plain">#</span><span class="identifier">include</span><span class="plain"> <</span><span class="identifier">limits</span><span class="plain">.</span><span class="identifier">h</span><span class="plain">></span>
|
|
<span class="plain">#</span><span class="identifier">include</span><span class="plain"> <</span><span class="identifier">unistd</span><span class="plain">.</span><span class="identifier">h</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="SP3"></a><b>§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>§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"> <</span><span class="identifier">strings</span><span class="plain">.</span><span class="identifier">h</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="inwebparagraph"><a id="SP5"></a><b>§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"> <</span><span class="identifier">strings</span><span class="plain">.</span><span class="identifier">h</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="inwebparagraph"><a id="SP6"></a><b>§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"> <</span><span class="identifier">strings</span><span class="plain">.</span><span class="identifier">h</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="inwebparagraph"><a id="SP7"></a><b>§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"> </span><span class="constant">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>§8. Environment variables. </b></p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="identifier">char</span><span class="plain"> *</span><span class="functiontext">Platform::getenv</span><span class="plain">(</span><span class="identifier">const</span><span class="plain"> </span><span class="identifier">char</span><span class="plain"> *</span><span class="identifier">name</span><span class="plain">) {</span>
|
|
<span class="identifier">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">§4</a>), 3/pth (<a href="3-pth.html#SP2">§2</a>, <a href="3-pth.html#SP3">§3</a>).</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP9"></a><b>§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="identifier">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="identifier">char</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="constant">1</span><span class="plain">];</span>
|
|
<<span class="cwebmacro">Follow the proc filesystem symlink to the real filesystem's file</span> <span class="cwebmacronumber">9.1</span>><span class="character">;</span>
|
|
<<span class="cwebmacro">Transcode buffer, which is locale-encoded, into the wide-char buffer</span> <span class="cwebmacronumber">9.2</span>><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">§9.1.1</a>, <a href="#SP9_1_2">§9.1.2</a>, <a href="#SP9_1_3">§9.1.3</a>, 1/wp (<a href="1-wp.html#SP5">§5</a>), 3/pth (<a href="3-pth.html#SP3">§3</a>).</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP9_1"></a><b>§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">
|
|
<<span class="cwebmacrodefn">Follow the proc filesystem symlink to the real filesystem's file</span> <span class="cwebmacronumber">9.1</span>> =
|
|
</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="identifier">if</span><span class="plain"> (</span><span class="identifier">link_len</span><span class="plain"> < </span><span class="constant">0</span><span class="plain">) </span><<span class="cwebmacro">Fail</span> <span class="cwebmacronumber">9.1.4</span>><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="constant">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">§9</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP9_2"></a><b>§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">
|
|
<<span class="cwebmacrodefn">Transcode buffer, which is locale-encoded, into the wide-char buffer</span> <span class="cwebmacronumber">9.2</span>> =
|
|
</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="identifier">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><<span class="cwebmacro">Fail</span> <span class="cwebmacronumber">9.1.4</span>><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">§9</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP9_1_1"></a><b>§9.1.1. </b>And now the Mac version:
|
|
</p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="identifier">int</span><span class="plain"> </span><span class="functiontext">_NSGetExecutablePath</span><span class="plain">(</span><span class="identifier">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="identifier">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="identifier">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"> + </span><span class="constant">1</span><span class="plain">];</span>
|
|
<span class="identifier">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"> + </span><span class="constant">1</span><span class="plain">];</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="identifier">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="identifier">if</span><span class="plain"> (</span><span class="functiontext">_NSGetExecutablePath</span><span class="plain">(</span><span class="identifier">relative_path</span><span class="plain">, &</span><span class="identifier">tempsize</span><span class="plain">) != </span><span class="constant">0</span><span class="plain">) </span><<span class="cwebmacro">Fail</span> <span class="cwebmacronumber">9.1.4</span>><span class="plain">;</span>
|
|
|
|
<span class="comment">Convert to canonical absolute path</span>
|
|
<span class="identifier">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><<span class="cwebmacro">Fail</span> <span class="cwebmacronumber">9.1.4</span>><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="identifier">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="identifier">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><<span class="cwebmacro">Fail</span> <span class="cwebmacronumber">9.1.4</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 _NSGetExecutablePath appears nowhere else.</p>
|
|
|
|
<p class="endnote">The function Platform::where_am_i is used in <a href="#SP9">§9</a>, <a href="#SP9_1_2">§9.1.2</a>, <a href="#SP9_1_3">§9.1.3</a>, 1/wp (<a href="1-wp.html#SP5">§5</a>), 3/pth (<a href="3-pth.html#SP3">§3</a>).</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP9_1_2"></a><b>§9.1.2. </b>For Unix, there's nothing we can generically do.
|
|
</p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="identifier">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="cwebmacro">Fail</span> <span class="cwebmacronumber">9.1.4</span>><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">§9</a>, <a href="#SP9_1_1">§9.1.1</a>, <a href="#SP9_1_3">§9.1.3</a>, 1/wp (<a href="1-wp.html#SP5">§5</a>), 3/pth (<a href="3-pth.html#SP3">§3</a>).</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP9_1_3"></a><b>§9.1.3. </b>On Android, there's no real need for this.
|
|
</p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="identifier">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="cwebmacro">Fail</span> <span class="cwebmacronumber">9.1.4</span>><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">§9</a>, <a href="#SP9_1_1">§9.1.1</a>, <a href="#SP9_1_2">§9.1.2</a>, 1/wp (<a href="1-wp.html#SP5">§5</a>), 3/pth (<a href="3-pth.html#SP3">§3</a>).</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP9_1_4"></a><b>§9.1.4. </b>All of the above make use of:
|
|
</p>
|
|
|
|
|
|
<p class="macrodefinition"><code class="display">
|
|
<<span class="cwebmacrodefn">Fail</span> <span class="cwebmacronumber">9.1.4</span>> =
|
|
</code></p>
|
|
|
|
|
|
<pre class="displaydefn">
|
|
<span class="identifier">p</span><span class="plain">[0] = </span><span class="character">'\</span><span class="constant">0</span><span class="character">'</span><span class="plain">;</span>
|
|
<span class="identifier">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">§9.1</a>, <a href="#SP9_2">§9.2</a>, <a href="#SP9_1_1">§9.1.1</a> (three times), <a href="#SP9_1_2">§9.1.2</a>, <a href="#SP9_1_3">§9.1.3</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP10"></a><b>§10. Shell commands. </b></p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="identifier">int</span><span class="plain"> </span><span class="functiontext">Platform::system</span><span class="plain">(</span><span class="identifier">const</span><span class="plain"> </span><span class="identifier">char</span><span class="plain"> *</span><span class="identifier">cmd</span><span class="plain">) {</span>
|
|
<span class="identifier">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 and if PLATFORM_MACOS is undefined.</p>
|
|
|
|
<p class="endnote">The function Platform::system is used in <a href="#SP11">§11</a>, <a href="#SP14">§14</a>, 1/wp (<a href="1-wp.html#SP6">§6</a>), 3/shl (<a href="3-shl.html#SP5">§5</a>).</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP11"></a><b>§11. </b>In MacOS 10.5, a new implementation of the C standard library
|
|
crippled performance of <code class="display"><span class="extract">system()</span></code> by placing it behind a global mutex, so
|
|
that it was impossible for two cores to be calling the function at the same
|
|
time. The net effect of this is that the Inform test suite, executing in
|
|
Intest, ran in 1/16th speed. This issue didn't come to light until 2019,
|
|
however, because the build setting <code class="display"><span class="extract">-mmacosx-version-min=10.4</span></code> turned out
|
|
to force use of the (perfectly good) pre-10.5 library, where <code class="display"><span class="extract">system()</span></code>
|
|
continued to run in a multi-threaded way, just as it does on Linux and
|
|
most all other Unixes. The old library was eventually withdrawn by Apple
|
|
in 2018, and in any case would stop working at some point in 2019-20 due
|
|
to the final removal of 32-bit binary support from MacOS.
|
|
</p>
|
|
|
|
<p class="inwebparagraph">It took several days to find a pthread-safe way to reimplement <code class="display"><span class="extract">system()</span></code>.
|
|
The obvious way, using <code class="display"><span class="extract">fork()</span></code> and then running <code class="display"><span class="extract">execve()</span></code> on the child
|
|
process — essentially the standard way to implement <code class="display"><span class="extract">system()</span></code>, if you forget
|
|
about signal-handling — led to obscure and unrepeatable memory corruption
|
|
bugs in Intest, with the worker threads apparently writing on each other's
|
|
memory space. Using <code class="display"><span class="extract">posix_spawn()</span></code> instead appears to work better.
|
|
</p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="plain">#</span><span class="identifier">include</span><span class="plain"> <</span><span class="identifier">spawn</span><span class="plain">.</span><span class="identifier">h</span><span class="plain">></span>
|
|
<span class="plain">#</span><span class="identifier">include</span><span class="plain"> <</span><span class="identifier">sys</span><span class="plain">/</span><span class="identifier">wait</span><span class="plain">.</span><span class="identifier">h</span><span class="plain">></span>
|
|
|
|
<span class="identifier">extern</span><span class="plain"> </span><span class="identifier">char</span><span class="plain"> **</span><span class="identifier">environ</span><span class="plain">;</span>
|
|
|
|
<span class="identifier">int</span><span class="plain"> </span><span class="functiontext">Platform::system</span><span class="plain">(</span><span class="identifier">const</span><span class="plain"> </span><span class="identifier">char</span><span class="plain"> *</span><span class="identifier">cmd</span><span class="plain">) {</span>
|
|
<span class="identifier">char</span><span class="plain"> *</span><span class="identifier">argv</span><span class="plain">[] = {</span><span class="string">"sh"</span><span class="plain">, </span><span class="string">"-c"</span><span class="plain">, (</span><span class="identifier">char</span><span class="plain"> *) </span><span class="identifier">cmd</span><span class="plain">, </span><span class="identifier">NULL</span><span class="plain">};</span>
|
|
<span class="identifier">pid_t</span><span class="plain"> </span><span class="identifier">pid</span><span class="plain">;</span>
|
|
<span class="identifier">int</span><span class="plain"> </span><span class="identifier">status</span><span class="plain"> = </span><span class="identifier">posix_spawn</span><span class="plain">(&</span><span class="identifier">pid</span><span class="plain">, </span><span class="string">"/bin/sh"</span><span class="plain">, </span><span class="identifier">NULL</span><span class="plain">, </span><span class="identifier">NULL</span><span class="plain">, </span><span class="identifier">argv</span><span class="plain">, </span><span class="identifier">environ</span><span class="plain">);</span>
|
|
<span class="identifier">if</span><span class="plain"> (</span><span class="identifier">status</span><span class="plain"> == </span><span class="constant">0</span><span class="plain">) {</span>
|
|
<span class="identifier">if</span><span class="plain"> (</span><span class="identifier">waitpid</span><span class="plain">(</span><span class="identifier">pid</span><span class="plain">, &</span><span class="identifier">status</span><span class="plain">, </span><span class="constant">0</span><span class="plain">) != -1) </span><span class="identifier">return</span><span class="plain"> </span><span class="identifier">status</span><span class="plain">;</span>
|
|
<span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"waitpid failed"</span><span class="plain">);</span>
|
|
<span class="plain">} </span><span class="identifier">else</span><span class="plain"> {</span>
|
|
<span class="identifier">WRITE_TO</span><span class="plain">(</span><span class="constant">STDERR</span><span class="plain">, </span><span class="string">"posix_spawn: %s\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">strerror</span><span class="plain">(</span><span class="identifier">status</span><span class="plain">));</span>
|
|
<span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"posix_spawn failed"</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
<span class="identifier">return</span><span class="plain"> -1;</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::system is used in <a href="#SP10">§10</a>, <a href="#SP14">§14</a>, 1/wp (<a href="1-wp.html#SP6">§6</a>), 3/shl (<a href="3-shl.html#SP5">§5</a>).</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP12"></a><b>§12. Directory handling. </b></p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="identifier">int</span><span class="plain"> </span><span class="functiontext">Platform::mkdir</span><span class="plain">(</span><span class="identifier">char</span><span class="plain"> *</span><span class="identifier">transcoded_pathname</span><span class="plain">) {</span>
|
|
<span class="identifier">errno</span><span class="plain"> = </span><span class="constant">0</span><span class="plain">;</span>
|
|
<span class="identifier">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="identifier">if</span><span class="plain"> (</span><span class="identifier">rv</span><span class="plain"> == </span><span class="constant">0</span><span class="plain">) </span><span class="identifier">return</span><span class="plain"> </span><span class="constant">TRUE</span><span class="plain">;</span>
|
|
<span class="identifier">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="identifier">return</span><span class="plain"> </span><span class="constant">TRUE</span><span class="plain">;</span>
|
|
<span class="identifier">return</span><span class="plain"> </span><span class="constant">FALSE</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
|
|
<span class="identifier">void</span><span class="plain"> *</span><span class="functiontext">Platform::opendir</span><span class="plain">(</span><span class="identifier">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="identifier">return</span><span class="plain"> (</span><span class="identifier">void</span><span class="plain"> *) </span><span class="identifier">dirp</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
|
|
<span class="identifier">int</span><span class="plain"> </span><span class="functiontext">Platform::readdir</span><span class="plain">(</span><span class="identifier">void</span><span class="plain"> *</span><span class="identifier">folder</span><span class="plain">, </span><span class="identifier">char</span><span class="plain"> *</span><span class="identifier">path_to_folder</span><span class="plain">, </span><span class="identifier">char</span><span class="plain"> *</span><span class="identifier">leafname</span><span class="plain">) {</span>
|
|
<span class="identifier">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="identifier">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="identifier">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="identifier">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="identifier">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="identifier">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">-></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">, &</span><span class="identifier">file_status</span><span class="plain">);</span>
|
|
<span class="identifier">if</span><span class="plain"> (</span><span class="identifier">rv</span><span class="plain"> != </span><span class="constant">0</span><span class="plain">) </span><span class="identifier">return</span><span class="plain"> </span><span class="constant">FALSE</span><span class="plain">;</span>
|
|
<span class="identifier">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">-></span><span class="identifier">d_name</span><span class="plain">);</span>
|
|
<span class="identifier">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">-></span><span class="identifier">d_name</span><span class="plain">);</span>
|
|
<span class="identifier">return</span><span class="plain"> </span><span class="constant">TRUE</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
|
|
<span class="identifier">void</span><span class="plain"> </span><span class="functiontext">Platform::closedir</span><span class="plain">(</span><span class="identifier">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">§7</a>), 3/pth (<a href="3-pth.html#SP8">§8</a>).</p>
|
|
|
|
<p class="endnote">The function Platform::opendir is used in 1/wp (<a href="1-wp.html#SP7">§7</a>), 3/drc (<a href="3-drc.html#SP2">§2</a>).</p>
|
|
|
|
<p class="endnote">The function Platform::readdir is used in 1/wp (<a href="1-wp.html#SP7">§7</a>), 3/drc (<a href="3-drc.html#SP2">§2</a>).</p>
|
|
|
|
<p class="endnote">The function Platform::closedir is used in 1/wp (<a href="1-wp.html#SP7">§7</a>), 3/drc (<a href="3-drc.html#SP2">§2</a>).</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP13"></a><b>§13. Timestamp. </b>There are implementations of the C standard library where <code class="display"><span class="extract">time_t</span></code> has
|
|
super-weird behaviour, but on almost POSIX systems, time 0 corresponds to
|
|
midnight on 1 January 1970. All we really need is that the "never" value
|
|
is one which is earlier than any possible timestamp on the files we'll
|
|
be dealing with.
|
|
</p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="identifier">time_t</span><span class="plain"> </span><span class="functiontext">Platform::never_time</span><span class="plain">(</span><span class="identifier">void</span><span class="plain">) {</span>
|
|
<span class="identifier">return</span><span class="plain"> (</span><span class="identifier">time_t</span><span class="plain">) </span><span class="constant">0</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
|
|
<span class="identifier">time_t</span><span class="plain"> </span><span class="functiontext">Platform::timestamp</span><span class="plain">(</span><span class="identifier">char</span><span class="plain"> *</span><span class="identifier">transcoded_filename</span><span class="plain">) {</span>
|
|
<span class="identifier">struct</span><span class="plain"> </span><span class="identifier">stat</span><span class="plain"> </span><span class="identifier">filestat</span><span class="plain">;</span>
|
|
<span class="identifier">if</span><span class="plain"> (</span><span class="identifier">stat</span><span class="plain">(</span><span class="identifier">transcoded_filename</span><span class="plain">, &</span><span class="identifier">filestat</span><span class="plain">) != -1) </span><span class="identifier">return</span><span class="plain"> </span><span class="identifier">filestat</span><span class="plain">.</span><span class="identifier">st_mtime</span><span class="plain">;</span>
|
|
<span class="identifier">return</span><span class="plain"> </span><span class="functiontext">Platform::never_time</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::never_time is used in 1/wp (<a href="1-wp.html#SP12">§12</a>).</p>
|
|
|
|
<p class="endnote">The function Platform::timestamp is used in 1/wp (<a href="1-wp.html#SP12">§12</a>), 3/fln (<a href="3-fln.html#SP12">§12</a>).</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP14"></a><b>§14. Sync. </b>Both names here are of directories which do exist. The function makes
|
|
the <code class="display"><span class="extract">dest</span></code> tree an exact copy of the <code class="display"><span class="extract">source</span></code> tree (and therefore deletes
|
|
anything different which was originally in <code class="display"><span class="extract">dest</span></code>).
|
|
</p>
|
|
|
|
<p class="inwebparagraph">In POSIX world, we can fairly well depend on <code class="display"><span class="extract">rsync</span></code> being around:
|
|
</p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="identifier">void</span><span class="plain"> </span><span class="functiontext">Platform::rsync</span><span class="plain">(</span><span class="identifier">char</span><span class="plain"> *</span><span class="identifier">transcoded_source</span><span class="plain">, </span><span class="identifier">char</span><span class="plain"> *</span><span class="identifier">transcoded_dest</span><span class="plain">) {</span>
|
|
<span class="identifier">char</span><span class="plain"> </span><span class="identifier">rsync_command</span><span class="plain">[10*</span><span class="constant">MAX_FILENAME_LENGTH</span><span class="plain">];</span>
|
|
<span class="identifier">sprintf</span><span class="plain">(</span><span class="identifier">rsync_command</span><span class="plain">, </span><span class="string">"rsync -a --delete "</span><span class="plain">);</span>
|
|
<span class="functiontext">Platform::quote_text</span><span class="plain">(</span><span class="identifier">rsync_command</span><span class="plain"> + </span><span class="identifier">strlen</span><span class="plain">(</span><span class="identifier">rsync_command</span><span class="plain">), </span><span class="identifier">transcoded_source</span><span class="plain">, </span><span class="constant">TRUE</span><span class="plain">);</span>
|
|
<span class="identifier">sprintf</span><span class="plain">(</span><span class="identifier">rsync_command</span><span class="plain"> + </span><span class="identifier">strlen</span><span class="plain">(</span><span class="identifier">rsync_command</span><span class="plain">), </span><span class="string">" "</span><span class="plain">);</span>
|
|
<span class="functiontext">Platform::quote_text</span><span class="plain">(</span><span class="identifier">rsync_command</span><span class="plain"> + </span><span class="identifier">strlen</span><span class="plain">(</span><span class="identifier">rsync_command</span><span class="plain">), </span><span class="identifier">transcoded_dest</span><span class="plain">, </span><span class="constant">FALSE</span><span class="plain">);</span>
|
|
<span class="functiontext">Platform::system</span><span class="plain">(</span><span class="identifier">rsync_command</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
|
|
<span class="identifier">void</span><span class="plain"> </span><span class="functiontext">Platform::quote_text</span><span class="plain">(</span><span class="identifier">char</span><span class="plain"> *</span><span class="identifier">quoted</span><span class="plain">, </span><span class="identifier">char</span><span class="plain"> *</span><span class="identifier">raw</span><span class="plain">, </span><span class="identifier">int</span><span class="plain"> </span><span class="identifier">terminate</span><span class="plain">) {</span>
|
|
<span class="identifier">quoted</span><span class="plain">[0] = </span><span class="constant">SHELL_QUOTE_CHARACTER</span><span class="plain">;</span>
|
|
<span class="identifier">int</span><span class="plain"> </span><span class="identifier">qp</span><span class="plain"> = </span><span class="constant">1</span><span class="plain">;</span>
|
|
<span class="identifier">for</span><span class="plain"> (</span><span class="identifier">int</span><span class="plain"> </span><span class="identifier">rp</span><span class="plain"> = </span><span class="constant">0</span><span class="plain">; </span><span class="identifier">raw</span><span class="plain">[</span><span class="identifier">rp</span><span class="plain">]; </span><span class="identifier">rp</span><span class="plain">++) {</span>
|
|
<span class="identifier">char</span><span class="plain"> </span><span class="identifier">c</span><span class="plain"> = </span><span class="identifier">raw</span><span class="plain">[</span><span class="identifier">rp</span><span class="plain">];</span>
|
|
<span class="identifier">if</span><span class="plain"> (</span><span class="identifier">c</span><span class="plain"> == </span><span class="constant">SHELL_QUOTE_CHARACTER</span><span class="plain">) </span><span class="identifier">quoted</span><span class="plain">[</span><span class="identifier">qp</span><span class="plain">++] = </span><span class="character">'\</span><span class="plain">\</span><span class="character">'</span><span class="plain">;</span>
|
|
<span class="identifier">quoted</span><span class="plain">[</span><span class="identifier">qp</span><span class="plain">++] = </span><span class="identifier">c</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
<span class="identifier">if</span><span class="plain"> (</span><span class="identifier">terminate</span><span class="plain">) </span><span class="identifier">quoted</span><span class="plain">[</span><span class="identifier">qp</span><span class="plain">++] = </span><span class="constant">FOLDER_SEPARATOR</span><span class="plain">;</span>
|
|
<span class="identifier">quoted</span><span class="plain">[</span><span class="identifier">qp</span><span class="plain">++] = </span><span class="constant">SHELL_QUOTE_CHARACTER</span><span class="plain">;</span>
|
|
<span class="identifier">quoted</span><span class="plain">[</span><span class="identifier">qp</span><span class="plain">++] = </span><span class="constant">0</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::rsync is used in 3/pth (<a href="3-pth.html#SP9">§9</a>).</p>
|
|
|
|
<p class="endnote">The function Platform::quote_text appears nowhere else.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP15"></a><b>§15. Sleep. </b></p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="identifier">void</span><span class="plain"> </span><span class="functiontext">Platform::sleep</span><span class="plain">(</span><span class="identifier">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="identifier">unsigned</span><span class="plain"> </span><span class="identifier">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">§8</a>).</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP16"></a><b>§16. 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="identifier">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="identifier">int</span><span class="plain"> </span><span class="identifier">happy</span><span class="plain">) {</span>
|
|
<span class="identifier">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="identifier">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="#SP17">§17</a>, 1/wp (<a href="1-wp.html#SP9">§9</a>).</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP17"></a><b>§17. </b></p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="identifier">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="identifier">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="#SP16">§16</a>, 1/wp (<a href="1-wp.html#SP9">§9</a>).</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP18"></a><b>§18. Concurrency. </b></p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="identifier">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="identifier">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="SP19"></a><b>§19. </b></p>
|
|
|
|
|
|
<pre class="display">
|
|
<span class="identifier">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="identifier">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="identifier">void</span><span class="plain"> *(*</span><span class="identifier">fn</span><span class="plain">)(</span><span class="identifier">void</span><span class="plain"> *), </span><span class="identifier">void</span><span class="plain"> *</span><span class="identifier">arg</span><span class="plain">) {</span>
|
|
<span class="identifier">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="identifier">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="identifier">void</span><span class="plain">** </span><span class="identifier">rv</span><span class="plain">) {</span>
|
|
<span class="identifier">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="identifier">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">if</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="constant">0</span><span class="plain">) </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"thread initialisation failed"</span><span class="plain">);</span>
|
|
<span class="identifier">if</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="constant">0</span><span class="plain">) </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"thread stack sizing failed"</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">, &</span><span class="identifier">mystacksize</span><span class="plain">);</span>
|
|
<span class="identifier">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">§11</a>).</p>
|
|
|
|
<p class="endnote">The function Platform::join_thread is used in 1/wp (<a href="1-wp.html#SP11">§11</a>).</p>
|
|
|
|
<p class="endnote">The function Platform::init_thread is used in 1/wp (<a href="1-wp.html#SP11">§11</a>).</p>
|
|
|
|
<p class="endnote">The function Platform::get_thread_stack_size is used in 1/wp (<a href="1-wp.html#SP11">§11</a>).</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP20"></a><b>§20. 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="identifier">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">(&</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">(&</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>
|
|
|
|
<hr class="tocbar">
|
|
<ul class="toc"><li><a href="1-fnd.html">Back to 'Foundation'</a></li><li><a href="1-wp.html">Continue with 'Windows Platform'</a></li></ul><hr class="tocbar">
|
|
<!--End of weave-->
|
|
</main>
|
|
</body>
|
|
</html>
|
|
|